rgl/0000755000176200001440000000000015026777212011047 5ustar liggesusersrgl/tests/0000755000176200001440000000000015026603601012177 5ustar liggesusersrgl/tests/indices.R0000644000176200001440000000164014771520323013746 0ustar liggesuserslibrary(rgl) tet <- tetrahedron3d() open3d() segments3d(t(tet$vb[1:3,]), indices = c(1,2,1,3,1,4,2,3,2,4,3,4)) open3d() text3d(t(tet$vb[1:3,]), text=1:4) triangles3d(t(tet$vb[1:3,]), indices = c(1,2,3,1,4,2,1,3,4,2,4,3), col = "red") # This displayed a triangle for the red quad (issue #154) quad <- cbind(x = c(-1, 1, 1, -1), y = c( 0, 0, 0, 0), z = c(-1, -1, 1, 1))/2 open3d() triangles3d(quad, alpha = 0.5, col = "red", indices=c(1,2,3,1,3,4)) id <- triangles3d(quad+1, col = "blue", indices=c(1,2,3,1,3,4)) # These signalled errors or warnings tri <- as.triangles3d(id) m <- as.mesh3d(id) filename <- tempfile(fileext = ".ply") writePLY(filename) unlink(filename) filename <- tempfile(fileext = ".obj") writeOBJ(filename, separateObjects = FALSE) readOBJ(filename) unlink(filename) filename <- tempfile(fileext = ".stl") writeSTL(filename) readSTL(filename) unlink(filename) rgl/tests/userTexture.R0000644000176200001440000000664714771520323014703 0ustar liggesuserslibrary(rgl) open3d() set.seed(3) x <- cube3d(col="white", texture = system.file("textures/rgl2.png", package = "rgl"), texcoords = matrix(runif(16), ncol=2)) id <- shade3d(x) # rglwidget() vShader <- " /* ****** quads object 13 vertex shader ****** */ #ifdef GL_ES #ifdef GL_FRAGMENT_PRECISION_HIGH precision highp float; #else precision mediump float; #endif #endif attribute vec3 aPos; attribute vec4 aCol; uniform mat4 mvMatrix; uniform mat4 prMatrix; varying vec4 vCol; varying vec4 vPosition; attribute vec3 aNorm; uniform mat4 normMatrix; varying vec4 vNormal; attribute vec2 aTexcoord; varying vec2 vTexcoord; void main(void) { vPosition = mvMatrix * vec4(aPos, 1.); gl_Position = prMatrix * vPosition; vCol = aCol; vNormal = normMatrix * vec4(-aNorm, dot(aNorm, aPos)); vNormal = vec4(normalize(vNormal.xyz/vNormal.w), 1); vTexcoord = aTexcoord; } " fShader <- " /* ****** quads object 13 fragment shader ****** */ #ifdef GL_ES #ifdef GL_FRAGMENT_PRECISION_HIGH precision highp float; #else precision mediump float; #endif #endif varying vec4 vCol; // carries alpha varying vec4 vPosition; varying vec2 vTexcoord; uniform sampler2D uSampler; uniform sampler2D userSampler; uniform int uFogMode; uniform vec3 uFogColor; uniform vec4 uFogParms; varying vec4 vNormal; uniform mat4 mvMatrix; uniform vec3 emission; uniform float shininess; uniform vec3 ambient0; uniform vec3 specular0; // light*material uniform vec3 diffuse0; uniform vec3 lightDir0; uniform bool viewpoint0; uniform bool finite0; void main(void) { vec4 fragColor; vec3 n = normalize(vNormal.xyz + texture2D(userSampler, vTexcoord).rgb); vec3 eye = normalize(-vPosition.xyz/vPosition.w); vec3 lightdir; vec4 colDiff; vec3 halfVec; vec4 lighteffect = vec4(emission, 0.); vec3 col; float nDotL; n = -faceforward(n, n, eye); colDiff = vec4(vCol.rgb * diffuse0, vCol.a); lightdir = lightDir0; if (!viewpoint0) lightdir = (mvMatrix * vec4(lightdir, 1.)).xyz; if (!finite0) { halfVec = normalize(lightdir + eye); } else { lightdir = normalize(lightdir - vPosition.xyz/vPosition.w); halfVec = normalize(lightdir + eye); } col = ambient0; nDotL = dot(n, lightdir); col = col + max(nDotL, 0.) * colDiff.rgb; col = col + pow(max(dot(halfVec, n), 0.), shininess) * specular0; lighteffect = lighteffect + vec4(col, colDiff.a); vec4 textureColor = lighteffect*vec4(1.,1.,1.,1.); fragColor = textureColor; float fogF; if (uFogMode > 0) { fogF = (uFogParms.y - vPosition.z/vPosition.w)/(uFogParms.y - uFogParms.x); if (uFogMode > 1) fogF = mix(uFogParms.w, 1.0, fogF); fogF = fogF*uFogParms.z; if (uFogMode == 2) fogF = 1.0 - exp(-fogF); else if (uFogMode == 3) fogF = 1.0 - exp(-fogF*fogF); fogF = clamp(fogF, 0.0, 1.0); gl_FragColor = vec4(mix(fragColor.rgb, uFogColor, fogF), fragColor.a); } else gl_FragColor = fragColor; } " s <- setUserShaders(id, vertexShader = vShader, fragmentShader = fShader, textures = c(userSampler = system.file("textures/rgl2.png", package = "rgl"), unusedSampler = system.file("textures/rgl2.png", package = "rgl")), uniforms = list(unusedUniform = 3), attributes = list(unusedAttribute = 1:10)) rglwidget(s) rgl/tests/boundary.R0000644000176200001440000000054014771520323014151 0ustar liggesuserslibrary(rgl) # WORKING x <- cube3d() b <- getBoundary3d(x) open3d(); shade3d(b) x <- cube3d() x$ib <- x$ib[,-(1:2)] b <- getBoundary3d(x) open3d(); shade3d(x, alpha=0.2, col = "blue"); shade3d(b) x <- cube3d() x$ib <- x$ib[,-(1:2)] b <- getBoundary3d(x, sorted = TRUE, simplify = FALSE) open3d(); shade3d(x, alpha=0.2, col = "blue"); shade3d(b) rgl/tests/unfixed.R0000644000176200001440000000114214771520323013767 0ustar liggesuserslibrary(rgl) mfrow3d(2,2, sharedMouse = TRUE) sprites3d( rnorm(10) + 6, rnorm(10), rnorm(10), shape = shade3d(tetrahedron3d(), col = "red"), rotating = FALSE, fixedSize = FALSE) next3d() sprites3d( rnorm(10) + 6, rnorm(10), rnorm(10), shape = shade3d(tetrahedron3d(), col = "red"), rotating = FALSE, fixedSize = TRUE) next3d() sprites3d( rnorm(10) + 6, rnorm(10), rnorm(10), shape = shade3d(tetrahedron3d(), col = "red"), rotating = TRUE, fixedSize = FALSE) next3d() sprites3d( rnorm(10) + 6, rnorm(10), rnorm(10), shape = shade3d(tetrahedron3d(), col = "red"), rotating = TRUE, fixedSize = TRUE) rglwidget() rgl/tests/bbox3dtests.R0000644000176200001440000000315414771520323014576 0ustar liggesusers# Tests of bbox3d improvements library(rgl) x <- cube3d(col="red", front="culled", back="filled"); open3d(); shade3d(x); rglwidget() open3d();points3d(1:10, 11:20, 21:30); bbox3d(col="red", lit=FALSE,draw_front=TRUE); rglwidget() open3d();points3d(1:10, 11:20, 21:30); bbox3d(col="red", lit=TRUE,draw_front=TRUE); rglwidget() open3d();points3d(1:10, 11:20, 21:30); bbox3d(col="red", lit=TRUE,draw_front=TRUE, front="lines", back = "lines"); rglwidget() open3d();points3d(1:10, 11:20, 21:30); bbox3d(col="red", lit=TRUE,draw_front=TRUE, front="lines", back = "lines"); rglwidget() open3d();points3d(1:10, 11:20, 21:30); bbox3d(col="red", lit=TRUE,draw_front=TRUE, front="lines", back = "filled"); rglwidget() open3d();points3d(1:10, 11:20, 21:30); bbox3d(col="red", lit=TRUE,draw_front=FALSE, front="lines", back = "lines"); rglwidget() open3d();points3d(1:10, 11:20, 21:30); bbox3d(col="red", lit=TRUE,draw_front=FALSE, front="filled", back = "culled"); rglwidget() open3d();points3d(1:10, 11:20, 21:30); bbox3d(col="red", lit=TRUE,draw_front=FALSE, front="culled", back = "filled"); rglwidget() open3d();points3d(1:10, 11:20, 21:30); bbox3d(col="red", lit=FALSE,draw_front=FALSE); rglwidget() open3d();points3d(1:10, 11:20, 21:30); bbox3d(col="red", lit=TRUE,draw_front=FALSE); rglwidget() example(bbox3d); rglwidget() open3d(); spheres3d(rnorm(10), rnorm(10), rnorm(10), radius = runif(10), color = rainbow(10)); rglwidget() open3d(); spheres3d(rnorm(10), rnorm(10), rnorm(10), radius = runif(10), color = rainbow(10), front = "lines", back="culled"); rglwidget() rgl/tests/testthat/0000755000176200001440000000000015026777212014051 5ustar liggesusersrgl/tests/testthat/test-surfaces.R0000644000176200001440000000131114771520323016753 0ustar liggesuserslibrary(rgl) test_that("surface dimensions work", { x <- 1:3 y <- 1:5 z <- matrix(1:15, 3, 5) open3d() surface3d(x, y, z, col = "red") surface3d(x, z, y, col = "blue") surface3d(z, y, x, col = "green") surface3d(x, z, z, col = "purple") surface3d(z, y, z, col = "orange") surface3d(z, z, y, col = "brown") surface3d(z, z, z, col = "white") surface3d(x, y, as.numeric(z + 1), col = "black") expect_error( surface3d(y, x, z)) expect_error( surface3d(y, z, x)) expect_error( surface3d(z, x, y)) expect_error( surface3d(y, z, z)) expect_error( surface3d(z, z, x)) expect_error( surface3d(z, x, z)) expect_error( surface3d(as.numeric(z), y, x)) expect_error( surface3d(x, as.numeric(z), y)) }) rgl/tests/testthat/test-r3d.R0000644000176200001440000000111114771520323015626 0ustar liggesusersset.seed(123) test_that("3D sprites work", { open3d() # Warning: these tests depend on order of evaluation # of the x, y, z arguments in sprites3d. particles3d( rnorm(100), rnorm(100), rnorm(100), color = rainbow(100) ) # is the same as sprites3d( rnorm(100), rnorm(100), rnorm(100), color = rainbow(100), lit = FALSE, alpha = .2, textype = "alpha", texture = system.file("textures/particle.png", package = "rgl") ) sprites3d( rnorm(10) + 6, rnorm(10), rnorm(10), shape = shade3d(tetrahedron3d(), col = "red") ) expect_known_scene("r3d") }) rgl/tests/testthat/test-getShaders.R0000644000176200001440000000032314771520323017233 0ustar liggesuserslibrary(rgl) test_that("getShaders works", { x <- 1:3 y <- 1:5 z <- matrix(1:15, 3, 5) open3d() id <- surface3d(x, y, z, col = "red") if (requireNamespace("V8")) expect_no_condition(getShaders(id)) }) rgl/tests/testthat/test-user2window.R0000644000176200001440000000140214771520323017431 0ustar liggesuserslibrary(rgl) test_that("rgl.user2window and rgl.window2user work", { xyz <- rbind(x = c(2, 4, 6)) abc <- rbind(x = c(0.1, 0.2, 0.3)) open3d() mfrow3d(2, 2) points3d(1:10, 1:10, 1:10) expect_equal(rgl.window2user(rgl.user2window(xyz)), xyz) expect_equal(rgl.user2window(rgl.window2user(abc)), abc) next3d() points3d(1:10, 1:10, 1:10) expect_equal(rgl.window2user(rgl.user2window(xyz)), xyz) expect_equal(rgl.user2window(rgl.window2user(abc)), abc) next3d() points3d(1:10, 1:10, 1:10) expect_equal(rgl.window2user(rgl.user2window(xyz)), xyz) expect_equal(rgl.user2window(rgl.window2user(abc)), abc) next3d() points3d(1:10, 1:10, 1:10) expect_equal(rgl.window2user(rgl.user2window(xyz)), xyz) expect_equal(rgl.user2window(rgl.window2user(abc)), abc) }) rgl/tests/testthat/test-tags.R0000644000176200001440000000154114771520323016103 0ustar liggesuserslibrary(rgl) test_that("tags work", { material3d(tag = "hello") expect_equal(material3d("tag"), "hello") file <- normalizePath(system.file("textures/worldsmall.png", package = "rgl")) material3d(texture = file) expect_equal(material3d("texture"), file) expect_equal(material3d("tag"), "hello") open3d() x <- points3d(1,2,3, tag = "hello2") expect_equal(unclass(x), tagged3d("hello2")) expect_equal(unclass(x), tagged3d("hello2", full = TRUE)$id) expect_equal(tagged3d(ids = x), "hello2") }) test_that("pop3d works on tags", { open3d() id1 <- points3d(1,1,1, tag = "id1") newSubscene3d() id2 <- points3d(2,2,2, tag = "id2") pop3d(tag = "id1") expect_equal(ids3d(subscene = 0, tags = TRUE), data.frame(id = as.numeric(id2), type = "points", tag = "id2")) }) rgl/tests/testthat/test-shapelist3d.R0000644000176200001440000000027515011677075017400 0ustar liggesuserstest_that("shapelist3d works with col (issue #462)", { col <- 1:5 open3d() shapelist3d(cube3d(), x = 1:2, y = 1, z = 1, col = c("red", "blue")) expect_known_scene("shapelist3d") }) rgl/tests/testthat/conversions.R0000644000176200001440000000244614771520323016545 0ustar liggesuserstest_that("asEuclidean works", { expect_equal(asEuclidean(c(1,2,3)), asEuclidean(matrix(c(1,2,3), ncol = 3))) expect_equal(asEuclidean(c(1,2,3)), asEuclidean(matrix(c(1,2,3,1), ncol = 4))) expect_equal(asEuclidean(c(1,2,3)), asEuclidean(c(2,4,6,2))) expect_equal(dim(asEuclidean(1:24)), c(6,3)) }) test_that("asEuclidean2 works", { expect_equal(asEuclidean2(c(1,2,3)), asEuclidean2(matrix(c(1,2,3), nrow = 3))) expect_equal(asEuclidean2(c(1,2,3)), asEuclidean2(matrix(c(1,2,3,1), nrow = 4))) expect_equal(asEuclidean2(c(1,2,3)), asEuclidean2(c(2,4,6,2))) expect_equal(dim(asEuclidean2(1:24)), c(3,6)) }) test_that("asHomogeneous works", { expect_equal(asHomogeneous(c(1,2,3)), asHomogeneous(matrix(c(1,2,3), ncol = 3))) expect_equal(asHomogeneous(c(1,2,3)), asHomogeneous(matrix(c(1,2,3,1), ncol = 4))) expect_equal(asHomogeneous(c(1,2,3)), asHomogeneous(c(1,2,3,1))) expect_equal(dim(asHomogeneous(1:24)), c(8,4)) }) test_that("asHomogeneous2 works", { expect_equal(asHomogeneous2(c(1,2,3)), asHomogeneous2(matrix(c(1,2,3), nrow = 3))) expect_equal(asHomogeneous2(c(1,2,3)), asHomogeneous2(matrix(c(1,2,3,1), nrow = 4))) expect_equal(asHomogeneous2(c(1,2,3)), asHomogeneous2(c(1,2,3,1))) expect_equal(dim(asHomogeneous2(1:24)), c(4,8)) }) rgl/tests/testthat/test-mesh3d.R0000644000176200001440000000232414771520323016330 0ustar liggesuserstest_that("ensureMatrix works", { expect_equal(dim(ensureMatrix(1, nrow=1)), c(1,1)) }) test_that("mesh3d works", { expect_s3_class(mesh3d(1:3, 1:3, 4, triangles=1:3), "mesh3d") }) test_that("tmesh3d works", { open3d() m <- tmesh3d(rbind(1, 2, 1:3), 1:3, homogeneous=FALSE) expect_s3_class(m, "mesh3d") expect_named(m, c("vb", "it", "material", "normals", "texcoords", "meshColor"), ignore.order = TRUE) shade3d(m) expect_known_scene("tmesh3d") }) test_that("qmesh3d works", { open3d() m <- qmesh3d(rbind(1, 2, 1:4), 1:4, homogeneous=FALSE) expect_s3_class(m, "mesh3d") expect_named(m, c("vb", "ib", "material", "normals", "texcoords", "meshColor"), ignore.order = TRUE) shade3d(m) expect_known_scene("qmesh3d") }) test_that("shade3d, wire3d and dot3d work", { open3d() mesh <- cuboctahedron3d(col = "red") shade3d(mesh) wire3d(translate3d(mesh, 1,1,1)) dot3d(translate3d(mesh, 2,2,2)) expect_known_scene("shade3detc") }) test_that("transformations work", { open3d() mesh <- cuboctahedron3d(col = "red") shade3d(translate3d(mesh, 1,2,3)) shade3d(rotate3d(mesh, 35, 1,2,3)) shade3d(scale3d(mesh, 1,2,3)) expect_known_scene("transformations", tolerance = 1.e-5) }) rgl/tests/testthat/test-as.mesh3d.R0000644000176200001440000000076414771520323016740 0ustar liggesuserstest_that("mergeVertices works", { # Pre 4.0.0, stringsAsFactors defaulted to TRUE options(stringsAsFactors = FALSE) open3d() col <- rainbow(14) # Older R versions added FF for default alpha=1 col <- sub("^(#......)FF$", "\\1", col) (mesh1 <- cuboctahedron3d(col = col, meshColor = "face")) id <- shade3d(mesh1) (mesh2 <- as.mesh3d(id)) shade3d(translate3d(mesh2, 3, 0, 0)) (mesh3 <- mergeVertices(mesh2)) shade3d(translate3d(mesh3, 6, 0, 0)) expect_known_scene("mergeVertices") }) rgl/tests/testthat/test-obj.R0000644000176200001440000000126514771520323015722 0ustar liggesusersset.seed(123) test_that("readOBJ works", { # textured rectangular prism obj_file <- "# geometric vertices v 1 1 -0.125 v 1 -1 -0.125 v -1 -1 -0.125 v -1 1 -0.125 v 1 1 0.125 v 1 -1 0.125 v -1 -1 0.125 v -1 1 0.125 # texture coordinates vt 0.025 1 vt 0.025 0 vt 0.425 0 vt 0.425 1 vt 0.575 1 vt 0.575 0 vt 0.975 0 vt 0.975 1 vt 0.52 0 vt 0.48 0 vt 0.48 1 vt 0.52 1 # Textured polygonal face element f 1/1 2/2 3/3 4/4 f 5/5 8/8 7/7 6/6 f 6/9 7/10 3/11 2/12 f 7/9 8/10 4/11 3/12 f 8/9 5/10 1/11 4/12 f 5/9 6/10 2/11 1/12" filename <- tempfile(fileext = ".obj") writeLines(obj_file, filename) mesh <- readOBJ(filename) unlink(filename) open3d() shade3d(mesh) expect_known_scene("obj") }) rgl/tests/testthat/testdata/0000755000176200001440000000000015011677075015662 5ustar liggesusersrgl/tests/testthat/testdata/transformations.rds0000644000176200001440000000510415011677075021625 0ustar liggesusers[MGn6e%h9R=^#%`ٱEN;=33tݽ?"\8p@ C@@$(!"'+k;-,Uk-_Wޫ;ÊB~@m~>7!_|^v \ID3J Py:5@iN7 Ԑj}?e'p v&m1oh.Fe&l6.9`K)_z#eԇ/9v}V3:-)vX&m3)\Gae2,Ǽ0Z#IJAuܓPںMcX9mr[eζBM{G?xYMvPMwV3]]3t hɝQX< xB8DD:L*LBbBs|}7Z #G$ ?}nbv +(Wr>*G㿮Pn}Nɩ~0b9mEj!(L  *mEZ96$%"wFfaZ92ܪ)KɈ[H dx2Yl}9DOL]lcwJDS>sICΚ,í^i+1+ھqWKeL>-+JoE7Dػ81#2W~$ADuOY=s;{Y9? zȨ{ΜyX %vgz^Ne~TP>x7:dT7ש?Wq=؁~Y9U q .>9ҘV i:0zLa;:,w}RV[= 虝y׿g90IplH@v^o.qu8ʱn z2q_Sk9/b/wNA\ÿ| Y==#ՍAjZ5=v%շ?K|/=8T!]"ω*Ys<@_pj^Y%xޥ?LSJdb$WI*c\&VN_ǨxTf>yT$).&̏qPMAX0$2RPdh 2S# 4d~dHZ5}oJo?4X.cizQF\^e~d̏,./+^_[g/-\j z(~O+B3ܨ7$@VfٍA駿t2U ms"7}Joi_n҈}UݨG`2YL7[_$|>2ۉv]dK7}=g_RRJbϼxw`oKݭbLcޡZv82eJS&q GOt38g:䘚Vam<9ceegT#LȹQaTr:-~nV?1?G ͡i'vI{\7#/me' Yb'5$bArgl/tests/testthat/testdata/shade3detc.rds0000644000176200001440000000364315011677075020411 0ustar liggesusersMoDԻ8 JTiVpD "PKݡ棗+G~PBɁBBJ8phz6ڑ͛7o=|>(JUҦPg>z5Co>WdG2$K[N]m)vG|"_UPa:04&NL)6mzq5@˖TU%:N\طACb2A̾v)jGDvFٲt QՉMM5-Ia.L.\TcT \òq,ΫDvCgkCcukELoA:Av^Q e daR#šn bs78ƶ1 ^$PKt-st\ ؆.jB1A!YolDD=]o-lYj lF2³> ׊Ck:t>,#|ķq c?:CP=ցX_*n ?ߪ1Y6cZ[i?z7G613t-x^[?e/+E鎖~DD70LqQ3^2~x7ryRƱe7ckJ:>>3FYJtg']r^xVĥ v~ְ.:j~b9/av/oᶃC:1%IGܺBv ޳-;[k6->1-ʉe :G:ja<`NM5F ppH'M8tQB/!]|"SF vZx80E+G!@9ɷfkDY}*}.JX@$SuסcMnS΃ds#b8睮yjp2X|C\6u] -6Џ'N΄bxʏbx.+ϰg;9 ȢUUg%BU*Tk2ev25*W@Vݽ{ERoyE):וom)Tolg;8'Ιgy尵gg(]yzg8<d >cG=.z{F82ϡkpxcu].RPK%޺[뼵^wSP%zXp,˻Pȯϰ;dp pC`rBrgl/tests/testthat/testdata/mergeVertices.rds0000644000176200001440000000442015011677075021200 0ustar liggesusers\oj$YlQA ([ +@JAXff$!:E/ r]F%($HQESQ[y|||$EMӚZК-m"UׂIJ+xLT W;AR4Ge5MGKC>zgפ;JEM'ҫ)LjEK6IuyxJ'wI~Y>GZ1gW瘎 Dcˤ>au)Խ1Mk:Qǎ;6ӂПg9 \'ǐ3~܇K#a0W$t$AI:(H}&ˌaH>{=Nă^/Sװj]9ӡc9Gcj>A!-߀\$v? 14/M2r'QW`J.Ӥ]&x6Wv#l\igczţCV%ƹ1SȜKzhoBBPAZZaɟ&i>?axme=Ps=]h?n75G[}jiyq[ n-|xz<^Kpq2&ͤz.w{׿{.ʡ_$y XY: Ȫ/"Rma^'yڏV Vprt ez2-:!`zjkK#}tӣwށw?=??w? ޝ{;^ɛGkaէCqZ`Rą s葇;]G>7aq:Ixh]JW7Ug$=?s缞-%#Ǎ6vcj])r `AQz^[b츄|: ,M:z4:2B Gh/ &e`]22)Ff@i%cLtrzIՁ_M L;w̱=MxH.~9-Nɾ[4< \rf PP!aEDlæ=4 f?/`;7I+@]/@޻[dd2mEz_ Kgc\~._ޓ\()_^cw[Ғ3W"ۢD-ԟhz2n*PU?i qG5AG9Oo"ܬ_w)M3$2||tOtZWOqt:X0LG-,cb,(r^?>4xDvn.D]\]Im<؞xP6(!LA`AQyc8|yʫ~VTN6c"0 P<^@Sx=h4"1˖F▼,@RE0m3g,$MYm}%N*YID3?sFZ31yUUUU-~%Vu*"s}b|v֗Wa`Qk*ŢM`ܢ_2G%TU_~_eR§Ң+v[VR~m*Q DuMλ_ ~}j_k P5kg|Yw( I#*WYU{ׂQQWϘ ~yo#NUܷu=Rêbj*ZhNy*2pMN=M>OpV_Ah*>X*Êseh.&ƯjÛn@amu8C?u0[4%l( Q7Qn#ʽވrofk!}:~~-O*Hx_rgl/tests/testthat/testdata/r3d.rds0000644000176200001440000001357215011677075017074 0ustar liggesusers] xSUھmR XҎMWōM@p :6*2(( Ȧ$P-m]H7ZyoN@y)}ηs9rq7'xq뭤/ZD_o'wh\^p [ dnJJTgs9=rEDR֦T Q*F!y,u]J׻K/v. uɉrUFVWQ$DG'vᣑz!0Y(p(Q) $BC>Cl$mP+zVc7.]F[j֐NvY$y zWQصgTm RcHk JJ){נeS8: ('Pg z@cιLƔ Ma@"Ðg%zSF'3:GX{ehUӴDmj^AK4% _J+7(54 $QCxgA?3I(lȭN~}$ǩtzlݧA{Tt~MTrVvth&-Θie8NJ)Q(OVBb$졿Ɲ74\T}EO|FVNe֬FE ~TBzgTTBL\Yϒ=]WgUWF3ZFL=6?pLh@v[gC1xq}bܮ.v.~$50u?,iN7UJ*t_W0Q"C'(ڙd>Peklݵ2U@ѠLV)Ф%A޳}x5)&\S^+NO'q14H:,n'tmlBMd˨#~ ֱ \ Z&ow4~˱2B=*r>(Kwjʊ>w,:~1B0ZχڄD@;ϯ?B56@yMˠ1e<\`go`W)f_i 3~v-_@ص{ZބO$_S Uom6n%?>~/y(w`Af;b2GGK{g\wr|q~@Ny_?I=`Oݽ<5fT1˸\M={YC\kv,~[#7Bo7-'8럁+-XzQ V<zb:3OYX"ʣ_[x/=o[z~ =9%)|[xqcw0 쾐=Vw{oS9kxį ĹE^ܒѤĩ{@o6o jW}v^ ~L);SdC_C쿄B ۓ'CY2˸}>u*s"l}zޏvaOϭ u{ Roþ1SOg!BkFK#?&rd'Ᏹx;>H譞cgbоaSd0zCw^!T{3n; =_L>X=ڕX8_6D$5 ~L[ {>\:s WkC[S]sV@p̋/A^#ЪH/qjnߌZ4zZ`pF9s⡇w>|v[Z8l?Fۗ >$[rvwao kηl@yƏDF{;=៹Ŷ>< -1!.T݆cO7~.EJ9c[?g@voK''x}y| سa$]vmWvy'ފj- 7ܛxPkzՁáЮ㯿zy՝:ںo yO܎s#,=?οt>3Ms: J7H S":R\J]?1=Dol/"ΕMR辺U'ܪ /{b]L)w1vbv)w1NrS.)߸C5{Fw'rB~ rP~|S:yRIOy$+4ǙuS) bGWBAdasȗ?~P<}xX").s2\Cb{;2PK%$I?7x DhK BeĹВrB%sV*mЂDy~l6[zƃu :[t?yJ"f_ܕ˷Eq2UG!ʷM}Zn@I $:Ztr9vJ1 7˂ Ug'!>VrЕFBKpxg4ޤ}t1?{/쵌 d>?X`G#5R1_V8$G>Iпa@Ρד={c~w1T|QNv]ÌCټ$:-[;_%W O,>x(/VBwM΂Sk |lV;ڟ/N|4.X;-&rM^ѥo|LHbֿ} |Sw$ȩ۱~7~mՇ{'KP/ǚ 3 UyuBbl#7 +~3 vW׾ yF- uo}|%oB;΃Bq~g$M BaÓoG: Bt(ߕT {"0$]烍ЏMcҼ? r^{;(eoƖ~dޚ{`_r!IcIiOcBLIȱlJJvosO''E;?<@H{q=\/%Z$ }dlzYBvG AWi漡ӧ!dow?k}(?b1?GŸNY _nME{c/!b> q0n+NuEr!$33?ߺY$cSƧ `m^灿W񍐴^N.[򎻄d>o`[P?=m< ?v?-$6Boِk:VB3/gO|qəC#䪠o۾6[Ռv**_C͟C)hװP CnAjxؗ[+r )}7D}ˈTѰ).tQ>]Wgn |2ɋо"o>v6@gujA~sM1Gy˟E껄}@Ej7KF}"=7O؋;D}ޓП{Nmfl;ԟ Iy 4KH25=_c{1Tx?,EF!r\5 _Zr®"D~(Cj"m /Z_{rͯ~jO3Ql= O>MomyQ"?M!|In $=(ʼ Yw|,g_$|yoOI{ǟ H>5I_ C&Cƭ 0-rqZ de@0Ĺrϻ&sF7OY:qѧi\͇ζᦻtw%;n#\:.i_s>}>c~!w$QPM4C ifFY'LU\5 Սs|.zsY\T«2r]aV3B}ƍk4!{z)_yǫAaDY_^+&%'px /Migwb".ݭ^'>E!: 9OxW5y1+h/y0_vHW8~M30XL^~81tӸ߅w`7$|j =LߜLrit}rgl/tests/testthat/testdata/obj.rds0000644000176200001440000000302315011677075017144 0ustar liggesusersMo5tvgw34!!B/*B$# [xwM=M^3 7~?@*P {f㝏l Kߗ Gl _ ]Q>3ЅSȜJi_MI(\Hts"^N(H+Bb,`D(YW"FYF# 07 $1aw@qG! ]%( 1!EsHKg{5}P u(p4(N235t9Orߧݟ`LS${p?OQ[amngpjǙ\nጺ> ~AֱvZ?UxUteQOu4d~,[o̬gpk;/ ֦K 7k GW!̽ NV.LjG8k 9Sh䱥U"2~@h& |m\xe'wӻ8dt籺OS7ⱁ|O%lMsa1"D#9 8+ rKRaܮ"=#u5og0`Z> }#9 stFyvȖ[;y6/ J[:l4wrWsQr(M]8h盖;mE#&(}:%r5.9MjFWuXXPa!E5(ܝURAR nS䋌>m;<&tU}xZMx~U9&^/Iqt-d .vne k=prW5MdVJ:{B,oA:\8::VɄ>}/ο^׶*lRߚ5k r U̮4l+){>P;<n|7Ԛb苶&I&ys̼o.֟5͛eL^^beaK@c2i/yiq_fʊA^DaZ$jOfiU^%5ZkmǪhz#kf4$sN[/Q]mqqz>T3饂 $5@R9EXTcΦ*wz/! /#pRkTZg]iQirŢ`^o@Ut2+D4M|{8Çݰ1WzN vZju@wq?s1 rgl/tests/testthat/testdata/tmesh3d.rds0000644000176200001440000000255415011677075017751 0ustar liggesusersM443ff?X GTsJH-TR68OƬGvfgw/-W~'EpTqBHı9N&vR{l8Nܞw=P?ۗ_>)hc-[C.a0R9Мot c6~](K2\Z# mb_?G5\u}#5|>|6E4]p͖ӳԞJHMIh@"4܆SqrRn8*$NK"^u/e,bɔt#P? e$ 8 sW!bA23"ܰp}\3c]Z4Oq}A.5@9cqy'NEio]DO42$Z!aHmZ`Ls3uDj} 3B/~Iz M$A `,65v;xG/ RDFB~,n\;}Y323e1ƣ{depޒ;FՀpA T{4;vS:X1>y:7X5XN^Wb!@m ͦLFyF I5-6ۣ{˩X=v#ΖaO+jZ<|̶B[쵇Fhg(7GlEC.pĜEYBwY6lѿ{׌ѧ;eGr1zXrgl/tests/testthat/testdata/subscenes.rds0000644000176200001440000007713515011677075020403 0ustar liggesusers}x*D+{M{ Dכ@҉ "{ {o;l `co}M#7W9SwŽ\lӆGe2q6G5-TtTȈ'hsGGU7hRY߱9meUC+6jݺYdTi٠eTq |:xTh22N]F11L89jCGlيZG6d#[FEŴkBBAkӦ4yoѨiKoߘ6i*:&UDEDGE=Md6mc#ɎI`R0պeDk8 Md3/i`V 8uf ZFĵ(&2VJlDVnݱiL1ME2bˈئQ&1mZrm"gё뮀WDŠ y6k*R^#;c|~Nϥg t_+Q0":bbZ:[9-sDt,է QMոq4Uh,22ZceKMU6X^)?c嶔x*\YϖwE"Pn>ZqTK8]^IuKni뙕wo u9e!Er=RmAxkԺ1z'g-Iߓ_W"xYhjU?[tx?:=&f,]Ps+y;*oG~y*55^GZS1qWn)S㎷/slȑ#lmOKt=:z(W:|G5mD6JQqV22+i|rzLøv8qfp~>MlpFؘEsZD86=s,ETdlԦp̭(~ .*}X{u|7lckժqLZ'{R2*G&uFlvAW GӃ5 p-#:<k@Fױ+TreBXN|`Ol(?G&,;/cio)8 站gy㬣o% Eǃk$\5UU~z-__/ 4MMQ> fe6(XWYpFdˆ;R0kFq 0rflh{P,Wv YAsoV(f>oVp2fG/ЛxoV` ZYA9;h??&ro"&'Sx"ptx ^*{o"D 겉@]*# aqVttطŵmqw<06"5cg}Ll;jބ;q۫w"b6#Z[!k=U>Y4sWAz{4{hwmoXF> _;.VàZh'e>/P.^S]vBq$ę̎놀 !;>l%l~ 3۴ߋtkK|̘!yuA~fi"sK/ۼiISUDCA}Pj`So1Ŏ6FeW#C:;RJ>/P.^S]vBq$ęf'~PCO@-Gn/ބ. )$t˲U>.е5ao&3raۣC~{7c^7{x#~=G^iRJ>/P.^S]vBq$ęCڋ(ܲ9蠔h7pУu-4G~w%&mߛsi>ֻ,|aoC~ =4_n_rqA7o|~;M3C!ewg=#ʥԋz޴övn@\q#ĕ8wagyBȸ Ѫ1+_ָ8 Q~_!.y_4jqph;}!3b Faw.w^#HA%>G=tF2؎|ȗr(zP/)z.Iq!Nč8WL MoF ݌Ge!ot3?A 'F^au,ۜU^484r@z绞G;kMS]a#@o5g@q#}HO3I9)Yȇ|)r78D܈#q%ĝ~HL3/MxjP3Qo8xq<9zi "\mFk*k. S5gBr5SSEۑRRE=EoaE;i7q .ĉGJms4}q+iO'q҉.ԛp?)gx!PL92gt: vK9K=imā'F+q&4=i+.~WԟV|Nc:~gMБ!3@WrT 8pСˀO8wTR&2zK9K=imā'F+q&Cwf}/P.^S]vBq$ę1+ُe+ǴǛ@;!xt71`؇j#?bǫjvٕӀ_vEۑRRE=EoaE;i7q .ĉGJ;#✫1_i_ͨzL[)j "`|~#S}'\w!sHk5;oi9_f$n@mA:ƯN|c;!_ʡ\AM;lh'&ą87H\3qrOƚYw=Q?#k-tjQoΕ{5ꚯЮ=B&7CR>F:I?*f+?-pM_ dv^Y;h95~g"dSۑRRE=EoaE;i7q .ĉGJ;IfW5Djz$kLϬQf<~Ihԁlpʛ8t뱡O&t䪏 =\ğ2+㵽)=)əp1hSp|*vCCԃzQOћvvNM q"nđgwL4g㶢~N]Hg7h ek>  ]J Cck#ߺha_C8|[%')/iFOO4#*[؏U=򙯾V2؎|ȗr(zP/)z.Iq!Nč8WLm?qf?Ү_׌SA}7jN[)6AuGY#52aX&.mϤ@Wt5J{=/j=8D=vwnz?GU;Ү}xqU[cv˽kwݡ׆O^fEۑRRE=EoaE;i7q .ĉGJN]Q";f.\%8bN?Rs&D`kw~b{V$\u৴?t~V<7*{As3{UG_^`Xx*vCCԃzQOћvvNM q"nđgnA,y _~9_7dƣ^P/cH8&.뤤h=*HDs,U `!՟ W+U׸t~Z4[3ٛR.7}*h'u ۑRRE=EoaE;i7q .ĉGJm;8+o<;875ztzЋ+^O{Qڏkݵ_gpy/xu;/yjw뾁w]qjt}Nᄈ;{pe{d={Kޒ=2w}lV/Vkvo}3?c?mK1j9WFw{u_ׯz|꽖|л~U:]0yٯ_{uz?z엗 E\{5=zuo9[Τ&¤] a"'L䆉aW&zabW&v aK& ak&?dAa>=F{fTߪ=ol.3'0ۮcvx\}jWw;nsE%m6Dlݿh QMsQ/bf[CC@RWROI;%|U"G\%z(KJVbةn%8(E NJpS\0P^ՋOԆgfc`~p~ {,_h 3~5Oӷ]ϵ2<0m owťߺʥ[P..%J)iJ(D%z)SJPb;ح%(I nJpT&~߶}q H3eknB]!uo3m?EwucuUrF3?FIh7@m`,Cy{~2< ;z-8~b WROI;%|U"G\%z(KJVbةn%8(E NJpS\'L0YE>`ϯîGzа#gȧװq{AGT[G>x^F=^G:2BwЏj?Gz`]HU=.f =)zJ)ᣄ9J*C^JT;إN%v+A .JpRg0ghK!=x>:lMpOGKDؙy)ɚ|WFBqc|ޘ=k?}7H*O/:)SN %|Q"WJRء.%v*[ JpQܔWy_=^_=w\ro= ΟH9^_H;%|U"G\%z(KJVbةn%8(E NJpS|=*fb{bđw8CO(;Wx> ɭB:6RɫqҷXgVoRO(sBV = ?9<&A(DJP=%v)SJpPGp<${^ ᯡ{8Yk#;NYOsjϔ&LEϟZuNmnwbgq>Lrhx}~l\Jp<Ἃ RΣ8^_%|Q"WJRء.%v*[ JpQM/0p~Gqz//@'?_Rߍxh6X;)ohZ6|O~O0*_|伂oH98qJ(D%z)SJPb;ح%(I nv?xy&~L|oI7SЩi{ܦt#zbL/_ &"~gNy[OޣW&|O8p ۤ\_p9J*C^JT;إN%v+A .Jp$w aٍt^ws}y jiHOT߇)𚑩%A3.3jJٱr xOyfZ;ߏGpu)\qq$rUDo%v(KJV\TOd<Ἃ=L0q 8J[utFP-ɘ8f{&3c/Ws0>HDλ>:q(R<Q"WJRء.%v*[ Jp"gs=*fGx⺛ Σ8^_Lo?)"(L[iJըC':rw|r5ס0~Gxer\%z(KJVbةn%8('O8x=L07<-><-+/c-P5\ez!7O(m5>9gp<Ἃb|(7Ny\w2>8&ܤ1~uw~!Do%v(KJVO8p w a>f|q 8/ ̾[˹"퇯}ܪ{tt ]f ~v?.Ogqa[2Nx\_pZ%z)SJPb;m=8zq/0(e_0Nx\_p+7"?6h;1D^ď|q^3י0n>Hf 8?8 qDo%v(KJ λ>:.ƅ0(?i1x\q33OxX"}+:hgO8xƻ H8-Q\ws}y _hDo%v(K|f/aq}=L08-Q\ws}y=^_:s襚n3?v3M9/s] 㔌sߋ'b1ב0.=O2u>";UO8ȼb\'g[,yrqrX|/ogP'2p w1.3r?>!㴌GqQ/~Vb8s^#,G2n- a-" i⺛ Σ8^Br_qa_azkq$s8ByGbqA?|6OsO8p w1.3r?^p?xp?]seRɯt[> iG~YWuo}\ wqY"gK[EõAdh*w;ts}K]i*zp^oAߡ{~8(zH=$>?<x?<x?<x?<x?<x?<x?<x?<x?<x(QwP}QWP3uQP< GAK蕯uߣx%q22~QwPƕ=xG]Aw;ǣ.K(-= dn=\;ޣ.O_QQ;(+y%< }uKnȿ.[u]'u~GAyƣ+vxEtnu]&qEGAyգ_:ݣ_\G]D?66ޣvxEt̳<qݣd;h-u&GBzMm/=bqK!^ďx|u[ = q!r+NE~?E׋wG;"~s~GYkoӸT57 WEDC~E"iO,p'?xʉ"~ēo?HG~t;a>Cʥk9B7mF{;L-sSZ5O!˗td$ | :]kʙf9=%/)_|C[ ;ă/G7ܡ=^~ / ?ēoT5鉁nEN lk@+ D7x[(ߦ5k/OCgQ>^~+;&|<m#w?&]wYlO~o3eT>K!^ďxZ !N'G:yI5uMz랋 oo7@ /eyLI?Vr)CA膨t~O  |'}9O?.(rg{NyO}y qO<"~ēo⟚{'ڥ>s9F,?ZP;碾e 2Z`yp^1ѹ~p'vT%%gxNޒ |S~#'E,8ۓS%?ĩ=}>3ŏ6ćxYo^{msm_Ʒɓ1zvGΣd>d}d^dȟ(P?K"K!^ďx_MOҴ$Ok|{UȮ(OZY (mʸg|:V9/ZijL@nCz/Q>%3o|4˭!t#ʣ|Co:ӶOW >ďxZNz=H7~{L||<&( (Οe]u>yLI?V_3Qz^9?coA[46;-GGԇQ_)N} x+ĉg|7Xz>U^:mEԛzbioȑqϴH:dk 8-|_[)SNf\f"{3hM~S4-oqKM8Q>~ǶO濦+l<+OI̭7j:sdtLJ[Z9g8/|Ϋ$ޥdMuH[~D5'[j{_2h漺h"i)g}'?ȋwʧ>ԏ2^'^O<~rgėx;Q/fL[A(qϔi _&j[^y v?Ƴ Xd]ERV'?򧼤EẛJ^O<+pI|+p⟽c#7.k޹Hg~:]o-~4w<HsxJ#1#X{Dg'|%%:%㙒~*QN^B:{g/aI_R>Dh (X!)" ?i1YHM7 |]0224uHxs{#&!ms}n_OiY |s:P9/ qYlO~OyO}崏~A|lA+jc>앸xu|ȼN_ҏ诲娗RrIAyn4YOˠGxaȟ{/.L^#_}'%J}o딌gJU[4a 3rg{#ʣ|C/1Fh/|x?i_?*/3GށrPߦMk?0'E{7crndv1ҌY`{{y|gfȟg`U^)>gG\wS>7ġ?W >ċOK^ݡ:M O u]aܐt3*?}@%J*ˑ/|%%:6c%6nVLٞȟ$ަ$mG}E{?ٲO97xEo7'ډտqϔ)$SL7/c:sh 'e|b8ho34ɝ5};'~c`{#]O}oCS!^O<"~Sޟ66^ǹຏ(tUB.[uH!Fe?\>J7URWYq8LY:O(|L^K6ʣ|Co}Gćxq}@<f١))ASIf˵7b}S'Mٷ7y%rbS+´dqSƋN"v?XHg{#K^S>~W=A ~/G$y;>_﯍~i{8qNa:Q>)ἆr8ăs^#މ5~ )ŝ_9Kq~ 9z?tH(O}|qSR_2x{~Iw%7 Oy> @e+¥)BOPow/}!q߸rk|.~ps܏9#+~SS {b9xB^}o42OpE(7Rn 78ӎEECxx?y'qǿ?}%Opg$ODߩܟ6'ܟF{{GP= @/@ =u|O,g}L'Sb'==>k;\] @, L;l_5B8;QޓFWf (㌎͠?s|oiKYތ~qʳP?fbOӾhߛ; 8_ۯa嚵H_R /^!^fA*V}'|Dn~ȷEz@nG{eڋJW|?%x* _6 ޣ &l?Z;M6Xz:dl] 톗x LUNRpe}僞?wہ#MQGn>I+)WR_YaS_<%},{P_Sbe<oESk}֮~={q 퇤lsZ;A1~Ұ;`UxZ큧S_<%D?%*_=ʲTUb9?h( ]p5]\Y픴W?bGZ)D%)WJQb{د,`93Ha'n~oI+)WR_I{%"O|%(K?ez{ا^%+C >JR~+x* _o%̬WaP1`^,^x>?|U}>wr+ c1Sf=|RB@'x&K9!u^Azѩ>l?tS)WV}"S_<%%)WʲGSm{e? JQ_eragO|m>^6*>\[xUYZO{)3#jh|*i-^ڹ jV;Kw:N6q#r[U}~6.\r%WOYS"_>JSh'+G}JUb@ZQ4}TU"1 =a;z۷Ͽ+ IzJgģߠz߫KVp$\I}5>Jw~J+KJQ_=JSbJm O%*[C^}a7߱nx<)ƿ'o5gLz.'Nz"fz!oz?Or\9'?'?{r^Z9 i%jaW?GD%)WY]zX!߲TWO%*[>M/剝B@'_Niu6ʧ=K3&GiOcF7Q?c.D(Ϙ9ZeNpN݃Jǝ륂&ы!=hǮrZ/봒r%WOj\-yH|%(O_k{ا^e*x(G ^JS_,+u0{[1bmP/mO+ 3ʢ~߹g¯){&}:wۛN~R{?ғ8X?6!w9VKJ+ᧄyJ+G~JU{ا,{!Dz_㌲|TJO-WSv҂"mhH2S/y_ZϧgJ._2N[>3~ =&/[v|:nGz.{GN?XibZA~J+D}D_%+Ge5د,JSأ>%*_ JQ_%x+gĖ2li{9}o6唫_Q ܧF/RCsv.׮3߃zS4Ay/dq|̮./.OmJ}%S_<%r-AD%(OJW|?e **[cþAcub݀?^W q//NF=gV<̝}^}r\93>z6Nc Oφ?FϿ}8}VIJ+p<%,4Z_%+G}JUb</%)S ^~OqNI9ԏ;C>D<|gqCǜcjT.{hmڏT~mtzHW'_ Y|g4+nDJQ_Y _Sb%x)O TVĿC^&Ly*q5S>E΋S h73Fgxy_f-g 99Ez<=pO{_b&G6s E0P)WR_I{%W"O|%gTD%(OJW|,_T{i oe'e =}2Lq cP/2exAk?yO@^>?w>:KH>eG|:*hϺ_M-zL>҉/$A=5"~ J+iJ)Kj}D%(OJWo_%x+ro𚶠{Rfr[7n}>gg^4}=g]N|^ڙͩ3u;Rʝo&ve>^}r%WOe\ JR<oExg5 ~.yԳw[Q?O;'CܬҎ+a|@;'1>>qA8z"O^%;0>]8>Yg'?񏨎vҎX| r0_R_I/!/ih{ا^%;K[| <)~;7h_ꗰ~}%+a٢IqX?~%XO/5Ht8:ӠXOCc= zzZ/;KH8;q%YYPG| !S"$KƗWK[_j :㭨J|C V_xu[5V"xk9⭨wtq}.pA/"sdp/y>!8it{|_y><|++|+N>oEy( E[A^)]]PV/|+O|+"[Q_)D%)9DRolVsϷ:{#]x[?ޠ%?Zq[7ҥ8 >%%FZs)ѷhoxU|%D_V-P 4->mS)|D%)W@(?@>;{ 8 Nl:7i[qSq!N?s?8:ǁ:ist1/*۾W}Q/|}Qh/ *5E-}Q=N:=ESr_U>/_/ yG ӫ@KqK xH+N?ѮӐ7OKK=}O = ~_{~O~p|O@]==zO=b9o|_Z} ԓW} k -~_5s5{WzF1ߛ%|oFSb7|Ŕ7{0L|o8X_f{3@{3h > }x_rT޶ʣ. f=teuSKgnֿSLA詥=Q7Ъ8PSLs=zjivtGO=;{̘kGO=ͨţ_[ף.f=z[9}Z7SL{c=41]~GO-Hܣz\GO=rFzګc?ӣv7SNi#ģs=Tkbj_}=Zυ{Sox1_=T=T_M>ԵEs:#i|j>W}L?({FPnϽyͅ7IOT^~K _ ?`~h$k'Ҡ?<'w ~CQo`Z؍f*vCCԃzQOћvvNM q"nđgw@z] HOov^x çSO&H.(7P?xPN`h77_F{Nn0ƿl5ӇƤ׃)ޘ2ԛfg\z2/vo=YJ>/P.^S]vBq$ę[Oph`J,7[@IxD\ 1Cw^z᧰uxNq4Azl0؝9 5r> '͌cQ>#p81-zɆB*vCCԃzQOћvvNM q"nđgN?,hO<ϧS/Ag/F1?!)I[i@ק#|J*0!#Ў݃y2?o;wN.G^&5?s }~*XP ZzlG>K9K=imā'F+q&Ò o%s^u1~93w~Q {D\aﬧ!q 'zI1#mH綼 vR,s<<>[O" pƢ{qXϯ >_o%ձ)Yȇ|)r78D܈#q%ĝ~Xq3~0‡$V[ tpC]w_A-C=E~j3 oPC ϫ6@jKWOޒˁ[ڡkE"$e>/P.^S]vBq$ękt^V~U>+ܥ R ,v,>|*>>% z&'+ĸ |AH7'EܪNߖ==ٯq|VN]}aivA*vCCԃzQOћvvNM q"nđgN?gލnC ~@׻ z,Y F/ ȝ{ 0hƬa_+y3`|zCwa:~zsTZ|X\-)zGSP}u!EۑRRE=EoaE;i7q .ĉGJ;Yc ߍ MDJ`-ϡݪwЯɕ ׂٌd5 te)!_7,# />p[gseG@Wt]Qoóh+id൹.~Rg=#ʥԋz޴övn@\q#ĕ8waK X?(=JkU\="W]_> &|=̙Hڥ+SU_Uǀ.6K~ZhWH 46ؤqo zmZkXUPJ>/P.^S]vBq$ę[gMwf'vӰ l rwס|A?[bSс! M˴לJ7/Zf]3:(X+7^иq~ pz3>kl]&nDvCCԃzQOћvvNM q"nđgN?li>8]*nCw}῍SX"eWb`"=N}>&Y谚cƦsۍ_NOyEzPop=.oiʷ7EsAʷgzlG>K9K=imā'F+qq?~)Ih=4ݲ)o _?wگ>*/.~*+>O `|dpvx#`{໮ϔg4Ε'O;'~'*l|c;!_ʡ\AM;lh'&ą87H\3qvG]o;؎n~[O, >{_kĠAa7'#;3|삅A>ƒ7Vޕ{@uztmڃ%whk"旅TYȇ|)r78D܈#q%ĝ~أ烁Kn՟s:ro? x ly=o{ =&xQf$JOYT 7?KU9ޝQr8OEۑRRE=EoaE;i7q .ĉGJ;({~ii`w%߹8}({ ޼W+ dL`EHs^D.7>nPocY8ؿ鴃ז A~߁޻4vCCԃzQOћvvNM q"nđgN?ykt<`ϛZή՛om)isL?AXu~O~}*ӡ:c-{s*Ղhw⧁/G?^[#}~yϟ{0퇟c }ĖMzlG>K9K=imā'F+q&=w~s#;Ov|@witus g%`o"Pe#"N?F"C(1Zǻw}~6p3@o(? hg=#ʥԋz޴övn@\q#ĕ8w^'TxKw^|~pm}:MuZh$ās >˕3NJ?`?ׯq=I# |r;L}S>S?cT)Yȇ|)r78D܈#q%ĝ~8ߟ t9p~":oUU{D>?y1;W烮yq ף;_f2V .cz\޹[fWp':ݤ5EۑRRE=EoaE;i7q .ĉGJ;pP֏j? itvVzBt\sWjVzʺaiv=0se wΕw'ڌ >oWtucWoPO}P~~|X<'Rg=#ʥԋz޴övn@\q#ĕ8wz_7gh {#-7;nEz[D nG3Rsw'O3.}ce_TaÃ{'?~i]s5_6qpo]]]9)Yȇ|)r78D܈#q%ĝ~8C~<y"wf<Q <_>̓uW#`W`XTǽ7>x!z^6;BB<]Ce3}^J>/P.^S]vBq$ę~u>뵟?XA8ng!vam/ O:W'io_|}sP^Dx^0؎ CQ~1^;*B%؎|ȗr(zP/)z.Iq!Nč8WLm?HP^/P.^S]vBq$ę~.x+㔿|<滦SS=փZzwKx^]vo?]Q~k :qyw_]ռwv}g{ w}/'}oU[G}Xaew_~Έ/w<ߜgriypn#Pt( \g8xa-U `08= ׺(8J~ v'TP*z^g*v]bg*8 .S*8 smG ~AI:5r ߀|8٤eRP/A}ӎT ̈@z׎G@ GzXsHyj&hcY9^_|{].'|C>5D!r     \  \ C1=agʠ-ʻ#kh ҙoրyF/̩0 ӫ^)s W#>HzoH=C1D!z!z!vb!vb!8!8!8!8{!~Mnyo) ?m 6lO_܋%K >Kn1_OD/~. ,ٙIzb>nw|nIi3!| kC!z!zb!vb!v!!!!?^=wc`+ |y{KٌvZC_} #^q^.Oz8/[j¿Kz>YX d+VW44֔V@ޘV>{-/H5j[|N>Hv1!r kemembNfj=T_%{/R%c/hs?96~|֍QG%9D?;G3[3^[rWC2hs .i'?r`v1!r kemembNf*~<WR@-!c?\&f.Fzefz൹i6M6vyڹՐPdz ?9<&A95DC2DOC6C2NC6Cp1'Cp3Gp<CC:ɚW{'? +Fz3gTuHo>pNсo~\#R]a%!Q ֮z|{YО ]\WrB95DC2DOC6C2NC6Cp1'Cp79CZ_tGq`Xz.y7t l 8n}ۺ}/pv=lGۊ;CN8'0lYR|伂oH98q1D!z!z!vb!vb!8!8O8p%Ap8xٰ>8mioۊ{G {>P[^#K9rou λ>z Σ8^__C"= = ; ;  l=݂{!ݰ Σ8^_lCJGӎ_~ERwޘuzvٖ?ָ68#os]ʸ)aor\8C!z!zb!vb!v!O8p*~j8zN|=vd] 'iahkAw>7YREc?xy'\3Eu7Gqc\C0D/C4DoC0.C4nCp0|/ry6ף{!GQn/8xaz=~wgN{tݻnݍo:MEz:nGY3߇7p~u(5ߑ2^ug>!n"= = ; ;  'O8x=T?VǛ<-+oz?בH:ݳp{b3< --'2p w1>Kx\_pZ!z!z!vb!vb!8{ΫdFp?q`2u7~x~0@+^}ӯ|q4ם087)z_p(]_a^iކa]i݆POd< w + [wu9/ ƹ2^hV)EWCz @~"5߁k]|nܷ eVnc_{`= = ; ; '{p-8C~e_,No;⺛ k>9^쩠 =`T@9?z~/~D}ߣ5>5D>יk֛@s~RϐvM"a^iކa]i݆`'>:.'|ޟ W T|Xv/nF`P~`{3?܏g?xy'zb\'H8-Q^_pB2DOC6C2NCsp%0C~4pbuEtec\_p@ᧃO~Shvw-7߬y$ʹdqJ?o;ψ^oc|8c\CEOC6C2~" ]\p/8"<{['ۚR|㼕3Czslo5A}ORe\xy고[gp!|CqZcx~!z!vb/8sf'WCp6PC~>/.㴌GqQ{U-ϡCoO0O}ΏdqI`/ ~*g88iކa]v?y'\3Ÿ0O(yy}U1NlǸwr{ZQ ]\pxזp[?qr澞3⺛ Σ8^Bmxy1׏nvܞ[C \}㴌GqQ/~Ӱ"~y·nd|qH빯_rr:Y|?~v ]\px?>#P{_!7kso |2փZzKx%D/x(o]ywg@kx 5:/ꝧvyjチxquǻj}Nw;뾳=w}^}O]ߓ-y#sȌCGxEQ|Qfu=ʣ.oMy=@ʣWۢ׋uݻtϣ{oTC|-9nׯuLӣ;Q{wzߧou-{)!GQuO~i9^;S|IÏG]x旖]i]'koiq,Roե|ǡ!'(?Y~iUŖ/W(Ꝩ/m]'%w ?^s"'+,?Y܊k7g_μ?JICN;Q+C/84SIih T;Yy'jdg_NgdH/xNωsO6dq+/:މڟlҶ;mouRd^=QҐȷzU}= H\Iqǫ+-+d--EI7 q_'=QM')R. u }B>@q.A+[9Xrˣ.rNѣ.rP]"Tι{%Tx%TIy%Tz%Tz-TCK|n;&u [GA}e}G?ζYWgr:|0iJ-ӁtO;Ȳas4*X*ߦcHm"c"n&Qd+6eRbbb3\㨖i"[YXrZؖLʈ|C4j:V.+g6k$d4l٨\Ji¢ %ĵnk+[U){WcqخE8;G{w!?/YUE/Aty MGCС$YeJUP֩±^R(W{I؈QQwA&qm^h:"6U%uyK!}^7:Di%:k;DFR%:k;DC!S,CC4dYpuNt[\EbjhIuCLZ\,CCDotķJuv&>Cb̦dyµ;D?!v W\;ĐeyUCD3#ZOTvw[1I6E2GӉrQT|PyT=Oϣ'[Ŵ RN,j '5*5㩨,,lJ5>|-9"C^zA>Gwygwyw |f{Wb.wPϊiSm8 w:>%Nns+L䐠rgl/tests/testthat/testdata/shapelist3d.rds0000644000176200001440000000310515011677075020616 0ustar liggesusersY͏4L2aa/8)#*m-gԉُ+ AGN !!!b'yNҌg{ u먦I7o[:E^{VRTsw#(-L)Ҳg1RuA},`f闽nWw ޿*N]udd&h"&hHc`p Қm= L2f7uu=}&--An _ŻeC Vҗ ĥ8ԗќS>KhgWj RWj3}igZL݊N6Q~EѮc> <#\!rgl/tests/testthat/testdata/qmesh3d.rds0000644000176200001440000000256315011677075017746 0ustar liggesusersMo5tvgw3I T *-ų5{6ҞK'8!Np' 3;3iҬߗ8]v+ _ߖ:N~[Yñׁ6aK3|q&PFhN3tS?PwyW@^ĂE)l- EIoֱG\u}#U׶2|(th2GbIp */܉isbL^&$kߞ3nI-$%SP0ެHöu).QM= Hp:EX!#&eNi ES|iW쎊 lev, nrow = 3) counts <- colSums(greater) crossings <- which(counts %in% 1:2) if (length(crossings)) { greater <- greater[,crossings, drop = FALSE] counts <- counts[crossings] # Find the single vertex on one side of the contour # line (v1), and the other two on the other side # (v2, v3) r1 <- ifelse(counts == 1, apply(greater, 2, which.max), apply(greater, 2, which.min)) v1 <- obj$it[cbind(r1, crossings)] r2 <- r1 %% 3 + 1 v2 <- obj$it[cbind(r2, crossings)] r3 <- (r1 + 1) %% 3 + 1 v3 <- obj$it[cbind(r3, crossings)] p1 <- (lev - values[v2])/(values[v1] - values[v2]) i1 <- p1*verts[v1,] + (1 - p1)*verts[v2,] p2 <- (lev - values[v3])/(values[v1] - values[v3]) i2 <- p2*verts[v1,] + (1 - p2)*verts[v3,] xyz <- matrix(t(cbind(i1, i2)), ncol = 3, byrow = TRUE) result <- rbind(result, data.frame(x = xyz[,1], y = xyz[,2], z = xyz[,3], fn = funnames[i], level = lev)) } } } if (plot) segments3d(result, ...) else result } rgl/R/tkpar3dsave.R0000644000176200001440000000240514771520323013616 0ustar liggesuserstkpar3dsave <- function(params = c("userMatrix", "scale", "zoom", "FOV"), times = FALSE, dev = cur3d(), ...) { if (!requireNamespace("tcltk", quietly = TRUE)) stop("This function requires 'tcltk'") results <- list() for (n in params) results[[n]] <- list() if (times) { start <- proc.time()[3] results$times <- numeric(0) } RecordParms <- function() { values <- par3d(params) if (length(params) == 1) { values <- list(values) names(values) <- params } for (n in params) results[[n]] <<- c(results[[n]], list(values[[n]])) if (times) results$times <<- c(results$times, proc.time()[3] - start) } base <- tcltk::tktoplevel(...) tcltk::tkwm.title(base, "par3d") text <- tcltk::tklabel(base, text="Click on Record to save par3d parameters.", justify="left", wraplength="2i") frame <- tcltk::tkframe(base) save <- tcltk::tkbutton(frame, text="Record", command=RecordParms) quit <- tcltk::tkbutton(frame,text="Quit", command=function()tcltk::tkdestroy(base)) tcltk::tkpack(save, quit, side="left") tcltk::tkpack(text, frame) tcltk::tkwait.window(base) results } rgl/R/scene.R0000644000176200001440000006624315011677075012503 0ustar liggesusers## ## R source file ## This file is part of rgl ## ## ## ## ===[ SECTION: scene management ]=========================================== ## ## ## clear scene ## ## rgl.clear <- function( type = "shapes", subscene = 0 ) { .Deprecated("clear3d") if (is.na(subscene)) subscene <- currentSubscene3d() typeid <- rgl.enum.nodetype(type) userviewpoint <- 4 %in% typeid material <- 5 %in% typeid modelviewpoint <- 8 %in% typeid drop <- typeid %in% c(4:5, 8) typeid <- typeid[!drop] type <- names(typeid) if (subscene == 0) { nobg <- setdiff(typeid, 6) idata <- as.integer(c(length(nobg), nobg)) ret <- .C( rgl_clear, success = FALSE, idata )$success if (6 %in% typeid) rgl.incrementID() # For back compatibility } else { sceneids <- ids3d(type=type, subscene = 0)$id thisids <- ids3d(type=type, subscene = subscene)$id if (length(thisids)) { delFromSubscene3d(ids = thisids, subscene = subscene) gc3d(protect = setdiff(sceneids, thisids)) } ret <- 1 } if ( userviewpoint || modelviewpoint) view3d(type = c("userviewpoint", "modelviewpoint")[c(userviewpoint, modelviewpoint)]) if ( material ) rgl.material0() if (! ret) stop("'rgl_clear' failed") lowlevel() } ## ## pop node ## ## pop3d <- function( type = "shapes", id = 0, tag = NULL) { if (!is.null(tag)) { if (!missing(id)) stop("Only one of 'id' and 'tag' should be specified.") allids <- ids3d(intersect(c("shapes", "bboxdeco"), type), subscene = 0, tags = TRUE) id <- allids$id[allids$tag %in% tag] } type <- rgl.enum.nodetype(type) save <- par3d(skipRedraw = TRUE) on.exit(par3d(save)) for (i in id) { idata <- as.integer(c(type, i)) ret <- .C( rgl_pop, success = FALSE, idata ) if (! ret$success) stop(gettextf("'rgl_pop' failed for id %d", i), domain = NA) } lowlevel() } rgl.pop <- pop3d ids3d <- function( type = "shapes", subscene = NA, tags = FALSE) { type <- c(rgl.enum.nodetype(type), 0) if (is.na(subscene)) subscene <- currentSubscene3d() count <- .C( rgl_id_count, as.integer(type), count = integer(1), subscene = as.integer(subscene))$count result <- as.data.frame( .C( rgl_ids, as.integer(type), id=integer(count), type=rep("",count), subscene = as.integer(subscene) )[2:3] ) if (tags) { result$tag <- rep("", nrow(result)) if (NROW(result)) { hasmaterial <- !(result$type %in% c("light", "userviewpoint", "background", "modelviewpoint", "subscene")) result$tag[hasmaterial] <- vapply(result$id[hasmaterial], function(id) { rgl.getmaterial(0, id = id)$tag }, "") } } result } rgl.ids <- ids3d rgl.attrib.count <- function( id, attrib ) { stopifnot(length(attrib) == 1) if (is.character(attrib)) attrib <- rgl.enum.attribtype(attrib) result <- integer(length(id)) for (i in seq_along(id)) result[i] <- .C( rgl_attrib_count, as.integer(id[i]), as.integer(attrib), count = integer(1))$count names(result) <- names(id) result } rgl.attrib.ncol.values <- c(vertices=3, normals=3, colors=4, texcoords=2, dim=2, texts=1, cex=1, adj=3, radii=1, centers=3, ids=1, usermatrix=4, types=1, flags=1, offsets=1, family=1, font=1, pos=1, fogscale=1, axes=3, indices=1, shapenum=1) rgl.attrib.info <- function( id = ids3d("all", 0)$id, attribs = NULL, showAll = FALSE) { ncol <- rgl.attrib.ncol.values if (is.null(attribs)) attribs <- names(ncol) else if (is.numeric(attribs)) attribs <- names(ncol)[attribs] na <- length(attribs) ni <- length(id) if (!ni) result <- data.frame(id = numeric(0), attrib = character(0), nrow = numeric(0), ncol = numeric(0), stringsAsFactors = FALSE) else result <- data.frame(id = rep(id, each = na), attrib = rep(attribs, ni), nrow = 0, ncol = rep(ncol[attribs], ni), stringsAsFactors = FALSE) for (j in seq_len(ni)) for (i in seq_len(na)) result$nrow[i + na*(j - 1)] <- rgl.attrib.count(id[j], result$attrib[i]) if (!showAll) result <- result[result$nrow != 0,] rownames(result) <- NULL result } rgl.attrib <- function( id, attrib, first=1, last=rgl.attrib.count(id, attrib) ) { stopifnot(length(attrib) == 1 && length(id) == 1 && length(first) == 1) if (is.character(attrib)) attrib <- rgl.enum.attribtype(attrib) ncol <- rgl.attrib.ncol.values[attrib] count <- max(last - first + 1, 0) if (attrib %in% c(6, 13, 16)) { # texts, types and family if (count) result <- .C(rgl_text_attrib, as.integer(id), as.integer(attrib), as.integer(first-1), as.integer(count), result = character(count*ncol))$result else result <- character(0) } else { if (count) result <- .C(rgl_attrib, as.integer(id), as.integer(attrib), as.integer(first-1), as.integer(count), result = numeric(count*ncol))$result else result <- numeric(0) } if (attrib == 14) # flags result <- as.logical(result) result <- matrix(result, ncol=ncol, byrow=TRUE) colnames(result) <- list(c("x", "y", "z"), # vertices c("x", "y", "z"), # normals c("r", "g", "b", "a"), # colors c("s", "t"), # texcoords c("r", "c"), # dim "text", # texts "cex", # cex c("x", "y", "z"), # adj "r", # radii c("x", "y", "z"), # centers "id", # ids c("x", "y", "z", "w"), # usermatrix "type", # types "flag", # flags "offset", # offsets "family", # family "font", # font "pos", # pos "fogscale", # fogscale c("x", "y", "z"), # axes "vertex", # indices "shape" )[[attrib]] if (attrib == 14 && count) # flags if (id %in% ids3d("lights", subscene = 0)$id) rownames(result) <- c("viewpoint", "finite")[first:last] else if (id %in% ids3d("background", subscene = 0)$id) rownames(result) <- c("sphere", "linear_fog", "exp_fog", "exp2_fog")[first:last] else if (id %in% ids3d("bboxdeco", subscene = 0)$id) rownames(result) <- c("draw_front", "marklen_rel")[first:last] else if (id %in% (ids <- ids3d("shapes", subscene = 0))$id) { type <- ids$type[ids$id == id] rownames(result) <- c("ignoreExtent", if (type == "surface") "flipped" else if (type == "spheres") "fastTransparency" else "fixedSize", "rotating")[first:last] } if (attrib == 20 && count) { # axes rownames(result) <- c("mode", "step", "nticks", "marklen", "expand") result <- result[first:last,] result <- as.data.frame(t(result)) result$mode <- c("custom", "fixednum", "fixedstep", "pretty", "user", "none")[result$mode + 1] } result } ## ## ===[ SECTION: environment ]================================================ ## ## ## set viewpoint ## ## rgl.viewpoint <- function( theta = 0.0, phi = 15.0, fov = 60.0, zoom = 1.0, scale = par3d("scale"), interactive = TRUE, userMatrix, type = c("userviewpoint", "modelviewpoint") ) { .Deprecated("view3d") zoom <- rgl.clamp(zoom,0,Inf) phi <- rgl.clamp(phi,-90,90) fov <- rgl.clamp(fov,0,179) type <- match.arg(type, several.ok = TRUE) polar <- missing(userMatrix) if (polar) userMatrix <- diag(4) idata <- as.integer(c(interactive,polar, "userviewpoint" %in% type, "modelviewpoint" %in% type)) ddata <- as.numeric(c(theta,phi,fov,zoom,scale,userMatrix[1:16])) ret <- .C( rgl_viewpoint, success = FALSE, idata, ddata ) if (! ret$success) stop("'rgl_viewpoint' failed") } ## ## set background ## ## rgl.bg <- function(sphere=FALSE, fogtype="none", color=c("black","white"), back="lines", fogScale = 1, ... ) { .Deprecated("bg3d") rgl.material0( color=color, back=back, ... ) fogtype <- rgl.enum.fogtype(fogtype) idata <- as.integer(c(sphere,fogtype)) fogScale <- as.numeric(fogScale) stopifnot(length(fogScale) == 1, fogScale > 0) ret <- .C( rgl_bg, success = as.integer(FALSE), idata, fogScale ) if (! ret$success) stop("'rgl_bg' failed") lowlevel(ret$success) } ## ## bbox ## ## rgl.bbox <- function( xat=NULL, xlab=NULL, xunit=0, xlen=5, yat=NULL, ylab=NULL, yunit=0, ylen=5, zat=NULL, zlab=NULL, zunit=0, zlen=5, marklen=15.0, marklen.rel=TRUE, expand=1, draw_front=FALSE, ...) { .Deprecated("bbox3d") rgl.material0( ... ) if (is.null(xat)) xlab <- NULL else { xlen <- length(xat) if (is.null(xlab)) xlab <- format(xat) else xlab <- rep(xlab, length.out=xlen) } if (is.null(yat)) ylab <- NULL else { ylen <- length(yat) if (is.null(ylab)) ylab <- format(yat) else ylab <- rep(ylab, length.out=ylen) } if (is.null(zat)) zlab <- NULL else { zlen <- length(zat) if (is.null(zlab)) zlab <- format(zat) else zlab <- rep(zlab,length.out=length(zat)) } xticks <- length(xat) yticks <- length(yat) zticks <- length(zat) if (identical(xunit, "pretty")) xunit <- -1 if (identical(yunit, "pretty")) yunit <- -1 if (identical(zunit, "pretty")) zunit <- -1 length(xlen) <- 1 length(ylen) <- 1 length(zlen) <- 1 length(marklen.rel) <- 1 length(draw_front) <- 1 length(xunit) <- 1 length(yunit) <- 1 length(zunit) <- 1 length(marklen) <- 1 length(expand) <- 1 idata <- as.integer(c(xticks,yticks,zticks, xlen, ylen, zlen, marklen.rel, draw_front)) ddata <- as.numeric(c(xunit, yunit, zunit, marklen, expand)) ret <- .C( rgl_bbox, success = as.integer(FALSE), idata, ddata, as.numeric(xat), as.character(xlab), as.numeric(yat), as.character(ylab), as.numeric(zat), as.character(zlab) ) if (! ret$success) stop("'rgl_bbox' failed") lowlevel(ret$success) } ## ## set lights ## ## rgl.light <- function( theta = 0, phi = 0, viewpoint.rel = TRUE, ambient = "#FFFFFF", diffuse = "#FFFFFF", specular = "#FFFFFF", x = NULL, y = NULL, z = NULL) { .Deprecated("light3d") ambient <- rgl.color(ambient) diffuse <- rgl.color(diffuse) specular <- rgl.color(specular) # if a complete set of x, y, z is given, the light source is assumed to be part of the scene, theta and phi are ignored # else the light source is infinitely far away and its direction is determined by theta, phi (default) if ( !is.null(x) ) { if ( !missing(theta) || !missing(phi) ) warning("'theta' and 'phi' ignored when 'x' is present") xyz <- xyz.coords(x,y,z, recycle = TRUE) x <- xyz$x y <- xyz$y z <- xyz$z if (length(x) > 1) stop("A light can only be in one place at a time") finite.pos <- TRUE } else { if ( !is.null(y) || !is.null(z) ) warning("'y' and 'z' ignored, spherical coordinates used") finite.pos <- FALSE x <- 0 y <- 0 z <- 0 } idata <- as.integer(c(viewpoint.rel, ambient, diffuse, specular, finite.pos)) ddata <- as.numeric(c(theta, phi, x, y, z)) ret <- .C( rgl_light, success = as.integer(FALSE), idata, ddata ) if (! ret$success) stop("Too many lights; maximum is 8 sources per scene") lowlevel(ret$success) } ## ## ===[ SECTION: shapes ]===================================================== ## ## ## add primitive ## ## rgl.primitive0 <- function( type, x, y=NULL, z=NULL, normals=NULL, texcoords=NULL, indices=NULL, ... ) { rgl.material0( ... ) type <- rgl.enum.primtype(type) vertex <- rgl.vertex(x,y,z) nvertex <- rgl.nvertex(vertex) if (is.null(indices)) { nindices <- 0 indices <- 0 # to avoid pointing out of range } else { nindices <- length(indices) if (!all(indices > 0 & indices <= nvertex)) stop("indices out of range") } if (nvertex > 0) { perelement <- c(points=1, lines=2, triangles=3, quadrangles=4, linestrips=1)[type] if (nindices > 0) { if (nindices %% perelement) stop("Illegal number of indices") } else if (nvertex %% perelement) stop("Illegal number of vertices") idata <- as.integer( c(type, nvertex, !is.null(normals), !is.null(texcoords), nindices, indices - 1 ) ) if (is.null(normals)) normals <- 0 else { normals <- xyz.coords(normals, recycle=TRUE) x <- rep(normals$x, length.out = nvertex) y <- rep(normals$y, length.out = nvertex) z <- rep(normals$z, length.out = nvertex) normals <- rgl.vertex(x,y,z) } if (is.null(texcoords)) texcoords <- 0 else { texcoords <- xy.coords(texcoords, recycle=TRUE) s <- rep(texcoords$x, length.out = nvertex) t <- rep(texcoords$y, length.out = nvertex) texcoords <- rgl.texcoords(s,t) } success <- .Call( rgl_primitive, as.integer(idata), as.numeric(vertex), as.numeric(normals), as.numeric(texcoords) ) if (!success) stop("'rgl_primitive' failed") lowlevel(success) } } rgl.primitive <- function(...) { .Deprecated("", msg = "Please call the primitive directly, e.g. points3d(...).") rgl.primitive0(...) } rgl.points <- function( x, y=NULL, z=NULL, ... ) { .Deprecated("points3d") rgl.primitive0( "points", x, y, z, ... ) } rgl.lines <- function(x, y=NULL, z=NULL, ... ) { .Deprecated("segments3d") rgl.primitive0( "lines", x, y, z, ... ) } rgl.triangles <- function(x, y=NULL, z=NULL, normals=NULL, texcoords=NULL, ... ) { .Deprecated("triangles3d") rgl.primitive0( "triangles", x, y, z, normals, texcoords, ... ) } rgl.quads <- function( x, y=NULL, z=NULL, normals=NULL, texcoords=NULL, ... ) { .Deprecated("quads3d") rgl.primitive0( "quadrangles", x, y, z, normals, texcoords, ... ) } rgl.linestrips<- function( x, y=NULL, z=NULL, ... ) { .Deprecated("lines3d") rgl.primitive0( "linestrips", x, y, z, ... ) } ## ## add surface ## ## # Utility function: # calculates the parity of a permutation of integers perm_parity <- function(p) { x <- seq_along(p) result <- 0 for (i in x) { if (x[i] != p[i]) { x[x==p[i]] <- x[i] result <- result+1 } } return(result %% 2) } rgl.surface <- function( x, z, y, coords=1:3, ..., normal_x=NULL, normal_y=NULL, normal_z=NULL, texture_s=NULL, texture_t=NULL) { .Deprecated("surface3d") rgl.material0(...) flags <- rep(FALSE, 4) if (is.matrix(x)) { nx <- nrow(x) flags[1] <- TRUE if ( !identical( dim(x), dim(y) ) ) stop(gettextf("Bad dimension for %s", "rows"), domain = NA) } else nx <- length(x) if (is.matrix(z)) { nz <- ncol(z) flags[2] <- TRUE } else nz <- length(z) if (is.matrix(y)) { if (any(dim(y) != c(nx, nz))) stop(gettextf("Bad dimension for %s", "y")) } else if (is.matrix(x)) { if (length(y) != nx) stop(gettextf("Bad length for %s", "y")) y <- matrix(y, nx, nz) } else y <- matrix(y, nx, nz, byrow = TRUE) ny <- length(y) if ( nx*nz != ny) stop("'y' length != 'x' rows * 'z' cols") if ( nx < 2 ) stop("rows < 2") if ( nz < 2 ) stop("cols < 2") if ( length(coords) != 3 || !identical(all.equal(sort(coords), 1:3), TRUE) ) stop("'coords' must be a permutation of 1:3") nulls <- c(is.null(normal_x), is.null(normal_y), is.null(normal_z)) if (!all( nulls ) ) { if (any( nulls )) stop("All normals must be supplied") if ( !identical(dim(y), dim(normal_x)) || !identical(dim(y), dim(normal_y)) || !identical(dim(y), dim(normal_z)) ) stop(gettextf("Bad dimension for %s", "normals"), domain = NA) flags[3] <- TRUE } nulls <- c(is.null(texture_s), is.null(texture_t)) if (!all( nulls ) ) { if (any( nulls )) stop("Both texture coordinates must be supplied") if ( !identical(dim(y), dim(texture_s)) || !identical(dim(y), dim(texture_t)) ) stop(gettextf("Bad dimension for %s", "textures"), domain = NA) flags[4] <- TRUE } idata <- as.integer( c( nx, nz ) ) xdecreasing <- diff(x[!is.na(x)][1:2]) < 0 zdecreasing <- diff(z[!is.na(z)][1:2]) < 0 parity <- (perm_parity(coords) + xdecreasing + zdecreasing ) %% 2 if (is.na(parity)) parity <- 0 ret <- .C( rgl_surface, success = as.integer(FALSE), idata, as.numeric(x), as.numeric(z), as.numeric(y), as.numeric(normal_x), as.numeric(normal_z), as.numeric(normal_y), as.numeric(texture_s), as.numeric(texture_t), as.integer(coords), as.integer(parity), as.integer(flags), NAOK=TRUE ) if (! ret$success) stop("'rgl_surface' failed") lowlevel(ret$success) } ## ## add spheres ## rgl.spheres <- function( x, y=NULL, z=NULL, radius=1.0, fastTransparency = TRUE, ...) { rgl.material0(...) vertex <- rgl.vertex(x,y,z) nvertex <- rgl.nvertex(vertex) radius <- rgl.attr(radius, nvertex) nradius <- length(radius) if (nvertex && nradius) { idata <- as.integer( c( nvertex, nradius ) ) ret <- .C( rgl_spheres, success = as.integer(FALSE), idata, as.numeric(vertex), as.numeric(radius), as.integer(fastTransparency), NAOK=TRUE ) if (! ret$success) stop("'rgl_spheres' failed") lowlevel(ret$success) } } ## ## add planes ## rgl.planes <- function( a, b=NULL, c=NULL, d=0,...) { .Deprecated("planes3d") rgl.material0(...) normals <- rgl.vertex(a, b, c) nnormals <- rgl.nvertex(normals) noffsets <- length(d) if (nnormals && noffsets) { idata <- as.integer( c( nnormals, noffsets ) ) ret <- .C( rgl_planes, success = as.integer(FALSE), idata, as.numeric(normals), as.numeric(d), NAOK=TRUE ) if (! ret$success) stop("'rgl_planes' failed") lowlevel(ret$success) } } ## ## add clip planes ## rgl.clipplanes <- function( a, b=NULL, c=NULL, d=0) { .Deprecated("clipplanes3d") normals <- rgl.vertex(a, b, c) nnormals <- rgl.nvertex(normals) noffsets <- length(d) if (nnormals && noffsets) { idata <- as.integer( c( nnormals, noffsets ) ) ret <- .C( rgl_clipplanes, success = as.integer(FALSE), idata, as.numeric(normals), as.numeric(d), NAOK=TRUE ) if (! ret$success) stop("'rgl_clipplanes' failed") lowlevel(ret$success) } } ## ## add abclines ## rgl.abclines <- function(x, y=NULL, z=NULL, a, b=NULL, c=NULL, ...) { .Deprecated("abclines3d") rgl.material0(...) bases <- rgl.vertex(x, y, z) nbases <- rgl.nvertex(bases) directions <- rgl.vertex(a, b, c) ndirs <- rgl.nvertex(directions) if (nbases && ndirs) { idata <- as.integer( c( nbases, ndirs ) ) ret <- .C( rgl_abclines, success = as.integer(FALSE), idata, as.numeric(bases), as.numeric(directions), NAOK=TRUE ) if (! ret$success) stop("'rgl_abclines' failed") lowlevel(ret$success) } } ## ## add texts ## rgl.texts <- function(x, y=NULL, z=NULL, text, adj = 0.5, pos = NULL, offset = 0.5, family=par3d("family"), font=par3d("font"), cex=par3d("cex"), useFreeType=par3d("useFreeType"), ... ) { .Deprecated("text3d") rgl.material0( ... ) vertex <- rgl.vertex(x,y,z) nvertex <- rgl.nvertex(vertex) if (!is.null(pos)) { npos <- length(pos) stopifnot(all(pos %in% 0:6)) stopifnot(length(offset) == 1) adj <- offset } else { pos <- 0 npos <- 1 } if (length(adj) > 3) warning("Only the first three entries of 'adj' are used") adj <- c(adj, 0.5, 0.5, 0.5)[1:3] if (!length(text)) { if (nvertex) warning("No text to plot") return(invisible(integer(0))) } if (nvertex) { text <- rep(text, length.out=nvertex) idata <- as.integer(nvertex) nfonts <- max(length(family), length(font), length(cex)) family <- rep(family, length.out = nfonts) font <- rep(font, length.out = nfonts) cex <- rep(cex, length.out = nfonts) family[font == 5] <- "symbol" font <- ifelse( font < 0 | font > 4, 1, font) ret <- .C( rgl_texts, success = as.integer(FALSE), idata, as.double(adj), as.character(text), as.numeric(vertex), as.integer(nfonts), as.character(family), as.integer(font), as.numeric(cex), as.integer(useFreeType), as.integer(npos), as.integer(pos), NAOK=TRUE ) if (! ret$success) stop("'rgl_texts' failed") lowlevel(ret$success) } } ## ## add sprites ## rgl.sprites <- function( x, y=NULL, z=NULL, radius=1.0, shapes=NULL, userMatrix=diag(4), fixedSize = FALSE, adj = 0.5, pos = NULL, offset = 0.25, rotating = FALSE, ... ) { .Deprecated("sprites3d") rgl.material0(...) center <- rgl.vertex(x,y,z) ncenter <- rgl.nvertex(center) radius <- rgl.attr(radius, ncenter) nradius <- length(radius) pos <- as.integer(pos) npos <- length(pos) if (npos) { pos <- rep(pos, length.out = ncenter) adj <- offset } adj <- c(adj, 0.5, 0.5, 0.5)[1:3] if (ncenter && nradius) { if (length(shapes) && length(userMatrix) != 16) stop("Invalid 'userMatrix'") if (length(fixedSize) != 1) stop("Invalid 'fixedSize'") idata <- as.integer( c(ncenter,nradius,length(shapes), fixedSize, npos, rotating) ) ret <- .C( rgl_sprites, success = as.integer(FALSE), idata, as.numeric(center), as.numeric(radius), as.integer(shapes), as.numeric(t(userMatrix)), as.numeric(adj), pos, as.numeric(offset), NAOK=TRUE ) if (! ret$success) stop("'rgl_sprites' failed") lowlevel(ret$success) } } ## ## convert user coordinate to window coordinate ## rgl.user2window <- function( x, y=NULL, z=NULL, projection = rgl.projection()) { xyz <- xyz.coords(x,y,z,recycle=TRUE) points <- rbind(xyz$x,xyz$y,xyz$z,1) v <- asEuclidean(with(projection, t(proj %*% model %*% points))) # nolint viewport <- projection$view cbind( (v[,1]*0.5 + 0.5) + viewport[1]/viewport[3], (v[,2]*0.5 + 0.5) + viewport[2]/viewport[4], (1 + v[,3])*0.5 ) } ## ## convert window coordinate to user coordinate ## rgl.window2user <- function( x, y = NULL, z = 0, projection = rgl.projection()) { xyz <- xyz.coords(x,y,z,recycle=TRUE) viewport <- projection$view normalized <- rbind( 2*(xyz$x - viewport[1]/viewport[3]) - 1, 2*(xyz$y - viewport[2]/viewport[4]) - 1, 2*xyz$z - 1, 1 ) asEuclidean(with(projection, t(solve(proj %*% model, normalized)))) # nolint } # Selectstate values msNONE <- 1 msCHANGING <- 2 msDONE <- 3 msABORT <- 4 rgl.selectstate <- function(dev = cur3d(), subscene = currentSubscene3d(dev)) { ret <- .C( rgl_selectstate, as.integer(dev), as.integer(subscene), success = FALSE, state = as.integer(0), mouseposition = double(4) ) if (! ret$success) stop("'rgl_selectstate' failed") return(ret) } rgl.select <- function(button = c("left", "middle", "right"), dev = cur3d(), subscene = currentSubscene3d(dev)) { if (rgl.useNULL()) return(NULL) button <- match.arg(button) newhandler <- par3d("mouseMode", dev = dev, subscene = subscene) newhandler[button] <- "selecting" oldhandler <- par3d(mouseMode = newhandler, dev = dev, subscene = subscene) on.exit(par3d(mouseMode = oldhandler, dev = dev, subscene = subscene)) while ((result <- rgl.selectstate(dev = dev, subscene = subscene))$state < msDONE) Sys.sleep(0.1) rgl.setselectstate("none", dev = dev, subscene = subscene) if (result$state == msDONE) return(result$mouseposition) else return(NULL) } rgl.setselectstate <- function(state = "current", dev = cur3d(), subscene = currentSubscene3d(dev)) { state <- rgl.enum(state, current=0, none = 1, middle = 2, done = 3, abort = 4) idata <- as.integer(c(state)) ret <- .C( rgl_setselectstate, as.integer(dev), as.integer(subscene), success = FALSE, state = idata ) if (! ret$success) stop("'rgl_setselectstate' failed") c("none", "middle", "done", "abort")[ret$state] } rgl.projection <- function(dev = cur3d(), subscene = currentSubscene3d(dev)) { list(model = par3d("modelMatrix", dev = dev, subscene = subscene), proj = par3d("projMatrix", dev = dev, subscene = subscene), view = par3d("viewport", dev = dev, subscene = subscene)) } rgl.select3d <- function(button = c("left", "middle", "right"), dev = cur3d(), subscene = currentSubscene3d(dev)) { .Deprecated("select3d") rect <- rgl.select(button = button, dev = dev, subscene = subscene) if (is.null(rect)) return(NULL) proj <- rgl.projection(dev = dev, subscene = subscene) llx <- rect[1] lly <- rect[2] urx <- rect[3] ury <- rect[4] selectionFunction3d(proj, region = c(llx, lly, urx, ury)) } selectionFunction3d <- function(proj, region = proj$region) { llx <- region[1] lly <- region[2] urx <- region[3] ury <- region[4] if ( llx > urx ) { temp <- llx llx <- urx urx <- temp } if ( lly > ury ) { temp <- lly lly <- ury ury <- temp } proj$view["x"] <- proj$view["y"] <- 0 function(x,y=NULL,z=NULL) { pixel <- rgl.user2window(x,y,z,projection=proj) x <- pixel[,1] y <- pixel[,2] z <- pixel[,3] (llx <= x) & (x <= urx) & (lly <= y) & (y <= ury) & (0 <= z) & (z <= 1) } } tagged3d <- function(tags = NULL, ids = NULL, full = FALSE, subscene = 0) { if ((missing(tags) + missing(ids)) != 1) stop("Exactly one of 'tags' and 'ids' should be specified.") all <- ids3d("all", subscene = subscene, tags = TRUE) if (!missing(tags)) all <- all[all$tag %in% tags,] else all <- all[match(ids, all$id),] if (full) all else if (!missing(tags) && !is.null(tags)) all$id else if (!missing(ids) && !is.null(ids)) all$tag else NULL } rgl/R/stl.R0000644000176200001440000001742415011677075012205 0ustar liggesuserswriteSTL <- function(con, ascii=FALSE, pointRadius=0.005, pointShape = icosahedron3d(), lineRadius = pointRadius, lineSides = 20, ids = tagged3d(tags), tags = NULL) { writeHeader <- function() { ident <- paste(filename, " produced by RGL\n") if (ascii) cat("solid ", ident, file=con) else { padding <- paste(rep(" ", 80), collapse="") ident <- substr( paste("binary", ident, padding), 1, 80) writeChar(ident, con, nchars=80, useBytes=TRUE, eos=NULL) writeBin(0L, con, size=4, endian="little") } } finish <- function() { if (!ascii) { seek(con, 80) writeBin(as.integer(triangles), con, size=4, endian="little") } else cat("endsolid\n", file = con) } triangles <- 0 writeTriangles <- function(vertices) { if (nrow(vertices) %% 3 != 0) stop("Need 3N vertices") n <- nrow(vertices) / 3 for (i in seq_len(n)) { vec0 <- vertices[3*i - 2,] vec1 <- vertices[3*i - 1,] vec2 <- vertices[3*i,] normal <- normalize(xprod(vec2-vec0, vec1-vec0)) if (ascii) { cat("facet normal ", normal, "\n", file=con) cat("outer loop\n", file=con) cat("vertex ", vec0, "\n", file=con) cat("vertex ", vec1, "\n", file=con) cat("vertex ", vec2, "\n", file=con) cat("endloop\n", file=con) cat("endfacet\n", file=con) } else { writeBin(c(normal, vec0, vec1, vec2), con, size=4, endian="little") writeBin(0L, con, size=2, endian="little") } } triangles <<- triangles + n } writeQuads <- function(vertices) { if (nrow(vertices) %% 4 != 0) stop("Need 4N vertices") n <- nrow(vertices) / 4 indices <- rep(seq_len(n)*4, each=6) - rep(c(3, 2, 1, 3, 1, 0), n) writeTriangles( vertices[indices,] ) } writeSurface <- function(id) { vertices <- expandVertices(id) dims <- rgl.attrib(id, "dim") nx <- dims[1] nz <- dims[2] indices <- integer(0) for (j in seq_len(nx-1) - 1) { v1 <- j + nx*(seq_len(nz) - 1) + 1 indices <- c(indices, rbind(v1[-nz], v1[-nz]+1, v1[-1]+1, v1[-1])) } writeQuads(vertices[indices,]) } writeMesh <- function(mesh, scale=1, offset=c(0,0,0)) { vertices <- asEuclidean(t(mesh$vb))*scale vertices <- vertices + rep(offset, each=nrow(vertices)) nt <- length(mesh$it)/3 nq <- length(mesh$ib)/4 newverts <- matrix(NA, 3*nt+6*nq, 3) if (nt) newverts[1:(3*nt),] <- vertices[c(mesh$it),] if (nq) newverts[3*nt+1:(6*nq),] <- vertices[c(mesh$ib[1:3,], mesh$ib[c(1,3,4),]),] writeTriangles(newverts) } writeSpheres <- function(id) { vertices <- expandVertices(id) radii <- rgl.attrib(id, "radii") # FIXME to handle indices? n <- nrow(vertices) radii <- rep(radii, length.out=n) x <- subdivision3d(icosahedron3d(),3) r <- sqrt(x$vb[1,]^2 + x$vb[2,]^2 + x$vb[3,]^2) x$vb[4,] <- r for (i in seq_along(radii)) writeMesh(x, radii[i], vertices[i,]) } avgScale <- function() { bbox <- par3d("bbox") ranges <- c(bbox[2]-bbox[1], bbox[4]-bbox[3], bbox[6]-bbox[5]) if (prod(ranges) == 0) 1 else exp(mean(log(ranges))) } writePoints <- function(id) { vertices <- expandVertices(id) n <- nrow(vertices) radius <- pointRadius*avgScale() for (i in seq_len(n)) writeMesh(pointShape, radius, vertices[i,]) } writeSegments <- function(id) { vertices <- expandVertices(id) n <- nrow(vertices)/2 radius <- lineRadius*avgScale() for (i in seq_len(n)) { cyl <- cylinder3d(vertices[(2*i-1):(2*i),], radius = radius, sides = lineSides, closed = -2) writeMesh(cyl) } } writeLines <- function(id) { vertices <- expandVertices(id) n <- nrow(vertices) - 1 radius <- lineRadius*avgScale() for (i in seq_len(n)) writeMesh( cylinder3d( vertices[i:(i+1),], radius = radius, sides = lineSides, closed = -2) ) } knowntypes <- c("triangles", "quads", "surface", "planes", "spheres", "points", "lines", "linestrip") # Execution starts here! if (is.character(con)) { con <- file(con, if (ascii) "w" else "wb") on.exit(close(con)) } filename <- summary(con)$description if (NROW(bbox <- ids3d("bboxdeco")) && (is.null(ids) || bbox$id %in% ids)) { ids <- setdiff(ids, bbox$id) save <- par3d(skipRedraw = TRUE) bbox <- convertBBox(bbox$id) on.exit({ pop3d(id=bbox); par3d(save) }, add=TRUE) # nolint dobbox <- TRUE } else dobbox <- FALSE if (is.null(ids)) { ids <- ids3d() types <- as.character(ids$type) ids <- ids$id } else { if (dobbox) ids <- c(ids, bbox) allids <- ids3d() ind <- match(ids, allids$id) keep <- !is.na(ind) if (any(!keep)) warning(gettextf("Object(s) with id %s not found", paste(ids[!keep], collapse=" ")), domain = NA) ids <- ids[keep] types <- allids$type[ind[keep]] } unknowntypes <- setdiff(types, knowntypes) if (length(unknowntypes)) warning(gettextf("Object type(s) %s not handled", paste("'", unknowntypes, "'", sep="", collapse=", ")), domain = NA) keep <- types %in% knowntypes ids <- ids[keep] types <- types[keep] writeHeader() for (i in seq_along(ids)) switch(types[i], planes =, triangles = writeTriangles(expandVertices(ids[i])), quads = writeQuads(expandVertices(ids[i])), surface = writeSurface(ids[i]), spheres = writeSpheres(ids[i]), points = writePoints(ids[i]), lines = writeSegments(ids[i]), linestrip = writeLines(ids[i]) ) finish() invisible(filename) } readSTL <- function(con, ascii=NA, plot=TRUE, ...) { # Utility functions and constants defined first; execution starts way down there... triangles <- NULL readHeader <- function() { if (is.na(ascii)) { summ <- summary(con) if (summ$class != "file" || readChar(con, 5) != "solid") ascii <<- FALSE else { ascii <<- TRUE filename <- summ$description close(con) con <<- file(filename, "rt") } } if (ascii) { ident <- readLines(con, 1) if (!grepl("^solid ", ident)) stop("This does not appear to be an ASCII STL file") } if (!ascii) { seek(con, 80) triangles <<- readBin(con, "integer", n=1, size=4, endian="little") } } readTriangles <- function(n) { if (ascii) { lines <- readLines(con) facet <- c(grep("^ *facet", lines), length(lines) + 1) # sentinel n <- length(facet) - 1 vertex <- grep("^ *vertex ", lines) } vertices <- matrix(NA, 3*n, 3) if (ascii) { for (i in seq_len(n)) { j <- vertex[facet[i] < vertex & vertex < facet[i+1]] if (any(is.na(j)) || length(j) != 3) { warning("problem on triangle ", i, " j = ", j) j <- j[1:3] } v <- read.table(text = lines[j], colClasses = c("character", "numeric", "numeric", "numeric")) vertices[3*i + c(-2, -1, 0),] <- as.matrix(v[, 2:4]) } } else { for (i in seq_len(n)) { m <- matrix(readBin(con, "double", n=12, size=4, endian="little"), 4, 3, byrow=TRUE) vertices[3*i + c(-2,-1,0),] <- m[2:4,] count <- readBin(con, "integer", n=1, size=2, endian="little") # nolint } } vertices } # Execution starts here! if (is.character(con)) { con <- file(con, if (isTRUE(ascii)) "rt" else "rb") on.exit(close(con)) } readHeader() vertices <- readTriangles(triangles) if (plot) triangles3d(vertices, ...) else vertices } rgl/R/internal.R0000644000176200001440000000442114771520323013203 0ustar liggesusers## ## R source file ## This file is part of rgl ## ## ## ## ===[ SECTION: internal ]=================================================== ## # # rgl.clamp # # clamp value if lower than low or higher than high # rgl.clamp <- function(value, low, high) { if (value < low) { warning( gettextf("Value clamped to %s",low), domain = NA ) result <- low } else if (value > high) { warning( gettextf("Value clamped to %s",high), domain = NA ) result <- high } else { result <- value } return(result) } ## ## types verification ## # # single field bool # rgl.bool <- function( x ) { if (length(x) > 1) stop( gettextf("'%s' must be a single boolean value", deparse(substitute(x))), domain = NA) } # # single field numeric # rgl.numeric <- function( x ) { if (length(x) > 1) stop( gettextf("'%s' must be a single numeric value", deparse(substitute(x))), domain = NA) } # # single string # rgl.string <- function( x ) { if (length(x) != 1) stop( gettextf("'%s' must be a single character value", deparse(substitute(x))), domain = NA) } # # vertex data object # rgl.vertex <- function(x, y = NULL, z = NULL) { xyz <- xyz.coords(x, y, z, recycle=TRUE) # This is not the same as just rbind(xyz$x,xyz$y,xyz$z)! # xyz.coords puts all of named vector x into xyz$x return( matrix( rbind(xyz$x,xyz$y,xyz$z), nrow=3, dimnames=list( c("x","y","z"), NULL ) ) ) } # # texture coordinate data object # rgl.texcoords <- function(s,t=NULL) { xy <- xy.coords(s, t, recycle=TRUE) return( matrix( rbind(xy$x, xy$y), nrow=2, dimnames=list( c("s", "t"), NULL ) ) ) } # # obtain number of vertices # rgl.nvertex <- function(vertex) { return( ncol(vertex) ) } # # rgl.color - single field color # rgl.color <- function( color ) { if (length(color) > 1) stop( gettextf("'%s' must be a single color character string", deparse(substitute(color))), domain = NA) else return(col2rgb(color)) } # # rgl.mcolor - multiple field colors # rgl.mcolor <- function( colors ) { return( col2rgb(colors) ) } # # if vattr > 1, recycle data # rgl.attr <- function(vattr, nvertex) { nvattr <- length(vattr) if ((nvattr > 1) && (nvattr != nvertex)) vattr <- rep(vattr,length.out=nvertex) return(vattr) } rgl/R/shadow3d.R0000644000176200001440000000416614771520323013111 0ustar liggesusers# Project the shadow of one mesh object onto another shadow3d <- function(obj, mesh, plot = TRUE, up = c(0, 0, 1), P = projectDown(up), outside = FALSE, ...) { triangles <- as.triangles3d(mesh) ntri <- nrow(triangles) / 3 P <- t(P) # The convention in rgl is row vectors on the left # but we'll be using column vectors on the right projected <- P %*% rbind(t(triangles), 1) projected <- projected[1:2,]/rep(projected[4,], each = 2) fn <- function(xyz) { result <- rep(-Inf, nrow(xyz)) r <- P %*% rbind(t(xyz), 1) r <- rbind(r[1:2,]/rep(r[4,], each = 2), 1) for (i in 1:ntri) { # For each triangle, find the barycentric parameters # of each point in xyz using relation R lambda = r = (x,y,1)' R <- rbind(projected[,(0:2) + 3*i - 2], 1) lambda <- tryCatch(solve(R, r), error = function(e) matrix(-Inf, 3, ncol(r))) # If the smallest barycentric coord is positive, the point # is in the triangle minlambda <- apply(lambda, 2, min) result <- pmax(result, minlambda) } result } if (outside) levels <- c(Inf, 0, -Inf) else levels <- c(0, Inf) filledContour3d(obj, fn, levels = levels, plot = plot, ...) } projectDown <- function(up) { if (length(up) == 4) up <- up[1:3]/up[4] else if (length(up) != 3) stop("'up' vector should be length 3.") P <- GramSchmidt(up, c(1, 0, 0), c(0, 1, 0)) if (det(P) < 0) P[3,] <- -P[3,] cbind(rbind(t(P[c(2,3,1),]), 0), c(0, 0, 0, 1)) } facing3d <- function(obj, up = c(0, 0, 1), P = projectDown(up), front = TRUE, strict = TRUE) { obj <- as.tmesh3d(obj) P <- t(P) # The convention in rgl is row vectors on the left # but we'll be using column vectors on the right r <- P %*% obj$vb r <- r[1:2,]/rep(r[4,], each = 2) area <- function(i) { x <- r[1,obj$it[,i]] y <- r[2,obj$it[,i]] area <- 0 for (j in 1:3) area <- area + x[j]*y[j %% 3 + 1] - x[j %% 3 + 1]*y[j] area } areas <- vapply(seq_len(ncol(obj$it)), area, 0) if (isTRUE(front)) keep <- areas > 0 else keep <- areas < 0 if (!strict) keep <- keep | areas == 0 obj$it <- obj$it[, keep] cleanMesh3d(obj) } rgl/R/hover3d.R0000644000176200001440000001341114771520323012740 0ustar liggesusershover3d <- function(x, y = NULL, z = NULL, labeller = NULL, tolerance = 20, persist = c("no", "one", "yes"), labels = seq_along(x), adj = c(-0.2, 0.5), scene = scene3d(minimal = FALSE), applyToScene = TRUE, ...) { save <- par3d(skipRedraw = TRUE) on.exit(par3d(save)) labelIndex <- function(sel, ...) text3d(x[sel], y[sel], z[sel], texts=labels[sel], adj=adj, ...) custom_labeller <- FALSE if (is.null(labeller)) labeller <- labelIndex else custom_labeller <- TRUE stopifnot(is.function(labeller)) persist <- match.arg(persist) opar <- par3d("mouseMode") odev <- cur3d() if (inherits(x, "rglId") || (length(x) == 1 && is.null(y) && is.null(z))) { if (length(x) != 1) stop("Exactly one object may be specified as x.") idverts <- x x <- expandVertices(idverts) } else idverts <- numeric() xyz <- xyz.coords(x, y, z) x <- xyz$x y <- xyz$y z <- xyz$z if (length(x)==0) stop("No points to identify.") force(labels) force(adj) selected <- list() hoverSelect <- function(mousex, mousey) { disp <- cur3d() save2 <- par3d(skipRedraw = TRUE) on.exit({par3d(save2); set3d(disp)}) set3d(odev) viewport <- par3d("viewport") winxyz <- rgl.user2window(xyz) winxyz[,1] <- winxyz[,1]*viewport[3] winxyz[,2] <- (1-winxyz[,2])*viewport[4] change <- FALSE dist <- sqrt( (mousex-winxyz[,1])^2 + (mousey - winxyz[,2])^2 ) dist[winxyz[,3] < 0 | winxyz[,3] > 1] <- Inf sel <- which.min(dist) if (dist[sel] <= tolerance) { if (persist != "yes") selected <<- Filter(function(s) if (s$sel != sel) { pop3d(id = s$ids) change <- TRUE FALSE } else TRUE, selected) prev <- Find(function(s) s$sel == sel, selected) if (is.null(prev)) { this <- list(sel = sel, ids = labeller(sel, ...)) change <- TRUE selected <<- c(selected, list(this)) } } else if (persist == "no" && length(selected)) { lapply(selected, function(s) pop3d(id = s$ids)) change <- TRUE selected <<- list() } if (change) { par3d(skipRedraw = FALSE) } } js <- NULL if (applyToScene) { # Define the Javascript functions with the same names to use in WebGL js <- 'window.hoverSelect = function(x, y) { var obj = this.getObj(%idverts%), i, newdist, dist = Infinity, pt, newclosest, text, customlabeller = %customlabeller%[0], idtexts = %idtexts%, change = false, selected = window.hoverSelect.selected; for (i = 0; i < obj.vertices.length; i++) { pt = obj.vertices[i].concat(1); pt = this.user2window(pt, %subid%); pt[0] = x - pt[0]*this.canvas.width; pt[1] = y - pt[1]*this.canvas.height; pt[2] = 0; newdist = rglwidgetClass.vlen(pt); if (newdist < dist) { dist = newdist; newclosest = i; } } if (dist <= %tolerance%) { if ("%persist%" !== "yes" && selected.length > 0 && selected[0] !== newclosest) { if (customlabeller) { idtexts[selected[0]].forEach(id => this.delFromSubscene(id, %subid%)); } else { text = this.getObj(idtexts[0]); text.colors[selected[0]][3] = 0; // invisible! } selected = []; change = true; } if (!selected.includes(newclosest)) { selected.push(newclosest); if (customlabeller) { idtexts[newclosest].forEach(id => this.addToSubscene(id, %subid%)); } else { text = this.getObj(idtexts[0]); text.colors[newclosest][3] = 1; // alpha is here! } change = true; } } else if ("%persist%" === "no" && selected.length > 0) { if (customlabeller) { idtexts[selected[0]].forEach(id => this.delFromSubscene(id, %subid%)); } else { text = this.getObj(%idtexts%); text.colors[selected[0]][3] = 0; } selected = []; change = true; } if (change) { if (!customlabeller) text.initialized = false; window.hoverSelect.selected = selected; this.drawScene(); } }; window.hoverSelect.selected = []; ' if (!length(idverts)) { idverts <- points3d(xyz) delFromSubscene3d(idverts) } if (custom_labeller) { idtexts <- vector("list", length(x)) for (i in seq_along(x)) { idtexts[[i]] <- labeller(i, ...) } delFromSubscene3d(unlist(idtexts)) } else { idtexts <- text3d(xyz, texts = labels, adj = adj, alpha = rep(0, length(labels)), ...) delFromSubscene3d(idtexts) } js <- gsub("%idverts%", idverts, js) js <- gsub("%subid%", subsceneInfo()$id, js) js <- gsub("%idtexts%", toJSON(idtexts), js) js <- gsub("%tolerance%", tolerance, js) js <- gsub("%persist%", persist, js) js <- gsub("%customlabeller%", toJSON(custom_labeller), js) } else idtexts <- numeric() setUserCallbacks(0, update="hoverSelect", scene = scene, applyToScene = applyToScene, applyToDev = TRUE, javascript = js) structure(lowlevel(c(idverts, unlist(idtexts))), oldPar = opar, oldDev = odev) } rgl/R/asy.R0000644000176200001440000003472414771520323012174 0ustar liggesuserswriteASY <- function(scene = scene3d(), title = "scene", outtype = c("pdf", "eps", "asy", "latex", "pdflatex"), prc = TRUE, runAsy = "asy %filename%", defaultFontsize = 12, width = 7, height = 7, ppi = 100, ids = tagged3d(tags), tags = NULL, version = "2.65") { withColors <- TRUE withNormals <- FALSE outtype <- match.arg(outtype) version <- numeric_version(version) writeHeader <- function() { outformat <- c(pdf = "pdf", eps = "eps", asy = "", latex = "eps", pdflatex = "pdf")[outtype] prc <- if (prc) "true" else "false" userMatrix <- get.par3d("userMatrix") defaultObserver <- (c(get.par3d("observer"), 1) %*% userMatrix)[1:3] up <- (c(0, 1, 0, 1) %*% userMatrix)[1:3] FOV <- get.par3d("FOV")*pi/180 if (FOV > 0) { projection <- "perspective" dist <- 0.8/tan(FOV/2) defaultObserver <- defaultObserver*dist/sqrt(sum(defaultObserver^2)) } else projection <- "orthographic" result <<- c(result, subst( '// %title% produced by rgl', title), if (outtype %in% c("pdf", "eps")) subst( 'settings.outformat = "%outformat%";', outformat), subst( 'settings.prc = %prc%; size(%width%inches, %height%inches); import graph3; currentprojection = %projection%(%x%, %y%, %z%, up = (%ux%, %uy%, %uz%)); defaultpen(fontsize(%defaultFontsize%)); ticklabel RGLstrings(real[] at, string[] label) { return new string(real x) { int i = search(at, x); if (i < 0) return ""; else return label[i]; }; } ticklabel RGLScale(real s) { return new string(real x) {return format(s*x);}; }', prc, width, height, x=defaultObserver[1], y=defaultObserver[2], z=defaultObserver[3], ux = up[1], uy = up[2], uz = up[3], projection, defaultFontsize)) } # simulate rgl.attrib get.attrib <- function(id, attrib) { obj <- scene$objects[[as.character(id)]] obj[[attrib]] } # simulate ids3d get.ids <- function(type = "shapes") { ids <- names(scene$objects) types <- vapply(ids, function(x) scene$objects[[x]]$type, "") if (length(s <- which(type %in% "shapes"))) { type <- c(type[-s], "points", "linestrip", "lines", "text", "triangles", "quads", "surface", "spheres", "planes", "abclines", "clipplanes", "sprites") } keep <- types %in% type data.frame(id = as.numeric(ids[keep]), type = types[keep]) } getmaterial <- function(id) { result <- scene$material this <- scene$objects[[as.character(id)]]$material result[names(this)] <- this result } getScaling <- function() { scale <- get.par3d("scale") scale/avgScale() } getCentre <- function() { bbox <- get.par3d("bbox") c(mean(bbox[1:2]), mean(bbox[3:4]), mean(bbox[5:6])) } getVertices <- function(id) { scale <- getScaling() vertices <- scale(get.attrib(id, "vertices"), center=FALSE, scale=1/scale) if (withColors) { colors <- get.attrib(id, "colors") if (nrow(colors) == 1) colors <- colors[rep(1, nrow(vertices)),,drop = FALSE] } if (withNormals) { normals <- get.attrib(id, "normals") if (!nrow(normals)) normals <- 0*vertices } cbind(vertices, if (withColors) colors, if (withNormals) normals) } get.par3d <- function(attr = NULL) { par3d <- scene$rootSubscene$par3d if (!is.null(attr)) par3d <- par3d[[attr]] par3d } rgba <- c("r", "g", "b", "a") lastCol <- c(0,0,0,1) lastSize <- 0.5 setPen <- function(col = lastCol, size = lastSize) { if (any(col[1:3] != lastCol[1:3])) { result <<- c(result, subst( 'currentpen = colorless(currentpen) + rgb(%r%, %g%, %b%);', r = col[1], g = col[2], b = col[3])) lastCol[1:3] <<- col[1:3] } if (col[4] != lastCol[4]) { result <<- c(result, subst( 'currentpen += opacity(%a%);', a = col[4])) lastCol[4] <<- col[4] } if (size != lastSize) { result <<- c(result, subst( 'currentpen += linewidth(%size%);', size)) lastSize <<- size } } writePoly <- function(vertices) { if (any(!is.finite(vertices))) return() setPen(apply(vertices[, rgba], 2, mean)) v <- vertices[1, 1:3] result <<- c(result, subst('draw(surface((%x%, %y%, %z%)', x=v[1], y=v[2], z=v[3])) for (j in seq_len(nrow(vertices))[-1]) { v <- vertices[j, 1:3] result <<- c(result, subst('--(%x%, %y%, %z%)', x=v[1], y=v[2], z=v[3])) } result <<- c(result, '--cycle), light=currentlight);') } writeTriangles <- function(id) { vertices <- getVertices(id) n <- nrow(vertices) %/% 3 for (i in seq_len(n)) writePoly(vertices[3*i-2:0,]) } writeQuads <- function(id) { vertices <- getVertices(id) n <- nrow(vertices) %/% 4 for (i in seq_len(n)) writePoly(vertices[4*i-3:0,]) } writeSurface <- function(id) { vertices <- getVertices(id) dims <- get.attrib(id, "dim") nx <- dims[1] nz <- dims[2] for (i in seq_len(nz)[-nz]) for (j in seq_len(nx)[-nx]) writePoly(vertices[c((i-1)*nx + j, i*nx + j, i*nx + j + 1, (i-1)*nx + j + 1),]) } writeSpheres <- function(id) { vertices <- getVertices(id) n <- nrow(vertices) radii <- get.attrib(id, "radii")/4 radii <- rep(radii, length.out=n) for (i in seq_len(n)) { setPen(vertices[i, rgba]) v <- vertices[i, 1:3] result <<- c(result, subst('draw(shift((%x%, %y%, %z%))*scale3(%r%)*unitsphere);', x = v[1], y = v[2], z = v[3], r = radii[i])) } } avgScale <- function() { bbox <- get.par3d("bbox") ranges <- c(bbox[2]-bbox[1], bbox[4]-bbox[3], bbox[6]-bbox[5]) if (prod(ranges) == 0) 1 else exp(mean(log(ranges))) } writePoints <- function(id) { setPen(size = getmaterial(id)$size) vertices <- getVertices(id) n <- nrow(vertices) for (i in seq_len(n)) { setPen(vertices[i, rgba]) result <<- c(result, subst('draw((%x%, %y%, %z%));', x = vertices[i, 1], y = vertices[i, 2], z = vertices[i, 3])) } } writeText <- function(id) { vertices <- getVertices(id) n <- nrow(vertices) texts <- get.attrib(id, "texts") texts <- rep(texts, length.out = n) adj <- get.attrib(id, "adj") adj <- adj[rep(seq_len(nrow(adj)), length.out = n),, drop = FALSE] for (i in seq_len(n)) { setPen(vertices[i, rgba]) if (all(!is.na(vertices[i, 1:3]))) result <<- c(result, subst('label("%text%", position = (%x%, %y%, %z%), align = (%ax%,%ay%));', x = vertices[i, 1], y = vertices[i, 2], z = vertices[i, 3], text = texts[i], ax = 1-2*adj[i, 1], ay = 1-2*adj[i, 2])) } } writeSegments <- function(id) { setPen(size = getmaterial(id)$lwd) vertices <- getVertices(id) n <- nrow(vertices) %/% 2 for (i in seq_len(n)) { i1 <- 2*i - 1 i2 <- i1 + 1 if (all(!is.na(vertices[c(i1, i2), 1:3]))) { setPen((vertices[i1, rgba] + vertices[i2, rgba])/2) result <<- c(result, subst('draw((%x1%, %y1%, %z1%)--(%x2%, %y2%, %z2%));', x1 = vertices[i1, 1], y1 = vertices[i1, 2], z1 = vertices[i1, 3], x2 = vertices[i2, 1], y2 = vertices[i2, 2], z2 = vertices[i2, 3])) } } } writeLines <- function(id) { setPen(size = getmaterial(id)$lwd) vertices <- getVertices(id) n <- nrow(vertices) open <- FALSE for (i in seq_len(n)) { if (open) { if (any(is.na(vertices[i, 1:3]))) { result <<- c(result, ");") open <- FALSE } else result <<- c(result, subst('--(%x%, %y%, %z%)', x = vertices[i, 1], y = vertices[i, 2], z = vertices[i, 3])) } else if (all(!is.na(vertices[i, 1:3]))) { setPen(vertices[i, rgba]) result <<- c(result, subst('draw((%x%, %y%, %z%)', x = vertices[i, 1], y = vertices[i, 2], z = vertices[i, 3])) open <- TRUE } } if (open) result <<- c(result, ');') } writeBackground <- function(id) { col <- get.attrib(id, "colors") result <<- c(result, subst( 'currentlight.background = rgb(%r%, %g%, %b%);', r = col[1], g=col[2], b=col[3] )) } writeBBox <- function(id) { setPen(size = getmaterial(id)$lwd) bbox <- get.par3d("bbox") scale <- getScaling() vertices <- getVertices(id) ticks <- vertices[,1] ticks <- ticks[!is.na(ticks)] if (length(ticks)) xticks <- subst('Ticks3(1, Ticks = new real[] {%ticks%}, ticklabel = RGLScale(%scale%))', scale = 1/scale[1], ticks = paste(ticks, collapse=",")) else xticks <- subst('Ticks3(1, ticklabel = RGLScale(%scale%))', scale = 1/scale[1]) ticks <- vertices[,2] ticks <- ticks[!is.na(ticks)] if (length(ticks)) yticks <- subst('Ticks3(1, Ticks = new real[] {%ticks%}, ticklabel = RGLScale(%scale%))', scale = 1/scale[2], ticks = paste(ticks, collapse=",")) else yticks <- subst('Ticks3(1, ticklabel = RGLScale(%scale%))', scale = 1/scale[2]) ticks <- vertices[,3] ticks <- ticks[!is.na(ticks)] if (length(ticks)) zticks <- subst('Ticks3(1, Ticks = new real[] {%ticks%}, ticklabel = RGLScale(%scale%))', scale = 1/scale[3], ticks = paste(ticks, collapse=",")) else xticks <- subst('Ticks3(1, ticklabel = RGLScale(%scale%))', scale = 1/scale[3]) bbox <- bbox * rep(scale, each = 2) result <<- c(result, subst( 'xaxis3(axis=YZEquals(y=%ymin%, z=%zmin%), xmin=%xmin%, xmax=%xmax%, ticks = %xticks%); xaxis3(axis=YZEquals(y=%ymin%, z=%zmax%), xmin=%xmin%, xmax=%xmax%); xaxis3(axis=YZEquals(y=%ymax%, z=%zmin%), xmin=%xmin%, xmax=%xmax%); xaxis3(axis=YZEquals(y=%ymax%, z=%zmax%), xmin=%xmin%, xmax=%xmax%); yaxis3(axis=XZEquals(x=%xmin%, z=%zmin%), ymin=%ymin%, ymax=%ymax%, ticks = %yticks%); yaxis3(axis=XZEquals(x=%xmin%, z=%zmax%), ymin=%ymin%, ymax=%ymax%); yaxis3(axis=XZEquals(x=%xmax%, z=%zmin%), ymin=%ymin%, ymax=%ymax%); yaxis3(axis=XZEquals(x=%xmax%, z=%zmax%), ymin=%ymin%, ymax=%ymax%); zaxis3(axis=XYEquals(x=%xmin%, y=%ymin%), zmin=%zmin%, zmax=%zmax%, ticks = %zticks%); zaxis3(axis=XYEquals(x=%xmin%, y=%ymax%), zmin=%zmin%, zmax=%zmax%); zaxis3(axis=XYEquals(x=%xmax%, y=%ymin%), zmin=%zmin%, zmax=%zmax%); zaxis3(axis=XYEquals(x=%xmax%, y=%ymax%), zmin=%zmin%, zmax=%zmax%);', xmin = bbox[1], xmax = bbox[2], ymin=bbox[3], ymax=bbox[4], zmin=bbox[5], zmax=bbox[6], xticks, yticks, zticks)) } writeLights <- function(ids) { if (!length(ids)) result <<- c(result, 'currentlight = nolight;') else { col <- array(NA, c(length(ids), 3, 3)) pos <- matrix(NA, nrow=length(ids), ncol=3) for (i in seq_along(ids)) { col[i,,] <- get.attrib(ids[i], "colors")[1:3, 1:3] pos[i,] <- get.attrib(ids[i], "vertices")[1,] } result <<- c(result, 'currentlight = light(') if (version < "2.50") { cols <- paste(paste0("rgb(", col[, 1, 1], ",", col[, 1, 2], ",", col[, 1, 3], ")"), collapse = ",") result <<- c(result, subst( 'ambient=new pen[] {%cols%},', cols )) } cols <- paste(paste0("rgb(", col[, 2, 1], ",", col[, 2, 2], ",", col[, 2, 3], ")"), collapse = ",") result <<- c(result, subst('diffuse = new pen[] {%cols%},', cols)) cols <- paste(paste0("rgb(", col[, 3, 1], ",", col[, 3, 2], ",", col[, 3, 3], ")"), collapse = ",") result <<- c(result, subst('specular = new pen[] {%cols%},', cols)) pos <- paste(paste0("(", pos[, 1], ",", pos[, 2], ",", pos[, 3], ")"), collapse = ",") result <<- c(result, subst('position = new triple[] {%pos%}', pos)) if (version < "2.47") result <<- c( result, subst( ', viewport = %viewpoint%', pos, viewpoint = if (get.attrib(ids[1], "viewpoint")) "true" else "false" ) ) result <<- c(result, ');') } } knowntypes <- c("points", "linestrip", "lines", "text", "triangles", "quads", "surface", "spheres", "planes", "abclines", "background", "bboxdeco", "light") # Execution starts here! allids <- get.ids(c("shapes", "background", "bboxdeco", "light")) if (is.null(ids)) { ids <- allids types <- as.character(ids$type) ids <- ids$id } else { ind <- match(ids, allids$id) keep <- !is.na(ind) if (any(!keep)) warning(gettextf("Object(s) with id %s not found", paste(ids[!keep], collapse=" ")), domain = NA) ids <- ids[keep] types <- allids$type[ind[keep]] } unknowntypes <- setdiff(types, knowntypes) if (length(unknowntypes)) warning(gettextf("Object type(s) %s not handled", paste("'", unknowntypes, "'", sep="", collapse=", ")), domain = NA) keep <- types %in% knowntypes ids <- ids[keep] types <- types[keep] result <- NULL writeHeader() # Lights are done first. writeLights(ids[types == "light"]) for (i in seq_along(ids)) { result <<- c(result, subst('// %type% object %id%', type = types[i], id = ids[i])) switch(types[i], planes =, triangles = writeTriangles(ids[i]), quads = writeQuads(ids[i]), surface = writeSurface(ids[i]), spheres = writeSpheres(ids[i]), points = writePoints(ids[i]), abclines =, lines = writeSegments(ids[i]), linestrip = writeLines(ids[i]), text = writeText(ids[i]), background = writeBackground(ids[i]), bboxdeco = writeBBox(ids[i]), light = {} # nolint ) } if (outtype %in% c("latex", "pdflatex")) { filename <- paste0(title, ".tex") result <- c("\\begin{asy}", result, "\\end{asy}") } else filename <- paste0(title, ".asy") base::writeLines(result, filename) if (outtype %in% c("pdf", "eps")) { system(subst(runAsy, filename)) filename <- paste0(title, ".", outtype) } invisible(filename) } rgl/R/enum.R0000644000176200001440000000527515011677075012350 0ustar liggesusers# enumerations rgl.enum <- function( name, ..., multi = FALSE) { choices <- list( ... ) names <- attr(choices,"names") if (multi) pos <- pmatch( name, c(names, "all") ) else pos <- pmatch( name, names ) max <- length(names) if ( any( is.na(pos) ) ) stop(gettextf("Symbolic value must be chosen from: %s", list(names)), domain = NA) else if ( (max+1) %in% pos ) pos <- seq_along(names) id <- unlist(choices[pos]) if ( length(id) > 1 && !multi ) stop("Multiple choices not allowed") return( id ) } rgl.enum.nodetype <- function(type) rgl.enum( type, shapes=1, lights=2, bboxdeco=3, userviewpoint=4, material=5, background=6, subscene=7, modelviewpoint=8, multi = TRUE ) rgl.enum.attribtype <- function(attrib) rgl.enum( attrib, vertices=1, normals=2, colors=3, texcoords=4, dim=5, texts=6, cex=7, adj=8, radii=9, centers=10, ids=11, usermatrix=12, types=13, flags=14, offsets=15, family=16, font=17, pos=18, fogscale=19, axes=20, indices=21, shapenum=22) rgl.enum.pixfmt <- function(fmt) rgl.enum( fmt, png=0 ) rgl.enum.polymode <- function(mode) rgl.enum( mode, filled=1, lines=2, points=3, culled=4) rgl.enum.textype <- function(textype) rgl.enum( textype, alpha=1, luminance=2, luminance.alpha=3, rgb=4, rgba=5 ) rgl.enum.fogtype <- function(fogtype) rgl.enum(fogtype, none=1, linear=2, exp=3, exp2=4) rgl.enum.primtype <- function(primtype) rgl.enum( primtype, points=1, lines=2, triangles=3, quadrangles=4, linestrips=5 ) rgl.enum.texminfilter <- function(minfiltertype) rgl.enum(minfiltertype, nearest=0, linear=1, nearest.mipmap.nearest=2, nearest.mipmap.linear=3, linear.mipmap.nearest=4, linear.mipmap.linear=5) rgl.enum.texmagfilter <- function(magfiltertype) rgl.enum(magfiltertype, nearest=0, linear=1) rgl.enum.gl2ps <- function(postscripttype) rgl.enum(postscripttype, ps=0, eps=1, tex=2, pdf=3, svg=4, pgf=5) rgl.enum.pixelcomponent <- function(component) rgl.enum(component, red=0, green=1, blue=2, alpha=3, depth=4, luminance=5) rgl.enum.depthtest <- function(depthtest) rgl.enum(depthtest, never=0, less=1, equal=2, lequal=3, greater=4, notequal=5, gequal=6, always= 7) rgl.enum.blend <- function(blend) rgl.enum(blend, zero=0, one=1, src_color=2, one_minus_src_color=3, dst_color=4, one_minus_dst_color=5, src_alpha=6, one_minus_src_alpha=7, dst_alpha=8, one_minus_dst_alpha=9, constant_color=10, one_minus_constant_color=11, constant_alpha=12, one_minus_constant_alpha=13, src_alpha_saturate=14) rgl.enum.texmode <- function(texmode) rgl.enum(texmode, replace = 0, modulate = 1, decal = 2, blend = 3, add = 4) rgl/R/clipMesh3d.R0000644000176200001440000005551114771520323013370 0ustar liggesusersas.tmesh3d <- function(x, ...) UseMethod("as.tmesh3d") as.tmesh3d.default <- function(x, drop = FALSE, ...) { as.tmesh3d(as.mesh3d(x, ...), drop = drop) } as.tmesh3d.mesh3d <- function(x, drop = FALSE, keepTags = FALSE, ...) { mesh <- x ib <- mesh$ib it <- mesh$it np <- length(mesh$ip) ns <- length(mesh$is)/2 nt <- length(it)/3 nq <- length(ib)/4 hasColors <- FALSE hasAlpha <- FALSE if (!is.null(mesh$material) && !is.null(mesh$meshColor) && mesh$meshColor == "faces") { hasColors <- length(mesh$material$color) > 1 hasAlpha <- length(mesh$material$alpha) > 1 } tags <- getTags(mesh) if (nq) { mesh$it <- cbind(it, matrix(ib[rep(4*(seq_len(nq) - 1), each = 6) + rep(c(1, 2, 3, 1, 3, 4), nq)], nrow = 3)) mesh$ib <- NULL ofs <- np + ns + nt if (hasColors) { color <- rep_len(mesh$material$color, ofs + nq) mesh$material$color[ofs + seq_len(2*nq)] <- rep(color[ofs + seq_len(nq)], each = 2) } if (hasAlpha) { alpha <- rep_len(mesh$material$alpha, ofs + nq) mesh$material$alpha[ofs + seq_len(2*nq)] <- rep(alpha[ofs + seq_len(nq)], each = 2) } tags[ofs + seq_len(2*nq)] <- rep(tags[ofs + seq_len(nq)], each = 2) } if (drop) { mesh$is <- NULL mesh$ip <- NULL if (ns + np) tags <- tags[-seq_len(ns + np)] } if (keepTags) mesh$tags <- tags else mesh$tags <- NULL mesh } .getVertexFn <- function(fn, envir) { if (is.character(fn)) fn <- switch(fn, x = function(xyz) xyz[,1], y = function(xyz) xyz[,2], z = function(xyz) xyz[,3], get(fn, envir = envir, mode = "function")) # Accept functions that take x, y, z as parameters if (all(c("x", "y", "z") %in% names(formals(fn)))) { oldfn <- fn fn <- function(xyz) oldfn(x = xyz[,1], y = xyz[,2], z = xyz[,3]) } fn } clipMesh3d <- function(mesh, fn = "z", bound = 0, greater = TRUE, minVertices = 0, plot = FALSE, keepValues = FALSE, keepTags = FALSE) { stopifnot(inherits(mesh, "mesh3d")) # First, convert quads to triangles mesh <- as.tmesh3d(mesh, keepTags = TRUE) nverts <- ncol(mesh$vb) oldnverts <- nverts - 1 while (nverts < minVertices && oldnverts < nverts && !is.numeric(fn)) { oldnverts <- nverts mesh <- subdivision3d(mesh, deform = FALSE, normalize = TRUE, keepTags = TRUE) nverts <- ncol(mesh$vb) } if (is.null(fn)) fn <- mesh$values if (is.null(fn)) stop("'fn' can only be NULL if 'mesh' contains values") if (is.numeric(fn)) values <- fn else { fn <- .getVertexFn(fn, parent.frame()) verts <- asEuclidean(t(mesh$vb)) values <- fn(verts) } # The bound might be infinite, which messes up the arithmetic. # Force it to a finite value r <- range(values) delta <- max(abs(r)) if (bound < r[1]) bound <- r[1] - delta else if (bound > r[2]) bound <- r[2] + delta values <- values - bound if (!greater) values <- -values if (length(values) != ncol(mesh$vb)) stop("'fn' should give one value per vertex") if (anyNA(values)) stop("'fn' should not include NA values") # Now, set all w values to 1 mesh$vb <- t( cbind(t(mesh$vb[1:3,])/mesh$vb[4,], 1)) if (!is.null(mesh$normals) && nrow(mesh$normals) == 4) mesh$normals <- t(t(mesh$normals[1:3,])/mesh$normals[4,]) tags <- getTags(mesh) np <- length(mesh$ip) ns <- length(mesh$is)/2 nt <- length(mesh$it)/3 # nq is zero because of as.tmesh3d ofs <- np + ns tags0 <- tags[ofs + seq_len(nt)] newVertices <- integer() getNewVertex <- function(good, bad) { names <- paste0(good, "_", bad) new <- which(!(names %in% names(newVertices))) if (length(new)) { goodvals <- values[good[new]] badvals <- values[bad[new]] alphas <- goodvals/(goodvals - badvals) newverts <- t((1 - alphas)*t(mesh$vb[, good[new]]) + alphas*t(mesh$vb[, bad[new]])) newvertnums <- seq_len(ncol(newverts)) + ncol(mesh$vb) if (!is.null(mesh$normals)) mesh$normals <<- cbind(mesh$normals, t((1 - alphas)*t(mesh$normals[, good[new]]) + alphas*t(mesh$normals[, bad[new]]))) if (!is.null(mesh$texcoords)) mesh$texcoords <<- cbind(mesh$texcoords, t((1 - alphas)*t(mesh$texcoords[, good[new]]) + alphas*t(mesh$texcoords[, bad[new]]))) if (!is.null(mesh$material)) { if (!is.null(mesh$material$color) && length(mesh$material$color) == ncol(mesh$vb)) { rgb <- col2rgb(mesh$material$color) newrgb <- (1 - alphas)*rgb[, good[new],drop = FALSE] + alphas*rgb[, bad[new], drop = FALSE] mesh$material$color <<- c(mesh$material$color, rgb(newrgb["red",], newrgb["green",], newrgb["blue",], maxColorValue = 255)) } if (!is.null(mesh$material$alpha) && length(mesh$material$alpha) == ncol(mesh$vb)) mesh$material$alpha <<- c(mesh$material$alpha, (1-alphas)*mesh$material$alpha[good[new]] + alphas*mesh$material$alpha[bad[new]]) } values <<- c(values, rep(0, ncol(newverts))) mesh$vb <<- cbind(mesh$vb, newverts) newVertices[names[new]] <<- newvertnums } newVertices[names] } keep <- values >= 0 keept <- matrix(keep[mesh$it], nrow = 3) counts <- colSums(keept) # Number of vertices to keep for each triangle singles <- which(counts == 1) if (length(singles)) { theseTriangles <- mesh$it[, singles, drop = FALSE] goodRow <- apply(keept[, singles, drop = FALSE], 2, function(col) which(col)) allcols <- seq_len(ncol(theseTriangles)) goodVertex <- theseTriangles[cbind(goodRow, allcols)] badVertex1 <- theseTriangles[cbind(goodRow %% 3 + 1, allcols)] badVertex2 <- theseTriangles[cbind((goodRow + 1) %% 3 + 1, allcols)] mesh$it[cbind(goodRow %% 3 + 1, singles)] <- getNewVertex(goodVertex, badVertex1) mesh$it[cbind((goodRow + 1) %% 3 + 1, singles)] <- getNewVertex(goodVertex, badVertex2) } doubles <- which(counts == 2) if (length(doubles)) { theseTriangles <- mesh$it[, doubles, drop = FALSE] badRow <- apply(keept[, doubles, drop = FALSE], 2, function(col) which(!col)) allcols <- seq_len(ncol(theseTriangles)) badVertex <- theseTriangles[cbind(badRow, allcols)] goodVertex1 <- theseTriangles[cbind(badRow %% 3 + 1, allcols)] goodVertex2 <- theseTriangles[cbind((badRow + 1) %% 3 + 1, allcols)] newVertex1 <- getNewVertex(goodVertex1, badVertex) newVertex2 <- getNewVertex(goodVertex2, badVertex) mesh$it[cbind(badRow, doubles)] <- newVertex1 mesh$it <- cbind(mesh$it, rbind(newVertex1, goodVertex2, newVertex2)) tags0 <- c(tags0, tags0[doubles]) } zeros <- which(counts == 0) if (length(zeros)) { mesh$it <- mesh$it[, -zeros] tags0 <- tags0[-zeros] } tags <- c(tags[seq_len(ofs)], tags0) mesh$tags <- tags if (plot) shade3d(mesh) else { if (keepValues) { if (!greater) values <- -values mesh$values <- values + bound } cleanMesh3d(mesh, keepTags = keepTags) } } cleanMesh3d <- function(mesh, onlyFinite = TRUE, allUsed = TRUE, rejoin = FALSE, keepTags = TRUE) { if (rejoin) { ntriangs <- ncol(mesh$it) oldntriangs <- ntriangs + 1 while (ntriangs < oldntriangs) { oldntriangs <- ntriangs mesh <- rejoinMesh3d(mesh) ntriangs <- ncol(mesh$it) } } tags <- getTags(mesh) nold <- ncol(mesh$vb) keep <- TRUE if (onlyFinite) keep <- keep & apply(mesh$vb, 2, function(col) all(is.finite(col))) if (allUsed) keep <- keep & (seq_len(nold) %in% c(mesh$ip, mesh$is, mesh$it, mesh$ib)) if (!all(keep)) { oldnums <- which(keep) newnums <- rep(NA, nold) nnew <- sum(keep) newnums[oldnums] <- seq_len(nnew) mesh$vb <- mesh$vb[,oldnums] np <- length(mesh$ip) ns <- length(mesh$is)/2 nt <- length(mesh$it)/3 nq <- length(mesh$ib)/4 if (!is.null(mesh$ip)) { newcols <- newnums[mesh$ip] dim(newcols) <- dim(mesh$ip) keep <- apply(newcols, 2, function(col) !is.na(col)) mesh$ip <- newcols[,keep, drop = FALSE] tags0 <- tags[seq_len(np)] tags0 <- tags0[keep] tags <- c(tags0, tags[np + seq_len(np + nt + nq)]) np <- length(tags0) } if (!is.null(mesh$is)) { newcols <- newnums[mesh$is] dim(newcols) <- dim(mesh$is) keep <- apply(newcols, 2, function(col) all(!is.na(col))) mesh$is <- newcols[,keep, drop = FALSE] tags0 <- tags[np + seq_len(ns)] tags0 <- tags0[keep] tags <- c(tags[seq_len(np)], tags0, tags[np + ns + seq_len(nt + nq)]) ns <- length(tags0) } if (!is.null(mesh$it)) { newcols <- newnums[mesh$it] dim(newcols) <- dim(mesh$it) keep <- apply(newcols, 2, function(col) all(!is.na(col))) mesh$it <- newcols[,keep, drop = FALSE] tags0 <- tags[np + ns + seq_len(nt)] tags0 <- tags0[keep] tags <- c(tags[seq_len(np + ns)], tags0, tags[np + ns + nt + seq_len(nq)]) nt <- length(tags0) } if (!is.null(mesh$ib)) { newcols <- newnums[mesh$ib] dim(newcols) <- dim(mesh$ib) keep <- apply(newcols, 2, function(col) all(!is.na(col))) mesh$ib <- newcols[,keep, drop = FALSE] tags0 <- tags[np + ns + nt + seq_len(nq)] tags0 <- tags0[keep] tags <- c(tags[seq_len(np + ns + nt)], tags0) nq <- length(tags0) } if (!is.null(mesh$normals)) mesh$normals <- mesh$normals[, oldnums] if (!is.null(mesh$texcoords)) mesh$texcoords <- mesh$texcoords[, oldnums] if (!is.null(mesh$meshColor) && mesh$meshColor == "vertices" && !is.null(mesh$material) && length(mesh$material$color) == nold) mesh$material$color <- mesh$material$color[oldnums] if (!is.null(mesh$values)) mesh$values <- mesh$values[oldnums] } if (keepTags) mesh$tags <- tags else mesh$tags <- NULL mesh } subdivideLines <- function(x) { nverts <- nrow(x$vertices) newverts <- nverts indices <- rbind(seq_len(nverts), NA, NA) finite <- apply(x$vertices, 1, function(row) all(is.finite(row))) type <- x$type if (type == "lines") { for (j in 2*seq_len(nverts %/% 2)) { i <- j - 1 if (finite[i] && finite[j]) { for (attr in c("vertices", "normals", "colors")) { if (!is.null(x[[attr]]) && nrow(x[[attr]]) > 1) { new <- (x[[attr]][i,] + x[[attr]][j,])/2 while (nrow(x[[attr]]) < newverts + 2) x[[attr]] <- rbind(x[[attr]], x[[attr]]) x[[attr]][newverts + 1,] <- new x[[attr]][newverts + 2,] <- new } } indices[2, i] <- newverts + 1 indices[3, i] <- newverts <- newverts + 2 } } } else if (x$type == "linestrip") { for (j in seq_len(nverts)[-1]) { i <- j - 1 if (finite[i] && finite[j]) { for (attr in c("vertices", "normals", "colors")) { if (!is.null(x[[attr]]) && nrow(x[[attr]]) > 1) { new <- (x[[attr]][i,] + x[[attr]][j,])/2 while (nrow(x[[attr]]) < newverts + 1) x[[attr]] <- rbind(x[[attr]], x[[attr]]) x[[attr]][newverts + 1,] <- new } } indices[2, i] <- newverts <- newverts + 1 } } } if (nverts < newverts) { indices <- c(indices) indices <- indices[!is.na(indices)] for (attr in c("vertices", "normals", "colors")) if (!is.null(x[[attr]]) && nrow(x[[attr]]) > 1) x[[attr]] <- x[[attr]][indices,,drop = FALSE] } x } # Undo subdivision for triangles rejoinMesh3d <- function(x, tol = 1.e-6) { ntriangs <- length(x$it)/3 if (ntriangs < 4) return(x) np <- length(x$ip) ns <- length(x$is)/2 nq <- length(x$ib)/4 ofs <- np + ns tags <- getTags(x) tags0 <- tags[ofs + seq_len(ntriangs)] vals <- if (nrow(x$vb) == 4) asEuclidean(t(x$vb)) else t(x$vb) if (!is.null(x$normals)) vals <- cbind(vals, if(nrow(x$normals) == 4) asEuclidean(t(x$normals)) else t(x$normals)) if (!is.null(x$texcoords)) vals <- cbind(vals, t(x$texcoords)) indices <- seq_len(ntriangs) for (j in seq_len(ntriangs)[-(1:3)]) { i <- j - (3:0) verts <- c(x$it[,i]) thistags <- tags0[i] if ( all(thistags == thistags[1]) && !any(is.na(indices[i])) && verts[2] == verts[6] && verts[3] == verts[8] && verts[5] == verts[9] && verts[6] == verts[11] && verts[8] == verts[10] && verts[9] == verts[12] && !(verts[1] %in% verts[-1]) && !(verts[4] %in% verts[-4]) && !(verts[7] %in% verts[-7])) { v1 <- verts[c(1,4,7,2,3,5)] diffs <- c(vals[v1[1],] - vals[v1[2],], vals[v1[1],] - vals[v1[3],], vals[v1[2],] - vals[v1[3],]) use <- !is.na(diffs) & diffs > tol if (any(use)) { p <- c(vals[v1[1],] - vals[v1[4],], vals[v1[1],] - vals[v1[5],], vals[v1[2],] - vals[v1[6],])[use]/diffs[use] if (max(abs(p - 0.5)) < tol) { # Found one! indices[i[-1]] <- NA x$it[,i[1]] <- c(v1[1], v1[2], v1[3]) } } } } indices <- indices[!is.na(indices)] x$it <- x$it[,indices] x$tags <- c(tags[seq_len(ofs)], tags0[indices], tags[ofs + ntriangs + seq_len(nq)]) x } rejoinLines3d <- function(x, tol = 1.e-6) { nverts <- nrow(x$vertices) indices <- seq_len(nverts) finite <- apply(x$vertices, 1, function(row) all(is.finite(row))) type <- x$type hasattrs <- character() for (attr in c("vertices", "normals", "colors")) if (!is.null(x[[attr]]) && nrow(x[[attr]]) > 1) hasattrs <- c(hasattrs, attr) if (type == "lines") { for (j in 2*seq_len(nverts %/% 2)[-1]) { i <- j - (3:0) if (all(finite[i])) { attrs <- matrix(numeric(), nrow = 4, ncol = 0) for (attr in hasattrs) attrs <- cbind(attrs, x[[attr]][i,]) diff <- attrs[4,] - attrs[1,] use <- !is.na(diff) & abs(diff) > tol p <- c((attrs[2,use] - attrs[1,use])/diff[use], (attrs[3,use] - attrs[1,use])/diff[use]) if (all(!is.na(p) & p >= 0 & p <= 1) && diff(range(p)) < tol) { # pts 2 & 3 are equal and are exactly between # pts 1 & 4. Merge them into 3,4. for (attr in hasattrs) x[[attr]][i[3],] <- x[[attr]][i[1],] indices[i[1:2]] <- NA } } } } else if (type == "linestrip") { for (j in seq_len(nverts)[-(1:2)]) { i <- j - (2:0) if (all(finite[i])) { attrs <- matrix(numeric(), nrow = 3, ncol = 0) for (attr in hasattrs) attrs <- cbind(attrs, x[[attr]][i,]) diff <- attrs[3,] - attrs[1,] use <- !is.na(diff) & abs(diff) > tol p <- (attrs[2,use] - attrs[1,use])/diff[use] if (all(!is.na(p) & p >= 0 & p <= 1) && diff(range(p)) < tol) { # pt 2 is exactly between # pts 1 & 3. Move 1 there. for (attr in hasattrs) x[[attr]][i[2],] <- x[[attr]][i[1],] indices[i[1]] <- NA } } } } if (anyNA(indices)) { indices <- indices[!is.na(indices)] for (attr in hasattrs) x[[attr]] <- x[[attr]][indices,] } x } clipObj3d <- function(ids = tagged3d(tags), fn, bound = 0, greater = TRUE, minVertices = 0, replace = TRUE, tags) { getValues <- function(obj) { verts <- obj$vertices nverts <- nrow(verts) values <- rep(NA_real_, nverts) finite <- apply(verts, 1, function(row) all(is.finite(row))) values[finite] <- fn(verts[finite,]) - bound if (!greater) values <- -values values } getKeep <- function(values) { !is.na(values) & values > 0 } applyKeep <- function() { for (attr in c("vertices", "normals", "colors", "texcoords", "centers", "adj")) if (!is.null(obj[[attr]]) && nrow(obj[[attr]]) > 1) obj[[attr]] <- obj[[attr]][keep,,drop = FALSE] for (attr in c("texts", "cex", "adj", "radii", "ids", "types", "flags", "offsets", "pos")) if (length(obj[[attr]]) > 1) obj[[attr]] <- obj[[attr]][keep] obj } scene <- scene3d() if (missing(ids)) ids <- names(scene$objects) names <- names(ids) ids <- as.character(ids) result <- integer() minVertices <- rep(minVertices, length.out = length(ids)) names(minVertices) <- ids fn <- .getVertexFn(fn, parent.frame()) for (id in ids) { obj <- scene$objects[[id]] type <- obj$type nverts <- nrow(obj$vertices) newid <- NA switch(type, triangles=, quads=, planes=, surface= { mesh <- as.mesh3d(obj) mesh <- cleanMesh3d(mesh) clipped <- clipMesh3d(mesh, fn, bound, greater, minVertices[id]) clipped <- cleanMesh3d(clipped, rejoin = TRUE) newid <- shade3d(clipped, override = FALSE) }, points =, text =, spheres =, sprites = { keep <- getKeep(getValues(obj)) if (!all(keep)) { obj <- applyKeep() newid <- plot3d(obj) } }, lines = { oldnverts <- nverts - 1 while (nverts < minVertices[id] && nverts > oldnverts) { oldnverts <- nverts obj <- subdivideLines(obj) nverts <- nrow(obj$vertices) } values <- getValues(obj) keep <- getKeep(values) if (!all(keep)) { for (j in 2*seq_len(nverts %/% 2)) { i <- j - 1 if (is.na(values[i]) || is.na(values[j])) { keep[i] <- keep[j] <- FALSE } else if (!keep[i] && !keep[j]) {# no change } else if (!keep[i]) { p <- 1 - abs(values[i])/(abs(values[i]) + values[j]) obj$vertices[i,] <- p*obj$vertices[i,] + (1-p)*obj$vertices[j,] keep[i] <- TRUE } else if (!keep[j]) { p <- 1 - abs(values[j])/(abs(values[j]) + values[i]) obj$vertices[j,] <- p*obj$vertices[j,] + (1-p)*obj$vertices[i,] keep[j] <- TRUE } } obj <- applyKeep() obj <- rejoinLines3d(obj) newid <- plot3d(obj) } }, linestrip = { oldnverts <- nverts - 1 while (nverts < minVertices[id] && nverts > oldnverts) { oldnverts <- nverts obj <- subdivideLines(obj) nverts <- nrow(obj$vertices) } newverts <- nverts values <- getValues(obj) if (!all(values >= 0, na.rm = TRUE)) { hasattrs <- character() for (attr in c("vertices", "normals", "colors")) if (!is.null(obj[[attr]]) && nrow(obj[[attr]]) > 1) hasattrs <- c(hasattrs, attr) indices <- rbind(seq_len(nverts), NA, NA) for (j in seq_len(nverts)[-1]) { i <- j - 1 # There are lots of cases to consider here. # We could have a point that was already ignored # to create a gap in the linestrip, a point # that should be deleted because it is outside the # range, or a point that should be kept. These # have value NA, negative, or non-negative respectively. # The 9 cases are handled as follows (assuming we # go through (i, j=i+1) pairs in sequence): # i j disposition # NA NA drop i, keep j # NA - drop i, keep j # NA + keep both # - NA drop i, keep j # - - drop i, keep j unless it is last # - + change i to NA (unless it's first, then drop it), insert interpolant, keep j # + NA keep both # + - keep i, insert interpolant then NA, move to j # + + keep both if (is.na(values[i])) { if (is.na(values[j]) || values[j] < 0) indices[1,i] <- NA } else if (values[i] < 0) { if (is.na(values[j]) || values[j] < 0) indices[1,i] <- NA else { indices[2,i] <- newverts + 1 p <- 1 - abs(values[i])/(abs(values[i]) + values[j]) for (attr in hasattrs) { while (nrow(obj[[attr]]) < newverts + 1) obj[[attr]] <- rbind(obj[[attr]], obj[[attr]]) new <- p*obj[[attr]][i,] + (1-p)*obj[[attr]][j,] obj[[attr]][newverts + 1,] <- new } newverts <- newverts + 1 obj$vertices[i,] <- NA if (j == 2) indices[1,i] <- NA } } else { if (!is.na(values[j]) && values[j] < 0) { indices[2,i] <- newverts + 1 indices[3,i] <- newverts + 2 p <- 1 - abs(values[j])/(abs(values[j]) + values[i]) obj$vertices <- rbind(obj$vertices, p*obj$vertices[j,] + (1-p)*obj$vertices[i,], c(NA, NA, NA)) for (attr in hasattrs) { while (nrow(obj[[attr]]) < newverts + 2) obj[[attr]] <- rbind(obj[[attr]], obj[[attr]]) new <- p*obj[[attr]][j,] + (1-p)*obj[[attr]][i,] obj[[attr]][newverts+1,] <- new obj[[attr]][newverts+2,] <- NA } newverts <- newverts + 2 if (j == nverts) indices[1,j] <- NA } } } indices <- c(indices) indices <- indices[!is.na(indices)] for (attr in hasattrs) obj[[attr]] <- obj[[attr]][indices,,drop = FALSE] } obj <- rejoinLines3d(obj) newid <- plot3d(obj) } ) if (!is.na(newid)) { result[id] <- newid if (replace) pop3d(id = id) } else result[id] <- as.integer(id) } if (!is.null(names)) names(result) <- names rglId(result) } rgl/R/hooks.R0000644000176200001440000000217214771520323012513 0ustar liggesusers# This file supports auto-printing of RGL scenes in # RStudio # Called just after a low level function has been # called, likely changing an existing display # Returns the ids that were created by the function, # which should be passed as the ids arg. lowlevel <- function(ids = integer()) { structure(ids, class = c("rglLowlevel", "rglId", "numeric")) } # Called just after a high level function (plot3d # or persp3d) has been called, if it wasn't # called with add = TRUE (in which case it would be # treated as low level). # Returns the ids that were created by the function, # which should be passed as the ids arg. highlevel <- function(ids = integer()) { structure(ids, class = c("rglHighlevel", "rglId", "numeric")) } rglId <- function(ids = integer()) { structure(ids, class = "rglId") } print.rglId <- function(x, rglwidget = getOption("rgl.printRglwidget", FALSE), ...) { if (!par3d("skipRedraw")) { if (rglwidget) # FIXME: For lowlevel, this should replace the scene, not update the history print(rglwidget(...)) else if (in_pkgdown_example()) pkgdown::pkgdown_print(x) } invisible(x) } rgl/R/as.triangles3d.R0000644000176200001440000000536014771520323014213 0ustar liggesusersas.triangles3d <- function(obj, ...) UseMethod("as.triangles3d") as.triangles3d.mesh3d <- function(obj, attribute = c("vertices", "normals", "texcoords", "colors"), ...) { indices <- NULL if (!is.null(obj$it)) { indices <- c(obj$it) } if (!is.null(obj$ib)) { indices <- c(indices, c(obj$ib[1:3,], obj$ib[c(1,3,4),])) } if (!is.null(indices)) switch(match.arg(attribute), vertices = t(obj$vb[1:3, indices])/obj$vb[4,indices], normals = if (!is.null(obj$normals)) if (nrow(obj$normals) == 4) t(obj$normals[1:3, indices]/obj$normals[4,indices]) else t(obj$normals[, indices]), texcoords = if (!is.null(obj$texcoords)) t(obj$texcoords[, indices]), colors = if (!is.null(obj$material) && !is.null(obj$material$color)) { col <- t(col2rgb(rep(obj$material$color, length.out = max(indices)))) alpha <- if (is.null(obj$material$alpha)) 1 else obj$material$alpha alpha <- rep(alpha, length.out = max(indices)) cbind(col, alpha)[indices,] }) } as.triangles3d.rglId <- function(obj, attribute = c("vertices", "normals", "texcoords", "colors"), subscene = NA, ...) { attribute <- match.arg(attribute) ids <- ids3d(subscene = subscene) ids <- ids[ids$id %in% obj,] result <- NULL for (i in seq_len(nrow(ids))) { id <- ids[i, "id"] nvert <- getExpandedNverts(id) attrib <- expandAttrib(id, attribute) if (nrow(attrib)) { if (nrow(attrib) < nvert) attrib <- apply(attrib, 2, function(col) rep(col, length.out = nvert)) type <- ids[i, "type"] result <- rbind(result, switch(as.character(type), triangles =, planes = attrib, quads = { nquads <- nrow(attrib)/4 attrib[4*rep(seq_len(nquads) - 1, each = 6) + c(1,2,3,1,3,4),,drop=FALSE] }, surface = { dim <- rgl.attrib(id, "dim") ul <- rep(2:dim[1], dim[2]-1) + dim[1]*rep(0:(dim[2]-2), each=dim[1]-1) if (rgl.attrib(id, "flags")["flipped",]) indices <- c(rbind(c(ul-1, ul-1+dim[1]), c(ul, ul), c(ul-1+dim[1], ul+dim[1]))) else indices <- c(rbind(c(ul, ul), c(ul-1, ul-1+dim[1]), c(ul-1+dim[1], ul+dim[1]))) attrib[indices,,drop = FALSE] }, NULL)) } } result } rgl/R/convertScene.R0000644000176200001440000004410315011677075014033 0ustar liggesusers convertScene <- function(x = scene3d(minimal), width = NULL, height = NULL, elementId = NULL, minimal = TRUE, webgl = TRUE, snapshot = FALSE, oldConvertBBox = FALSE, useBuffer = TRUE) { # Lots of utility functions and constants defined first; execution starts way down there... getObj <- function(id) { result$objects[[as.character(id)]] } setObj <- function(id, newval) { result$objects[[as.character(id)]] <<- newval } getIdsByType <- function(type, subscene = NULL) { if (is.null(subscene)) ids <- vapply(result$objects, function(x) if (x$type == type) x$id else NA, numeric(1)) else { ids <- vapply(getObj(subscene)$objects, function(x) { obj <- getObj(x) if (obj$type == type) obj$id else NA }, numeric(1)) } ids[!is.na(ids)] } getMaterial <- function(id) { default <- result$material obj <- getObj(id) mat <- obj$material missing <- setdiff(names(default), names(mat)) mat[missing] <- default[missing] mat } # This counts how many clipping planes might affect a particular object countClipplanes <- function(id, minValue = getOption("rgl.minClipplanes", 0)) { recurse <- function(subscene) { count <- 0 ids <- getIdsByType("clipplanes", subscene) for (clipid in ids) count <- count + nrow(getObj(clipid)$normals) subscenes <- getIdsByType("subscene", subscene) for (sub in subscenes) { if (count >= bound) break count <- max(count, recurse(sub)) } count } ids <- getIdsByType("clipplanes") bound <- 0 for (i in seq_along(ids)) bound <- bound + nrow(getObj(ids[i])$normals) if (bound < minValue) return(minValue) max(minValue, recurse(result$rootSubscene)) } makeList <- function(x) { if (is.list(x)) x <- lapply(x, makeList) if (length(names(x))) x <- as.list(x) x } initResult <- function() { result <<- makeList(x) recurse <- function(subscene) { subscenes <- subscene$subscenes for (i in seq_along(subscenes)) { subscenes[[i]]$parent <- subscene$id subscenes[[i]] <- recurse(subscenes[[i]]) } if (length(subscenes)) { subscene$subscenes <- unlist(subscenes) subscene$objects <- c(subscene$objects, subscene$subscenes) } else subscene$subscenes <- numeric(0) setObj(subscene$id, subscene) subscene$id } result$rootSubscene <<- recurse(result$rootSubscene) if (snapshot) result$snapshot <- getSnapshot() } flagnames <- c("is_lit", "is_smooth", "has_texture", "depth_sort", "fixed_quads", "is_transparent", "is_lines", "sprites_3d", "is_subscene", "is_clipplanes", "fixed_size", "is_points", "is_twosided", "fat_lines", "is_brush", "has_fog", "rotating") getFlags <- function(id) { obj <- getObj(id) if (is.null(obj)) { warning("object", id, " not found.") return(structure(rep(FALSE, length(flagnames)), names = flagnames)) } type <- obj$type if (type == "subscene") return(getSubsceneFlags(id)) result <- structure(rep(FALSE, length(flagnames)), names = flagnames) if (type == "clipplanes") { result["is_clipplanes"] <- TRUE return(result) } if (type == "light") return(result) result["is_transparent"] <- any(obj$colors[,"a"] < 1); # More later... mat <- getMaterial(id) result["is_lit"] <- mat$lit && type %in% c("triangles", "quads", "surface", "planes", "spheres", "sprites", "bboxdeco") result["is_smooth"] <- mat$smooth && type %in% c("triangles", "quads", "surface", "planes", "spheres") result["sprites_3d"] <- sprites_3d <- type == "sprites" && length(obj$ids) result["has_texture"] <- has_texture <- !is.null(mat$texture) && (!is.null(obj$texcoords) || (type == "sprites" && !sprites_3d) || (type == "background" && obj$sphere) || (type == "spheres")) result["is_transparent"] <- is_transparent <- (has_texture && mat$isTransparent) || result["is_transparent"] result["depth_sort"] <- depth_sort <- is_transparent && type %in% c("triangles", "quads", "surface", "spheres", "sprites", "text") result["fixed_quads"] <- type %in% c("text", "sprites") && !sprites_3d result["is_lines"] <- type %in% c("lines", "linestrip", "abclines") result["is_points"] <- type == "points" || "points" %in% c(mat$front, mat$back) result["is_twosided"] <- (type %in% c("quads", "surface", "triangles", "spheres", "bboxdeco") && length(unique(c(mat$front, mat$back))) > 1) || (type == "background" && obj$sphere) if (result["is_twosided"] && !is.null(obj$indices) && is.null(obj$normals)) { warning("Object ", obj$id, " is two-sided and indexed. It requires normals.") result["is_twosided"] <- FALSE } result["fixed_size"] <- type == "text" || isTRUE(obj$fixedSize) result["rotating"] <- isTRUE(obj$rotating) result["fat_lines"] <- mat$lwd != 1 && (result["is_lines"] || "lines" %in% unlist(mat[c("front", "back")])) result["is_brush"] <- !is.na(brushId) && id == brushId result["has_fog"] <- mat$fog result } getSubsceneFlags <- function(id) { result <- structure(rep(FALSE, length(flagnames)), names = flagnames) result["is_subscene"] <- TRUE objs <- getObj(id)$objects for (i in seq_along(objs)) result <- result | getFlags(objs[i]) return(result) } numericFlags <- function(flags) { if (is.matrix(flags)) n <- ncol(flags) else n <- length(flags) unname(flags %*% 2^(seq_len(n)-1)) } expandFlags <- function(numericflags) { result <- matrix(FALSE, nrow = length(numericflags), ncol = length(flagnames), dimnames = list(names(numericflags), flagnames)) for (i in seq_along(flagnames)) { result[,i] <- numericflags %% 2 == 1 numericflags <- numericflags %/% 2 } result } plotClipplanes <- function(subscene) { for (id in subscene$objects) { obj <- getObj(id) if (obj$type == "clipplanes") { class(obj) <- "rglobject" plot3d(obj) } else if (obj$type == "subscene") plotClipplanes(getObj(id)) } } convertBBox <- function(id, subscene) { obj <- getObj(id) verts <- obj$vertices text <- obj$texts if (!length(text)) text <- rep("", NROW(verts)) else text <- text[,"text"] mat <- getMaterial(id) if (length(mat$color) > 1) mat$color <- mat$color[2] # We ignore the "box" colour if(any(missing <- text == "")) text[missing] <- apply(verts[missing,], 1, function(row) format(row[!is.na(row)])) res <- numeric(0) bbox <- subscene$par3d$bbox repeat { # Need to make sure the ids here don't clash with those in the scene tempID <- points3d(bbox[1:2], bbox[3:4], bbox[5:6]) if (tempID > lastID) break else delFromSubscene3d(tempID) } lastID <<- tempID intersect <- function(limits, points) which(limits[1] <= points & points <= limits[2]) # plot the clipping planes as they affect the bounding box plotClipplanes(subscene) mat$front <- mat$back <- "filled" if (any(inds <- is.na(verts[,2]) & is.na(verts[,3])) && length(keep <- intersect(bbox[1:2], verts[inds, 1]))) res <- c(res, do.call(axis3d, c(list(edge = "x", at = verts[inds, 1][keep], labels = text[inds][keep]), mat))) if (any(inds <- is.na(verts[,1]) & is.na(verts[,3])) && length(keep <- intersect(bbox[3:4], verts[inds, 2]))) res <- c(res, do.call(axis3d, c(list(edge = "y", at = verts[inds, 2][keep], labels = text[inds][keep]), mat))) if (any(inds <- is.na(verts[,1]) & is.na(verts[,2])) && length(keep <- intersect(bbox[5:6], verts[inds, 3]))) res <- c(res, do.call(axis3d, c(list(edge = "z", at = verts[inds, 3][keep], labels = text[inds][keep]), mat))) res <- c(res, do.call(box3d, mat)) delFromSubscene3d(c(res, tempID)) res } convertBBoxes <- function(id) { if (!oldConvertBBox) return(NULL) ids <- origIds <- NULL id <- as.character(id) sub <- getObj(id) types <- vapply(sub$objects, function(x) getObj(x)$type, character(1)) names(types) <- as.character(sub$objects) if (length(bboxes <- names(types)[types == "bboxdeco"])) { for (i in bboxes) { newids <- convertBBox(i, sub) sub$objects <- c(sub$objects, as.numeric(newids)) setObj(id, sub) ids <- c(ids, newids) origIds <- c(origIds, rep(i, length(newids))) } } children <- sub$subscenes for (i in children) { childids <- convertBBoxes(i) ids <- c(ids, childids) origIds <- c(origIds, attr(childids, "origIds")) } if (length(origIds)) names(origIds) <- as.character(ids) if (is.null(ids)) ids else structure(ids, origIds = origIds) } createBrush <- function() { repeat { # Need to make sure the id doesn't clash with those in the scene tempID <- lines3d(x = c(0, 1, 1, 0, 0), y = c(0, 0, 1, 1, 0), z = rep(-.999, 5), depth_test = "always", lit = FALSE, alpha = 0.5) if (tempID > lastID) break else delFromSubscene3d(tempID) } lastID <<- tempID } getSnapshot <- function() knitr::include_graphics(snapshot3d(scene = x, width = width, height = height)) knowntypes <- c("points", "linestrip", "lines", "triangles", "quads", "surface", "text", "abclines", "planes", "spheres", "sprites", "clipplanes", "light", "background", "bboxdeco", "subscene") # Execution starts here! # Do a few checks first if (!webgl) return(getSnapshot()) if (is.null(elementId)) elementId <- "" if (is.list(x$rootSubscene)) rect <- x$rootSubscene$par3d$windowRect else rect <- x$objects[[x$rootSubscene]]$par3d$windowRect rwidth <- rect[3] - rect[1] + 1 rheight <- rect[4] - rect[2] + 1 if (!length(width)) { if (!length(height)) { wfactor <- hfactor <- 1 # width = wfactor*rwidth, height = hfactor*rheight } else wfactor <- hfactor <- height/rheight } else { if (!length(height)) { wfactor <- hfactor <- width/rwidth } else { wfactor <- width/rwidth hfactor <- height/rheight } } width <- wfactor*rwidth height <- hfactor*rheight shared <- x$crosstalk$id result <- NULL initResult() result$width <- width result$height <- height types <- vapply(result$objects, function(x) x$type, character(1)) lastID <- max(vapply(result$objects, function(x) x$id, numeric(1))) if (any(types == "bboxdeco")) { saveNULL <- options(rgl.useNULL = TRUE) dev <- cur3d() open3d() ids <- convertBBoxes(result$rootSubscene) origIds <- attr(ids, "origIds") scene <- scene3d(minimal) temp <- lapply(as.character(ids), function(id) { x <- scene$objects[[id]] x$origId <- as.numeric(origIds[id]) x }) result$objects[as.character(ids)] <- temp for (id in unique(origIds)) result$objects[[as.character(id)]]$newIds <- as.numeric(ids[origIds == id]) types <- vapply(result$objects, function(x) x$type, character(1)) close3d() if (dev) set3d(dev) options(saveNULL) } if (length(shared)) { saveNULL <- options(rgl.useNULL = TRUE) dev <- cur3d() open3d() result$brushId <- brushId <- createBrush() brush <- as.character(result$brushId) scene <- scene3d(minimal) result$objects[[brush]] <- scene$objects[[brush]] close3d() if (dev) set3d(dev) options(saveNULL) } else brushId <- NA ids <- vapply(result$objects, function(x) x$id, numeric(1)) flags <- vapply(result$objects, function(obj) numericFlags(getFlags(obj$id)), numeric(1), USE.NAMES = FALSE) unknowntypes <- setdiff(types, knowntypes) if (length(unknowntypes)) warning(gettextf("Object type(s) %s not handled", paste("'", unknowntypes, "'", sep="", collapse=", ")), domain = NA) keep <- types %in% setdiff(knowntypes, c("light")) ids <- ids[keep] cids <- as.character(ids) nflags <- flags[keep] types <- types[keep] flags <- expandFlags(nflags) rownames(flags) <- cids fullviewport <- getObj(result$rootSubscene)$par3d$viewport for (i in seq_along(ids)) { obj <- getObj(cids[i]) obj$flags <- nflags[i] if (obj$type != "subscene") { texturefile <- "" if (!is.null(obj$material) && "texture" %in% names(obj$material)) texture <- obj$material$texture else texture <- result$material$texture if (!is.null(texture) && nchar(texture)) { texturefile <- texture obj$material$uri <- image_uri(texturefile) obj$material$texture <- NULL } if (!is.null(obj$material)) # Never use material$color obj$material$color <- NULL if (!is.null(obj$material) && !is.null(obj$material$smooth) && !obj$material$smooth) obj <- nonSmooth(obj) } else if (obj$type == "subscene") { obj$par3d$viewport$x <- obj$par3d$viewport$x/fullviewport$width obj$par3d$viewport$width <- obj$par3d$viewport$width/fullviewport$width obj$par3d$viewport$y <- obj$par3d$viewport$y/fullviewport$height obj$par3d$viewport$height <- obj$par3d$viewport$height/fullviewport$height } if (obj$type == "planes" && nrow(obj$vertices) > 3) { obj$vertices <- obj$vertices[1:3,] # These will be redone # in Javascript } else if (obj$type == "spheres") obj$centers <- obj$vertices if (!is.null(obj$material$margin)) { margin <- parseMargin(obj$material$margin, obj$material$floating) obj$material$margin <- margin$coord - 1 obj$material$floating <- margin$floating obj$material$edge <- margin$edge } if (is.list(obj$userTextures) && length(obj$userTextures) && !is.list(obj$userTextures[[1]])) { textureNames <- names(obj$userTextures) userTextures <- as.character(obj$userTextures) obj$userTextures <- list() for (j in seq_along(userTextures)) { texturefile <- userTextures[j] obj$userTextures[[j]] <- list(file = texturefile, uri = image_uri(texturefile)) } names(obj$userTextures) <- textureNames } setObj(cids[i], obj) } if (useBuffer) { # Put the data into the buffer buffer <- Buffer$new() for (i in seq_along(ids)) { obj <- getObj(cids[i]) # This list needs to match the one in buffer.src.js for (n in c("vertices", "normals", "indices", "texcoords", "colors", "centers")) { if (!is.null(obj[[n]])) { normalized <- FALSE normalization <- "" if (length(obj[[n]]) > 6 && # Don't bother for short ones n %in% c("colors","texcoords") && !anyNA(objrange <- range(obj[[n]])) && 0 <= objrange[1] && objrange[2] <= 1) { scaled <- 255*obj[[n]] rounded <- round(scaled) normalized <- max(abs(scaled - rounded))/255 < 1.e-7 if (normalized) normalization <- "ubyte" else { scaled <- 65535*obj[[n]] rounded <- round(scaled) normalized <- max(abs(scaled - rounded))/65535 < 1.e-7 if (normalized) normalization <- "ushort" } } if (normalized) obj[[n]] <- as.character(buffer$addAccessor(t(rounded), types = normalization, normalized = TRUE)) else obj[[n]] <- as.character(buffer$addAccessor(t(obj[[n]]))) } } setObj(cids[i], obj) } buffer$closeBuffers() buf <- buffer$as.list() result$buffer <- buf } result$context <- list(shiny = inShiny(), rmarkdown = rmarkdownOutput()) result } # Modify objects that have smooth = FALSE. Convert # surfaces to triangles, add vertices so that we can # set all triangles or quads to solid colours. nonSmooth <- function(obj) { oldcolors <- obj$colors ncolors <- NROW(oldcolors) if (ncolors > 1) { if (obj$type == "surface") { dim <- obj$dim ul <- rep(2:dim[1], dim[2]-1) + dim[1]*rep(0:(dim[2]-2), each=dim[1]-1) if (obj$flipped) indices <- c(rbind(ul-1, ul, ul-1+dim[1], ul+dim[1], ul-1+dim[1], ul )) else indices <- c(rbind(ul, ul-1, ul-1+dim[1], ul-1+dim[1], ul+dim[1], ul)) } else indices <- obj$indices if (!is.null(indices)) { obj$vertices <- obj$vertices[indices,] oldcolors <- obj$colors[indices,] obj$normals <- obj$normals[indices,] if (!is.null(obj$texcoords)) obj$texcoords <- obj$texcoords[indices,] obj$indices <- NULL } newcolors <- oldcolors i <- seq_len(NROW(newcolors)) nverts <- switch(obj$type, "triangles" = 3, "quads" = 4, "surface" = 6) for (j in seq_len(nverts-1)) newcolors[i %% nverts == j] <- newcolors[i %% nverts == 0] obj$colors <- newcolors if (obj$type == "surface") { obj$type <- "triangles" obj$dim <- NULL obj$centers <- (obj$vertices[i %% 3 == 0,] + obj$vertices[i %% 3 == 1,] + obj$vertices[i %% 3 == 2,])/3 } } obj } rgl/R/extrafont.R0000644000176200001440000000524314771520323013404 0ustar liggesusers# This function is modelled on similar functions in # the extrafont package. loadfonts_rgl <- function(..., quiet = TRUE) { makeRglFont <- function(family) { getIndex <- function(Bold, Italic) 1 + Bold + 2*Italic fontdata <- fontdata[fontdata$FamilyName == family,,drop = FALSE] result <- rep(NA, 4) for (i in seq_len(nrow(fontdata))) { index <- with(fontdata, getIndex(Bold[i], Italic[i])) if (is.na(result[index])) result[index] <- fontdata$fontfile[i] } value <- result[1] # Propagate to more conditions for (i in 2:4) if (is.na(result[i])) result[i] <- result[i-1] # Propagate to fewer for (i in 3:1) if (is.na(result[i])) result[i] <- result[i+1] result } register_family_rgl <- function(family) { # Now we can register the font with rgl with something like this: # rglFonts("Arial" = rglFont("Arial")) if (family %in% cfonts) { if (!quiet) { message(family, " already registered with rglFonts().") } return(NULL) } if (!quiet) { message("Registering font with R using rglFonts(): ", family) } # Since 'family' is a string containing the name of the argument, we # need to use do.call args <- list() args[[family]] <- makeRglFont(family) if (!is.null(args[[family]])) do.call(rglFonts, args) } if (!requireNamespace("extrafont", quietly = TRUE)) stop("This function requires the extrafont package.") fontdata <- extrafont::fonttable() # remove empty FamilyNames fontdata <- fontdata[fontdata$FamilyName != "", , drop = FALSE] families <- unique(fontdata$FamilyName) # If args were given, limit attention to those args <- list(...) if (length(args)) families <- intersect(families, args) cfonts <- names(rglFonts()) lapply(families, register_family_rgl) allfonts <- rglFonts() names <- names(args) for (i in seq_along(names)) { origname <- args[[names[i]]] if (origname %in% names(allfonts)) { font <- allfonts[[origname]] arg <- list() arg[[names[i]]] <- font do.call(rglFonts, arg) } } } rglExtrafonts <- function(..., quiet = TRUE) { if (!requireNamespace("extrafont", quietly = TRUE)) return() args <- list(...) names <- names(args) result <- character() if (is.null(names)) names <- rep("", length(args)) for (i in seq_along(args)) { choices <- args[[i]] if (length(choices)) { font <- extrafont::choose_font(choices) result[i] <- font if (nchar(font)) { arg <- list(quiet = quiet) if (!nchar(names[i])) names[i] <- font arg[[names[i]]] <- font do.call(loadfonts_rgl, arg) } else warning("Fonts ", paste0('"', choices, '"', collapse = ", "), " not found.") } } names(result) <- names invisible(result) } rgl/R/filledContour3d.R0000644000176200001440000000375414771520323014437 0ustar liggesusersfilledContour3d <- function(obj, ...) UseMethod("filledContour3d") filledContour3d.rglId <- function(obj, plot = TRUE, replace = plot, ...) { mesh <- as.mesh3d(obj) result <- filledContour3d(mesh, plot = plot, ...) if (replace) pop3d(id = obj) result } if (getRversion() < "3.6.0") { hcl.colors <- function(n, ...) grDevices::cm.colors(n) } else hcl.colors <- grDevices::hcl.colors filledContour3d.mesh3d <- function(obj, fn = "z", nlevels = 20, levels = pretty(range(values), nlevels), color.palette = function(n) hcl.colors(n, "YlOrRd", rev = TRUE), col = color.palette(length(levels) - 1), minVertices = 0, plot = TRUE, keepValues = FALSE, ...) { nverts <- ncol(obj$vb) oldnverts <- nverts - 1 while (nverts < minVertices && oldnverts < nverts) { oldnverts <- nverts obj <- subdivision3d(obj, deform = FALSE, normalize = TRUE) nverts <- ncol(obj$vb) } if (is.null(fn)) fn <- obj$values if (is.null(fn)) stop("'fn' can only be NULL if 'obj' contains values.") verts <- asEuclidean(t(obj$vb)) if (is.numeric(fn)) values <- fn else { fn <- .getVertexFn(fn, parent.frame()) values <- fn(verts) } if (length(levels) < 2) stop("Must have at least 2 levels.") reverse <- levels[1] > levels[2] if (any((levels[-length(levels)] > levels[-1]) != reverse)) stop("Levels must be monotone increasing or decreasing") if (is.null(obj$material)) obj$material <- list() obj$material$color <- NA obj$values <- values result <- list() ivals <- seq_along(col) if (reverse) ivals <- rev(ivals) for (i in ivals) { r <- range(levels[c(i, i+1)]) obj <- clipMesh3d(obj, NULL, bound = r[1], keepValues = TRUE) strip <- clipMesh3d(obj, NULL, bound = r[2], greater = FALSE, keepValues = keepValues && !plot) strip$material$color <- col[i] result[[i]] <- cleanMesh3d(strip, rejoin = TRUE) } result <- do.call(merge, result) if (plot) shade3d(result, ...) else result } rgl/R/triangulate.R0000644000176200001440000001507415011677075013721 0ustar liggesusers pointInPoly <- function(poly, pt) { # polygon is 2 x n, columns are vertices # point is 2 vector n <- ncol(poly) i1 <- seq_len(n) i2 <- i1 %% n + 1 x <- poly[1,i1] + (poly[1,i2] - poly[1,i1])*(pt[2] - poly[2,i1])/(poly[2,i2] - poly[2,i1]) crossings <- ((poly[2,i1] < pt[2]) & (pt[2] <= poly[2,i2]) | (poly[2,i2] < pt[2]) & (pt[2] <= poly[2,i1])) & pt[1] < x sum(crossings) %% 2 == 1 } intersectSegSeg <- function(seg1,seg2) { # do segments intersect? # both segments have endpoints as columns coeffs <- try(solve(cbind(seg1[,2]-seg1[,1], seg2[,1]-seg2[,2]), seg2[,1]-seg1[,1]), silent=TRUE) if (inherits(coeffs, "try-error")) return(FALSE) all(zapsmall(coeffs) >= 0) && all(zapsmall(1-coeffs) >= 0) } intersectTriSeg <- function(tri, seg) { # intersect a triangle with a segment # tri is 2 x 3, columns are vertices # seg is 2 x 2, columns are endpoints coeffs <- try(solve(rbind(tri,1), rbind(seg,1)), silent=TRUE) if (inherits(coeffs, "try-error")) return(TRUE) coeffs <- zapsmall(coeffs) if (any(apply(coeffs <= 0, 1, all))) return(FALSE) if (any(apply(coeffs > 0, 2, all))) return(TRUE) up <- coeffs[,1] < 0 dn <- coeffs[,2] < 0 lb <- max( -coeffs[up,1]/(coeffs[up,2]-coeffs[up,1]) ) ub <- 1 - max( -coeffs[dn,2]/(coeffs[dn,1] - coeffs[dn,2]) ) lb <= ub } triangulate <- function(x, y = NULL, z = NULL, random = TRUE, plot = FALSE, partial = NA) { xyz <- xyz.coords(x, y, z) if (xyz$xlab == "Index" && is.null(z) && (is.null(ncol(x)) || ncol(x) == 2L)) { x <- xyz$y y <- xyz$z } else { x <- xyz$x y <- xyz$y if (!diff(range(x, na.rm = TRUE))) x <- xyz$z else if (!diff(range(y, na.rm = TRUE))) y <- xyz$z } nesting <- nestPolys(x, y) verts <- nesting$verts processInside <- function(v) { result <- matrix(NA, ncol = 0, nrow = 3) indices <- verts[[v]] for (i in nesting$nesting[[v]]) { result <- cbind(result, processOutside(i)) indices <- c(indices, NA, verts[[i]]) } res0 <- .Call(rgl_earcut, x[indices], y[indices]) result <- cbind(result, matrix(indices[res0+1], nrow = 3)) } processOutside <- function(fwd) { result <- matrix(NA, ncol = 0, nrow = 3) for (i in nesting$nesting[[fwd]]) result <- cbind(result, processInside(i)) result } # Done all polys, now combine res <- matrix(nrow=3, ncol=0) for (i in nesting$toplevel) res <- cbind(res, processInside(i)) # Get vertex order nextvert <- rep(NA, length(x)) for (i in seq_along(verts)) { poly <- verts[[i]] first <- poly[1] second <- poly[2] # Find first triangle holding first # and second tri <- intersect(col(res)[res == first], col(res)[res == second]) if (!length(tri)) warning("edge not found:", first, " ", second) else { tri <- tri[1] counter <- (which(res[,tri] == first) - which(res[,tri] == second) + 3) %% 3 == 2 if (counter) { nextvert[poly[-length(poly)]] <- poly[-1] nextvert[poly[length(poly)]] <- poly[1] } else { nextvert[poly[-1]] <- poly[-length(poly)] nextvert[poly[1]] <- poly[length(poly)] } } } if (plot) { for (i in seq_len(ncol(res))) polygon(x[res[,i]], y[res[,i]], col = i) } attr(res, "nextvert") <- nextvert res } # Rewrite a complex polygon as a list of the individual parts, oriented correctly, # with attribute showing nesting nestPolys <- function(x,y = NULL) { xy <- xy.coords(x, y) x <- xy$x y <- xy$y n <- length(x) nas <- c(which(is.na(x) | is.na(y)), n + 1L) prev <- 0L verts <- list() for (i in seq_along(nas)) { verts[[i]] <- (prev + 1L):(nas[i] - 1L) prev <- nas[i] } # nesting is a list of vectors # of poly numbers that are directly nested within the corresponding element of verts # The last one at length(verts)+1 lists polys not nested anywhere nesting <- rep(list(integer()), length(verts)+1) place <- function(new, toplevel) { placed <- FALSE contains <- integer() if (length(nesting[[toplevel]])) { newverts <- rbind(x[verts[[new]]], y[verts[[new]]]) for (j in nesting[[toplevel]]) { prev <- rbind(x[verts[[j]]], y[verts[[j]]]) if (pointInPoly(prev, newverts[,1])) { place(new, j) placed <- TRUE break } if (pointInPoly(newverts, prev[,1])) contains <- c(contains, j) } } if (!placed) { nesting[[toplevel]] <<- c(setdiff(nesting[[toplevel]], contains), new) nesting[[new]] <<- contains } } for (i in seq_along(verts)) { place(i, length(verts)+1) } list(verts=verts, nesting=nesting[-length(nesting)], toplevel=nesting[length(nesting)]) } extrude3d <- function(x,y = NULL, thickness=1, smooth=FALSE, ...) { xy <- xy.coords(x, y) x <- xy$x y <- xy$y it <- triangulate(x, y) nextvert <- attr(it, "nextvert") n <- length(x) res <- tmesh3d(rbind(c(x,x), c(y,y), c(rep(thickness,n), rep(0,n)), 1), cbind(it, it[c(1,3,2),]+n), ...) i1 <- seq_len(n) i2 <- nextvert i3 <- i2 + n i4 <- i1 + n keep <- !is.na(nextvert) res$ib <- rbind(i4,i3,i2,i1)[,keep] if (smooth) { res$ib <- res$ib + ncol(res$vb) res$vb <- cbind(res$vb, res$vb) i3 <- nextvert[nextvert] diff <- cbind(x[i3] - x[i1], y[i3] - y[i1]) len <- sqrt(apply(diff^2, 1, sum)) diff <- diff/len res$normals <- cbind( rbind(0,0,c(rep(1, n), rep(-1, n))) ) res$normals <- cbind(res$normals, res$normals) i2 <- c(i2 + 2*n, i2 + 3*n) keep <- !is.na(i2) res$normals[,i2[keep]] <- rbind(rep(diff[,2], 2), -rep(diff[,1], 2), 0)[,keep] } res } polygon3d <- function(x, y = NULL, z = NULL, fill = TRUE, plot = TRUE, coords, random = TRUE, ...) { xyz <- xyz.coords(x,y,z, recycle = TRUE) if (!fill) { n <- length(xyz$x) nas <- with(xyz, c(which(is.na(x) | is.na(y) | is.na(z)), n + 1L)) prev <- 0L loop <- integer() for (i in seq_along(nas)) { loop <- c(loop, if (i > 1) NA, (prev + 1L):(nas[i] - 1L), prev + 1L) prev <- nas[i] } res <- cbind(xyz$x[loop], xyz$y[loop], xyz$z[loop]) if (plot) lines3d(res, ...) else res } else { if (missing(coords)) tri <- triangulate(xyz) else { cnames <- c("x", "y", "z") x <- xyz[[cnames[coords[1]]]] y <- xyz[[cnames[coords[2]]]] tri <- triangulate(x, y) } shape <- tmesh3d(rbind(xyz$x, xyz$y, xyz$z, 1), indices = tri) if (plot) shade3d(shape, ...) else shape } } rgl/R/webGLcontrols.R0000644000176200001440000000446214771520323014160 0ustar liggesusers # This displays an HTML5 input widget to show a subset of objects. It assigns a random id # and returns that invisibly. subsetSlider <- function(subsets, labels = names(subsets), fullset = Reduce(union, subsets), subscenes = currentSubscene3d(), prefixes = "", accumulate = FALSE, ...) { .Defunct("subsetControl") } subsetSetter <- function(subsets, subscenes = currentSubscene3d(), prefixes = "", fullset = Reduce(union, subsets), accumulate = FALSE) { .Defunct("subsetControl") } toggleButton <- function(subset, subscenes = currentSubscene3d(), prefixes = "", label = deparse(substitute(subset)), id = paste0(basename(tempfile("input"))), name = id) { .Defunct("toggleWidget") } clipplaneSlider <- function(a=NULL, b=NULL, c=NULL, d=NULL, plane = 1, clipplaneids, prefixes = "", labels, ...) { .Defunct("clipplaneControl") } propertySlider <- function(setter = propertySetter, minS = NULL, maxS = NULL, step = 1, init = NULL, labels, id = basename(tempfile("input")), name = id, outputid = paste0(id, "text"), index = NULL, ...) { .Defunct("propertyControl") } propertySetter <- function(values = NULL, entries, properties, objids, prefixes = "", param = seq_len(NROW(values)), interp = TRUE, digits = 7) { .Defunct("propertyControl") } vertexSetter <- function(values = NULL, vertices = 1, attributes, objid, prefix = "", param = seq_len(NROW(values)), interp = TRUE, digits = 7) { .Defunct("vertexControl") } par3dinterpSetter <- function(fn, from, to, steps, subscene = NULL, omitConstant = TRUE, rename = character(), ...) { .Defunct("par3dinterpControl") } matrixSetter <- function(fns, from, to, steps, subscene = currentSubscene3d(), matrix = "userMatrix", omitConstant = TRUE, prefix = "", ...) { .Defunct("par3dinterpControl") } ageSetter <- function(births, ages, colors = NULL, alpha = NULL, radii = NULL, vertices = NULL, normals = NULL, origins = NULL, texcoords = NULL, objids, prefixes = "", digits = 7, param = seq(floor(min(births)), ceiling(max(births)))) { .Defunct("ageControl") } rgl/R/indices.R0000644000176200001440000000213114771520323013001 0ustar liggesusers # Get the attribute expanded by the indices, if any expandAttrib <- function(id, attrib) { result <- rgl.attrib(id, attrib) if (length(result)) { indices <- rgl.attrib(id, "indices") if (length(indices)) result <- result[indices,] } result } expandVertices <- function(id) expandAttrib(id, "vertices") expandColors <- function(id) { result <- rgl.attrib(id, "colors") if (nrow(result) > 1) result <- expandAttrib("colors") result } getExpandedNverts <- function(id) { result <- length(rgl.attrib(id, "indices")) if (!result) result <- NROW(rgl.attrib(id, "vertices")) result } getIndices <- function(id) { result <- rgl.attrib(id, "indices") if (!length(result)) result <- seq_len(NROW(rgl.attrib(id, "vertices"))) result } # Check for indices that differ from default checkForIndices <- function(id, warn = TRUE) { has_indices <- length(indices <- rgl.attrib(id, "indices")) > 0 && !all(indices == seq_along(indices)) if (has_indices && warn) warning("Indices not supported. Skipping id", id, call. = FALSE) has_indices } rgl/R/obj.R0000644000176200001440000003647614771520323012160 0ustar liggesuserswriteOBJ <- function(con, pointRadius=0.005, pointShape = icosahedron3d(), lineRadius = pointRadius, lineSides = 20, pointsAsPoints = FALSE, linesAsLines = FALSE, withNormals = TRUE, withTextures = TRUE, separateObjects = TRUE, ids = tagged3d(tags), tags = NULL) { writeHeader <- function() { ident <- paste(filename, " produced by RGL") cat("#", ident, "\n", file=con) } Vertices <- 0 Normals <- 0 Texcoords <- 0 writeData <- function(id) { vbase <- Vertices tbase <- Texcoords nbase <- Normals vertices <- rgl.attrib(id, "vertices") cat(paste("v", vertices[,1], vertices[,2], vertices[,3]), sep="\n", file=con) n <- nrow(vertices) Vertices <<- Vertices + n if (withTextures) { textures <- rgl.attrib(id, "texcoords") if (nrow(textures)) cat(paste("vt", textures[,1], textures[,2]), sep="\n", file=con) Texcoords <<- Texcoords + nrow(textures) } if (withNormals) { normals <- rgl.attrib(id, "normals") if (nrow(normals)) cat(paste("vn", normals[,1], normals[,2], normals[,3]), sep="\n", file=con) Normals <<- Normals + nrow(normals) } list(n=n, ntexcoords=if (withTextures) nrow(textures) else 0, nnormals=if (withNormals) nrow(normals) else 0, vbase=vbase, tbase=tbase, nbase=nbase) } refnum <- function(n) sprintf("%d", n) writeTriangles <- function(id) { if (separateObjects) cat("o triangles", id, "\n", sep="", file=con) x <- writeData(id) indices <- refnum(x$vbase + getIndices(id)) if (x$ntexcoords) indices <- paste0(indices, "/", refnum(x$tbase + getIndices(id))) if (x$nnormals) indices <- paste0(indices, if (!x$ntexcoords) "/", "/", refnum(x$nbase + getIndices(id))) indices <- matrix(indices, ncol=3, byrow=TRUE) cat(paste("f", indices[,1], indices[,2], indices[,3]), sep="\n", file=con) } writeQuads <- function(id) { if (separateObjects) cat("o quads", id, "\n", sep="", file=con) x <- writeData(id) indices <- refnum(x$vbase + getIndices(id)) if (x$ntexcoords) indices <- paste0(indices, "/", refnum(x$tbase + getIndices(id))) if (x$nnormals) indices <- paste0(indices, if (!x$ntexcoords) "/", "/", refnum(x$nbase + getIndices(id))) indices <- matrix(indices, ncol=4, byrow=TRUE) cat(paste("f", indices[,1], indices[,2], indices[,3], indices[,4]), sep="\n", file=con) } writeSurface <- function(id) { if (separateObjects) cat("o surface", id, "\n", sep="", file=con) x <- writeData(id) dims <- rgl.attrib(id, "dim") nx <- dims[1] nz <- dims[2] rows <- seq_len(nx) vertices <- matrix(character(0), ncol=3) for (i in seq_len(nz)[-nz]) { indices <- getIndices(id)[(i-1)*nx + c(rows[-nx],rows[-nx], rows[-1]+nx,rows[-nx]+nx, rows[-1],rows[-1]+nx)] cindices <- refnum(x$vbase + indices) if (x$ntexcoords) cindices <- paste0(cindices, "/", refnum(x$tbase + indices)) if (x$nnormals) cindices <- paste0(cindices, if (!x$ntexcoords) "/", "/", refnum(x$nbase + indices)) vertices <- rbind(vertices, matrix(cindices, ncol=3)) } cat(paste("f", vertices[,1], vertices[,2], vertices[,3]), sep="\n", file=con) } writeMesh <- function(mesh, scale=1, offset=c(0,0,0)) { vertices <- asEuclidean(t(mesh$vb))*scale n <- nrow(vertices) vertices <- vertices + rep(offset, each=n) vbase <- Vertices cat(paste("v", vertices[,1], vertices[,2], vertices[,3]), sep="\n", file=con) Vertices <<- Vertices + n if (withTextures && length(textures <- mesh$texcoords)) { tbase <- Texcoords textures <- asEuclidean(t(textures)) cat(paste("vt", textures[,1], textures[,2]), sep="\n", file=con) Texcoords <<- Texcoords + nrow(textures) } else withTextures <- FALSE if (withNormals && length(normals <- mesh$normals)) { nbase <- Normals normals <- asEuclidean(t(normals)) cat(paste("vn", normals[,1], normals[,2], normals[,3]), sep="\n", file=con) Normals <<- Normals + nrow(normals) } else withNormals <- FALSE nt <- length(mesh$it)/3 nq <- length(mesh$ib)/4 if (nt) { indices <- t(mesh$it) cindices <- refnum(vbase + indices) if (withTextures) cindices <- paste0(cindices, "/", refnum(tbase + indices)) if (withNormals) cindices <- paste0(cindices, if (!withTextures) "/", "/", refnum(nbase + indices)) cindices <- matrix(cindices, ncol=3) cat(paste("f", cindices[,1], cindices[,2], cindices[,3]), sep="\n", file=con) } if (nq) { indices <- t(mesh$ib) cindices <- refnum(vbase + indices) if (withTextures) cindices <- paste0(cindices, "/", refnum(tbase + indices)) if (withNormals) cindices <- paste0(cindices, if (!withTextures) "/", "/", refnum(nbase + indices)) cindices <- matrix(cindices, ncol=4) cat(paste("f", cindices[,1], cindices[,2], cindices[,3], cindices[,4]), sep="\n", file=con) } } writeSpheres <- function(id) { if (separateObjects) cat("o sphere", id, "\n", sep="", file=con) vertices <- expandVertices(id) n <- nrow(vertices) radii <- expandAttrib(id, "radii") radii <- rep(radii, length.out=n) x <- subdivision3d(icosahedron3d(),3) r <- sqrt(x$vb[1,]^2 + x$vb[2,]^2 + x$vb[3,]^2) x$vb[4,] <- r x$normals <- x$vb for (i in seq_len(n)) writeMesh(x, radii[i], vertices[i,]) } avgScale <- function() { bbox <- par3d("bbox") ranges <- c(bbox[2]-bbox[1], bbox[4]-bbox[3], bbox[6]-bbox[5]) if (prod(ranges) == 0) 1 else exp(mean(log(ranges))) } writePoints <- function(id) { if (separateObjects) cat("o points", id, "\n", sep="", file=con) if (pointsAsPoints) { x <- writeData(id) cat("p", refnum(x$vbase + getIndices(id)), "\n", file=con) } else { vertices <- expandVertices(id) n <- nrow(vertices) radius <- pointRadius*avgScale() if (withNormals && is.null(pointShape$normals)) pointShape <- addNormals(pointShape) for (i in seq_len(n)) writeMesh(pointShape, radius, vertices[i,]) } } writeSegments <- function(id) { if (separateObjects) cat("o segments", id, "\n", sep="", file=con) if (linesAsLines) { x <- writeData(id) indices <- matrix(refnum(x$vbase + getIndices(id)), ncol=2, byrow=TRUE) cat(paste("l", indices[,1], indices[,2]), sep="\n", file=con) } else { vertices <- expandVertices(id) n <- nrow(vertices) n <- n/2 radius <- lineRadius*avgScale() for (i in seq_len(n)) { cyl <- cylinder3d( vertices[(2*i-1):(2*i),1:3], radius = radius, sides = lineSides, closed = -2 ) if (withNormals) cyl <- addNormals(cyl) writeMesh(cyl) } } } writeLines <- function(id) { if (separateObjects) cat("o lines", id, "\n", sep="", file=con) if (linesAsLines) { x <- writeData(id) indices <- refnum(x$vbase + getIndices(id)) cat("l", indices, "\n", file=con) } else { vertices <- expandVertices(id) n <- nrow(vertices) - 1 radius <- lineRadius*avgScale() for (i in seq_len(n)) { cyl <- cylinder3d( vertices[i:(i+1),], radius = radius, sides = lineSides, closed = -2 ) if (withNormals) cyl <- addNormals(cyl) writeMesh(cyl) } } } knowntypes <- c("triangles", "quads", #, "surface", "spheres", "points", "linestrip", "lines", "planes") # Execution starts here! if (is.character(con)) { con <- file(con, "w") on.exit(close(con)) } filename <- summary(con)$description if (NROW(bbox <- ids3d("bboxdeco")) && (is.null(ids) || bbox$id %in% ids)) { ids <- setdiff(ids, bbox$id) save <- par3d(skipRedraw = TRUE) bbox <- convertBBox(bbox$id) on.exit({ pop3d(id=bbox); par3d(save) }, add=TRUE) # nolint dobbox <- TRUE } else dobbox <- FALSE if (is.null(ids)) { ids <- ids3d() types <- as.character(ids$type) ids <- ids$id } else { if (dobbox) ids <- c(ids, bbox) allids <- ids3d() ind <- match(ids, allids$id) keep <- !is.na(ind) if (any(!keep)) warning(gettextf("Object(s) with id %s not found", paste(ids[!keep], collapse=" ")), domain = NA) ids <- ids[keep] types <- allids$type[ind[keep]] } unknowntypes <- setdiff(types, knowntypes) if (length(unknowntypes)) warning(gettextf("Object type(s) %s not handled", paste("'", unknowntypes, "'", sep="", collapse=", ")), domain = NA) keep <- types %in% knowntypes ids <- ids[keep] types <- types[keep] writeHeader() for (i in seq_along(ids)) switch(types[i], planes =, triangles = writeTriangles(ids[i]), quads = writeQuads(ids[i]), surface = writeSurface(ids[i]), spheres = writeSpheres(ids[i]), points = writePoints(ids[i]), lines = writeSegments(ids[i]), linestrip = writeLines(ids[i]) ) invisible(filename) } readOBJ <- function(con, ...) { lines <- readLines(con) lines <- sub("^[[:blank:]]*", "", lines) instrs <- sub("[[:blank:]].*", "", lines) instrs <- sub("^#.*", "#", instrs) vertices <- read.table(textConnection(lines[instrs == "v"]), col.names = c("instr", "x", "y", "z"), colClasses = c(instr = "character", x="numeric", y="numeric", z="numeric")) vertices <- with(vertices, rbind(x, y, z)) # nolint subset <- lines[instrs == "vn"] if (length(subset)) { fields <- count.fields(textConnection(subset)) if (!all(fields == 4)) stop("Normals must have 4 fields") vn <- read.table(textConnection(subset), col.names = c("instr", "x", "y", "z"), colClasses = c(instr = "character", x="numeric", y="numeric", z="numeric")) vn <- rbind(t(vn[,2:4]), 1) } else vn <- matrix(numeric(), nrow = 4, ncol = 0) subset <- lines[instrs == "vt"] if (length(subset)) { fields <- count.fields(textConnection(subset)) if (length(unique(fields)) != 1) stop("Textures must have consistent field count") fields <- fields[1] colClasses <- c("character", rep("numeric", fields - 1)) vt <- read.table(textConnection(subset), colClasses = colClasses) if (fields == 2) vt <- cbind(vt, 0) vt <- t(vt[, 2:3]) } else vt <- matrix(numeric(), nrow = 2, ncol = 0) # Get rid of texture and normal info polys <- gsub("/[^[:blank:]]*", "", lines[instrs == "f"]) polys <- strsplit(polys, "[[:blank:]]+") polys <- lapply(polys, function(poly) as.numeric(poly[-1])) # Regexp suggested by Bill Dunlap -- thanks! Modified # by DJM to replace " " with "[[:blank:]]" normals <- gsub("(^|[[:blank:]]*)([^/[:blank:]]*/?){0,2}", "\\1", lines[instrs == "f"]) # nolint normals <- strsplit(normals, "[[:blank:]]+") normals <- lapply(normals, function(normal) as.numeric(normal[nchar(normal) > 0])) textures <- gsub("(^|[[:blank:]]*)([^/[:blank:]]*/?){0,1}", "\\1", lines[instrs == "f"]) # nolint textures <- gsub("/[^[:blank:]]*", "", textures) textures <- strsplit(textures, "[[:blank:]]+") textures <- lapply(textures, function(texture) as.numeric(texture[nchar(texture) > 0])) nverts <- sapply(polys, length) nnorms <- sapply(normals, length) ntexts <- sapply(textures, length) hasnormals <- nnorms == nverts hastextures <- ntexts == nverts if (any(hasnormals) || any(hastextures)) { # OBJ format allows different normals to be associated # with a single vertex in different polygons. rgl # doesn't, so may need to replicate some vertices. # This could be slow... vlinks <- vector("list", ncol(vertices)) for (i in seq_along(polys)) { nvec <- tvec <- NA if (hasnormals[i]) nvec <- as.numeric(normals[[i]]) if (hastextures[i]) tvec <- as.numeric(textures[[i]]) vvec <- as.numeric(polys[[i]]) for (j in seq_along(vvec)) vlinks[[vvec[j]]] <- rbind(vlinks[[vvec[j]]], c(nvec[j], tvec[j], i, j)) } total <- 0 for (i in seq_along(vlinks)) { # Sort by texture vlinks[[i]] <- vlinks[[i]][order(vlinks[[i]][,2]),,drop=FALSE] total <- total + max(1, length(unique(vlinks[[i]][,2]))) } last <- ncol(vertices) vertices <- cbind(vertices, matrix(NA_real_, 3, total - ncol(vertices))) vnormals <- matrix(0, 4, total) vtexcoords <- matrix(NA_real_, 2, total) for (i in seq_along(vlinks)) { links <- vlinks[[i]] if (nrow(links)) { # Average the normals at this vertex by # summing the homogeneous coordinates for (j in seq_len(nrow(links))) if (!is.na(links[j,1])) vnormals[,i] <- vnormals[,i] + vn[,links[1,1]] # A given vertex may have more than one texture # coordinate; rgl doesn't allow this, so we # duplicate vertices where that happened if (!is.na(links[1,2])) vtexcoords[,i] <- vt[,links[1,2]] same <- duplicated(links[,2]) duped <- FALSE for (j in seq_len(nrow(links))[-1]) { if (!same[j]) { last <- last + 1 vertices[,last] <- vertices[,i] vnormals[,last] <- vnormals[,i] duped <- TRUE } # Update the polygon and texture links to the new copy if (duped) { polys[[links[j, 3]]][links[j, 4]] <- last if (!is.na(links[j, 2])) vtexcoords[,last] <- vt[,links[j, 2]] } } } } } triangles <- do.call(cbind, polys[nverts == 3]) if (!length(triangles)) triangles <- matrix(numeric(), 3, 0) # We build quads transposed, because we're going to stick # it directly into the structure quads <- do.call(cbind, polys[nverts == 4]) others <- which(!(nverts %in% 3:4)) # FIXME: this will be really slow if there are a lot of others # Should pre-allocate extra space. for (i in seq_along(others)) { v <- polys[[others[i]]] tri <- triangulate(t(vertices[,v])) tri <- structure(v[tri], dim = dim(tri)) triangles <- cbind(triangles, tri) } ignored <- unique(instrs) ignored <- ignored[!(ignored %in% c("v", "vn", "vt", "f", "", "#"))] if (length(ignored)) warning(gettextf("Instructions %s ignored", paste0('"', ignored, '"', collapse = ", ")), domain = NA) result <- tmesh3d(vertices, triangles, homogeneous = FALSE, ...) if (length(quads)) result$ib <- quads if (any(hasnormals)) result$normals <- vnormals[1:3,]/rep(vnormals[4,], each=3) if (any(hastextures)) result$texcoords <- vtexcoords result } rgl/R/matrices.R0000644000176200001440000000712314771520323013200 0ustar liggesusers# Functions for creating 4x4 graphics matrices identityMatrix <- function() diag(nrow=4) scaleMatrix <- function(x,y,z) diag(c(x,y,z,1)) translationMatrix <- function(x,y,z) { result <- diag(4) result[4,1:3] <- c(x,y,z) result } rotationMatrix <- function(angle,x,y,z,matrix) { if (missing(matrix)) { if (angle == 0) return(identityMatrix()) u <- c(x,y,z)/sqrt(x^2+y^2+z^2) cosa <- cos(angle) sina <- sin(angle) matrix <- (1-cosa)*outer(u,u) matrix <- matrix + diag(3)*cosa matrix[1,2] <- matrix[1,2] - sina*u[3] matrix[1,3] <- matrix[1,3] + sina*u[2] matrix[2,1] <- matrix[2,1] + sina*u[3] matrix[2,3] <- matrix[2,3] - sina*u[1] matrix[3,1] <- matrix[3,1] - sina*u[2] matrix[3,2] <- matrix[3,2] + sina*u[1] } if (identical(all.equal(dim(matrix), c(3,3)), TRUE)) matrix <- cbind(rbind(matrix,c(0,0,0)),c(0,0,0,1)) return(matrix) } # Coordinate conversions asHomogeneous <- function(x) { if (is.matrix(x)) { if (ncol(x) == 3) return(cbind(x,1)) if (ncol(x) == 4) return(x) } else { if (length(x) %% 3 == 0) return(cbind(matrix(x, ncol = 3, byrow = TRUE),1)) if (length(x) %% 4 == 0) return(matrix(x, ncol = 4, byrow = TRUE)) } stop("Don't know how to convert x") } asHomogeneous2 <- function(x) { if (is.matrix(x)) { if (nrow(x) == 3) return(rbind(x,1)) if (nrow(x) == 4) return(x) } else { if (length(x) %% 3 == 0) return(rbind(matrix(x, nrow = 3), 1)) if (length(x) %% 4 == 0) return(matrix(x, nrow = 4)) } stop("Don't know how to convert x") } asEuclidean <- function(x) { if (is.matrix(x)) { if (ncol(x) == 4) return(x[, 1:3, drop = FALSE]/x[, 4]) if (ncol(x) == 3) return(x) } else { if (length(x) %% 4 == 0) return(asEuclidean(matrix(x, ncol = 4, byrow = TRUE))) if (length(x) %% 3 == 0) return(matrix(x, ncol = 3, byrow = TRUE)) } stop("Don't know how to convert x") } asEuclidean2 <- function(x) { if (is.matrix(x)) { if (nrow(x) == 4) return(rbind(x[1,]/x[4,], x[2,]/x[4,], x[3,]/x[4,])) if (nrow(x) == 3) return(x) } else { if (length(x) %% 4 == 0) return(asEuclidean2(matrix(x, nrow = 4))) if (length(x) %% 3 == 0) return(matrix(x, nrow = 3)) } stop("Don't know how to convert x") } # Default implementations of transformations translate3d.default <- function(obj,x,y,z,...) { if (is.matrix(obj)) n <- dim(obj)[1] else n <- 1 if (length(obj) == 3 || (is.matrix(obj) && dim(obj)[2] == 3)) return(obj + cbind(rep(x,n), rep(y,n), rep(z,n))) else if (length(obj) == 4 || (is.matrix(obj) && dim(obj)[2] == 4)) return(obj %*% translationMatrix(x,y,z)) else stop("Unsupported object for translation") } scale3d.default <- function(obj,x,y,z,...) { if (is.matrix(obj)) n <- dim(obj)[1] else n <- 1 if (length(obj) == 3 || (is.matrix(obj) && dim(obj)[2] == 3)) return(obj * cbind(rep(x,n), rep(y,n), rep(z,n))) else if (length(obj) == 4 || (is.matrix(obj) && dim(obj)[2] == 4)) return(obj %*% scaleMatrix(x,y,z)) else stop("Unsupported object for scaling") } rotate3d.default <- function(obj,angle,x,y,z,matrix,...) { if (length(obj) == 3 || (is.matrix(obj) && dim(obj)[2] == 3)) return(asEuclidean(asHomogeneous(obj) %*% rotationMatrix(angle,x,y,z,matrix))) else if (length(obj) == 4 || (is.matrix(obj) && dim(obj)[2] == 4)) return(obj %*% rotationMatrix(angle,x,y,z,matrix)) else stop("Unsupported object for rotation") } rgl/R/identify3d.R0000644000176200001440000000437114555455305013444 0ustar liggesusersidentify3d <- function(x, y = NULL, z = NULL, labels = seq_along(x), n = length(x), plot = TRUE, adj = c(-0.1, 0.5), tolerance = 20, buttons = c("right", "middle")) { cat <- function(...) { base::cat(...) flush.console() } opar <- par3d("mouseMode") odisp <- cur3d() on.exit( { disp <- cur3d() if (odisp != disp) try(set3d(odisp), silent=TRUE) if (cur3d() == odisp) par3d(mouseMode = opar) try(set3d(disp), silent=TRUE) } ) xyz <- xyz.coords(x, y, z) x <- xyz$x y <- xyz$y z <- xyz$z if (length(x)==0) return(numeric()) force(labels) force(adj) buttons <- match.arg(buttons, c("left", "right", "middle"), several.ok = TRUE) if (length(buttons > 1)) cat(gettextf("Use the %s button to select, the %s button to quit\n", buttons[1], buttons[2])) else cat(gettextf("Use the %s button to select\n"), buttons[1]) buttons <- c(left=1, right=2, middle=3)[buttons] selected <- NULL select <- function(mousex, mousey) { disp <- cur3d() if (disp != odisp) { set3d(odisp) on.exit(set3d(disp)) } viewport <- par3d("viewport") winxyz <- rgl.user2window(xyz) winxyz[,1] <- winxyz[,1]*viewport[3] winxyz[,2] <- (1-winxyz[,2])*viewport[4] dist <- sqrt( (mousex-winxyz[,1])^2 + (mousey - winxyz[,2])^2 ) dist[winxyz[,3] < 0 | winxyz[,3] > 1] <- Inf sel <- which.min(dist) if (dist[sel] > tolerance) cat(gettext("Warning: no point within tolerance\n")) else if (sel %in% selected) cat(gettext("Warning: nearest point already identified\n")) else { selected <<- c(selected, sel) if (plot) text3d(x[sel], y[sel], z[sel], texts=labels[sel], adj=adj) } } doquit <- FALSE quit <- function(mousex, mousey) { doquit <<- TRUE } rgl.setMouseCallbacks(buttons[1], begin=select) if (length(buttons) > 1) rgl.setMouseCallbacks(buttons[2], begin=quit) while(!doquit && length(selected) < n) Sys.sleep(0.2) selected } rgl/R/fonts.R0000644000176200001440000000407314771520323012523 0ustar liggesusers# The rgl font database is only used when rgl is configured for FreeType. # Since 0.105.13 this is always true on Windows, but since 0.106.2 # r3dDefaults sets useFreeType to FALSE, so the windowsFonts() are used instead. # This code is closely modelled on the Quartz font database. .rglEnv <- new.env() assign(".rglFonts", list(), envir = .rglEnv) # Check that the font has the correct structure and information checkrglFont <- function(font) { if (!is.character(font) || length(font) != 4) stop("Invalid rgl font: must be 4 filenames") font } setrglFonts <- function(fonts, fontNames) { fonts <- lapply(fonts, checkrglFont) fontDB <- get(".rglFonts", envir=.rglEnv) existingFonts <- fontNames %in% names(fontDB) if (sum(existingFonts) > 0) fontDB[fontNames[existingFonts]] <- fonts[existingFonts] if (sum(existingFonts) < length(fontNames)) fontDB <- c(fontDB, fonts[!existingFonts]) assign(".rglFonts", fontDB, envir=.rglEnv) } printFont <- function(font) { paste(font, "\n", sep="") } printFonts <- function(fonts) { cat(paste(names(fonts), ": ", unlist(lapply(fonts, printFont)), sep="", collapse="")) } # If no arguments spec'ed, return entire font database # If no named arguments spec'ed, all args should be font names # to get info on them from the database # Else, must specify new fonts to enter into database (all # of which must be valid filenames and # all of which must be named args) rglFonts <- function(...) { ndots <- length(fonts <- list(...)) if (ndots==0) { get(".rglFonts", .rglEnv) } else { fontNames <- names(fonts) nnames <- length(fontNames) if (nnames == 0) { if (!all(sapply(fonts, is.character))) { stop("Invalid arguments in 'rglFonts' (must be font names)") } else { get(".rglFonts", .rglEnv)[unlist(fonts)] } } else { if (ndots != nnames) { stop("Invalid arguments in 'rglFonts' (need named args)") } setrglFonts(fonts, fontNames) } } } rglFont <- function(family) { checkrglFont(family) } rgl/R/setUserCallbacks.R0000644000176200001440000001366615011677075014641 0ustar liggesusersrgl.callback.env <- new.env(parent = emptyenv()) findSubscene <- function(subscene, id) { if (subscene$id == id) return(subscene) subscenes <- subscene$subscenes if (!is.null(subscenes)) { for (i in seq_along(subscenes)) { if (!is.null(result <- findSubscene(subscenes[[i]], id))) return(result) } } NULL } findBboxdeco <- function(scene, subscene, root = scene$rootSubscene, guess = NULL) { active <- root for (id in active$objects) if (scene$objects[[as.character(id)]]$type == "bboxdeco") guess <- id if (active$id == subscene) if (is.null(guess)) return(NULL) else return(scene$objects[[as.character(guess)]]) for (sub in active$subscenes) if (!is.null(bbox <- findBboxdeco(scene, subscene, sub, guess))) return(bbox) return(NULL) } replaceSubscene <- function(subscene, id, newvalue) { if (as.character(subscene$id) == id) return(newvalue) subscenes <- subscene$subscenes if (!is.null(subscenes)) for (i in seq_along(subscenes)) if (!is.null(result <- replaceSubscene(subscenes[[i]], id, newvalue))) { subscene$subscenes[[i]] <- result return(subscene) } NULL } getfn <- function(fn, up = 2) { if (is.character(fn)) result <- eval(parse(text = fn), envir = parent.frame(up)) else result <- fn if (!is.function(result)) stop(fn, " is not a function.") result } setUserCallbacks <- function(button = NULL, begin = NULL, update = NULL, end = NULL, rotate = NULL, javascript = NULL, subscene = scene$rootSubscene$id, scene = scene3d(minimal = FALSE), applyToScene = TRUE, applyToDev = missing(scene)) { force(applyToDev) stopifnot(inherits(scene, "rglscene")) subscene <- as.character(subscene) sub <- findSubscene(scene$rootSubscene, subscene) if (is.null(sub)) stop("subscene ", subscene, " not found.") if (is.null(sub$par3d) || is.null(sub$par3d$mouseMode) || is.null(sub$embeddings)) stop("Internal error: subscene missing mouseMode or embeddings") if (is.null(sub$callbacks)) sub$callbacks <- list() if (!is.null(button)) { if (is.numeric(button)) button <- c("none", "left", "right", "middle", "wheel")[button + 1] sub$par3d$mouseMode[button] <- "user" sub$callbacks[[button]] <- list(begin = begin, update = update, end = end, rotate = rotate) sub$embeddings["mouse"] <- "replace" } javascript <- paste(c(scene$javascript, javascript), collapse = "\n") if (applyToScene) { scene$rootSubscene <- replaceSubscene(scene$rootSubscene, subscene, sub) scene$javascript <- javascript } if (applyToDev) { dev <- cur3d() devname <- paste0("dev", dev) callbacks <- rgl.callback.env[[devname]] if (is.null(callbacks)) callbacks <- list() callbacks[[paste0("sub", subscene)]] <- sub$callbacks callbacks$javascript <- javascript rgl.callback.env[[devname]] <- callbacks if (dev > 0) { callbacks <- sub$callbacks if (!is.null(button)) { fns <- callbacks[[button]] if (!is.null(fns)) { for (f in c("begin", "update", "end", "rotate")) if (!is.null(fns[[f]])) fns[[f]] <- getfn(fns[[f]]) callbacks[[button]] <- fns if (button == "wheel" && is.function(fns$rotate)) rgl.setWheelCallback(rotate = fns$rotate, dev = dev, subscene = subscene) fns$rotate <- NULL if (any(vapply(fns, is.function, TRUE))) do.call(rgl.setMouseCallbacks, c(list(button = c(none = 0, left = 1, right = 2, middle = 3, wheel = 4)[button], dev = dev, subscene = subscene), fns)) } } } } invisible(scene) } setAxisCallbacks <- function(axes, fns, javascript = NULL, subscene = scene$rootSubscene$id, scene = scene3d(minimal = FALSE), applyToScene = TRUE, applyToDev = missing(scene)) { force(applyToDev) stopifnot(inherits(scene, "rglscene")) subscene <- as.character(subscene) if (!is.character(axes)) axes <- c("x", "y", "z")[axes] else axes <- tolower(axes) stopifnot(all(axes %in% c("x", "y", "z"))) if (!is.list(fns)) fns <- list(fns) n <- max(length(axes), length(fns)) axes <- rep(axes, length.out = n) fns <- rep(fns, length.out = n) # Call each function once to set things up before grabbing # the scene for (i in seq_len(n)) getfn(fns[[i]])(paste0(axes[i], "--")) sub <- findSubscene(scene$rootSubscene, subscene) if (is.null(sub)) stop("subscene ", subscene, " not found.") bbox <- findBboxdeco(scene, subscene) if (is.null(bbox)) stop("No bbox decoration found.") if (is.null(bbox$callbacks)) bbox$callbacks <- list() for (i in seq_len(n)) bbox$callbacks[[axes[i]]] <- fns[[i]] javascript <- paste(c(scene$javascript, javascript), collapse = "\n") if (applyToScene) { scene$objects[[as.character(bbox$id)]] <- bbox scene$javascript <- javascript } if (applyToDev) { dev <- cur3d() devname <- paste0("dev", dev) callbacks <- rgl.callback.env[[devname]] if (is.null(callbacks)) callbacks <- list() callbacks[[paste0("bbox", bbox$id)]] <- bbox$callbacks callbacks$javascript <- javascript rgl.callback.env[[devname]] <- callbacks if (dev > 0) { callbacks <- bbox$callbacks for (i in seq_len(n)) { fn <- getfn(fns[[i]]) axis <- match(axes[i], c("x", "y", "z")) .Call(rgl_setAxisCallback, fn, as.integer(dev), as.integer(subscene), as.integer(axis - 1)) } } } invisible(scene) } rgl/R/solids3d.R0000644000176200001440000000702414771520323013115 0ustar liggesusers# # R 3d object : cube3d # cube3d.vb <- c( -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0 ) cube3d.ib <- c( 1, 3, 4, 2, 3, 7, 8, 4, 2, 4, 8, 6, 1, 5, 7, 3, 1, 2, 6, 5, 5, 6, 8, 7 ) cube3d <- function( trans = identityMatrix(), ... ) { rotate3d( mesh3d( vertices = cube3d.vb, quads = cube3d.ib, material=.fixMaterialArgs2(...) ), matrix = trans) } # # tetrahedron # tetra3d.vb <- c( -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0 ) tetra3d.it <- c( 1, 2, 3, 3, 2, 4, 4, 2, 1, 1, 3, 4 ) tetrahedron3d <- function( trans = identityMatrix(), ... ) { rotate3d( mesh3d(vertices = tetra3d.vb, triangles = tetra3d.it, material=.fixMaterialArgs2(...) ), matrix = trans) } # # octahedron # octa3d.vb <- c( -1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, -1.0, 0.0, 0.0, 1.0 ) octa3d.it <- c( 1,5,3, 1,3,6, 1,4,5, 1,6,4, 2,3,5, 2,6,3, 2,5,4, 2,4,6 ) octahedron3d <- function( trans = identityMatrix(), ... ) { rotate3d( mesh3d( vertices = octa3d.vb, triangles = octa3d.it, material=.fixMaterialArgs2(...) ), matrix = trans) } # # icosahedron # phi <- (1+sqrt(5))/2 ico3d.vb <- c( 0, 1/phi, 1, 0, 1/phi, -1, 0, -1/phi, 1, 0, -1/phi,-1, 1/phi, 1, 0, 1/phi, -1, 0, -1/phi, 1, 0, -1/phi, -1, 0, 1, 0, 1/phi, -1, 0, 1/phi, 1, 0, -1/phi, -1, 0, -1/phi ) ico3d.it <- c( 1, 3, 9, 1, 9, 5, 1, 5, 7, 1, 7, 10, 1, 10, 3, 4, 12, 2, 4, 2, 11, 4, 11, 6, 4, 6, 8, 4, 8, 12, 9, 3, 6, 5, 9, 11, 7, 5, 2, 10, 7, 12, 3, 10, 8, 2, 12, 7, 11, 2, 5, 6, 11, 9, 8, 6, 3, 12, 8, 10) icosahedron3d <- function( trans = identityMatrix(), ... ) { rotate3d( mesh3d( vertices = ico3d.vb, triangles = ico3d.it, material=.fixMaterialArgs2(...) ), matrix = trans) } dodec3d.vb <- c( -1/phi, -1/phi, -1/phi, 1/phi, -1/phi, -1/phi, -1/phi, 1/phi, -1/phi, 1/phi, 1/phi, -1/phi, -1/phi, -1/phi, 1/phi, 1/phi, -1/phi, 1/phi, -1/phi, 1/phi, 1/phi, 1/phi, 1/phi, 1/phi, 0, -1/phi^2, 1, 0, 1/phi^2, 1, 0, -1/phi^2,-1, 0, 1/phi^2,-1, -1/phi^2, 1, 0, 1/phi^2, 1, 0, -1/phi^2,-1, 0, 1/phi^2,-1, 0, 1, 0,-1/phi^2, 1, 0, 1/phi^2, -1, 0,-1/phi^2, -1, 0, 1/phi^2 ) dodec3d.if <- c( 1, 11, 2, 16, 15, 1, 15, 5, 20, 19, 1, 19, 3, 12, 11, 2, 11, 12, 4, 17, 2, 17, 18, 6, 16, 3, 13, 14, 4, 12, 3, 19, 20, 7, 13, 4, 14, 8, 18, 17, 5, 9, 10, 7, 20, 5, 15, 16, 6, 9, 6, 18, 8,10, 9, 7, 10, 8,14, 13) dodecahedron3d <- function( trans = identityMatrix(), ...) { m <- matrix(dodec3d.if, 5, 12) rotate3d( mesh3d( vertices = dodec3d.vb, triangles = c(m[c(1,2,3, 1,3,4, 1,4,5),]), material=.fixMaterialArgs2(...) ), matrix=trans) } cuboct3d.vb <- c( -1, -1, 0, -1, 1, 0, 1, -1, 0, 1, 1, 0, -1, 0,-1, -1, 0, 1, 1, 0,-1, 1, 0, 1, 0, -1,-1, 0, -1, 1, 0, 1,-1, 0, 1, 1 ) cuboct3d.ib <- c( 1, 6, 2, 5, 1, 9, 3, 10, 2, 12,4, 11, 3, 7, 4, 8, 5, 11, 7, 9, 6, 10, 8, 12) cuboct3d.it <- c( 1, 5, 9, 1, 10, 6, 2, 11, 5, 2, 6, 12, 3, 9, 7, 3, 8, 10, 4, 7, 11, 4, 12, 8) cuboctahedron3d <- function( trans = identityMatrix(), ...) { rotate3d( mesh3d( vertices = cuboct3d.vb, triangles = cuboct3d.it, quads = cuboct3d.ib, material=.fixMaterialArgs2(...) ), matrix = trans) } rgl/R/pch3d.R0000644000176200001440000001075714555455305012410 0ustar liggesuserspch3d <- function(x, y = NULL, z = NULL, pch = 1, bg = material3d("color")[1], cex = 1, radius = avgscale*cex/8, color = "black", lit = FALSE, ...) { xyz <- xyz.coords(x, y, z) xyz <- cbind(xyz$x, xyz$y, xyz$z) pch <- rep(pch, length.out = nrow(xyz)) color <- rep(color, length.out = nrow(xyz)) bg <- rep(bg, length.out = nrow(xyz)) basic <- function(p) switch(as.character(p), '0' = { # square theta <- seq(pi/4, 2*pi + pi/4, length.out = 5) cbind(cos(theta), sin(theta), 0) }, '1' = { # circle (actually 16-gon) theta <- seq(0, 2*pi, length.out = 17) cbind(cos(theta), sin(theta), 0)*sqrt(0.75) }, '2' = { # triangle theta <- seq(pi/2, 2*pi + pi/2, length.out = 4) cbind(cos(theta), sin(theta), 0) }, '-2' = { # triangle in square cbind(c(0, -1, 1, 0), c(1, -1, -1, 1), 0)*sqrt(0.5) }, '3' = { # plus theta <- seq(0, 2*pi, length.out = 5) rbind(cbind(cos(theta[c(1,3)]), sin(theta[c(1,3)]), 0), c(NA, NA, NA), cbind(cos(theta[c(2,4)]), sin(theta[c(2,4)]), 0)) }, '4' = { # cross theta <- seq(pi/4, 2*pi + pi/4, length.out = 5) rbind(cbind(cos(theta[c(1,3)]), sin(theta[c(1,3)]), 0), c(NA, NA, NA), cbind(cos(theta[c(2,4)]), sin(theta[c(2,4)]), 0)) }, '5' = { # diamond theta <- seq(0, 2*pi, length.out = 5) cbind(cos(theta), sin(theta), 0) }, '6' = { # nabla theta <- seq(3*pi/2, 2*pi + 3*pi/2, length.out = 4) cbind(cos(theta), sin(theta), 0) })*radius join <- function(s1, s2) rbind(s1, c(NA, NA, NA), s2) if (missing(radius)) avgscale <- sqrt(sum(c(diff(range(xyz[,1],na.rm=TRUE)), diff(range(xyz[,2],na.rm=TRUE)), diff(range(xyz[,3],na.rm=TRUE)))^2/3)) rot <- rotate3d(r3dDefaults$userMatrix, pi/2, 1, 0, 0) draw <- function(s, color) { sprites3d(thisxyz, shapes = lines3d(s, color = color, lit = lit, ...), userMatrix = rot) } fill <- function(s, color) sprites3d(thisxyz, shapes = polygon3d(s, color = color, lit = lit, ...), userMatrix = rot) outline <- function(s, color, bg) { dots <- list(...) dots$color <- bg sprites3d(thisxyz, shapes = c(lines3d(s, color = color, lit = lit, ...), do.call(polygon3d, c(list(s, lit = lit), dots))), userMatrix = rot) } save <- par3d(skipRedraw = TRUE) on.exit(par3d(save)) ids <- numeric() if (is.numeric(pch)) { bg[!(pch %in% 21:25)] <- bg[1] pchcol <- data.frame(pch, color, bg) uniquePchcol <- unique(pchcol) for (i in seq_len(nrow(uniquePchcol))) { p <- uniquePchcol$pch[i] cl <- uniquePchcol$color[i] b <- uniquePchcol$bg[i] thisxyz <- xyz[p == pch & cl == color & b == bg,, drop = FALSE] ids <- c(ids, switch(as.character(p), '0' =, '1' =, '2' =, '3' =, '4' =, '5' =, '6' = draw(basic(p), color = cl), '7' = draw(join(basic(0), basic(4)), color = cl), '8' = draw(join(basic(3), basic(4)), color = cl), '9' = draw(join(basic(3), basic(5)), color = cl), '10' = draw(join(basic(1), basic(3)*sqrt(0.75)), color = cl), '11' = draw(join(basic(2), basic(6)), color = cl), '12' = draw(join(basic(0), basic(3)*sqrt(0.5)), color = cl), '13' = draw(join(basic(1), basic(4)), color = cl), '14' = draw(join(basic(0), basic(-2)), color = cl), '15' = fill(basic(0), color = cl), '16' = fill(basic(1), color = cl), '17' = fill(basic(2), color = cl), '18' = fill(basic(5)/sqrt(2), color = cl), '19' = fill(basic(1), color = cl), '20' = fill(basic(1)*(2/3), color = cl), '21' = outline(basic(1), color = cl, bg = b), '22' = outline(basic(0), color = cl, bg = b), '23' = outline(basic(5), color = cl, bg = b), '24' = outline(basic(2), color = cl, bg = b), '25' = outline(basic(6), color = cl, bg = b))) } letters <- 32 <= pch & pch <= 255 xyz <- xyz[letters,, drop = FALSE] if (nrow(xyz)) { pch <- rawToChar(as.raw(pch[letters]), multiple = TRUE) color <- color[letters] } } if (nrow(xyz)) { pch <- substr(pch, start = 1, stop = 1) ids <- c(ids, text3d(xyz, texts = pch, cex = cex, color = color, ...)) } lowlevel(ids) } rgl/R/grid3d.R0000644000176200001440000000370014555455305012551 0ustar liggesusersgrid3d <- function(side, at = NULL, col="gray", lwd = 1, lty = 1, n = 5) { save <- par3d(skipRedraw = TRUE, ignoreExtent = TRUE) on.exit(par3d(save)) if (!missing(side) && length(side)>1) return(lowlevel(sapply(side,grid3d,at=at,col=col,lwd=lwd,lty=lty,n=n))) ranges <- .getRanges() side <- c(strsplit(side, '')[[1]], '-')[1:2] coord <- match(toupper(side[1]), c('X', 'Y', 'Z')) spos <- match(side[2],c('-','+')) sidenames <- c('x', 'y', 'z') sides <- 1:3 sides <- sides[-coord] if (is.null(at)) at <- list() else if (is.numeric(at)) { at <- list(x=at, y=at, z=at) at[[coord]] <- NULL } result <- integer() for (cside in sides) { range <- ranges[[cside]] if (is.null(at1 <- at[[sidenames[cside]]])) at1 <- pretty(range, n) at1 <- at1[at1 >= range[1] & at1 <= range[2]] mpos1 <- matrix(rep(c(ranges$x[1],ranges$y[1],ranges$z[1]), each=length(at1)), ncol=3) mpos2 <- matrix(rep(c(ranges$x[2],ranges$y[2],ranges$z[2]), each=length(at1)), ncol=3) mpos1[,cside] <- mpos2[,cside] <- at1 if (is.null(at[[sidenames[coord]]])) mpos1[,coord] <- mpos2[,coord] <- ranges[c("x","y","z")][[coord]][spos] else { # may need to duplicate temp1 <- temp2 <- matrix(NA, nrow=0, ncol=3) planes <- at[[sidenames[coord]]] planes <- planes[planes >= ranges[[coord]][1] & planes <= ranges[[coord]][2]] for (at2 in planes) { mpos1[,coord] <- mpos2[,coord] <- at2 temp1 <- rbind(temp1, mpos1) temp2 <- rbind(temp2, mpos2) } mpos1 <- temp1 mpos2 <- temp2 } if (nrow(mpos1) + nrow(mpos2) > 0) result[sidenames[cside]] <- segments3d(x=c(rbind(mpos1[,1],mpos2[,1])), y=c(rbind(mpos1[,2],mpos2[,2])), z=c(rbind(mpos1[,3],mpos2[,3])), lwd=lwd,color=col) } lowlevel(result) } rgl/R/plugin.R0000644000176200001440000000021114555455305012665 0ustar liggesusers## ## R source file ## This file is part of rgl ## ## ## ## quit R plugin ## ## rgl.quit <- function() { unloadNamespace("rgl") } rgl/R/noOpenGL.R.in0000644000176200001440000000014514555455305013463 0ustar liggesusers# The RGL_NO_OPENGL setting is TRUE if configured with --disable-opengl noOpenGL <- @RGL_NO_OPENGL@ rgl/R/mesh3d.R0000644000176200001440000003530415011677075012563 0ustar liggesusersensureMatrix <- function(x, nrow) { if (!is.matrix(x)) x <- matrix(x, nrow = nrow) x } mesh3d <- function( x, y = NULL, z = NULL, vertices, material = NULL, normals = NULL, texcoords = NULL, points = NULL, segments = NULL, triangles = NULL, quads = NULL, meshColor = c("vertices", "edges", "faces", "legacy")) { if (missing(vertices)) { xyz <- xyz.coords(x, y, z, recycle=TRUE) if (length(xyz$x) && length(xyz$y) && length(xyz$z)) vertices <- rbind(xyz$x, xyz$y, xyz$z, 1) else vertices <- matrix(numeric(), nrow = 4) } else vertices <- asHomogeneous2(vertices) # Remove dimnames dimnames(vertices) <- NULL if (missing(meshColor) && !is.null(material) && !is.null(material$meshColor)) { meshColor <- material$meshColor material$meshColor <- NULL } meshColor <- match.arg(meshColor) if (is.null(texcoords) && !is.null(material) && !is.null(material$texcoords)) { texcoords <- material$texcoords material$texcoords <- NULL } nvertex <- ncol(vertices) if ( !is.null(normals) ) { normals <- xyz.coords(normals, recycle=TRUE) x <- rep(normals$x, length.out = nvertex) y <- rep(normals$y, length.out = nvertex) z <- rep(normals$z, length.out = nvertex) normals <- rgl.vertex(x, y, z) } if ( !is.null(texcoords) ) { texcoords <- xy.coords(texcoords, recycle = TRUE) x <- rep(texcoords$x, length.out = nvertex) y <- rep(texcoords$y, length.out = nvertex) texcoords <- rbind(x, y) } object <- list( vb = vertices, material = .getMaterialArgs(material = material), normals = normals, texcoords = texcoords, meshColor = meshColor ) if (!is.null(points)) object$ip <- ensureMatrix(points, 1) if (!is.null(segments)) object$is <- ensureMatrix(segments, 2) if (!is.null(triangles)) object$it <- ensureMatrix(triangles, 3) if (!is.null(quads)) object$ib <- ensureMatrix(quads, 4) register_compare_proxy() class(object) <- c("mesh3d", "shape3d") object } register_compare_proxy <- local({ registered <- FALSE function() { if (!registered && isNamespaceLoaded("waldo")) { if ("path" %in% names(formals(waldo::compare_proxy))) { # appeared after 0.2.5 registerS3method("compare_proxy", "mesh3d", compare_proxy.mesh3d, envir = asNamespace("waldo")) registerS3method("compare_proxy", "rglscene", compare_proxy.rglscene, envir = asNamespace("waldo")) } else { registerS3method("compare_proxy", "mesh3d", old_compare_proxy.mesh3d, envir = asNamespace("waldo")) registerS3method("compare_proxy", "rglscene", old_compare_proxy.rglscene, envir = asNamespace("waldo")) } registered <<- TRUE } } }) compare_proxy.mesh3d <- function(x, path = "x") { list(object = old_compare_proxy.mesh3d(x), path = paste0("compare_proxy(", path, ")")) } old_compare_proxy.mesh3d <- function(x) { for (n in names(x)) # Some elements are NULL, some are not there if (is.null(x[[n]])) x[[n]] <- NULL if (is.null(x$material) || length(x$material$color) < 2) x$meshColor <- NULL # It doesn't matter. for (n in c("ip", "is", "it", "ib")) if (!is.null(x[[n]])) x[[n]] <- as.numeric(x[[n]]) x$primitivetype <- NULL # Not used since before 0.100.x x[sort(names(x))] } # # triangle mesh object # tmesh3d <- function( vertices, indices, homogeneous=TRUE, material=NULL, normals=NULL, texcoords = NULL, meshColor = c("vertices", "edges", "faces", "legacy")) { if (missing(meshColor) && !is.null(material$meshColor)) meshColor <- material$meshColor meshColor <- match.arg(meshColor) if (is.null(dim(vertices))) vertices <- matrix(vertices, nrow = if (homogeneous) 4 else 3) # For back-compatibility: colnames(indices) <- NULL mesh3d(vertices = vertices, triangles = indices, material = material, normals = normals, texcoords = texcoords, meshColor = meshColor) } # # R 3d object : quad mesh # qmesh3d <- function( vertices, indices, homogeneous=TRUE, material=NULL, normals=NULL, texcoords=NULL, meshColor = c("vertices", "edges", "faces", "legacy")) { if (missing(meshColor) && !is.null(material$meshColor)) meshColor <- material$meshColor meshColor <- match.arg(meshColor) if (is.null(dim(vertices))) vertices <- matrix(vertices, nrow = if (homogeneous) 4 else 3) # For back-compatibility colnames(indices) <- NULL mesh3d(vertices = vertices, quads = indices, material = material, normals = normals, texcoords = texcoords, meshColor = meshColor) } as.mesh3d <- function(x, ...) UseMethod("as.mesh3d") as.mesh3d.deldir <- function(x, col = "gray", coords = c("x", "y", "z"), smooth = TRUE, normals = NULL, texcoords = NULL, ...) { checkDeldir(error = TRUE) if (!identical(sort(coords), c("x", "y", "z"))) stop(sQuote("coords"), " should be a permutation of c('x', 'y', 'z')") if (!all(coords %in% names(x$summary))) stop("The 'deldir' object needs x, y, and z coordinates.") if (smooth && !is.null(normals)) { warning("'smooth' ignored as 'normals' was specified.") smooth <- FALSE } pointnames <- as.numeric(rownames(x$summary)) points <- matrix(NA, max(pointnames), 3) points[pointnames, ] <- as.matrix(x$summary[, coords]) points <- t(points) triangs <- do.call(rbind, deldir::triang.list(x)) if (!is.null(texcoords)) texcoords <- texcoords[triangs$ptNum, ] material <- .getMaterialArgs(...) material$color <- col result <- mesh3d(vertices = asHomogeneous2(points), triangles = triangs$ptNum, normals = normals, texcoords = texcoords, material = material) if (smooth) result <- addNormals(result) result } as.mesh3d.triSht <- as.mesh3d.tri <- function(x, z, col = "gray", coords = c("x", "y", "z"), smooth = TRUE, normals = NULL, texcoords = NULL, ...) { if (inherits(x, "tri")) triangles <- tripack::triangles else if (inherits(x, "triSht")) { triangles <- interp::triangles } if (!identical(sort(coords), c("x", "y", "z"))) stop(sQuote("coords"), " should be a permutation of c('x', 'y', 'z')") if (!is.numeric(z) || length(z) != x$n) stop("z should be a numeric vector with one entry per node of x") if (smooth && !is.null(normals)) { warning("'smooth' ignored as 'normals' was specified.") smooth <- FALSE } points <- rbind(x$x, x$y, z) rownames(points) <- c("x", "y", "z") points <- points[coords,] triangs <- t(triangles(x)[, 1:3]) if (inherits(x, "tri") && x$nc) { constraintIndex <- min(x$lc) keep <- apply(triangs, 2, function(col) any(col < constraintIndex)) triangs <- triangs[, keep] } if (!is.null(texcoords)) texcoords <- texcoords[triangs, ] material <- .getMaterialArgs(...) material$color <- col result <- mesh3d(vertices = asHomogeneous2(points), triangles = triangs, normals = normals, texcoords = texcoords, material = material) if (smooth) result <- addNormals(result) result } # NO OP (issue #454) as.mesh3d.mesh3d <- function(x, ...) x # rendering support dot3d.mesh3d <- function(x, ..., front = "points", back = "points") { if (missing(front) && !is.null(x$material$front)) front <- x$material$front if (missing(back) && !is.null(x$material$back)) back <- x$material$back shade3d.mesh3d(x, ..., front = front, back = back) } wire3d.mesh3d <- function(x, ..., front = "lines", back = "lines") { if (missing(front) && !is.null(x$material$front)) front <- x$material$front if (missing(back) && !is.null(x$material$back)) back <- x$material$back shade3d.mesh3d(x, ..., front = front, back = back) } allowedMeshColor <- function(meshColor, modes) { meshColor != "edges" || (modes[1] == modes[2] && modes[1] == "lines") } shade3d.mesh3d <- function( x, override = TRUE, meshColor = c("vertices", "edges", "faces", "legacy"), texcoords = NULL, ..., front = "filled", back = "filled") { if (missing(front) && !is.null(x$material$front)) front <- x$material$front if (missing(back) && !is.null(x$material$back)) back <- x$material$back argMaterial <- c(list(front = front, back = back), .getMaterialArgs(...)) xHasColor <- !is.null(x$material) && !is.null(x$material$color) hasMeshColor <- !missing(meshColor) if ( override ) { material <- x$material if (is.null(material)) material <- list() material[names(argMaterial)] <- argMaterial if (hasMeshColor || is.null(x$meshColor)) meshColor <- match.arg(meshColor) else meshColor <- x$meshColor if (is.null(texcoords) && !is.null(x$texcoords)) texcoords <- t(x$texcoords) } else { material <- argMaterial material[names(x$material)] <- x$material if (is.null(x$meshColor)) meshColor <- match.arg(meshColor) else meshColor <- x$meshColor if (!is.null(x$texcoords)) texcoords <- t(x$texcoords) } normals <- x$normals if (!is.null(normals)) normals <- t(normals) modes <- c(front, back) if (!allowedMeshColor(meshColor, modes)) stop("'meshColor = ", meshColor, "' not supported.") if (meshColor != "legacy") { if (is.null(material$color)) material$color <- material3d("color") if (is.null(material$alpha)) material$alpha <- material3d("alpha") } vertices <- t(asEuclidean2(x$vb)) result <- integer(0) prev <- 0 doVertices <- function(vals, inds, setPrev) { inds <- as.numeric(inds) if (length(unique(vals)) > 1) { vals <- rep_len(vals, max(inds)) vals[inds] } else vals } doLegacy <- function(vals, inds, setPrev) { inds <- as.numeric(inds) + prev if (setPrev) prev <<- prev + length(inds) if (length(unique(vals)) > 1) vals <- rep_len(vals, length(inds)) vals } doFaces <- function(vals, inds, setPrev) { if (!is.matrix(inds)) inds <- matrix(inds, nrow = 1) if (prev) { vals <- rep_len(vals, prev + ncol(inds)) vals <- vals[-seq_len(prev)] } if (setPrev) prev <<- prev + ncol(inds) vals <- rep_len(vals, ncol(inds)) rep(vals, each = nrow(inds)) } doEdges <- function(vals, inds, setPrev) { if (!is.matrix(inds)) inds <- matrix(inds, nrow = 1) inds <- inds + prev if (setPrev) prev <<- prev + length(inds) newlen <- ncol(inds) if (nrow(inds) > 1) newlen <- newlen * nrow(inds) / 2 vals <- rep_len(vals, newlen) if (nrow(inds) > 1) vals <- rep(vals, each = 2) vals } getArgs <- function(inds) { args <- c(list(x = vertices[as.numeric(inds),]), material) if (!is.null(texcoords)) args$texcoords <- texcoords[as.numeric(inds),] if (!is.null(normals)) args$normals <- normals[as.numeric(inds),] args$color <- repfn(args$color, inds, is.null(args$alpha)) args$alpha <- repfn(args$alpha, inds, TRUE) args } repfn <- switch(meshColor, vertices = doVertices, legacy = doLegacy, faces = doFaces, doLegacy) if (length(x$ip)) { args <- getArgs(x$ip) result <- c(result, points = do.call(points3d, args = args )) } if (length(x$is)) { args <- getArgs(x$is) result <- c(result, segments = do.call(segments3d, args = args )) } if (length(x$it)) { if (meshColor == "edges") { x$it <- x$it[c(1,2,2,3,3,1),] fn <- segments3d } else fn <- triangles3d args <- getArgs(x$it) result <- c(result, triangles = do.call(fn, args = args )) } if (length(x$ib)) { if (meshColor == "edges") { x$ib <- x$ib[c(1,2,2,3,3,4,4,1),] fn <- segments3d } else fn <- quads3d args <- getArgs(x$ib) result <- c(result, quads = do.call(fn, args = args )) } lowlevel(result) } # transformation support translate3d.mesh3d <- function( obj, x, y, z, ... ) { obj$vb <- t(translate3d(t(obj$vb), x, y, z)) return(obj) } rotate3d.mesh3d <- function( obj,angle,x,y,z,matrix, ... ) { obj$vb <- t(rotate3d(t(obj$vb), angle, x, y, z, matrix)) if ( !is.null(obj$normals) ) { normals <- obj$normals # 4xn matrix if ( missing(matrix) ) normals <- rotate3d(t(normals), angle, x, y, z) # nx4 else { if (nrow(matrix) == 4) matrix[4,1:3] <- 0 if (ncol(matrix) == 4) matrix[1:3,4] <- 0 normals <- rotate3d(t(normals), angle, x, y, z, t(solve(matrix))) # nx4 # Reverse the normals if the transformation # changes the orientation of the mesh if (det(matrix) < 0) normals[, 1:3] <- -normals[, 1:3] # nx4 } normals <- asEuclidean(normals) # nx3 normals <- normals/sqrt(rowSums(normals^2)) obj$normals <- rbind( t(normals), 1 ) # 4xn } return(obj) } scale3d.mesh3d <- function( obj, x, y, z, ... ) { obj$vb <- t(scale3d(t(obj$vb), x, y, z)) if ( !is.null(obj$normals) ) { obj$normals <- scale3d(t(obj$normals), 1/x, 1/y, 1/z) obj$normals <- t( obj$normals/sqrt(apply(obj$normals[,1:3]^2, 1, sum)) ) if (nrow(obj$normals) == 4) obj$normals[4,] <- 1 } return(obj) } # for debugging showNormals <- function(obj, scale = 1) { v <- obj$vb n <- obj$normals if (is.null(n)) { warning("No normals found.") return() } save <- par3d(skipRedraw = TRUE) on.exit(par3d(save)) for (i in seq_len(ncol(n))) { p0 <- v[1:3, i]/v[4, i] p1 <- p0 + n[1:3, i]*scale if (all(is.finite(c(p0, p1)))) arrow3d(p0, p1, type = "lines") } } print.mesh3d <- function(x, prefix = "", ...) { cat(prefix, " mesh3d object with ", ncol(x$vb), " vertices, ", paste(c( if (length(x$ip)) paste(length(x$ip), "points"), if (length(x$is)) paste(ncol(x$is), "segments"), if (length(x$it)) paste(ncol(x$it), "triangles"), if (length(x$ib)) paste(ncol(x$ib), "quads")), collapse = ", "), ".\n", sep = "") } match_names <- function(x, reference) { if (!is.null(x)) structure(x[names(reference)], class = class(x)) } # Compare old and new meshes all.equal.mesh3d <- function(target, current, ...) { if (inherits(current, "mesh3d")) all.equal(compare_proxy.mesh3d(target), compare_proxy.mesh3d(current), ...) else "'current' is not a mesh3d object" } rgl/R/axes.R0000644000176200001440000002150214771520323012326 0ustar liggesusers# This internal function returns a list with the following components: # xlim, ylim, zlim: the bounding box expanded so no coordinate has zero or negative extent # strut: a boolean indicating whether an expansion was done above # x, y, z: the box above expanded by a factor of expand .getRanges <- function(expand = 1.03, ranges=par3d('bbox')) { ranges <- list(xlim=ranges[1:2], ylim=ranges[3:4], zlim=ranges[5:6]) strut <- FALSE ranges <- lapply(ranges, function(r) { d <- diff(r) if (d > 0) return(r) strut <<- TRUE if (d < 0) return(c(0,1)) else if (r[1] == 0) return(c(-1, 1)) else return(r[1] + 0.4*abs(r[1])*c(-1,1)) }) ranges$strut <- strut ranges$x <- (ranges$xlim - mean(ranges$xlim))*expand + mean(ranges$xlim) ranges$y <- (ranges$ylim - mean(ranges$ylim))*expand + mean(ranges$ylim) ranges$z <- (ranges$zlim - mean(ranges$zlim))*expand + mean(ranges$zlim) ranges } axis3d <- function(edge, at = NULL, labels = TRUE, tick = TRUE, line = 0, pos = NULL, nticks = 5, ...) { save <- par3d(skipRedraw = TRUE, ignoreExtent = TRUE) on.exit(par3d(save)) ranges <- .getRanges() edge <- c(strsplit(edge, '')[[1]], '-', '-')[1:3] coord <- match(toupper(edge[1]), c('X', 'Y', 'Z')) # Put the sign in the appropriate entry of edge if (coord == 2) edge[1] <- edge[2] else if (coord == 3) edge[1:2] <- edge[2:3] range <- ranges[[coord]] if (is.null(at)) { at <- pretty(range, nticks) at <- at[at >= range[1] & at <= range[2]] } if (length(at)) { if (is.logical(labels)) { if (labels) labels <- format(at) else labels <- NA } mpos <- matrix(NA,3,length(at)) if (edge[1] == '+') mpos[1,] <- ranges$x[2] else mpos[1,] <- ranges$x[1] if (edge[2] == '+') mpos[2,] <- ranges$y[2] else mpos[2,] <- ranges$y[1] if (edge[3] == '+') mpos[3,] <- ranges$z[2] else mpos[3,] <- ranges$z[1] ticksize <- 0.05*(mpos[,1]-c(mean(ranges$x),mean(ranges$y),mean(ranges$z))) ticksize[coord] <- 0 if (!is.null(pos)) mpos <- matrix(pos,3,length(at)) mpos[coord,] <- at x <- c(mpos[1,1],mpos[1,length(at)]) y <- c(mpos[2,1],mpos[2,length(at)]) z <- c(mpos[3,1],mpos[3,length(at)]) if (tick) { x <- c(x,as.double(rbind(mpos[1,],mpos[1,]+ticksize[1]))) y <- c(y,as.double(rbind(mpos[2,],mpos[2,]+ticksize[2]))) z <- c(z,as.double(rbind(mpos[3,],mpos[3,]+ticksize[3]))) } result <- c(ticks=segments3d(x,y,z,...)) if (!all(is.na(labels))) result <- c(result, labels=text3d(mpos[1,]+3*ticksize[1], mpos[2,]+3*ticksize[2], mpos[3,]+3*ticksize[3], labels, ...)) lowlevel(result) } } axes3d <- function(edges='bbox', labels=TRUE, tick=TRUE, nticks = 5, box = FALSE, expand = 1.03, ...) { save <- par3d(skipRedraw = TRUE, ignoreExtent = TRUE) on.exit(par3d(save)) if (identical(edges, 'bbox')) { bboxargs <- names(formals(rgl.bbox)) bboxargs <- intersect(bboxargs, names(list(...))) otherargs <- setdiff(names(list(...)), bboxargs) bboxargs <- list(...)[bboxargs] otherargs <- list(...)[otherargs] result <- do.call('bbox3d', c(list(draw_front=box, expand=expand), bboxargs, do.call('.fixMaterialArgs', c(otherargs, list(Params = list(front='lines', back='lines')))))) } else { result <- numeric(0) for (e in edges) result <- c(result, axis3d(e,labels=labels,tick=tick,nticks=nticks, ...)) names(result) <- e } lowlevel(result) } box3d <- function(...) { save <- par3d(ignoreExtent = TRUE) on.exit(par3d(save)) result <- numeric(0) ranges <- .getRanges() if (ranges$strut) { par3d(ignoreExtent = FALSE) result <- c(result, strut=segments3d(rep(ranges$xlim, c(2,2)), rep(ranges$ylim, c(2,2)), rep(ranges$zlim, c(2,2)))) par3d(ignoreExtent = TRUE) } x <- c(rep(ranges$x[1],8),rep(ranges$x,4),rep(ranges$x[2],8)) y <- c(rep(ranges$y,2),rep(ranges$y,c(2,2)),rep(ranges$y,c(4,4)), rep(ranges$y,2),rep(ranges$y,c(2,2))) z <- c(rep(ranges$z,c(2,2)),rep(ranges$z,2),rep(rep(ranges$z,c(2,2)),2), rep(ranges$z,c(2,2)),rep(ranges$z,2)) lowlevel(c(result, lines=segments3d(x,y,z,...))) } # Convert edge code into values: # coord = 1:3 for coordinate # edge = 3 of "+" or "-" for other coords (ignore the one # that matches coord) # floating = TRUE if edge should move as bboxdeco moves # labels parseMargin <- function(code, floating = FALSE) { stopifnot(length(code) == 1) if (!nchar(code)) list(coord = 0, edge = c(0,0,0), floating = floating) else { default <- if (isTRUE(floating)) "+" else "-" edge <- c(strsplit(code, '')[[1]], default, default)[1:3] coord <- match(toupper(edge[1]), c('X', 'Y', 'Z')) edge <- match(edge, c("-", "+"))*2 - 3 # +/- 1 edge[is.na(edge)] <- 0 # Put the sign in the appropriate entry of edge if (coord == 2) edge[1] <- edge[2] else if (coord == 3) edge[1:2] <- edge[2:3] list(coord = coord, edge = edge, floating = floating) } } deparseMargin <- function(margin) { if (margin$coord %in% 1:3) { coord <- margin$coord edge <- margin$edge[-coord] edge <- c("-", ".", "+")[edge + 2] paste(c("x", "y", "z")[coord], edge[1], edge[2], sep = "") } else "" } mtext3d <- function(text, edge, at = NULL, line = 0, level = 0, floating = FALSE, pos = NA, ...) { save <- par3d(ignoreExtent = TRUE) on.exit(par3d(save)) bboxdeco <- ids3d("bboxdeco") if (!is.na(floating) && !nrow(bboxdeco)) { dummyBbox() bboxdeco <- ids3d("bboxdeco") } if (!nrow(bboxdeco) || (missing(floating) && !missing(pos))) floating <- NA ranges <- .getRanges() if (is.language(text)) text <- as.expression(text) newlen <- max(length(text),length(line),length(at)) text <- rep(text, length.out = newlen) line <- rep(line, length.out = newlen) if (is.na(floating)) { margin <- parseMargin(edge, floating) coord <- margin$coord if (!(coord %in% 1:3)) stop("Bad edge spec.") range <- ranges[[coord]] if (is.null(at)) at <- mean(range) at <- rep(at, length.out = newlen) if (all(is.na(pos))) { edge <- margin$edge pos <- matrix(NA,3,length(at)) if (edge[1] == +1) pos[1,] <- ranges$x[2] else pos[1,] <- ranges$x[1] if (edge[2] == +1) pos[2,] <- ranges$y[2] else pos[2,] <- ranges$y[1] if (edge[3] == +1) pos[3,] <- ranges$z[2] else pos[3,] <- ranges$z[1] } else pos <- matrix(pos,3,length(at)) pos[coord,] <- at ticksize <- 0.05*(pos[,1]-c(mean(ranges$x),mean(ranges$y),mean(ranges$z))) ticksize[coord] <- 0 text3d(pos[1,]+3*ticksize[1]*line, pos[2,]+3*ticksize[2]*line, pos[3,]+3*ticksize[3]*line, text, ...) } else { if (!missing(pos)) stop("'pos' is only used with floating = NA") if (is.null(at)) at <- NA text3d(x = cbind(at, line, level), texts = text, margin = edge, floating = floating, ...) } } title3d <- function(main = NULL, sub = NULL, xlab = NULL, ylab = NULL, zlab = NULL, line = NA, level = NA, floating = NULL, ...) { save <- par3d(skipRedraw = TRUE, ignoreExtent = TRUE) on.exit(par3d(save)) if (length(floating)) { floatingtitles <- floating floatinglabels <- floating } else { floatingtitles <- FALSE floatinglabels <- TRUE } result <- numeric(0) if (!is.null(main)) { aline <- ifelse(is.na(line), 2, line) alevel <- ifelse(is.na(level), 2, level) result <- c(result, main=mtext3d(main, 'x++', line = aline, level = alevel, floating = floatingtitles, ...)) } if (!is.null(sub)) { aline <- ifelse(is.na(line), 2, line) alevel <- ifelse(is.na(level), 2, level) result <- c(result, sub=mtext3d(sub, 'x--', line = aline, floating = floatingtitles, ...)) } if (!is.null(xlab)) { aline <- ifelse(is.na(line), 4, line) alevel <- ifelse(is.na(level), 1, level) result <- c(result, xlab=mtext3d(xlab, 'x', line = aline, level = alevel, floating = floatinglabels, ...)) } if (!is.null(ylab)) { aline <- ifelse(is.na(line), 4, line) alevel <- ifelse(is.na(level), 1, level) result <- c(result, ylab=mtext3d(ylab, 'y', line = aline, level = alevel, floating = floatinglabels, ...)) } if (!is.null(zlab)) { aline <- ifelse(is.na(line), 4, line) alevel <- ifelse(is.na(level), 1, level) result <- c(result, zlab=mtext3d(zlab, 'z', line = aline, level = alevel, floating = floatinglabels, ...)) } lowlevel(result) } rgl/R/as.mesh3d.default.R0000644000176200001440000004130714771541704014611 0ustar liggesusersas.mesh3d.default <- function(x, y = NULL, z = NULL, type = c("triangles", "quads", "segments", "points"), smooth = FALSE, tolerance = sqrt(.Machine$double.eps), notEqual = NULL, merge = TRUE, ..., triangles) { if (missing(x)) { x <- rglId(ids3d()$id) return(as.mesh3d(x, ...)) } verts <- rgl.vertex(x, y, z) if (!missing(triangles)) { warning("Argument 'triangles' is deprecated; please use 'type' instead.") if (missing(type)) { if (triangles) type <- "triangles" else type <- "quads" } } type <- match.arg(type, several.ok = TRUE) pcs <- c(triangles = 3, quads = 4, segments = 2, points = 1) nvert <- ncol(verts) okay <- FALSE for (i in seq_along(type)) { if (nvert %% pcs[type[i]] == 0) { okay <- TRUE break } } if (okay) type <- type[i] else stop("Wrong number of vertices") indices <- matrix(seq_len(nvert), nrow = pcs[type]) if (merge) { if (!is.null(notEqual)) { dim <- dim(notEqual) if (length(dim) != 2 || dim[1] != nvert || dim[2] != nvert) stop("'notEqual' should be a ", nvert, " by ", nvert, " logical matrix.") notEqual <- notEqual | t(notEqual) # Make it symmetric } else notEqual <- matrix(FALSE, nvert, nvert) o <- order(verts[1,], verts[2,], verts[3,]) i1 <- seq_len(nvert)[o] for (i in seq_len(nvert)[-1]) { if (isTRUE(all.equal(verts[,i1[i-1]], verts[,i1[i]], tolerance = tolerance)) && (!isTRUE(notEqual[i1[i-1], i1[i]]))) { indices[indices == i1[i]] <- i1[i-1] notEqual[i1[i], ] <- notEqual[i1[i-1], ] <- notEqual[i1[i], ] | notEqual[i1[i-1], ] notEqual[, i1[i]] <- notEqual[, i1[i-1]] <- notEqual[i1[i], ] | notEqual[, i1[i-1]] i1[i] <- i1[i-1] } } i1 <- sort(unique(i1)) keep <- seq_along(i1) for (i in keep) { verts[,i] <- verts[,i1[i]] indices[indices == i1[i]] <- i } } else keep <- seq_len(ncol(verts)) mesh <- mesh3d(vertices = rbind(verts[,keep, drop = FALSE], 1), points = if (type == "points") indices, triangles = if (type == "triangles") indices, quads = if (type == "quads") indices, segments = if (type == "segments") indices, material = list(...)) if (smooth && type != "points") mesh <- addNormals(mesh) mesh } as.mesh3d.rglId <- function(x, type = NA, subscene = NA, ...) { local_t <- function(x) { if (!is.null(x)) t(x) } colorByFaces <- function(mesh) { constColumns <- function(m) all(apply(m, 2, function(col) length(unique(col))) == 1) # See if we can use meshColor = "faces" if (!is.null(mesh$material) && !is.null(mesh$meshColor) && mesh$meshColor == "vertices") { cols <- mesh$material$color alpha <- mesh$material$alpha texcoords <- mesh$texcoords if (length(cols) == 1 && length(alpha) == 1 && is.null(texcoords)) { mesh$meshColor <- "faces" return(mesh) } if (length(cols) == 1) cols <- rep(cols, length.out = ncol(mesh$vb)) if (length(alpha) == 1) alpha <- rep(alpha, length.out = ncol(mesh$vb)) prev <- 0 newcols <- NULL newalpha <- NULL newtexcoords <- NULL if (!is.null(mesh$ip)) { inds <- mesh$ip newcols <- cols[inds] newalpha <- alpha[inds] } if (!is.null(mesh$is)) { inds <- as.numeric(mesh$is) cols <- matrix(cols[inds], nrow = 2) alpha <- matrix(alpha[inds], nrow = 2) if (!constColumns(cols) || !constColumns(alpha)) return(mesh) newcols <- c(newcols, cols[1,]) newalpha <- c(newalpha, alpha[1,]) } if (!is.null(mesh$it)) { inds <- as.numeric(mesh$it) cols <- matrix(cols[inds], nrow = 3) alpha <- matrix(alpha[inds], nrow = 3) if (!constColumns(cols) || !constColumns(alpha)) return(mesh) if (!is.null(texcoords)) { tex1 <- matrix(texcoords[1, inds], nrow = 3) tex2 <- matrix(texcoords[2, inds], nrow = 3) if (!constColumns(tex1) || !constColumns(tex2)) return(mesh) } newcols <- c(newcols, cols[1,]) newalpha <- c(newalpha, alpha[1,]) if (!is.null(texcoords)) newtexcoords <- cbind(newtexcoords, rbind(tex1[1,], tex2[1,])) } if (!is.null(mesh$ib)) { inds <- as.numeric(mesh$ib) cols <- matrix(cols[inds], nrow = 3) alpha <- matrix(alpha[inds], nrow = 3) tex1 <- matrix(texcoords[1, inds], nrow = 3) tex2 <- matrix(texcoords[2, inds], nrow = 3) if (!constColumns(cols) || !constColumns(alpha) || !constColumns(tex1) || !constColumns(tex2)) return(mesh) newcols <- c(newcols, cols[1,]) newalpha <- c(newalpha, alpha[1,]) newtexcoords <- cbind(newtexcoords, rbind(tex1[1,], tex2[1,])) } mesh$meshColor <- "faces" mesh$material$color <- if (length(unique(newcols)) == 1) newcols[1] else newcols mesh$material$alpha <- if (length(unique(newalpha)) == 1) newalpha[1] else newalpha mesh$texcoords <- newtexcoords } mesh } mergeMaterials <- function(oldmat, newmat, n, type) { if (length(newmat$color) == 1) newmat$color <- rep(newmat$color, length.out = n) if (length(newmat$alpha) == 1) newmat$alpha <- rep(newmat$alpha, length.out = n) # meshColor isn't a material property, but put it here # for now... newmat$meshColor <- "vertices" if (is.null(oldmat)) result <- newmat else { cols <- c(oldmat$color, newmat$color) oldmat$color <- newmat$color <- NULL alpha <- c(oldmat$alpha, newmat$alpha) oldmat$alpha <- newmat$alpha <- NULL same <- all.equal(oldmat, newmat) if (!isTRUE(same)) warning(same, "\nOnly last material used") result <- newmat result$color <- cols result$alpha <- alpha result$meshColor <- "vertices" } result } ids <- ids3d(subscene = subscene) ids <- ids[ids$id %in% x,] # Parts will be drawn in order ip, is, it, ib, # so sort that way now ordered <- c(points = 1, lines = 2, linestrip = 3, triangles = 4, planes = 5, quads = 6, surface = 7) if (!is.na(type)) ids <- ids[ids$type %in% type,] ids <- ids[order(ordered[ids$type]),] ip <- NULL is <- NULL it <- NULL vertices <- NULL normals <- NULL texcoords <- NULL material <- NULL for (i in seq_len(NROW(ids))) { id <- ids[i, "id"] verts <- rgl.attrib(id, "vertices") nvert <- NROW(verts) nvertExpanded <- getExpandedNverts(id) if (nvertExpanded) { type <- ids[i, "type"] prev <- length(vertices)/3 indices <- getIndices(id) inds <- switch(as.character(type), points = indices + prev, lines = # from segments3d matrix(indices + prev, nrow = 2), linestrip = # from lines3d rbind(indices[-nvertExpanded], indices[-1]) + prev, triangles =, planes = matrix(indices + prev, nrow = 3), quads = { nquads <- nvertExpanded/4 matrix(indices[4*rep(seq_len(nquads) - 1, each = 6) + c(1,2,3,1,3,4)] + prev, nrow = 3) }, surface = { dim <- rgl.attrib(id, "dim") ul <- rep(2:dim[1], dim[2]-1) + dim[1]*rep(0:(dim[2]-2), each=dim[1]-1) if (rgl.attrib(id, "flags")["flipped",]) rbind(indices[c(ul-1, ul-1+dim[1])] + prev, indices[c(ul, ul)] + prev , indices[c(ul-1+dim[1], ul+dim[1])] + prev) else rbind(indices[c(ul, ul)] + prev, indices[c(ul-1, ul-1+dim[1])] + prev, indices[c(ul-1+dim[1], ul+dim[1])] + prev) }, NULL) if (length(inds)) { if (type == "points") { ip <- c(ip, inds) normals <- rbind(normals, matrix(NA, ncol = 3, nrow = nvert)) } else if (type %in% c("lines", "linestrip")) { is <- cbind(is, inds) normals <- rbind(normals, matrix(NA, ncol = 3, nrow = nvert)) } else { it <- cbind(it, inds) normals <- rbind(normals, rgl.attrib(id, "normals")) } vertices <- cbind(vertices, local_t(verts)) if (rgl.attrib.count(id,"texcoords")) texcoords <- rbind(texcoords, rgl.attrib(id, "texcoords")) else texcoords <- rbind(texcoords, matrix(NA, ncol = 2, nrow = nvert)) mat <- rgl.getmaterial(nvert, id = id) material <- mergeMaterials(material, mat, nvert, type) } } } if (length(vertices)) { if (length(unique(material$color)) == 1) material$color <- material$color[1] if (length(unique(material$alpha)) == 1) material$alpha <- material$alpha[1] meshColor <- material$meshColor material$meshColor <- NULL colorByFaces(mesh3d(vertices = vertices, points = ip, segments = is, triangles = it, material = material, normals = normals, texcoords = if (any(!is.na(texcoords))) texcoords, meshColor = meshColor)) } } as.mesh3d.rglobject <- function(x, ...) { vertices <- x$vertices if (is.null(indices <- x$indices)) if (x$type == "surface") { dim <- x$dim ul <- rep(2:dim[1], dim[2]-1) + dim[1]*rep(0:(dim[2]-2), each=dim[1]-1) if (x$flipped) indices <- rbind(c(ul-1, ul-1+dim[1]), c(ul, ul), c(ul-1+dim[1], ul+dim[1])) else indices <- rbind(c(ul, ul), c(ul-1, ul-1+dim[1]), c(ul-1+dim[1], ul+dim[1])) } else indices <- seq_len(NROW(vertices)) material <- x$material if (length(indices)) switch(x$type, points = mesh3d(x = vertices, normals = x$normals, texcoords = x$texcoords, points = indices, material = x$material), linestrip = { indices <- as.numeric(rbind(indices[-length(indices)], indices[-1])) mesh3d(x = vertices, segments = indices, material = x$material) }, lines = mesh3d(x = vertices, normals = x$normals, texcoords = x$texcoords, segments = indices, material = x$material), surface =, triangles = mesh3d(x = vertices, normals = x$normals, texcoords = x$texcoords, triangles = indices, material = x$material), quads = mesh3d(x = vertices, normals = x$normals, texcoords = x$texcoords, quads = indices, material = x$material), NULL ) else NULL } as.mesh3d.rglsubscene <- function(x, rglscene, transform = diag(4), simplify = TRUE, ...) { outmeshes <- list() objects <- rglscene$objects for (i in x$objects) { m <- as.mesh3d(objects[[as.character(i)]]) if (!is.null(m)) outmeshes <- c(outmeshes, list(rotate3d(m, matrix = transform))) } for (i in seq_along(x$subscenes)) { child <- x$subscenes[[i]] outmeshes <- c(outmeshes, as.mesh3d(child, rglscene, transform %*% child$par3d$userMatrix, simplify = FALSE)) } if (simplify && length(outmeshes) == 1) outmeshes[[1]] else if (length(outmeshes)) shapelist3d(outmeshes, plot = FALSE) else NULL } as.mesh3d.rglscene <- function(x, ...) { result <- as.mesh3d(x$rootSubscene, rglscene = x, ...) } mergeVertices <- function(mesh, notEqual = NULL, attribute = "vertices", tolerance = sqrt(.Machine$double.eps)) { dropNormals <- function(mesh) { if (is.null(mesh$normals)) return(FALSE) normals <- mesh$normals v <- with(mesh, rbind(vb[1,]/vb[4,], vb[2,]/vb[4,], vb[3,]/vb[4,])) it <- mesh$it if (!is.null(it)) for (i in seq_len(ncol(it))) { normal <- xprod( v[, it[1, i]] - v[, it[3, i]], v[, it[2, i]] - v[, it[1, i]]) normal <- normal/sqrt(sum(normal^2)) for (j in 1:3) { normij <- normals[, it[j, i]] normij <- normij/sqrt(sum(normij^2)) same <- all.equal(normal, normij, tolerance = tolerance, check.attributes = FALSE) if (!isTRUE(same)) return(FALSE) } } ib <- mesh$ib if (!is.null(ib)) for (i in seq_len(ncol(ib))) { norm1 <- xprod( v[, it[1, i]] - v[, it[3, i]], v[, it[2, i]] - v[, it[1, i]]) norm1 <- norm1/sqrt(sum(norm1^2)) norm2 <- xprod( v[, it[2, i]] - v[, it[4, i]], v[, it[3, i]] - v[, it[2, i]]) norm2 <- norm1/sqrt(sum(norm2^2)) for (j in 1:4) { normij <- normals[, it[j, i]] normij <- normij/sqrt(sum(normij^2)) same1 <- all.equal(norm1, normij, tolerance = tolerance, check.attributes = FALSE) same2 <- all.equal(norm2, normij, tolerance = tolerance, check.attributes = FALSE) if (!isTRUE(same1) || !isTRUE(same2)) return(FALSE) } } TRUE } if (dropNormals(mesh)) mesh$normals <- NULL if (is.null(mesh$vb)) return(mesh) nvert <- ncol(mesh$vb) if (!is.null(notEqual)) { dim <- dim(notEqual) if (length(dim) != 2 || dim[1] != nvert || dim[2] != nvert) stop("'notEqual' should be a ", nvert, " by ", nvert, " logical matrix.") notEqual <- notEqual | t(notEqual) # Make it symmetric } else notEqual <- matrix(FALSE, nvert, nvert) attribute <- match.arg(attribute, choices = c("vertices", "colors", "normals", "texcoords"), several.ok = TRUE) verts <- matrix(numeric(), ncol = 0, nrow = nvert) if ("vertices" %in% attribute) verts <- cbind(mesh$vb[1,]/mesh$vb[4,], mesh$vb[2,]/mesh$vb[4,], mesh$vb[3,]/mesh$vb[4,]) if (!is.null(normals <- mesh$normals) && "normals" %in% attribute) if (nrow(normals) == 3) verts <- cbind(verts, t(normals)) else verts <- cbind(verts, normals[1,]/normals[4,], normals[2,]/normals[4,], normals[3,]/normals[4,]) colors <- NULL if ("colors" %in% attribute && !is.null(mesh$meshColor) && mesh$meshColor == "vertices" && !is.null(mesh$material) && !is.null(colors <- mesh$material$color)) verts <- cbind(verts, t(col2rgb(colors))) if (!is.null(texcoords <- mesh$texcoords) && "texcoords" %in% attribute) verts <- cbind(verts, t(texcoords)) o <- do.call(order, as.data.frame(verts)) indices <- c(mesh$ip, mesh$is, mesh$it, mesh$ib) i1 <- seq_len(nvert)[o] for (i in seq_len(nvert)[-1]) { if (isTRUE(all.equal(verts[i1[i-1],], verts[i1[i],], tolerance = tolerance)) && (!isTRUE(notEqual[i1[i-1], i1[i]]))) { notEqual[i1[i], ] <- notEqual[i1[i-1], ] <- notEqual[i1[i], ] | notEqual[i1[i-1], ] notEqual[, i1[i]] <- notEqual[, i1[i-1]] <- notEqual[i1[i], ] | notEqual[, i1[i-1]] i1[i] <- i1[i-1] } } indices <- i1[order(o)][indices] keep <- sort(unique(i1)) newvals <- numeric(nvert) newvals[keep] <- seq_along(keep) indices <- newvals[indices] mesh$vb <- mesh$vb[,keep] if (!is.null(normals)) mesh$normals <- normals[, keep] if (!is.null(texcoords)) mesh$texcoords <- texcoords[, keep] if (!is.null(colors)) mesh$material$color <- colors[keep] if (np <- length(mesh$ip)) mesh$ip <- indices[seq_len(np)] if (ns <- length(mesh$is)) mesh$is <- matrix(indices[seq_len(ns) + np]) if (nt <- length(mesh$it)) mesh$it <- matrix(indices[seq_len(nt) + np + ns], nrow = 3) if (nq <- length(mesh$ib)) mesh$ib <- matrix(indices[seq_len(nq) + np + ns + nt], nrow = 4) mesh } rgl/R/cylinder3d.R0000644000176200001440000001604414771520323013433 0ustar liggesusersGramSchmidt <- function(v1, v2, v3, order=1:3) { A <- rbind(v1, v2, v3) A <- A[order,] v1 <- A[1,] v2 <- A[2,] v3 <- A[3,] if (isTRUE(all.equal(as.numeric(v1), c(0,0,0)))) v1 <- xprod(v2, v3) v1 <- normalize(v1) v2 <- v2 - sum(v2*v1)*v1 if (isTRUE(all.equal(as.numeric(v2), c(0,0,0)))) v2 <- xprod(v3, v1) v2 <- normalize(v2) v3 <- v3 - sum(v3*v1)*v1 - sum(v3*v2)*v2 if (isTRUE(all.equal(as.numeric(v3), c(0,0,0)))) v3 <- xprod(v1, v2) v3 <- normalize(v3) rbind(v1, v2, v3)[order(order),] } cylinder3d <- function(center, radius = 1, twist = 0, e1 = NULL, e2 = NULL, e3 = NULL, sides = 8, section = NULL, closed = 0, rotationMinimizing = is.null(e2) && is.null(e3), debug = FALSE, keepVars = FALSE, ...) { force(rotationMinimizing) # Need this since e2 and e3 get changed later center <- as.matrix(as.data.frame(xyz.coords(center)[c("x", "y", "z")])) n <- nrow(center) inds <- seq_len(n) if (closed > 0) { ind0 <- c(n-1-closed, n-closed, inds) ind1 <- c(n-closed, inds, 1+closed) # nolint ind2 <- c(inds, 1+closed, 2+closed) } else { ind0 <- c(1, 1, inds) ind1 <- c(1, inds, n) # nolint ind2 <- c(inds, n, n) } missings <- c(e1=is.null(e1), e2=is.null(e2), e3=is.null(e3)) fixup <- function(coord) { usable <- apply(coord, 1, function(v) all(is.finite(v)) & (veclen(v) > 0)) if (!any(usable) ) stop(gettextf("No usable coordinate values in '%s'", deparse(substitute(coord))), domain = NA) firstgood <- min(which(usable)) inds <- seq_len(n) if (firstgood > 1) { coord[inds[inds < firstgood],] <- coord[rep(firstgood,firstgood-1),] usable[seq_len(firstgood)] <- TRUE } for (i in inds[-1]) inds[i] <- ifelse(usable[i], inds[i], inds[i-1]) coord[inds,] } if (!is.null(e1)) { e1 <- as.matrix(as.data.frame(xyz.coords(e1)[c("x", "y", "z")])) e1 <- e1[rep(seq_len(nrow(e1)), length.out = n),] } else e1 <- (center[ind2,] - center[ind0,])[inds,] # Fix up degenerate cases by repeating existing ones, or using arbitrary ones zeros <- rowSums(e1^2) == 0 if (all(zeros)) { e1[,1] <- 1 zeros <- FALSE } else if (any(zeros)) { e1[1,] <- e1[which(!zeros)[1],] zeros[1] <- FALSE if (any(zeros)) { zeros <- which(zeros) for (i in zeros) e1[i,] <- e1[i-1,] } } if (!is.null(e2)) { e2 <- as.matrix(as.data.frame(xyz.coords(e2)[c("x", "y", "z")])) e2 <- e2[rep(seq_len(nrow(e2)), length.out = n),] } else e2 <- (e1[ind2,] - e1[ind0,])[inds,] # Fix up degenerate e2's similarly, then force different than e1 zeros <- rowSums(e2^2) == 0 if (all(zeros)) { e2[,2] <- 1 zeros <- FALSE } else if (any(zeros)) { e2[1,] <- e2[which(!zeros)[1],] zeros[1] <- FALSE if (any(zeros)) { zeros <- which(zeros) for (i in zeros) e2[i,] <- e2[i-1,] } } parallel <- sapply(inds, function(i) all(xprod(e1[i,], e2[i,]) == 0)) if (any(parallel)) { # rotate in the xy plane e2[parallel,] <- cbind(-e2[parallel,2], e2[parallel,1], e2[parallel,3]) parallel <- sapply(inds, function(i) all(xprod(e1[i,], e2[i,]) == 0)) if (any(parallel)) { # if any are still parallel, they must be the z axis e2[parallel,1] <- 1 e2[parallel,3] <- 0 } } if (!is.null(e3)) { e3 <- as.matrix(as.data.frame(xyz.coords(e3)[c("x", "y", "z")])) e3 <- e3[rep(seq_len(nrow(e3)), length.out = n),] } else { e3 <- matrix(NA_real_, n, 3) for (i in inds) e3[i,] <- xprod(e1[i,], e2[i,]) } for (i in inds) { A <- GramSchmidt(e1[i,], e2[i,], e3[i,], order=order(missings)) e1[i,] <- A[1,] e2[i,] <- A[2,] e3[i,] <- A[3,] } e1 <- fixup(e1) e2 <- fixup(e2) e3 <- fixup(e3) if (rotationMinimizing) { # Keep e1 and the first entries in e2 and e3, # modify the rest according to Wang et al (2008). t <- e1 r <- e2 s <- e3 for (i in seq_len(n-1)) { v1 <- center[i+1,] - center[i,] c1 <- sum(v1^2) rL <- r[i,] - (2/c1)*sum(v1*r[i,])*v1 tL <- t[i,] - (2/c1)*sum(v1*t[i,])*v1 v2 <- t[i+1,] - tL c2 <- sum(v2^2) r[i+1,] <- rL - (2/c2)*sum(v2*rL)*v2 s[i+1,] <- xprod(t[i+1,], r[i+1,]) } e2 <- r e3 <- s } radius <- rep(radius, length.out = n) twist <- rep(twist, length.out = n) if (debug) { for (i in inds) { segments3d(rbind(center[i,],center[i,]+e3[i,]*radius[i]*1.5, center[i,],center[i,]+e2[i,]*radius[i]*1.5, center[i,],center[i,]+e1[i,]*radius[i]*1.5), col = rep(c("red", "green", "blue"), each=2)) text3d(center, texts=inds) } } if (closed > 0) { n <- n - closed + 1 if (isTRUE(all.equal(e1[1,], e1[n,]))) { # Need to match starting and ending e2 as # well. angle <- atan2(sum(xprod(e2[1,], e2[n,])*e1[1,]), sum(e2[1,]*e2[n,])) twist <- twist + (twist[n] - twist[1] - angle)*(seq_len(n) - 1)/(n-1) } } if (is.null(section)) { theta <- seq(0, 2*pi, length.out = sides+1)[-1] section <- cbind(cos(theta), sin(theta), 0) } else sides <- nrow(section) vertices <- matrix(0, 3, sides*n) indices <- matrix(0, 4, sides*(n-1)) if (ncol(section) == 2) section <- cbind(section, 0) for (i in seq_len(n-1)) { transform <- rbind(e3[i,], e2[i,], e1[i,]) p <- rotate3d(section, twist[i], 0,0,1) p <- radius[i] * p %*% transform p[,1] <- p[,1] + center[i,"x"] p[,2] <- p[,2] + center[i,"y"] p[,3] <- p[,3] + center[i,"z"] vertices[,(i-1)*sides+seq_len(sides)] <- t(p) for (j in seq_len(sides)) indices[, (i-1)*sides + j] <- (c(0,0,1,1) + j) %% sides + 1 + c((i-1)*sides, i*sides, i*sides, (i-1)*sides) } transform <- rbind(e3[n,], e2[n,], e1[n,]) p <- rotate3d(section, twist[n], 0,0,1) p <- radius[n] * p %*% transform p[,1] <- p[,1] + center[n,"x"] p[,2] <- p[,2] + center[n,"y"] p[,3] <- p[,3] + center[n,"z"] vertices[,(n-1)*sides+seq_len(sides)] <- t(p) # Add end cap at start if (closed < 0) { vertices <- cbind(vertices, center[1,]) triangles <- rbind(ncol(vertices), seq_len(sides), c(2:sides, 1)) } # Add end cap at end if (closed < -1) { vertices <- cbind(vertices, center[n,]) triangles <- cbind(triangles, rbind(ncol(vertices), c(2:sides, 1) + (n-1)*sides, seq_len(sides) + (n-1)*sides)) } result <- qmesh3d(vertices, indices, homogeneous=FALSE) if (closed > 0) { # Look for repeated vertices, and edit the links nv <- ncol(result$vb) for (i in seq_len(sides)) { dupe <- which(apply(result$vb[,(nv-sides+1):nv,drop=FALSE], 2, function(x) isTRUE(all.equal(x, result$vb[,i]))))+nv-sides for (j in dupe) { f <- result$ib == j result$ib[f] <- i } } } else if (closed < 0) result$it <- triangles if (keepVars) attr(result, "vars") <- environment() result$material <- .fixMaterialArgs2(...) result } rgl/R/zzz.R0000644000176200001440000001430515011677075012233 0ustar liggesusers## ## R source file ## This file is part of rgl ## ## ## ## ===[ SECTION: package entry/exit point ]=================================== ## ## ## entry-point ## ## .onLoad <- function(lib, pkg) { in_pkgload_loadall <- function() { caller <- deparse(sys.call(-4)) isNamespaceLoaded("pkgload") && any(grepl("load_all", caller)) } getDir <- function(useNULL) { if (in_pkgload_loadall()) { dir <- if (useNULL) file.path("inst", "useNULL") else "src" } else { dir <- if (useNULL) "useNULL" else "libs" if (nchar(.Platform$r_arch)) dir <- file.path(dir, .Platform$r_arch) } dir } getDynlib <- function(dir) system.file(dir, paste0("rgl", .Platform$dynlib.ext), package = pkg, lib.loc = lib, mustWork = TRUE) # OS-specific initValue <- 0 onlyNULL <- noOpenGL || rgl.useNULL() useNULL <- onlyNULL && !noOpenGL && .Platform$OS.type != "windows" dir <- getDir(useNULL) unixos <- "none" if (.Platform$OS.type == "unix") unixos <- Sys.info()["sysname"] dll <- try(dyn.load(dynlib <- getDynlib(dir))) if (inherits(dll, "try-error")) { warning(paste("\tLoading rgl's DLL failed.", if (unixos == "Darwin" && !onlyNULL) { paste("\n\tThis build of rgl depends on XQuartz, which failed to load.\n", "See the discussion in https://stackoverflow.com/a/66127391/2554330") }), call. = FALSE) if (!onlyNULL) { dir <- getDir(TRUE) warning("Trying without OpenGL...", call. = FALSE) noOpenGL <<- TRUE dll <- try(dyn.load(dynlib <- getDynlib(dir))) } if (inherits(dll, "try-error")) stop("Loading failed.") } routines <- getDLLRegisteredRoutines(dll, addNames = FALSE) ns <- asNamespace(pkg) for(i in 1:4) lapply(routines[[i]], function(sym) assign(sym$name, sym, envir = ns)) if ( !noOpenGL && .Platform$OS.type == "windows" && !onlyNULL) { frame <- getWindowsHandle("Frame") # nolint ## getWindowsHandle was numeric pre-2.6.0 if ( !is.null(frame) ) initValue <- getWindowsHandle("Console") # nolint } if (onlyNULL) { rglFonts(serif = rep("serif", 4), sans = rep("sans", 4), mono = rep("mono", 4), symbol = rep("symbol", 4)) } else { rglFonts(serif = rep(system.file("fonts", "FreeSerif.ttf", package="rgl"), 4), sans = rep(system.file("fonts", "FreeSans.ttf", package="rgl"), 4), mono = rep(system.file("fonts", "FreeMono.ttf", package="rgl"), 4), symbol = rep(system.file("fonts", "FreeSerif.ttf", package="rgl"), 4)) if (requireNamespace("extrafont", quietly = TRUE)) suppressWarnings( rglExtrafonts(sans = c("Helvetica", "Arial"), serif = c("Times", "Times New Roman"), mono = c("Courier", "Courier New"))) } register_compare_proxy() .rglEnv$subsceneList <- NULL dir <- tempfile("rgl") dir.create(dir) .rglEnv$textureDir <- normalizePath(dir) # Workaround for incompatibility with quartz device # By default only run this if we'll be using the X11 display on macOS # and we're not on R.app. options("rgl.startQuartz") can # override this. # Then we need to start quartz() before starting rgl. # See https://github.com/dmurdoch/rgl/issues/27 if (getOption("rgl.startQuartz", !onlyNULL && interactive() && unixos == "Darwin" && !(.Platform$GUI %in% c("AQUA", "RStudio"))) && exists("quartz", getNamespace("grDevices"))) { grDevices::quartz() safe.dev.off() } ret <- rgl.init(initValue, onlyNULL) if (!ret) { warning("'rgl.init' failed, will use the null device.\nSee '?rgl.useNULL' for ways to avoid this warning.", call. = FALSE) options(rgl.useNULL = TRUE) rgl.init(initValue, TRUE) } if (!rgl.useNULL()) setGraphicsDelay(unixos = unixos) # Are we running in reprex::reprex? If so, do # the knitr setup so our output appears there. if (in_reprex()) { setupKnitr(autoprint = TRUE) } } # Do we need a delay opening graphics? # Work around bug in MacOS Catalina: if base plotting happens # too quickly after first call to quartz, R crashes. # This inserts a delay after the # first call to the graphics device. The default is # no delay, unless on Catalina with no graphics device # currently open, when a 1 second delay will be introduced. # Use "RGL_SLOW_DEV = value" to change the delay from # the default to "value" seconds. setGraphicsDelay <- function(delay = Sys.getenv("RGL_SLOW_DEV", 0), unixos = "none") { if (unixos == "Darwin") { version <- try(numeric_version(Sys.info()["release"])) if (missing(delay) && !inherits(version, "try-error") && !is.na(version) && version >= "19.0.0" && dev.cur() == 1 && identical(getOption("device"), grDevices::quartz)) delay <- Sys.getenv("RGL_SLOW_DEV", 1) } delay <- suppressWarnings(as.numeric(delay)) if (is.na(delay)) delay <- 1 if (delay > 0) { olddev <- getOption("device") if (is.character(olddev)) { if (exists(olddev, globalenv(), mode = "function")) olddev <- get(olddev, envir = globalenv(), mode = "function") else if (exists(olddev, asNamespace("grDevices"), mode = "function")) olddev <- get(olddev, asNamespace("grDevices"), mode = "function") } if (is.function(olddev)) options(device = function(...) { olddev(...) Sys.sleep(delay) options(device = olddev) }) } } rgl.init <- function(initValue = 0, onlyNULL = FALSE, debug = getOption("rgl.debug", FALSE)) .Call( rgl_init, initValue, onlyNULL, environment(rgl.init), debug ) .onAttach <- function(libname, pkgname) { if (noOpenGL) packageStartupMessage( "This build of rgl does not include OpenGL functions. Use rglwidget() to display results, e.g. via options(rgl.printRglwidget = TRUE).") } ## ## exit-point ## ## .onUnload <- function(libpath) { unregisterShinyHandlers() unlink(.rglEnv$textureDir, recursive = TRUE) # shutdown .C( rgl_quit, success=FALSE ) } in_reprex <- function() !is.null(getOption("reprex.current_venue")) rgl/R/ply.R0000644000176200001440000002614715011677075012211 0ustar liggesuserswritePLY <- function(con, format=c("little_endian", "big_endian", "ascii"), pointRadius=0.005, pointShape = icosahedron3d(), lineRadius = pointRadius, lineSides = 20, pointsAsEdges = FALSE, linesAsEdges = pointsAsEdges, withColors = TRUE, withNormals = !(pointsAsEdges || linesAsEdges), ids = tagged3d(tags), tags = NULL) { writeData <- function() { cat("ply\n", file=con) fmt <- switch(format, little_endian = "binary_little_endian", big_endian = "binary_big_endian", ascii = "ascii") cat("format", fmt, "1.0\n", file=con) cat("element vertex", nrow(Vertices), "\n", file=con) cat("property float x property float y property float z\n", file=con) if (withNormals) cat("property float nx property float ny property float nz\n", file=con) if (withColors) cat("property uchar red property uchar green property uchar blue property uchar alpha\n", file=con) cat("element face", nrow(Triangles)+nrow(Quads), "\n", file=con) cat("property list uchar int vertex_indices\n", file=con) if (nrow(Edges) > 0) { cat("element edge", nrow(Edges), "\n", file=con) cat("property int vertex1 property int vertex2\n", file=con) } cat("end_header\n", file=con) if (format == "ascii") { for (i in seq_len(nrow(Vertices))) { cat(Vertices[i,], file=con) if (withColors) cat("", Colors[i,], file=con) cat("\n", file=con) } for (i in seq_len(nrow(Triangles))) cat("3", Triangles[i,], "\n", file=con) for (i in seq_len(nrow(Quads))) cat("4", Quads[i,], "\n", file=con) for (i in seq_len(nrow(Edges))) cat(Edges[i,], "\n", file=con) } else { endian <- if (format == "little_endian") "little" else "big" if (nrow(Vertices)) { if (!withColors) writeBin(as.numeric(t(Vertices)), con, size = 4, endian=endian) else { for (i in seq_len(nrow(Vertices))) { writeBin(Vertices[i,], con, size = 4, endian = endian) writeBin(Colors[i,], con, size = 1) } } } if (nrow(Triangles)) { for (i in seq_len(nrow(Triangles))) { writeBin(3L, con, size = 1) writeBin(as.integer(Triangles[i,]), con, size = 4, endian = endian) } } if (nrow(Quads)) { for (i in seq_len(nrow(Quads))) { writeBin(4L, con, size = 1) writeBin(as.integer(Quads[i,]), con, size = 4, endian = endian) } } if (nrow(Edges)) writeBin(as.integer(t(Edges)), con, size=4, endian=endian) } } Vertices <- matrix(0, 0, 3 + 3*withNormals) Colors <- matrix(0L, 0, 4) Triangles <- matrix(1L, 0, 3) Quads <- matrix(1L, 0, 4) Edges <- matrix(1L, 0, 2) getVertices <- function(id) { vertices <- rgl.attrib(id, "vertices") if (withNormals) { normals <- rgl.attrib(id, "normals") if (!nrow(normals)) normals <- 0*vertices } cbind(vertices, if (withNormals) normals) } getColors <- function(id) { vertices <- rgl.attrib(id, "vertices") if (withColors) { colors <- rgl.attrib(id, "colors") if (nrow(colors) == 1) colors <- colors[rep(1, nrow(vertices)),, drop = FALSE] colors <- round(255*colors) mode(colors) <- "integer" colors } else NULL } writeTriangles <- function(id) { vertices <- getVertices(id) colors <- getColors(id) n <- nrow(vertices) base <- nrow(Vertices) Vertices <<- rbind(Vertices, vertices) Colors <<- rbind(Colors, colors) Triangles <<- rbind(Triangles, matrix(base + getIndices(id) - 1, ncol=3, byrow=TRUE)) } writeQuads <- function(id) { vertices <- getVertices(id) colors <- getColors(id) n <- nrow(vertices) base <- nrow(Vertices) Vertices <<- rbind(Vertices, vertices) Colors <<- rbind(Colors, colors) Quads <<- rbind(Quads, matrix(base + getIndices(id) - 1, ncol=4, byrow=TRUE)) } writeSurface <- function(id) { vertices <- getVertices(id) colors <- getColors(id) dims <- rgl.attrib(id, "dim") nx <- dims[1] nz <- dims[2] base <- nrow(Vertices) Vertices <<- rbind(Vertices, vertices) Colors <<- rbind(Colors, colors) rows <- seq_len(nx) for (i in seq_len(nz)[-nz]) { indices <- getIndices(id)[(i-1)*nx + c(rows[-nx],rows[-nx], rows[-1]+nx,rows[-nx]+nx, rows[-1],rows[-1]+nx)] Triangles <<- rbind(Triangles, matrix(base + indices - 1, ncol=3)) } } writeMesh <- function(mesh, scale=1, offset=c(0,0,0)) { vertices <- asEuclidean(t(mesh$vb))*scale vertices <- vertices + rep(offset, each=nrow(vertices)) if (withColors) { colors <- mesh$material$col if (!length(colors)) colors <- material3d("color") colors <- rep(colors, length.out = nrow(vertices)) colors <- t(col2rgb(colors, alpha=TRUE)) Colors <<- rbind(Colors, colors) } if (withNormals) normals <- asEuclidean(t(mesh$normals)) base <- nrow(Vertices) Vertices <<- rbind(Vertices, cbind(vertices, if (withNormals) normals)) nt <- length(mesh$it)/3 nq <- length(mesh$ib)/4 if (nt) Triangles <<- rbind(Triangles, t(mesh$it) - 1 + base) if (nq) Quads <<- rbind(Quads, t(mesh$ib) - 1 + base) } writeSpheres <- function(id) { vertices <- expandVertices(id) n <- nrow(vertices) colors <- expandColors(id) if (nrow(colors) == 1) colors <- colors[rep(1, n),, drop = FALSE] radii <- expandAttrib(id, "radii") radii <- rep(radii, length.out=n) x <- subdivision3d(icosahedron3d(),3) r <- sqrt(x$vb[1,]^2 + x$vb[2,]^2 + x$vb[3,]^2) x$vb[4,] <- r x$normals <- x$vb for (i in seq_len(n)) { col <- colors[i,] x$material$col <- rgb(col[1], col[2], col[3], col[4], maxColorValue = 255) writeMesh(x, radii[i], vertices[i,]) } } avgScale <- function() { bbox <- par3d("bbox") ranges <- c(bbox[2]-bbox[1], bbox[4]-bbox[3], bbox[6]-bbox[5]) if (prod(ranges) == 0) 1 else exp(mean(log(ranges))) } writePoints <- function(id) { vertices <- getVertices(id) colors <- getColors(id) n <- nrow(vertices) inds <- getIndices(id) if (pointsAsEdges) { base <- nrow(Vertices) Vertices <<- rbind(Vertices, vertices) Colors <<- rbind(Colors, colors) Edges <<- rbind(Edges, base + cbind(inds, inds) - 1 ) } else { radius <- pointRadius*avgScale() if (withNormals && is.null(pointShape$normals)) pointShape <- addNormals(pointShape) for (i in inds) { if (withColors) { col <- vertices[i,4:7] pointShape$material$col <- rgb(col[1], col[2], col[3], col[4], maxColorValue = 255) } writeMesh(pointShape, radius, vertices[i,1:3]) } } } writeSegments <- function(id) { vertices <- getVertices(id) colors <- getColors(id) inds <- getIndices(id) n <- length(inds)/2 if (linesAsEdges) { base <- nrow(Vertices) Vertices <<- rbind(Vertices, vertices) Colors <<- rbind(Colors, colors) Edges <<- rbind(Edges, base + matrix(inds, ncol = 2, byrow = TRUE) - 1) } else { radius <- lineRadius*avgScale() for (i in seq_len(n)) { cyl <- cylinder3d( vertices[inds[(2*i-1):(2*i)],1:3], radius = radius, sides = lineSides, closed = -2 ) if (withColors) { col1 <- colors[inds[2*i-1],] col1 <- rgb(col1[1], col1[2], col1[3], col1[4], maxColorValue = 255) col2 <- colors[inds[2*i],] col2 <- rgb(col2[1], col2[2], col2[3], col2[4], maxColorValue = 255) cyl$material$col <- c(rep(col1, lineSides), rep(col2, lineSides), col1, col2) } if (withNormals) cyl <- addNormals(cyl) writeMesh(cyl) } } } writeLines <- function(id) { vertices <- getVertices(id) colors <- getColors(id) if (linesAsEdges) { inds <- getIndices(id) n <- length(inds) base <- nrow(Vertices) Vertices <<- rbind(Vertices, vertices) Colors <<- rbind(Colors, colors) Edges <<- rbind(Edges, base + cbind(inds[-n], inds[-1]) - 1) } else { n <- nrow(vertices) - 1 radius <- lineRadius*avgScale() colors <- vertices[, 4:7, drop = FALSE] for (i in seq_len(n)) { cyl <- cylinder3d( vertices[inds[i:(i+1)],1:3], radius = radius, sides = lineSides, closed = -2 ) if (withColors) { col1 <- colors[inds[i],] col1 <- rgb(col1[1], col1[2], col1[3], col1[4], maxColorValue = 255) col2 <- colors[inds[i+1],] col2 <- rgb(col2[1], col2[2], col2[3], col2[4], maxColorValue = 255) cyl$material$col <- c(rep(col1, lineSides), rep(col2, lineSides), col1, col2) } if (withNormals) cyl <- addNormals(cyl) writeMesh(cyl) } } } knowntypes <- c("triangles", "quads", "surface", "spheres", "linestrip", "lines", "planes", "points") # Execution starts here! format <- match.arg(format) if (is.character(con)) { con <- file(con, if (format=="ascii") "w" else "wb") on.exit(close(con)) } filename <- summary(con)$description if (NROW(bbox <- ids3d("bboxdeco")) && (is.null(ids) || bbox$id %in% ids)) { ids <- setdiff(ids, bbox$id) save <- par3d(skipRedraw = TRUE) bbox <- convertBBox(bbox$id) on.exit({ pop3d(id=bbox); par3d(save) }, add=TRUE) # nolint dobbox <- TRUE } else dobbox <- FALSE if (is.null(ids)) { ids <- ids3d() types <- as.character(ids$type) ids <- ids$id } else { if (dobbox) ids <- c(ids, bbox) allids <- ids3d() ind <- match(ids, allids$id) keep <- !is.na(ind) if (any(!keep)) warning(gettextf("Object(s) with id %s not found", paste(ids[!keep], collapse=" ")), domain = NA) ids <- ids[keep] types <- allids$type[ind[keep]] } unknowntypes <- setdiff(types, knowntypes) if (length(unknowntypes)) warning(gettextf("Object type(s) %s not handled", paste("'", unknowntypes, "'", sep="", collapse=", ")), domain = NA) keep <- types %in% knowntypes ids <- ids[keep] types <- types[keep] for (i in seq_along(ids)) switch(types[i], planes =, triangles = writeTriangles(ids[i]), quads = writeQuads(ids[i]), surface = writeSurface(ids[i]), spheres = writeSpheres(ids[i]), points = writePoints(ids[i]), lines = writeSegments(ids[i]), linestrip = writeLines(ids[i]) ) writeData() invisible(filename) } rgl/R/pkgdown.R0000644000176200001440000000606114771520323013042 0ustar liggesusers# Functions related to working in pkgdown pkgdown_rdname <- function() getOption("downlit.rdname", "") in_pkgdown <- function() requireNamespace("pkgdown", quietly = TRUE) && pkgdown::in_pkgdown() in_pkgdown_example <- function() nchar(pkgdown_rdname()) && requireNamespace("downlit", quietly = TRUE) && requireNamespace("pkgdown", quietly = TRUE) fns <- local({ plotnum <- 0 pkgdown_print.rglId <- function(x, visible = TRUE) { if (inherits(x, "rglHighlevel")) plotnum <<- plotnum + 1 if (visible) { scene <- scene3d() structure(list(plotnum = plotnum, scene = scene), class = c("rglRecordedplot", "otherRecordedplot")) } else invisible() } pkgdown_print.rglOpen3d <- function(x, visible = TRUE) { plotnum <<- plotnum + 1 invisible(x) } list(pkgdown_print.rglId = pkgdown_print.rglId, pkgdown_print.rglOpen3d = pkgdown_print.rglOpen3d) }) pkgdown_print.rglId <- fns[["pkgdown_print.rglId"]] pkgdown_print.rglOpen3d <- fns[["pkgdown_print.rglOpen3d"]] rm(fns) globalVariables("fig.asp") pkgdown_dims <- function() { settings <- pkgdown::fig_settings() rgl <- settings$other.parameters$rgl settings[names(rgl)] <- rgl numparms <- length(intersect(names(rgl), c("fig.width", "fig.height", "fig.asp"))) if (numparms > 0 && numparms < 3) { settings <- within(settings, { if (is.null(rgl$fig.height)) fig.height <- fig.width * fig.asp if (is.null(rgl$fig.width)) fig.width <- fig.height / fig.asp }) } width <- with(settings, dpi*fig.width) height <- with(settings, dpi*fig.height) list(width = width, height = height) } replay_html.rglRecordedplot <- local({ rdname <- "" function(x, ...) { if (pkgdown_rdname() != rdname) rdname <<- pkgdown_rdname() settings <- pkgdown_dims() rendered <- htmltools::renderTags(rglwidget(x$scene, width = settings$width, height = settings$height)) structure(rendered$html, dependencies = rendered$dependencies) } }) pkgdown_info <- local({ info <- NULL function() { if (!is.null(info)) return(info) path <- "." repeat { if (file.exists(file.path(path, "DESCRIPTION"))) { info <<- pkgdown::as_pkgdown(path) return(info) } newpath <- file.path(path, "..") if (normalizePath(newpath) == normalizePath(path)) return(list()) path <- newpath } } }) register_pkgdown_methods <- local({ registered <- FALSE function(register = in_pkgdown_example()) { if (!registered && register) { registerS3method("replay_html", "rglRecordedplot", replay_html.rglRecordedplot, envir = asNamespace("downlit")) registerS3method("is_low_change", "rglRecordedplot", is_low_change.rglRecordedplot, envir = asNamespace("downlit")) registerS3method("pkgdown_print", "rglId", pkgdown_print.rglId, envir = asNamespace("pkgdown")) registerS3method("pkgdown_print", "rglOpen3d", pkgdown_print.rglOpen3d, envir = asNamespace("pkgdown")) registered <<- TRUE } } }) rgl/R/saveURI.R0000644000176200001440000000063014555455305012712 0ustar liggesuserssaveURI <- function(uri, con) { if (!grepl("^data:", uri)) stop("Does not appear to be a data URI") header <- sub(",.*", "", uri) type <- sub(";.*", "", sub("^data:", "", header)) encoding <- sub("^.*;", "", header) if (encoding != "base64") stop("Not encoded in base64") payload <- sub(paste0(header, ","), "", uri, fixed = TRUE) writeBin(base64_dec(payload), con) invisible(type) } rgl/R/subdivision.mesh3d.R0000644000176200001440000002605414771520323015115 0ustar liggesusers# # subdivision.mesh3d # # an *efficient* algorithm for subdivision of mesh3d objects # using addition operations and homogenous coordinates # by Daniel Adler # # edgemap <- function( size ) { data<-vector( mode="numeric", length=( size*(size+1) )/2 ) data[] <- -1 return(data) } edgeindex <- function( from, to, size, row=min(from,to), col=max(from,to) ) return( row*size - ( row*(row+1) )/2 - (size-col) ) getTags <- function(mesh) { len <- length(mesh$ip) + length(mesh$is)/2 + length(mesh$it)/3 + length(mesh$ib)/4 tags <- mesh$tags if (is.null(tags)) tags <- seq_len(len) else if (length(tags) != len) stop("mesh$tags length must equal total number of points, segments, triangles and quads") tags } divide.mesh3d <- function(mesh, vb = mesh$vb, ib = mesh$ib, it = mesh$it, is = mesh$is, keepTags = FALSE) { nv <- dim(vb)[2] inds <- seq_len(nv) np <- length(mesh$ip) ns <- length(is)/2 nt <- length(it)/3 nq <- length(ib)/4 newnp <- np newns <- 2*ns newnt <- 4*nt newnq <- 4*nq meshColor <- mesh$meshColor if (is.null(meshColor)) meshColor <- "vertices" hasColors <- !is.null(mesh$material) && length(mesh$material$color) > 1 && !(meshColor %in% c("edges", "legacy")) if (hasColors && meshColor == "vertices") { color <- rep_len(mesh$material$color, nv) rgb <- col2rgb(color) interpRGB <- TRUE } else interpRGB <- FALSE hasAlpha <- !is.null(mesh$material) && length(mesh$material$alpha) > 1 && !(meshColor %in% c("edges", "legacy")) if (hasAlpha && meshColor == "vertices") { alpha <- rep_len(mesh$material$alpha, nv) interpAlpha <- TRUE } else interpAlpha <- FALSE oldtags <- getTags(mesh) newtags <- integer(newnp + newns + newnt + newnq) nvmax <- nv + nq + ( nv*(nv+1) )/2 outvb <- matrix(data=0,nrow=4,ncol=nvmax) # copy old points outvb[,seq_len(nv)] <- vb vcnt <- nv em <- edgemap( nv ) if (interpRGB) outrgb <- cbind(rgb, matrix(0, nrow = 3, ncol = nvmax - nv)) if (interpAlpha) outalpha <- c(alpha, rep(0, nvmax - nv)) if (!is.null(mesh$normals)) { if (NROW(mesh$normals) == 4) mesh$normals <- t(asEuclidean(t(mesh$normals))) newnormals <- matrix(data=0,nrow=3,ncol=nvmax) newnormals[,inds] <- mesh$normals } else newnormals <- NULL if (!is.null(mesh$texcoords)) { newtexcoords <- matrix(data=0,nrow=2,ncol=nvmax) newtexcoords[,inds] <- mesh$texcoords } else newtexcoords <- NULL if (!is.null(newnormals) || !is.null(newtexcoords)) { newcount <- rep(0, nvmax) newcount[inds] <- 1 } result <- structure(list(material=mesh$material), class="mesh3d") if (nq) { outib <- matrix(nrow=4,ncol=newnq) vcnt <- vcnt + nq for (i in 1:nq ) { isurf <- nv + i if (interpRGB) outrgb[, isurf] <- rowSums(rgb[, ib[, i]])/4 if (interpAlpha) outalpha[isurf] <- sum(alpha(ib[,i]))/4 for (j in 1:4 ) { iprev <- ib[((j+2)%%4) + 1, i] ithis <- ib[j,i] inext <- ib[ (j%%4) + 1, i] # get or alloc edge-point this->next mindex <- edgeindex(ithis, inext, nv) enext <- em[mindex] if (enext == -1) { vcnt <- vcnt + 1 enext <- vcnt em[mindex] <- enext if (interpRGB) outrgb[, enext] <- (rgb[, inext] + rgb[, ithis])/2 if (interpAlpha) outalpha[enext] <- (alpha[inext] + alpha[ithis])/2 } # get or alloc edge-point prev->this mindex <- edgeindex(iprev, ithis, nv) eprev <- em[mindex] if (eprev == -1) { vcnt <- vcnt + 1 eprev <- vcnt em[mindex] <- eprev if (interpRGB) outrgb[, eprev] <- (rgb[, iprev] + rgb[, ithis])/2 if (interpAlpha) outalpha[eprev] <- (alpha[iprev] + alpha[ithis])/2 } # gen grid outib[, (i-1)*4+j ] <- c( ithis, enext, isurf, eprev ) newtags[newnp + newns + newnt + (i-1)*4+j] <- np + ns + nt + i # calculate surface point outvb[,isurf] <- outvb[,isurf] + vb[,ithis] # calculate edge point outvb[,enext] <- outvb[,enext] + vb[,ithis] outvb[,eprev] <- outvb[,eprev] + vb[,ithis] if (!is.null(newnormals)) { thisnorm <- mesh$normals[,ithis] newnormals[,isurf] <- newnormals[,isurf] + thisnorm newnormals[,enext] <- newnormals[,enext] + thisnorm newnormals[,eprev] <- newnormals[,eprev] + thisnorm } if (!is.null(newtexcoords)) { thistexcoord <- mesh$texcoords[,ithis] newtexcoords[,isurf] <- newtexcoords[,isurf] + thistexcoord newtexcoords[,enext] <- newtexcoords[,enext] + thistexcoord newtexcoords[,eprev] <- newtexcoords[,eprev] + thistexcoord } if (!is.null(newnormals) || !is.null(newtexcoords)) { newcount[isurf] <- newcount[isurf] + 1 newcount[enext] <- newcount[enext] + 1 newcount[eprev] <- newcount[eprev] + 1 } } } result$ib <- outib } if (nt) { outit <- matrix(nrow=3,ncol=newnt) for (i in 1:nt ) { for (j in 1:3 ) { iprev <- it[((j+1)%%3) + 1, i] ithis <- it[j,i] inext <- it[ (j%%3) + 1, i] # get or alloc edge-point this->next mindex <- edgeindex(ithis, inext, nv) enext <- em[mindex] if (enext == -1) { vcnt <- vcnt + 1 enext <- vcnt em[mindex] <- enext if (interpRGB) outrgb[, enext] <- (rgb[, inext] + rgb[, ithis])/2 if (interpAlpha) outalpha[enext] <- (alpha[inext] + alpha[ithis])/2 } # get or alloc edge-point prev->this mindex <- edgeindex(iprev, ithis, nv) eprev <- em[mindex] if (eprev == -1) { vcnt <- vcnt + 1 eprev <- vcnt em[mindex] <- eprev if (interpRGB) outrgb[, eprev] <- (rgb[, iprev] + rgb[, ithis])/2 if (interpAlpha) outalpha[eprev] <- (alpha[iprev] + alpha[ithis])/2 } # gen grid outit[, (i-1)*4+j ] <- c( ithis, enext, eprev ) newtags[newnp + newns + (i-1)*4+j ] <- np + ns + i # calculate edge point outvb[,enext] <- outvb[,enext] + vb[,ithis] outvb[,eprev] <- outvb[,eprev] + vb[,ithis] if (!is.null(newnormals)) { thisnorm <- mesh$normals[,ithis] newnormals[,enext] <- newnormals[,enext] + thisnorm newnormals[,eprev] <- newnormals[,eprev] + thisnorm } if (!is.null(newtexcoords)) { thistexcoord <- mesh$texcoords[,ithis] newtexcoords[,enext] <- newtexcoords[,enext] + thistexcoord newtexcoords[,eprev] <- newtexcoords[,eprev] + thistexcoord } if (!is.null(newnormals) || !is.null(newtexcoords)) { newcount[enext] <- newcount[enext] + 1 newcount[eprev] <- newcount[eprev] + 1 } } # Now central triangle outit[, (i-1)*4+4 ] <- c( em[edgeindex(ithis, inext, nv)], em[edgeindex(inext, iprev, nv)], em[edgeindex(iprev, ithis, nv)] ) newtags[newnp + newns + (i-1)*4+4] <- np + ns + i } result$it <- outit } if (ns) { outis <- matrix(nrow=2,ncol=newns) for (i in 1:ns ) { for (j in 1:2 ) { ithis <- is[j,i] inext <- is[ (j%%2) + 1, i] # get or alloc edge-point this->next mindex <- edgeindex(ithis, inext, nv) enext <- em[mindex] if (enext == -1) { vcnt <- vcnt + 1 enext <- vcnt em[mindex] <- enext if (interpRGB) outrgb[, enext] <- (rgb[, inext] + rgb[, ithis])/2 if (interpAlpha) outalpha[enext] <- (alpha[inext] + alpha[ithis])/2 } # gen grid outis[, (i-1)*2+j ] <- c( ithis, enext) newtags[newnp + (i-1)*2+j ] <- np + i # calculate edge point outvb[,enext] <- outvb[,enext] + vb[,ithis] if (!is.null(newnormals)) { thisnorm <- mesh$normals[,ithis] newnormals[,enext] <- newnormals[,enext] + thisnorm } if (!is.null(newtexcoords)) { thistexcoord <- mesh$texcoords[,ithis] newtexcoords[,enext] <- newtexcoords[,enext] + thistexcoord } if (!is.null(newnormals) || !is.null(newtexcoords)) { newcount[enext] <- newcount[enext] + 1 } } } result$is <- outis } if (np) { result$ip <- mesh$ip newtags[seq_len(np)] <- seq_len(np) } if (!is.null(newnormals) || !is.null(newtexcoords)) newcount <- newcount[seq_len(vcnt)] if (!is.null(newnormals)) newnormals <- newnormals[, seq_len(vcnt)]/rep(newcount, each=3) if (!is.null(newtexcoords)) newtexcoords <- newtexcoords[, seq_len(vcnt)]/rep(newcount, each=2) result$vb <- outvb[,seq_len(vcnt)] result$normals <- newnormals result$texcoords <- newtexcoords result$meshColor <- mesh$meshColor result$material <- mesh$material if (interpRGB) result$material$color <- rgb(t(outrgb[, seq_len(vcnt)]), maxColorValue = 255) else if (hasColors && meshColor == "faces") { colors <- rep_len(mesh$material$color, np + ns + nt + nq) result$material$color <- colors[newtags] } if (interpAlpha) result$material$alpha <- alpha[seq_len(vcnt)] else if (hasAlpha && meshColor == "faces") { alpha <- rep_len(mesh$material$alpha, np + ns + nt + nq) result$material$alpha <- alpha[newtags] } if (keepTags) result$tags <- oldtags[newtags] return( result ) } normalize.mesh3d <- function(mesh) { mesh$vb[1,] <- mesh$vb[1,]/mesh$vb[4,] mesh$vb[2,] <- mesh$vb[2,]/mesh$vb[4,] mesh$vb[3,] <- mesh$vb[3,]/mesh$vb[4,] mesh$vb[4,] <- 1 return(mesh) } deform.mesh3d <- function( mesh, vb = mesh$vb, ib = mesh$ib, it = mesh$it, is = mesh$is) { nv <- dim(vb)[2] nq <- if (is.null(ib)) 0 else dim(ib)[2] nt <- if (is.null(it)) 0 else dim(it)[2] ns <- if (is.null(is)) 0 else dim(is)[2] out <- matrix(0, nrow=4, ncol=nv ) if (nq) { for ( i in 1:nq ) { for (j in 1:4 ) { iprev <- ib[((j+2)%%4) + 1, i] ithis <- ib[j,i] inext <- ib[ (j%%4) + 1, i] out[ ,ithis ] <- out[ , ithis ] + vb[,iprev] + vb[,ithis] + vb[,inext] } } mesh$vb <- out } if (nt) { for ( i in 1:nt ) { for (j in 1:3 ) { iprev <- it[((j+1)%%3) + 1, i] ithis <- it[j,i] inext <- it[ (j%%3) + 1, i] out[ ,ithis ] <- out[ , ithis ] + vb[,iprev] + vb[,ithis] + vb[,inext] } } mesh$vb <- out } if (ns) { for ( i in 1:ns ) { for (j in 1:2 ) { ithis <- is[j,i] inext <- is[ (j%%2) + 1, i] out[ ,ithis ] <- out[ , ithis ] + vb[,ithis] + vb[,inext] } } mesh$vb <- out } return(mesh) } subdivision3d.mesh3d <- function(x, depth = 1, normalize = FALSE, deform = TRUE, keepTags = FALSE, ...) { mesh <- x if (depth) { mesh <- divide.mesh3d(mesh, keepTags = TRUE) if (normalize) mesh <- normalize.mesh3d(mesh) if (deform) mesh <- deform.mesh3d(mesh) mesh<-subdivision3d.mesh3d(mesh, depth-1, normalize, deform, keepTags = TRUE) } if (!keepTags) mesh$tags <- NULL return(mesh) } rgl/R/selectpoints3d.R0000644000176200001440000000361514771520323014336 0ustar liggesusersselectpoints3d <- function(objects = ids3d()$id, value = TRUE, closest = TRUE, multiple = FALSE, ...) { if (value) result <- cbind(x = numeric(0), y = numeric(0), z = numeric(0)) else result <- cbind(id = integer(0), index = integer(0)) first <- TRUE prevdist <- dist <- Inf while (first || is.function(multiple) || multiple) { f <- select3d(...) if (is.null(f)) break e <- environment(f) prev <- nrow(result) # Number to keep from previous selection for (id in objects) { verts <- expandVertices(id) hits <- f(verts) if (any(hits)) dist <- 0 else if (closest && dist > 0 && nrow(verts)) { wincoords <- rgl.user2window(verts, projection = e$proj) wz <- wincoords[,3] keep <- (0 <= wz) & (wz <= 1) wincoords <- wincoords[keep,,drop=FALSE] if (!nrow(wincoords)) next wx <- wincoords[,1] xdist <- ifelse(wx < e$llx, (wx-e$llx)^2, ifelse(wx < e$urx, 0, (wx-e$urx)^2)) wy <- wincoords[,2] ydist <- ifelse(wy < e$lly, (wy-e$lly)^2, ifelse(wy < e$ury, 0, (wy-e$ury)^2)) dists <- xdist + ydist hits <- (dists < dist) & (dists == min(dists)) dist <- min(c(dist, dists)) } if (!any(hits)) next if (prev && prevdist > dist) { result <- result[FALSE, , drop = FALSE] prev <- 0 } if (value) result <- rbind(result, verts[hits,]) else { indices <- getIndices(id)[which(hits)] result <- rbind(result, cbind(id, indices)) } if (is.function(multiple) && nrow(result) > prev && !multiple(result[(prev+1):nrow(result),,drop=FALSE])) break prevdist <- dist prev <- nrow(result) first <- FALSE } if (value) result <- unique(result) } result } rgl/R/addNormals.mesh3d.R0000644000176200001440000000326214771520323014637 0ustar liggesusersaddNormals <- function(x, ...) UseMethod("addNormals") addNormals.mesh3d <- function(x, angleWeighted = TRUE, ...) { v <- x$vb # Make sure v is homogeneous with unit w if (nrow(v) == 3) v <- rbind(v, 1) else v <- t( t(v)/v[4,] ) v <- v[1:3,] normals <- v*0 if (is.na(angleWeighted)) { reproduceBug <- TRUE angleWeighted <- FALSE } else reproduceBug <- FALSE dopolys <- function(it, normals) { n <- nrow(it) for (i in seq_len(ncol(it))) { normal <- xprod( v[, it[1, i]] - v[, it[3, i]], v[, it[2, i]] - v[, it[1, i]]) if (reproduceBug) normal <- normalize(normal) if (!any(is.na(normal))) { if (angleWeighted) normal <- normalize(normal) for (j in seq_len(n)) { if (angleWeighted) { jm1 <- (j + n - 2) %% n + 1 jp1 <- j %% n + 1 weight <- angle(v[, it[jm1, i]] - v[, it[j, i]], v[, it[jp1, i]] - v[, it[j, i]]) } else weight <- 1 normals[, it[j,i]] <- normals[, it[j,i]] + normal*weight } } } normals } if (length(x$it)) normals <- dopolys(x$it, normals) if (length(x$ib)) normals <- dopolys(x$ib, normals) normals <- rbind(apply(normals, 2, function(n) n/veclen(n)), 1) x$normals <- normals x } veclen <- function(v) sqrt(sum(v^2)) normalize <- function(v) v/veclen(v) xprod <- function(v, w) c( v[2]*w[3] - v[3]*w[2], v[3]*w[1] - v[1]*w[3], v[1]*w[2] - v[2]*w[1] ) angle <- function(a,b) { dot <- sum(a*b) acos(pmin(1, pmax(-1, dot/veclen(a)/veclen(b)))) } rgl/R/ashape3d.R0000644000176200001440000000725214555455305013073 0ustar liggesusers# Support for objects from alphashape3d package persp3d.ashape3d <- function(x, ..., add = FALSE) { plot3d(as.mesh3d(x, ...), add = add, ...) } plot3d.ashape3d <- function(x, ...) persp3d(x, ...) reOrient <- function(vertices) { warned <- FALSE # Count how many other triangles touch each edge of this one, in order 2-3, 1-3, 1-2: edgeCounts <- function(index) { triangle <- vertices[,index] result <- integer(3) for (i in 1:3) { result[i] <- sum(apply(vertices, 2, function(col) all(triangle[-i] %in% col))) } result - 1 } polys <- ncol(vertices) verts <- nrow(vertices) fixed <- 0L for (i in seq_len(polys - 1)) { fixed <- max(i, fixed) # Get all polygons touching polygon i thistriangle <- vertices[,i] if (any(is.na(thistriangle))) next touches <- which(matrix(vertices %in% thistriangle,nrow=3), arr.ind = TRUE) if (!nrow(touches)) next counts <- table(touches[,2L]) # Get col number of all polygons sharing an edge with i shared <- as.numeric(names(counts)[counts > 1L]) shared <- shared[shared != i] if (!length(shared)) next otherverts <- vertices[, shared, drop=FALSE] # FIXME: otherverts may include multiple triangles sharing the # same edge, because ashape3d sometimes embeds # tetrahedrons (or larger polyhedra?) in the surfaces # it produces. It doesn't appear to be safe to just # delete these if (!warned && length(shared) > 1L && any( edgeCounts(i) > 1)) { warning("Surface may not be simple; smoothing may not be possible.") warned <- TRUE } shared <- shared[shared > fixed] if (!length(shared)) next otherverts <- vertices[, shared, drop=FALSE] for (m in seq_len(ncol(otherverts))) { # m is intersection number # For each vertex in i, see if it is in the shared one, and # if they have opposite orientations as we need for (j in seq_len(verts)) { # Where is j in the others? jother <- which(otherverts[,m] == vertices[j,i]) if (!length(jother)) next k <- j %% verts + 1L # k follows j kother <- jother %% verts + 1L # kother is entry following jother if (vertices[k, i] == otherverts[kother, m]) { otherverts[, m] <- rev(otherverts[, m]) break } } } # Now move all of shared to the front unshared <- (fixed+1L):max(shared) unshared <- unshared[!(unshared %in% shared)] if (length(unshared)) vertices[, (fixed+length(shared)+1L):max(shared)] <- vertices[,unshared] vertices[, fixed + seq_along(shared)] <- otherverts fixed <- fixed + length(shared) } vertices } as.mesh3d.ashape3d <- function(x, alpha = x$alpha[1], tri_to_keep = 2L, col = "gray", smooth = FALSE, normals = NULL, texcoords = NULL, ...) { whichAlpha <- which(alpha == x$alpha)[1] if (!length(whichAlpha)) stop("'alpha = ", alpha, "' not found in ", deparse(substitute(x))) triangles <- x$triang keep <- triangles[,8 + whichAlpha] %in% tri_to_keep triangs <- t(triangles[keep, 1:3]) points <- t(x$x) if (!is.null(texcoords)) texcoords <- texcoords[triangs, ] material <- .getMaterialArgs(...) material$color <- col result <- tmesh3d(points, triangs, homogeneous = FALSE, normals = normals, texcoords = texcoords, material = material) if (smooth) { if (is.null(normals)) { result$it <- reOrient(result$it) result <- addNormals(result) } else warning("smoothing ignored when 'normals' specified") } result } rgl/R/subscenes.R0000644000176200001440000002226314771520323013365 0ustar liggesuserscurrentSubscene3d <- function(dev = cur3d()) { .C(rgl_getsubsceneid, id = 1L, dev = as.integer(dev))$id } subsceneInfo <- function(id = NA, embeddings, recursive = FALSE) { if (is.na(id)) id <- currentSubscene3d() else if (is.character(id) && id == "root") id <- .C(rgl_getsubsceneid, id = 0L, dev = as.integer(cur3d()))$id if (!id) stop("No subscene info available.") id <- as.integer(id) result <- list(id = id) parent <- .C(rgl_getsubsceneparent, id = id)$id if (is.na(parent)) stop(gettextf("Subscene %s not found", id), domain = NA) if (!parent) parent <- NULL result[["parent"]] <- parent n <- .C(rgl_getsubscenechildcount, id = id, n = integer(1))$n if (n) { children <- .C(rgl_getsubscenechildren, id = id, children=integer(n))$children if (recursive) { childlist <- list() for (i in seq_len(n)) childlist[[i]] <- subsceneInfo(id = children[i], recursive = TRUE) result[["children"]] <- childlist } else result[["children"]] <- children } embeddingNames <- c("inherit", "modify", "replace") if (!missing(embeddings)) { embeddings <- pmatch(embeddings, embeddingNames, duplicates.ok = TRUE) if (any(is.na(embeddings)) || length(embeddings) != 4) stop(gettextf("Four embeddings must be specified; names chosen from %s", paste(dQuote(embeddingNames), collapse=", ")), domain = NA) if (embeddings[4] == "modify") stop("The mouseMode embedding cannot be 'modify'") .C(rgl_setEmbeddings, id = id, embeddings = as.integer(embeddings)) } embeddings <- .C(rgl_getEmbeddings, id = id, embeddings = integer(4))$embeddings embeddings <- embeddingNames[embeddings] names(embeddings) <- c("viewport", "projection", "model", "mouse") result[["embeddings"]] <- embeddings result } newSubscene3d <- function(viewport = "replace", projection = "replace", model = "replace", mouseMode = "inherit", parent = currentSubscene3d(), copyLights = TRUE, copyShapes = FALSE, copyBBoxDeco = copyShapes, copyBackground = FALSE, newviewport, ignoreExtent) { embedding <- c("inherit", "modify", "replace") viewport <- pmatch(viewport, embedding) projection <- pmatch(projection, embedding) model <- pmatch(model, embedding) mouseMode <- pmatch(mouseMode, embedding) if (missing(ignoreExtent)) ignoreExtent <- model == 3 stopifnot(length(viewport) == 1L, length(projection) == 1L, length(model) == 1L, length(mouseMode) ==1L, mouseMode != 2L, !is.na(viewport), !is.na(projection), !is.na(model)) embedding <- c(viewport, projection, model, mouseMode) id <- .C(rgl_newsubscene, id = integer(1), parent = as.integer(parent), embedding = as.integer(embedding), as.integer(ignoreExtent))$id if (id) { if (copyLights || copyShapes || copyBBoxDeco || copyBackground) { useSubscene3d(parent) ids <- ids3d(type = c("lights", "shapes", "bboxdeco", "background")[c(copyLights, copyShapes, copyBBoxDeco, copyBackground)])$id if (length(ids)) addToSubscene3d(ids, subscene = id) } useSubscene3d(id) if (!missing(newviewport)) { embedding <- subsceneInfo(id)$embeddings if (embedding[1] > 1) par3d(viewport = as.integer(newviewport)) } } else stop("Subscene creation failed") lowlevel(id) } useSubscene3d <- function(subscene) { result <- .C(rgl_setsubscene, id=as.integer(subscene))$id if (!result) stop(gettextf("Subscene %d not found.", subscene), domain = NA) invisible(result) } addToSubscene3d <- function(ids = tagged3d(tags), tags, subscene = currentSubscene3d()) { ids <- as.integer(ids) dups <- intersect(ids, ids3d("all", subscene)$id) if (length(dups)) stop(gettextf("Cannot add %s, already present", paste(dups, collapse = ", ")), domain = NA) result <- .C(rgl_addtosubscene, success = as.integer(subscene), n = as.integer(length(ids)), ids = ids)$success if (!result) stop(gettextf("Failed to add objects to subscene %s", subscene), domain = NA) lowlevel(subscene) } delFromSubscene3d <- function(ids = tagged3d(tags), tags, subscene = currentSubscene3d()) { result <- .C(rgl_delfromsubscene, success = as.integer(subscene), n = as.integer(length(ids)), ids = as.integer(ids))$success if (!result) stop(gettextf("Failed to delete objects from subscene %s", subscene), domain = NA) lowlevel(subscene) } # This destroys any objects that are in the scene but # not in either the protect vector or visible in a subscene gc3d <- function(protect=NULL) { protect <- as.integer(protect) invisible( .C(rgl_gc, n = length(protect), protect)$n ) } subsceneList <- function(value, window = cur3d()) { alllists <- .rglEnv$subsceneLists # This cleans up lists for closed windows: alllists <- alllists[names(alllists) %in% rgl.dev.list()] if (!missing(value)) { if (is.null(alllists)) alllists <- list() alllists[[as.character(window)]] <- value assign("subsceneLists", alllists, envir = .rglEnv) } if (is.null(alllists)) return(NULL) else return(alllists[[as.character(window)]]) } next3d <- function(current = NA, clear = TRUE, reuse = TRUE) { .check3d() if (is.na(current)) current <- currentSubscene3d() subscenes <- subsceneList() while (!is.null(subscenes) && !(current %in% subscenes)) subscenes <- attr(subscenes, "prev") if (is.null(subscenes)) subscenes <- current this <- which(current == subscenes) if (reuse && !nrow(ids3d(subscene = current))) { # do nothing } else if (this == length(subscenes)) this <- 1 else this <- this + 1 repeat{ current <- subscenes[this] result <- try(useSubscene3d(current)) if (inherits(result, "try-error")) { subsceneList(subscenes <- subscenes[-this]) if (length(subscenes) == 0) stop("'subsceneList()' contained no valid subscenes") if (this > length(subscenes)) this <- 1 } else break } if (clear) clear3d(subscene = current) } clearSubsceneList <- function(delete = currentSubscene3d() %in% subsceneList(), window = cur3d()) { if (!missing(window)) set3d(window) thelist <- subsceneList() if (delete && length(thelist)) { parent <- subsceneInfo(thelist[1])$parent if (is.null(parent)) parent <- rootSubscene() pop3d(type="subscene", id=thelist) useSubscene3d(parent) gc3d() } subsceneList(attr(thelist, "prev")) invisible(currentSubscene3d()) } mfrow3d <- function(nr, nc, byrow = TRUE, parent = NA, sharedMouse = FALSE, ...) { stopifnot(nr >= 1, nc >= 1) .check3d() if (missing(parent)) clearSubsceneList() if (is.na(parent)) parent <- currentSubscene3d() useSubscene3d(parent) result <- integer(nr*nc) parentvp <- par3d("viewport") if (byrow) for (i in seq_len(nr)) for (j in seq_len(nc)) { newvp <- c(parentvp[1] + (j - 1)*parentvp[3]/nc, parentvp[2] + (nr - i)*parentvp[4]/nr, parentvp[3]/nc, parentvp[4]/nr) result[(i-1)*nc + j] <- newSubscene3d(newviewport = newvp, parent = parent, ...) } else for (j in seq_len(nc)) for (i in seq_len(nr)) { newvp <- c(parentvp[1] + (j - 1)*parentvp[3]/nc, parentvp[2] + (nr - i)*parentvp[4]/nr, parentvp[3]/nc, parentvp[4]/nr) result[(j-1)*nr + i] <- newSubscene3d(newviewport = newvp, parent = parent, ...) } if (sharedMouse) for (sub in result) par3d(listeners = result, subscene = sub) useSubscene3d(result[1]) attr(result, "prev") <- subsceneList() subsceneList(result) invisible(result) } layout3d <- function(mat, widths = rep.int(1, ncol(mat)), heights = rep.int(1, nrow(mat)), parent = NA, sharedMouse = FALSE, ...) { storage.mode(mat) <- "integer" mat <- as.matrix(mat) num.figures <- max(mat) if (!all(seq_len(num.figures) %in% as.integer(mat))) stop(gettextf("Layout matrix must contain at least one reference\nto each of the values {1 ... %d}\n", num.figures), domain = NA) .check3d() if (missing(parent)) clearSubsceneList() if (is.na(parent)) parent <- currentSubscene3d() useSubscene3d(parent) parentvp <- par3d("viewport") widths <- parentvp["width"]*widths/sum(widths) heights <- parentvp["height"]*heights/sum(heights) xs <- c(0, cumsum(widths)) ys <- rev(c(0, cumsum(rev(heights))))[-1] result <- integer(num.figures) for (i in seq_len(num.figures)) { rows <- range(row(mat)[mat == i]) cols <- range(col(mat)[mat == i]) newvp <- c(xs[cols[1]], ys[rows[2]], sum(widths[cols[1]:cols[2]]), sum(heights[rows[1]:rows[2]])) result[i] <- newSubscene3d(newviewport = newvp, parent = parent, ...) } if (sharedMouse) for (sub in result) par3d(listeners = result, subscene = sub) useSubscene3d(result[1]) attr(result, "prev") <- subsceneList() subsceneList(result) invisible(result) } rgl/R/arc3d.R0000644000176200001440000000541714771520323012371 0ustar liggesusersarc3d <- function(from, to, center, radius, n, circle = 50, base = 0, plot = TRUE, ...) { fixarg <- function(arg) { if (is.matrix(arg)) arg[, 1:3, drop = FALSE] else matrix(arg, 1, 3) } normalize <- function(v) v / veclen(v) getrow <- function(arg, i) { arg[1 + (i - 1) %% nrow(arg),] } from <- fixarg(from) to <- fixarg(to) center <- fixarg(center) m <- max(nrow(from), nrow(to), nrow(center), length(base)) base <- rep_len(base, m) result <- matrix(NA_real_, nrow = 1, ncol = 3) for (j in seq_len(m)) { from1 <- getrow(from, j) to1 <- getrow(to, j) center1 <- getrow(center, j) # The "arc" might be a straight line if (isTRUE(all.equal(from1, center1)) || isTRUE(all.equal(to1, center1)) || isTRUE(all.equal(normalize(from1 - center1), normalize(to1 - center1)))) { result <- rbind(result, from1, to1) } else { base1 <- base[j] logr1 <- log(veclen(from1 - center1)) logr2 <- log(veclen(to1 - center1)) A <- normalize(from1 - center1) B <- normalize(to1 - center1) steps <- if (base1 <= 0) 4*abs(base1) + 1 else 4*base1 - 1 for (k in seq_len(steps)) { if (k %% 2) { A1 <- A * (-1)^(k %/% 2) B1 <- B * (-1)^(k %/% 2 + (base1 > 0)) } else { A1 <- B * (-1)^(k %/% 2 + (base1 <= 0)) B1 <- A * (-1)^(k %/% 2) } theta <- acos(sum(A1*B1)) if (isTRUE(all.equal(theta, pi))) warning("Arc ", j, " points are opposite each other! Arc is not well defined.") if (missing(n)) n1 <- ceiling(circle*theta/(2*pi)) else n1 <- n if (missing(radius)) { pretheta <- (k %/% 2)*pi - (k %% 2 == 0)*theta if (k == 1) totaltheta <- (steps %/% 2)*pi - (steps %% 2 == 0)*theta + theta p1 <- pretheta/totaltheta p2 <- (pretheta + theta)/totaltheta radius1 <- exp(seq(from = (1 - p1)*logr1 + p1*logr2, to = (1 - p2)*logr1 + p2*logr2, length.out = n1 + 1)) } else radius1 <- rep_len(radius, n1 + 1) arc <- matrix(NA_real_, nrow = n1 + 1, ncol = 3) p <- seq(0, 1, length.out = n1 + 1) arc[1,] <- center1 + radius1[1]*A1 arc[n1 + 1,] <- center1 + radius1[n1 + 1]*B1 AB <- veclen(A1 - B1) for (i in seq_len(n1)[-1]) { ptheta <- p[i]*theta phi <- pi/2 + (0.5 - p[i])*theta q <- (sin(ptheta) / sin(phi))/AB D <- (1-q)*A1 + q*B1 arc[i,] <- center1 + radius1[i] * normalize(D) } if (k == 1) result <- rbind(result, arc) else result <- rbind(result[-nrow(result), ,drop = FALSE], arc) } } result <- rbind(result, result[1,]) } if (plot) lines3d(result[c(-1, -nrow(result)), , drop = FALSE], ...) else result[c(-1, -nrow(result)), , drop = FALSE] } rgl/R/getscene.R0000644000176200001440000003617215011677075013201 0ustar liggesusersscene3d <- function(minimal = TRUE) { saveSubscene <- currentSubscene3d() on.exit(useSubscene3d(saveSubscene)) defaultmaterial <- material3d() matdiff <- function(mat) { for (m in names(mat)) { if (identical(mat[[m]], defaultmaterial[[m]])) mat[[m]] <- NULL } mat } getObject <- function(id, type) { result <- list(id=id, type=type) if (!(type %in% c("light", "clipplanes"))) { mat <- rgl.getmaterial(id=id) lit <- mat$lit result$material <- matdiff(mat) } else lit <- FALSE attribs <- c("vertices", "colors", "texcoords", "dim", "texts", "cex", "adj", "radii", "ids", "usermatrix", "types", "offsets", "centers", "family", "font", "pos", "axes", "indices", "normals", "shapenum") for (a in attribs) if (rgl.attrib.count(id, a)) result[[a]] <- rgl.attrib(id, a) flags <- rgl.attrib(id, "flags") if (length(flags)) { if ("ignoreExtent" %in% rownames(flags)) result$ignoreExtent <- flags["ignoreExtent", 1] if ("fixedSize" %in% rownames(flags)) result$fixedSize <- flags["fixedSize", 1] if ("rotating" %in% rownames(flags)) result$rotating <- flags["rotating", 1] if ("fastTransparency" %in% rownames(flags)) result$fastTransparency <- flags["fastTransparency", 1] if ("flipped" %in% rownames(flags)) result$flipped <- flags["flipped", 1] } if (!is.null(result$ids)) { objlist <- vector("list", nrow(result$ids)) for (i in seq_len(nrow(result$ids))) objlist[[i]] <- getObject(result$ids[i,1], result$types[i,1]) result$objects <- objlist } if (type == "background") { flags <- rgl.attrib(id, "flags") result$sphere <- flags["sphere", 1] result$fogtype <- if (flags["linear_fog", 1]) "linear" else if (flags["exp_fog", 1]) "exp" else if (flags["exp2_fog", 1]) "exp2" else "none" result$fogscale <- as.numeric(rgl.attrib(id, "fogscale")) } else if (type == "bboxdeco") { flags <- rgl.attrib(id, "flags") result$draw_front <- flags["draw_front", 1] } else if (type == "light") { flags <- rgl.attrib(id, "flags") result$viewpoint <- flags["viewpoint", 1] result$finite <- flags["finite", 1] } class(result) <- c(paste0("rgl", type), "rglobject") result } getSubscene <- function(id) { useSubscene3d(id) result <- list(id = id, type = "subscene", par3d = par3d()) result$embeddings <- subsceneInfo()$embeddings objs <- ids3d(c("background", "bboxdeco", "shapes", "lights")) result$objects <- objs$id if (nrow(obj <- ids3d("subscene", subscene = id))) { subscenes <- vector("list", nrow(obj)) ids <- obj$id for (i in seq_len(nrow(obj))) subscenes[[i]] <- getSubscene(ids[i]) result$subscenes <- subscenes } class(result) <- c("rglsubscene", "rglobject") result } result <- list() result$material <- defaultmaterial result$rootSubscene <- getSubscene(rootSubscene()) objs <- ids3d(c("shapes", "lights", "background", "bboxdeco"), subscene=0) objlist <- vector("list", nrow(objs)) ids <- objs$id types <- as.character(objs$type) for (i in seq_len(nrow(objs))) { objlist[[i]] <- getObject(ids[i], types[i]) names(objlist)[i] <- as.character(ids[i]) } result$objects <- objlist # If there are user callbacks for the mouse, they'll # be recorded in rgl.callback.env devname <- paste0("dev", cur3d()) callbacks <- rgl.callback.env[[devname]] if (!is.null(callbacks)) { for (name in names(callbacks)) { subscene <- sub("^sub", "", name) sub <- findSubscene(result$rootSubscene, subscene) if (!is.null(sub)) { sub$callbacks <- callbacks[[name]] result$rootSubscene <- replaceSubscene(result$rootSubscene, subscene, sub) } bboxid <- sub("^bbox", "", name) bbox <- result$objects[[bboxid]] if (!is.null(bbox)) { bbox$callbacks <- callbacks[[name]] result$objects[[bboxid]] <- bbox } } result$javascript <- callbacks$javascript } class(result) <- "rglscene" result } print.rglscene <- function(x, ...) { cat(gettext("RGL scene containing:\n")) if (!is.null(x$par3d)) cat(gettext(" par3d:\tscene information\n")) if (!is.null(x$material)) cat(gettext(" material:\tdefault material properties\n")) if (!is.null(x$objects)) { cat(gettextf(" objects:\tlist of %d object(s):\n", length(x$objects))) cat(" \t", sapply(x$objects, function(obj) obj$type), "\n") } if (!is.null(x$root)) cat(gettext(" root:\ta root subscene\n")) invisible(x) } summary.rglscene <- function(object, ...) { result <- list() nobjs <- length(object$objects) if (nobjs) result$objects <- data.frame(type=sapply(object$objects, function(obj) obj$type)) if (!is.null(object$rootSubscene)) result$subscenes <- summary(object$rootSubscene) result } summary.rglsubscene <- function(object, ...) { result <- data.frame(id = object$id, parent = NA, objects = 0) result$objects <- list(object$objects) if (length(object$subscenes)) { children <- do.call(rbind, lapply(object$subscenes, summary)) children[is.na(children$parent),"parent"] <- object$id result <- rbind(result, children) } result } print.rglobject <- function(x, ...) { cat(gettextf("RGL object of type %s containing components\n", x$type)) cat(" ") cat(names(x), sep=", ") cat("\n") } print.rglsubscene <- function(x, ...) { cat(gettext("RGL subscene containing components\n")) cat(" ") cat(names(x), sep=", ") cat("\n") } plot3d.rglscene <- function(x, add=FALSE, open3dParams = getr3dDefaults(), ...) { root <- x$rootSubscene if (is.null(root)) root <- x # Should work with pre-subscene objects if (!add) { args <- list(...) params <- open3dParams params[names(args)] <- args if (!is.null(x$material)) { if (is.null(params$material)) params$material <- list() params$material[names(x$material)] <- x$material } if (!is.null(root$bg)) { if (is.null(params$bg)) params$bg <- list() params$bg[names(params$material)] <- params$material params$bg[names(x$bg$material)] <- x$bg$material x$bg$material <- x$bg$id <- x$bg$type <- NULL params$bg[names(x$bg)] <- x$bg } if (!is.null(root$par3d)) { ind <- !(names(root$par3d) %in% rgl.par3d.readonly) params[names(root$par3d)[ind]] <- root$par3d[ind] } open3d(params = params) # Some older scenes might not have a light in them, so only clear if one is there for (i in seq_along(x$objects)) { obj <- x$objects[[i]] if (obj$type == "light") { clear3d("lights") break } } } save <- par3d(skipRedraw = TRUE) on.exit(par3d(save)) if (is.null(x$rootSubscene)) { results <- NULL for (i in seq_along(x$objects)) { obj <- x$objects[[i]] results <- c(results, plot3d(obj)) } if (!is.null(obj <- x$bbox)) plot3d(obj) } else results <- plot3d(root, x$objects, root = TRUE, ...) highlevel(results) } plot3d.rglsubscene <- function(x, objects, root = TRUE, ...) { if (root) { if (!is.null(x$embeddings)) { info <- subsceneInfo(embeddings = x$embeddings) subscene <- info$id } else subscene <- currentSubscene3d() if (!is.null(x$par3d$viewport)) par3d(viewport = x$par3d$viewport) } else subscene <- newSubscene3d(viewport = x$embeddings["viewport"], projection = x$embeddings["projection"], model = x$embeddings["model"], newviewport = x$par3d$viewport, copyLights = FALSE) if (!is.null(scale <- x$par3d$scale)) par3d(scale = scale) if (!is.null(userMatrix <- x$par3d$userMatrix)) par3d(userMatrix = userMatrix) listeners <- list(x$par3d$listeners) # list contains old ids names(listeners) <- subscene # names are new ids results <- subscene names(results) <- paste0("subscene", as.character(x$id)) objs <- x$objects for (id in as.character(objs)) { obj <- objects[[id]] if (is.null(obj$newid)) results <- c(results, objects[[id]]$newid <- plot3d(obj, ...)) else addToSubscene3d(obj$newid) } for (i in seq_along(x$subscenes)) { useSubscene3d(subscene) res <- plot3d(x$subscenes[[i]], objects, root=FALSE, ...) results <- c(results, res$results) listeners <- c(listeners, res$listeners) objects <- res$objects } if (root) { # Translate all the listener values dotranslations <- function(id) { info <- subsceneInfo(id = id) oldlisteners <- listeners[[as.character(id)]] par3d(listeners = results[paste0("subscene", oldlisteners)], subscene = id) for (child in info$children) dotranslations(child) } dotranslations(subscene) useSubscene3d(subscene) return(results) } else return(list(results=results, objects=objects, listeners=listeners)) } plot3d.rglobject <- function(x, ...) { type <- x$type fn <- switch(type, points = points3d, lines = segments3d, linestrip = lines3d, triangles = triangles3d, quads = quads3d, text = texts3d, spheres = spheres3d, abclines = abclines3d, planes = planes3d, surface = surface3d, sprites = sprites3d, light = light3d, clipplanes = clipplanes3d, NULL) if (is.null(fn)) { warning(gettextf("Object type '%s' not handled.", type), domain = NA) return() } if (!is.null(x$ignoreExtent)) { save <- par3d(ignoreExtent = x$ignoreExtent) on.exit(par3d(save)) } args <- list() args$x <- x$vertices args$normals <- x$normals args$texcoords <- x$texcoords args$texts <- x$texts args$cex <- x$cex args$adj <- x$adj args$radius <- x$radii args$d <- x$offsets args$indices <- x$indices switch(type, abclines = { odd <- seq_len(nrow(args$x)) %% 2 == 1 ends <- args$x[odd,,drop=FALSE] args$a <- args$x[!odd,,drop=FALSE] - ends args$x <- ends }, planes =, clipplanes = { args$a <- args$normals args$x <- NULL args$normals <- NULL }, surface = { dim <- x$dim args$y <- matrix(args$x[,2], dim[1], dim[2]) args$z <- matrix(args$x[,3], dim[1], dim[2]) args$x <- matrix(args$x[,1], dim[1], dim[2]) if (!is.null(args$normals)) { args$normal_x <- matrix(args$normals[,1], dim[1], dim[2]) args$normal_y <- matrix(args$normals[,2], dim[1], dim[2]) args$normal_z <- matrix(args$normals[,3], dim[1], dim[2]) args$normals <- NULL } if (!is.null(args$texcoords)) { args$texture_s <- matrix(args$texcoords[,1], dim[1], dim[2]) args$texture_t <- matrix(args$texcoords[,2], dim[1], dim[2]) args$texcoords <- NULL } }, sprites = { save2 <- par3d(skipRedraw = TRUE) on.exit(par3d(save2), add=TRUE) if (!is.null(x$objects)) { ids <- numeric(length(x$objects)) for (i in seq_along(ids)) ids[i] <- plot3d(x$objects[[i]]) args$shapes <- ids } args$userMatrix <- x$usermatrix }) mat <- x$material if (is.null(mat)) mat <- list() if (!is.null(col <- x$colors)) { mat$color <- rgb(col[,1], col[,2], col[,3]) mat$alpha <- col[,4] } if (type == "light") { if (!x$finite) { args$x <- NULL vx <- x$vertices[1] vy <- x$vertices[2] vz <- x$vertices[3] args$phi <- atan2(vy, sqrt(vx^2 + vz^2))*180/pi args$theta <- atan2(vx, vz)*180/pi } args$viewpoint.rel <- x$viewpoint args$ambient <- mat$color[1] args$diffuse <- mat$color[2] args$specular <- mat$color[3] } else args <- c(args, mat) do.call(fn, args) } plot3d.rglbboxdeco <- function(x, ...) { args <- list() v <- x$vertices t <- x$texts m <- x$axes$mode if (m[1] == "none") args$xat <- numeric() else if (m[1] != "pretty") { ind <- is.na(v[,2]) & is.na(v[,3]) if (any(ind)) { args$xat <- v[ind,1] if (!is.null(t)) args$xlab <- t[ind] else args$xlab <- signif(args$xat, 4) } } if (m[2] == "none") args$yat <- numeric() else if (m[2] != "pretty") { ind <- is.na(v[,1]) & is.na(v[,3]) if (any(ind)) { args$yat <- v[ind,2] if (!is.null(t)) args$ylab <- t[ind] else args$ylab <- signif(args$yat, 4) } } if (m[3] == "none") args$zat <- numeric() else if (m[3] != "pretty") { ind <- is.na(v[,1]) & is.na(v[,2]) if (any(ind)) { args$zat <- v[ind,3] if (!is.null(t)) args$zlab <- t[ind] else args$zlab <- signif(args$zat, 4) } } args$draw_front <- x$draw_front args <- c(args, x$material) do.call("bbox3d", args) } plot3d.rglbackground <- function(x, ...) { mat <- x$material if (is.null(mat)) mat <- list() if (!is.null(col <- x$colors)) { mat$color <- rgb(col[,1], col[,2], col[,3]) mat$alpha <- col[,4] } args <- c(list(sphere = x$sphere, fogtype = x$fogtype), mat) do.call("bg3d", args) } plot3d.rglWebGL <- function(x, ...) { plot3d(attr(x, "origScene"), ...) } compare_proxy.rglscene <- function(x, path = "x") { list(object = old_compare_proxy.rglscene(x), path = paste0("compare_proxy(", path, ")")) } old_compare_proxy.rglscene <- function(x) { doSubscene <- function(obj) { if (!is.null(obj$par3d)) { rect <- obj$par3d$windowRect if (!is.null(rect)) { rect <- rect - rect[1:2] obj$par3d$windowRect <- rect } } ids <<- c(ids, obj$id) if (is.list(obj$subscenes)) obj$subscenes <- lapply(obj$subscenes, doSubscene) } ids <- c(x$rootSubscene$id, sapply(x$objects, function(obj) obj$id)) x$rootSubscene <- doSubscene(x$rootSubscene) ids <- unique(ids) newids <- ids - min(ids) + 1 names(newids) <- ids newid <- function(id) { result <- if (is.null(id)) NULL else unname(newids[as.character(id)]) if (any(is.na(result))) stop("id gives NA") result } newidc <- function(id) as.character(newid(id)) fixvec <- function(vec) { if (is.list(vec)) lapply(vec, fixobj) else newid(vec) } fixobj <- function(obj) { obj$id <- newid(obj$id) obj$objects <- fixvec(obj$objects) obj$ids <- fixvec(obj$ids) if (!is.null(obj$par3d)) { obj$par3d$listeners <- newid(obj$par3d$listeners) obj$par3d$fontname <- NULL obj$par3d$maxClipPlanes <- NULL obj$par3d$glVersion <- NULL } if (!is.null(obj$material)) { obj$material$texture <- NULL } obj$subscenes <- fixvec(obj$subscenes) obj } x$rootSubscene <- fixobj(x$rootSubscene) x$objects <- lapply(x$objects, fixobj) names(x$objects) <- newidc(names(x$objects)) class(x) <- NULL x } # Compare old and new scenes all.equal.rglscene <- function(target, current, ...) { if (inherits(current, "rglscene")) { target <- compare_proxy.rglscene(target) current <- compare_proxy.rglscene(current) result <- all.equal(target, current, ...) if (!isTRUE(result) && isNamespaceLoaded("waldo")) result <- waldo::compare(target, current) result } else "'current' is not an rglscene object" } as.rglscene <- function(x, ...) { UseMethod("as.rglscene") } rgl/R/plotmath3d.R0000644000176200001440000000404115011677075013451 0ustar liggesusersplotmath3d <- function(x, y = NULL, z = NULL, text, cex = par("cex"), adj = 0.5, pos = NULL, offset = 0.5, fixedSize = TRUE, startsize = 480, initCex = 5, margin = "", floating = FALSE, tag = "", ...) { xyz <- xyz.coords(x, y, z, recycle = TRUE) n <- length(xyz$x) if (is.vector(text)) text <- rep(text, length.out = n) cex <- rep(cex, length.out = n) if (!is.null(pos)) pos <- rep_len(pos, n) adj <- c(adj, 0.5, 0.5, 0.5)[1:3] save3d <- par3d(skipRedraw = TRUE) save <- options(device.ask.default = FALSE) on.exit({options(save); par3d(save3d)}) # nolint result <- integer(n) for (i in seq_len(n)) { # Open the device twice. The first one is to measure the text... f <- tempfile(fileext = ".png") png(f, bg = "transparent", width = startsize, height = startsize) par(mar = c(0, 0, 0, 0), xaxs = "i", xaxt = "n", yaxs = "i", yaxt = "n", usr = c(0, 1, 0, 1)) plot.new() if (is.vector(text)) thistext <- text[i] else thistext <- text w <- strwidth(thistext, cex = initCex, ...) w1 <- strwidth("m", cex = initCex, ...) h <- strheight(thistext, cex = initCex, ...) safe.dev.off() # Now make a smaller bitmap expand <- 1.5 size <- round(expand*startsize*max(c(w, h))) png(f, bg = "transparent", width = size, height = size) par(mar = c(0, 0, 0, 0), xaxs = "i", xaxt = "n", yaxs = "i", yaxt = "n", usr = c(0, 1, 0, 1)) plot.new() text(0.5, 0.5, thistext, adj = c(0.5,0.5), cex = initCex, ...) safe.dev.off() # The 0.4 tries to match the text3d offset offseti <- 0.4*offset*h/w posi <- if (is.null(pos)) NULL else pos[i] result[i] <- with(xyz, sprites3d(x[i], y[i], z[i], texture = f, textype = "rgba", col = "white", lit = FALSE, radius = cex[i]*size/initCex/20, adj = adj, pos = posi, offset = offseti, fixedSize = fixedSize, margin = margin, floating = floating, tag = tag)) } lowlevel(result) } rgl/R/setUserShaders.R0000644000176200001440000000704014771520323014333 0ustar liggesuserssetUserShaders <- function(ids, vertexShader = NULL, fragmentShader = NULL, attributes = NULL, uniforms = NULL, textures = NULL, scene = scene3d(minimal), minimal = TRUE) { stopifnot(inherits(scene, "rglscene")) for (i in ids) { id <- as.character(i) obj <- scene$objects[[id]] if (!is.null(vertexShader)) obj$userVertexShader <- paste(vertexShader, collapse = "\n") if (!is.null(fragmentShader)) obj$userFragmentShader <- paste(fragmentShader, collapse = "\n") obj$userAttributes <- attributes obj$userUniforms <- uniforms obj$userTextures <- textures alldata <- c(obj$userAttributes, obj$userUniforms, obj$userTextures) allnames <- names(alldata) if (length(allnames) != length(alldata) || any(nchar(allnames) == 0) || any(duplicated(allnames))) stop("attributes, uniforms and textures should be named") scene$objects[[id]] <- obj } scene } getShaders <- function(id, scene = scene3d(minimal), minimal = TRUE) { obj <- scene$objects[[as.character(id)]] vertexShader <- obj$userVertexShader fragmentShader <- obj$userFragmentShader if (is.null(vertexShader) || is.null(fragmentShader)) { if (!requireNamespace("V8")) stop("This function requires the V8 package.") scene <- convertScene(scene) obj <- scene$objects[[as.character(id)]] ctx <- V8::v8() ctx$source(system.file("htmlwidgets/lib/rglClass/rglClass.src.js", package="rgl")) ctx$source(system.file("htmlwidgets/lib/rglClass/utils.src.js", package="rgl")) ctx$source(system.file("htmlwidgets/lib/rglClass/shaders.src.js", package="rgl")) pointSize <- obj$material$size if (is.null(pointSize)) pointSize <- scene$material$size antialias <- obj$material$point_antialias if (is.null(antialias)) antialias <- scene$material$point_antialias textype <- obj$material$textype if (is.null(textype)) textype <- scene$material$textype texmode <- obj$material$texmode if (is.null(texmode)) texmode <- scene$material$texmode texenvmap <- obj$material$texenvmap if (is.null(texenvmap)) texenvmap <- scene$material$texenvmap nclipplanes <- 0 nlights <- 0 for (i in seq_along(scene$objects)) { nclipplanes <- nclipplanes + (scene$objects[[i]]$type == "clipplanes") nlights <- nlights + (scene$objects[[i]]$type == "light") } if (is.null(vertexShader)) vertexShader <- readLines(system.file("htmlwidgets/lib/rglClass/shaders/rgl_vertex.glsl", package = "rgl")) if (is.null(fragmentShader)) fragmentShader <- readLines(system.file("htmlwidgets/lib/rglClass/shaders/rgl_fragment.glsl", package = "rgl")) } defines <- ctx$eval(subst( 'rglwidgetClass.getDefines(%id%, "%type%", %flags%, %nclipplanes%, %nlights%, %normals%, %pointSize%, "%textype%", "%texmode%", %texenvmap%, %antialias%)', id = id, type = obj$type, flags = obj$flags, nclipplanes = nclipplanes, nlights = nlights, normals = if (is.null(obj$normals)) "undefined" else 1, pointSize = pointSize, textype = textype, texmode = texmode, texenvmap = tolower(texenvmap), antialias = tolower(antialias) )) structure(list(vertexShader = vertexShader, fragmentShader = fragmentShader, defines = defines), class = "rglshaders") } print.rglshaders <- function(x, ...) { cat(x$defines, sep = "\n") cat(x$vertexShader, sep = "\n") cat("\n") cat(x$defines, sep = "\n" ) cat(x$fragmentShader, sep = "\n") invisible(x) }rgl/R/conversions.R0000644000176200001440000000107314265301464013740 0ustar liggesusersrglToLattice <- function(rotm = par3d("userMatrix")) { if (!requireNamespace("orientlib", quietly = TRUE)) stop("The orientlib package is needed for this function") e <- -orientlib::eulerzyx(orientlib::rotmatrix(rotm[1:3, 1:3]))@x*180/pi list(z = e[1], y = e[2], x = e[3]) } rglToBase <- function(rotm = par3d("userMatrix")) { if (!requireNamespace("orientlib", quietly = TRUE)) stop("The orientlib package is needed for this function") e <- (orientlib::eulerzyx(orientlib::rotmatrix((rotm[1:3,1:3]))))@x*180/pi list(theta = e[1], phi = 90 - e[3]) } rgl/R/oh3d.R0000644000176200001440000000367314555455305012243 0ustar liggesusers# # R 3d object : o3d # oh3d.vb <- c( -1.5, -1.5, -0.5, 1.0, # 1 -0.5, -1.5, -0.5, 1.0, # 2 0.5, -1.5, -0.5, 1.0, # 3 1.5, -1.5, -0.5, 1.0, # 4 -1.5, -0.5, -0.5, 1.0, # 5 -0.5, -0.5, -0.5, 1.0, # 6 0.5, -0.5, -0.5, 1.0, # 7 1.5, -0.5, -0.5, 1.0, # 8 -1.5, 0.5, -0.5, 1.0, # 9 -0.5, 0.5, -0.5, 1.0, # 10 0.5, 0.5, -0.5, 1.0, # 11 1.5, 0.5, -0.5, 1.0, # 12 -1.5, 1.5, -0.5, 1.0, # 13 -0.5, 1.5, -0.5, 1.0, # 14 0.5, 1.5, -0.5, 1.0, # 15 1.5, 1.5, -0.5, 1.0, # 16 -1.5, -1.5, 0.5, 1.0, # 17 -0.5, -1.5, 0.5, 1.0, # 18 0.5, -1.5, 0.5, 1.0, # 19 1.5, -1.5, 0.5, 1.0, # 20 -1.5, -0.5, 0.5, 1.0, # 21 -0.5, -0.5, 0.5, 1.0, # 22 0.5, -0.5, 0.5, 1.0, # 23 1.5, -0.5, 0.5, 1.0, # 24 -1.5, 0.5, 0.5, 1.0, # 25 -0.5, 0.5, 0.5, 1.0, # 26 0.5, 0.5, 0.5, 1.0, # 27 1.5, 0.5, 0.5, 1.0, # 28 -1.5, 1.5, 0.5, 1.0, # 29 -0.5, 1.5, 0.5, 1.0, # 30 0.5, 1.5, 0.5, 1.0, # 31 1.5, 1.5, 0.5, 1.0 # 32 ) oh3d.ib <- c( 1, 5, 6, 2, 2, 6, 7, 3, 3, 7, 8, 4, 5, 9, 10, 6, 7, 11, 12, 8, 9, 13, 14, 10, 10, 14, 15, 11, 11, 15, 16, 12, 17, 18, 22, 21, 18, 19, 23, 22, 19, 20, 24, 23, 21, 22, 26, 25, 23, 24, 28, 27, 25, 26, 30, 29, 26, 27, 31, 30, 27, 28, 32, 31, 1, 2, 18, 17, 2, 3, 19, 18, 3, 4, 20, 19, 6, 22, 23, 7, 10, 11, 27, 26, 13, 29, 30, 14, 14, 30, 31, 15, 15, 31, 32, 16, 17, 21, 5, 1, 21, 25, 9, 5, 25, 29, 13, 9, 4, 8, 24, 20, 8, 12, 28, 24, 12, 16, 32, 28, 6, 10, 26, 22, 7, 23, 27, 11 ) oh3d <- function( trans = identityMatrix(), ... ) { return(rotate3d(qmesh3d( oh3d.vb, oh3d.ib, material=list(...) ), matrix=trans)) } rgl/R/shiny.R0000644000176200001440000000760514771520323012530 0ustar liggesusers# shiny support functions # Shiny objects if the widget sets elementId, so we # need to detect it. Thanks to Joe Cheng for suggesting this code. inShiny <- function() isNamespaceLoaded("shiny") && !is.null(shiny::getDefaultReactiveDomain()) fns <- local({ registered <- FALSE registerShinyHandlers <- function() { if (!registered) { if (requireNamespace("shiny")) { shiny::registerInputHandler("shinyPar3d", convertShinyPar3d, force = TRUE) shiny::registerInputHandler("shinyMouse3d", convertShinyMouse3d, force = TRUE) registered <<- TRUE } else stop("Not in Shiny") } } unregisterShinyHandlers <- function() { if (registered) { shiny::removeInputHandler("shinyPar3d") shiny::removeInputHandler("shinyMouse3d") } } list(registerShinyHandlers = registerShinyHandlers, unregisterShinyHandlers = unregisterShinyHandlers) }) registerShinyHandlers <- fns$registerShinyHandlers unregisterShinyHandlers <- fns$unregisterShinyHandlers rm(fns) # Widget output function for use in Shiny rglwidgetOutput <- function(outputId, width = '512px', height = '512px') { registerShinyHandlers() tagList(tags$p("3D plot", id = ariaLabelId(outputId), hidden = NA), shinyWidgetOutput(outputId, 'rglWebGL', width, height, package = 'rgl')) } # Widget render function for use in Shiny renderRglwidget <- function(expr, env = parent.frame(), quoted = FALSE, outputArgs = list()) { registerShinyHandlers() if (!quoted) expr <- substitute(expr) # force quoted shiny::markRenderFunction(rglwidgetOutput, shinyRenderWidget(expr, rglwidgetOutput, env, quoted = TRUE), outputArgs = outputArgs) } shinySetPar3d <- function(..., session, subscene = currentSubscene3d(cur3d())) { registerShinyHandlers() args <- list(...) argnames <- names(args) if (length(args) == 1 && is.null(argnames)) { args <- args[[1]] } # We might have been passed modified shinyGetPar3d output; # clean it up. args[["subscene"]] <- NULL args[["tag"]] <- NULL argnames <- names(args) if (is.null(argnames) || any(argnames == "")) stop("Parameters must all be named") badargs <- argnames[!(argnames %in% rgl.par3d.names)] if (length(badargs)) stop("Invalid parameter(s): ", badargs) for (arg in argnames) { session$sendCustomMessage("shinySetPar3d", list(subscene = subscene, parameter = arg, value = args[[arg]])) } } shinyGetPar3d <- function(parameters, session, subscene = currentSubscene3d(cur3d()), tag = "") { registerShinyHandlers() badargs <- parameters[!(parameters %in% rgl.par3d.names)] if (length(badargs)) stop("invalid parameter(s): ", badargs) session$sendCustomMessage("shinyGetPar3d", list(tag = tag, subscene = subscene, parameters = parameters)) } convertShinyPar3d <- function(par3d, ...) { for (parm in c("modelMatrix", "projMatrix", "userMatrix", "userProjection")) if (!is.null(par3d[[parm]])) par3d[[parm]] <- matrix(unlist(par3d[[parm]]), 4, 4) for (parm in c("mouseMode", "observer", "scale", "viewport", "bbox", "windowRect")) if (!is.null(par3d[[parm]])) par3d[[parm]] <- unlist(par3d[[parm]]) par3d } shinyResetBrush <- function(session, brush) { registerShinyHandlers() session$sendCustomMessage("resetBrush", brush) } convertShinyMouse3d <- function(mouse3d, ...) { for (parm in c("model", "proj")) if (!is.null(mouse3d[[parm]])) mouse3d[[parm]] <- matrix(unlist(mouse3d[[parm]]), 4, 4) if (length(unlist(mouse3d$view)) == 4) mouse3d$view <- structure(unlist(mouse3d$view), names = c("x", "y", "width", "height")) if (all(c("p1", "p2") %in% names(mouse3d$region))) mouse3d$region <- with(mouse3d$region, c(x1 = (p1$x + 1)/2, y1 = (p1$y + 1)/2, x2 = (p2$x + 1)/2, y2 = (p2$y + 1)/2)) structure(mouse3d, class = "rglMouseSelection") } rgl/R/shapelist3d.R0000644000176200001440000000553715011677075013630 0ustar liggesusersshapelist3d <- function(shapes,x=0,y=NULL,z=NULL,size=1,matrix=NULL,override=TRUE, ..., plot=TRUE) { # This function gets an element with recycling e <- function(x, i) x[[ (i-1) %% length(x) + 1 ]] xyz <- xyz.coords(x, y, z, recycle = TRUE) x <- xyz$x y <- xyz$y if (length(y) == 0) y <- 0 z <- xyz$z if (length(z) == 0) z <- 0 if (inherits(shapes, "shape3d")) shapes <- list(shapes) material <- .fixMaterialArgs2(...) if (!is.null(matrix)) { if (!is.list(matrix)) matrix <- list(matrix) len <- length(matrix) } else len <- 0 len <- max(len, length(x), length(shapes), length(size), length(override)) if (length(material)) len <- max(len, sapply(material, length)) result <- vector("list", len) class(result) <- c("shapelist3d", "shape3d") for (i in seq_len(len)) { if (is.null(matrix)) this <- e(shapes, i) else this <- rotate3d(e(shapes,i), matrix=e(matrix,i)) thissize <- e(size, i) this <- translate3d(scale3d(this, thissize, thissize, thissize), e(x,i), e(y,i), e(z,i)) thismaterial <- lapply(material, function(item) e(item,i)) if (!e(override,i)) thismaterial[names(this$material)] <- this$material this$material[names(thismaterial)] <- thismaterial result[[i]] <- this } if (plot) { shade3d(result) lowlevel(result) } else invisible(result) } dot3d.shapelist3d <- function(x, override = TRUE, ...) { .check3d() save <- par3d(skipRedraw = TRUE) on.exit(par3d(save)) lowlevel(unlist(sapply( x, function(item) dot3d(item, override=override, ...) ) ) ) } wire3d.shapelist3d <- function(x, override = TRUE, ...) { .check3d() save <- par3d(skipRedraw = TRUE) on.exit(par3d(save)) lowlevel(unlist(sapply( x, function(item) wire3d(item, override=override, ...) ) ) ) } shade3d.shapelist3d <- function(x, override = TRUE, ...) { .check3d() save <- par3d(skipRedraw = TRUE) on.exit(par3d(save)) lowlevel(unlist(sapply( x, function(item) shade3d(item, override=override, ...) ) ) ) } translate3d.shapelist3d <- function( obj, x, y, z, ... ) { structure(lapply( obj, function(item) translate3d(item, x, y, z, ...) ), class = class(obj)) } rotate3d.shapelist3d <- function( obj,angle,x,y,z,matrix, ... ) { structure(lapply( obj, function(item) rotate3d(item,angle, x,y,z,matrix,...) ), class = class(obj)) } scale3d.shapelist3d <- function( obj, x, y, z, ... ) { structure(lapply( obj, function(item) scale3d(item, x,y,z,...) ), class = class(obj)) } addNormals.shapelist3d <- function( x, ... ) { structure(lapply( x, function(item) addNormals(item, ...) ), class = class(x)) } print.shapelist3d <- function(x, prefix = "", ...) { cat(prefix, " shapelist3d object with ", length(x), " items:\n", sep = "") for (i in seq_along(x)) print(x[[i]], prefix = paste0(prefix, "[[", i, "]]")) } rgl/R/webGL.R0000644000176200001440000001125114771520323012366 0ustar liggesuserssubst <- function(strings, ..., digits=7) { substitutions <- list(...) names <- names(substitutions) if (is.null(names)) names <- rep("", length(substitutions)) for (i in seq_along(names)) { if ((n <- names[i]) == "") n <- as.character(sys.call()[[i+2]]) value <- substitutions[[i]] if (is.numeric(value)) value <- formatC(unclass(value), digits=digits, width=1) strings <- gsub(paste("%", n, "%", sep=""), value, strings) } strings } convertBBox <- function(id, verts = rgl.attrib(id, "vertices"), text = rgl.attrib(id, "text"), mat = rgl.getmaterial(id = id)) { if (!length(text)) text <- rep("", NROW(verts)) if (length(mat$color) > 1) mat$color <- mat$color[2] # We ignore the "box" colour if(any(missing <- text == "")) text[missing] <- apply(verts[missing,], 1, function(row) format(row[!is.na(row)])) res <- integer(0) if (any(inds <- is.na(verts[,2]) & is.na(verts[,3]))) res <- c(res, do.call(axis3d, c(list(edge = "x", at = verts[inds, 1], labels = text[inds]), mat))) if (any(inds <- is.na(verts[,1]) & is.na(verts[,3]))) res <- c(res, do.call(axis3d, c(list(edge = "y", at = verts[inds, 2], labels = text[inds]), mat))) if (any(inds <- is.na(verts[,1]) & is.na(verts[,2]))) res <- c(res, do.call(axis3d, c(list(edge = "z", at = verts[inds, 3], labels = text[inds]), mat))) res <- c(res, do.call(box3d, mat)) res } rootSubscene <- function() { id <- currentSubscene3d() repeat { info <- subsceneInfo(id) if (is.null(info$parent)) return(id) else id <- info$parent } } writeWebGL <- function(dir="webGL", filename=file.path(dir, "index.html"), template = system.file(file.path("WebGL", "template.html"), package = "rgl"), prefix = "", snapshot = TRUE, commonParts = TRUE, reuse = NULL, font="Arial", width = NULL, height = NULL) { .Deprecated("rglwidget") # Lots of utility functions and constants defined first; execution starts way down there... header <- function() if (commonParts) c( as.character(includeScript(system.file("htmlwidgets/lib/CanvasMatrix/CanvasMatrix.src.js", package = "rgl"))), as.character(includeScript(system.file("htmlwidgets/lib/rglClass/rglClass.src.js", package = "rgl"))) ) scriptheader <- function() subst( '
', prefix, elementId, json, width, height) footer <- function() subst('

You must enable Javascript to view this page properly.

', prefix) # Execution starts here! # Do a few checks first elementId <- paste0(prefix, "div") if (!file.exists(dir)) dir.create(dir) if (!file.info(dir)$isdir) stop(gettextf("'%s' is not a directory", dir), domain = NA) if (!is.null(template)) { templatelines <- readLines(template) templatelines <- subst(templatelines, rglVersion = packageVersion("rgl"), prefix = prefix) target <- paste("%", prefix, "WebGL%", sep="") replace <- grep( target, templatelines, fixed=TRUE) if (length(replace) != 1) stop(gettextf("template '%s' does not contain '%s'", template, target), domain = NA) result <- c(templatelines[seq_len(replace-1)], header()) } else result <- header() scene <- convertScene(width = width, height = height, elementId = elementId, snapshot = snapshot) scene$crosstalk <- list(key = list(), group = character(), id = integer(), options = list()) if (is.null(width)) width <- scene$width if (is.null(height)) height <- scene$height json <- toJSON(I(scene), dataframe = "columns", null = "null", na = "string", auto_unbox = TRUE, digits = getOption("shiny.json.digits", 7), use_signif = TRUE, force = TRUE, POSIXt = "ISO8601", UTC = TRUE, rownames = FALSE, keep_vec_names = TRUE) result <- c(result, scriptheader(), footer(), if (!is.null(template)) templatelines[replace + seq_len(length(templatelines)-replace)] else subst("", prefix = prefix) ) cat(result, file=filename, sep="\n") invisible(filename) } rgl/R/arrow3d.R0000755000176200001440000000656514771520323012766 0ustar liggesusers## Original by Barry Rowlingson, R-help, 1/10/2010 ## Modified by Michael Friendly: added barblen (to specify absolute barb length) ## Modified by DJM: multiple changes arrow3d <- function(p0=c(1,1,1), p1=c(0,0,0), barblen, s=1/3, theta=pi/12, type = c("extrusion", "lines", "flat", "rotation"), n = 3, width = 1/3, thickness = 0.618*width, spriteOrigin = NULL, plot = TRUE, ...) { ## p0: start point ## p1: end point ## barblen: length of barb ## s: length of barb as fraction of line length (unless barblen is specified) ## theta: opening angle of barbs ## type: type of arrow to draw ## n: number of barbs ## width: width of shaft as fraction of barb width ## thickness: thickness of shaft as fraction of barb width ## spriteOrigin: origin if drawn as sprite ## ...: args passed to lines3d for line styling ## ## Returns (invisibly): integer ID(s) of the shape added to the scene type <- match.arg(type) nbarbs <- if (type == "lines") n else 2 ## Work in isometric display coordinates save <- par3d(FOV = 0) # Compute the center line in window # coordinates xyz <- rgl.user2window(rbind(p0, p1)) p0 <- xyz[1,] p1 <- xyz[2,] ## rotational angles of barbs phi <- seq(pi/nbarbs, 2*pi-pi/nbarbs, length.out = nbarbs) ## length of line lp <- sqrt(sum((p1-p0)^2)) if (missing(barblen)) barblen <- s*lp else s <- barblen/lp ## point down the line where the barb ends line up cpt <- p1 + s*cos(theta)*(p0-p1) ## need to find a right-angle to the line. gs <- GramSchmidt(p1-p0, c(0,0,-1), c(1,0,0)) r <- gs[2,] ## now compute the barb end points and draw: for(i in seq_along(phi)) { ptb <- rotate3d(r,phi[i],(p1-p0)[1],(p1-p0)[2],(p1-p0)[3]) xyz <- rbind(xyz, p1, cpt + barblen*sin(theta)*ptb) } if (type != "lines") { xyz <- xyz[c(3, # 1 head 6, # 2 end of barb 1 6, # 3 end of barb 1 again (to be shrunk) 1, # 4 end of line (to be pushed out) 1, # 5 end of line 1, # 6 end of line (to be pushed the other way) 4, # 7 end of barb 2 (to be shrunk) 4, # 8 end of barb 2 3),] # 9 head mid <- (xyz[2,] + xyz[8,])/2 xyz[3,] <- mid + width*(xyz[2,] - mid) xyz[7,] <- mid + width*(xyz[8,] - mid) xyz[4,] <- xyz[4,] + xyz[3,] - mid xyz[6,] <- xyz[6,] + xyz[7,] - mid } if (type %in% c("extrusion", "rotation")) { xyz <- xyz %*% t(gs) if (type == "extrusion") { thickness <- thickness*sqrt(sum((xyz[2,]-xyz[8,])^2)) ext <- extrude3d(xyz[,c(1,3)], thickness = thickness) } else { mid <- xyz[1,3] xyz[,3] <- abs(xyz[,3] - mid) xyz <- xyz[5:9,] ext <- turn3d(xyz[,c(1,3)], n = n) ext$vb[2,] <- ext$vb[2,] + mid thickness <- 0 } ext$vb <- ext$vb[c(1,3,2,4),] ext$vb[2,] <- ext$vb[2,] + xyz[1,2] - thickness/2 ext$vb[1:3,] <- t(gs) %*% ext$vb[1:3,] ext$vb[1:3,] <- t(rgl.window2user(t(ext$vb[1:3,]))) } else xyz <- rgl.window2user(xyz) par3d(save) if (plot) { if (type == "flat") id <- polygon3d(xyz, ...) else if (type %in% c("extrusion", "rotation")) id <- shade3d(ext, ...) else id <- segments3d(xyz, ...) if (is.null(spriteOrigin)) lowlevel(id) else sprites3d(spriteOrigin, shapes=id) } else { if (type %in% c("extrusion", "rotation")) ext else xyz } } rgl/R/playwidget.R0000644000176200001440000001206414771520323013542 0ustar liggesusers # Widget output function for use in Shiny playwidgetOutput <- function(outputId, width = '0px', height = '0px') { registerShinyHandlers() shinyWidgetOutput(outputId, 'rglPlayer', width, height, package = 'rgl') } # Widget render function for use in Shiny renderPlaywidget <- function(expr, env = parent.frame(), quoted = FALSE, outputArgs = list()) { registerShinyHandlers() if (!quoted) expr <- substitute(expr) # force quoted shiny::markRenderFunction(playwidgetOutput, shinyRenderWidget(expr, playwidgetOutput, env, quoted = TRUE), outputArgs = outputArgs) } playwidget <- function(sceneId, controls, start = 0, stop = Inf, interval = 0.05, rate = 1, components = c("Reverse", "Play", "Slower", "Faster", "Reset", "Slider", "Label"), loop = TRUE, step = 1, labels = NULL, precision = 3, elementId = NULL, respondTo = NULL, reinit = NULL, buttonLabels = components, pause = "Pause", height = 40, ...) { if (is.null(elementId) && !inShiny()) elementId <- newElementId("rgl-play") # sceneId = NA turns into prevRglWidget = NULL upstream <- processUpstream(sceneId, playerId = elementId) if (!is.null(respondTo)) components <- buttonLabels <- NULL if (length(stop) != 1 || !is.finite(stop)) stop <- NULL if (identical(controls, NA)) stop(dQuote("controls"), " should not be NA.") stopifnot(is.list(controls)) if (inherits(controls, "rglControl")) controls <- list(controls) okay <- vapply(controls, inherits, TRUE, "rglControl") if (any(bad <- !okay)) { bad <- which(bad)[1] stop("Controls should inherit from 'rglControl', control ", bad, " is ", class(controls[[bad]])) } names(controls) <- NULL if (length(reinit)) { bad <- vapply(controls, function(x) x$type == "vertexSetter" && length(intersect(reinit, x$objid)), FALSE) if (any(bad)) warning("'vertexControl' is incompatible with re-initialization") } if (!length(components)) components <- character() else components <- match.arg(components, c("Reverse", "Play", "Slower", "Faster", "Reset", "Slider", "Label", "Step"), several.ok = TRUE) buttonLabels <- as.character(buttonLabels) pause <- as.character(pause) stopifnot(length(buttonLabels) == length(components), length(pause) == 1) dependencies <- list(rglDependency) for (i in seq_along(controls)) { control <- controls[[i]] if (is.null(labels)) labels <- control$labels if (!is.null(control$param)) { start <- min(start, control$param[is.finite(control$param)]) stop <- max(stop, control$param[is.finite(control$param)]) } if (!is.null(control$dependencies)) dependencies <- c(dependencies, control$dependencies) } if (is.null(stop) && length(labels)) { stop <- start + (length(labels) - 1)*step } if (is.null(stop)) { if ("Slider" %in% components) { warning("Cannot have slider with non-finite limits") components <- setdiff(components, "Slider") } labels <- NULL } else { if (stop == start) warning("'stop' and 'start' are both ", start) } control <- list( actions = controls, start = start, stop = stop, value = start, interval = interval, rate = rate, components = components, buttonLabels = buttonLabels, pause = pause, loop = loop, step = step, labels = labels, precision = precision, reinit = reinit, sceneId = upstream$prevRglWidget, respondTo = respondTo) result <- createWidget( name = 'rglPlayer', x = control, elementId = elementId, package = 'rgl', height = height, sizingPolicy = sizingPolicy(defaultWidth = "auto", defaultHeight = "auto"), dependencies = dependencies, ... ) if (is.list(upstream$objects)) { if (requireNamespace("manipulateWidget", quietly = TRUE)) result <- do.call(manipulateWidget::combineWidgets, c(upstream$objects, list(manipulateWidget::combineWidgets(result, nrow = 1), rowsize = c(upstream$rowsizes, height), ncol = 1))) else warning("Combining widgets requires the 'manipulateWidget' package.", call. = FALSE) } result } toggleWidget <- function(sceneId, ids = tagged3d(tags), tags = NULL, hidden = integer(), subscenes = NULL, label, ...) { if (missing(label)) if (missing(ids)) label <- paste(tags, collapse = ", ") else label <- deparse(substitute(ids)) playwidget(sceneId, subsetControl(subsets = list(ids, hidden), subscenes = subscenes), start = 0, stop = 1, components = "Step", buttonLabels = label, interval = 1, ...) } rgl/R/aspect3d.R0000644000176200001440000000125014771520323013072 0ustar liggesusersaspect3d <- function(x, y = NULL, z = NULL) { if (is.character(x) && pmatch(x, "iso") == 1) { scale <- c(1,1,1) } else { if (is.null(y)) { x <- rep(x, length.out = 3) z <- x[3] y <- x[2] x <- x[1] } for (i in 1:5) { # To handle spheres, repeat this bbox <- .getRanges() scale <- c(diff(bbox$xlim), diff(bbox$ylim), diff(bbox$zlim)) scale <- ifelse(scale <= 0, 1, scale) avgscale <- sqrt(sum(scale^2)/3) scale <- c(x,y,z)*avgscale/scale oldscale <- par3d(scale = scale)$scale if (isTRUE(all.equal(scale, oldscale))) break } } par3d(scale = scale) } rgl/R/thigmophobe3d.R0000644000176200001440000000171214771520323014123 0ustar liggesusersthigmophobe3d <- function(x, y = NULL, z = NULL, P = par3d("projMatrix"), M = par3d("modelMatrix"), windowRect = par3d("windowRect")) { if (!requireNamespace("plotrix", quietly = TRUE) || packageVersion("plotrix") < "3.7-3") stop("This function requires the plotrix package, version 3.7-3 or higher.") xyz <- xyz.coords(x, y, z) pts3d <- rbind(xyz$x, xyz$y, xyz$z, 1) pts2d <- asEuclidean(t(P %*% M %*% pts3d)) w <- diff(windowRect[c(1,3)]) h <- diff(windowRect[c(2,4)]) pts2d <- cbind(w*pts2d[,1], h*pts2d[,2]) if (packageVersion("plotrix") < "3.7.6") plotrix::thigmophobe(pts2d, plot.span = c(-w, w, -h, h), xlog = FALSE, ylog = FALSE) else plotrix::thigmophobe(pts2d, usr = c(-w, w, -h, h), xlog = FALSE, ylog = FALSE, pin = c(w, h)/50) # This doesn't seem to matter... } rgl/R/windows/0000755000176200001440000000000014771520323012735 5ustar liggesusersrgl/R/windows/noOpenGL.R0000644000176200001440000000006014771520323014535 0ustar liggesusers# Windows always uses OpenGL noOpenGL <- FALSE rgl/R/rglcontroller.R0000644000176200001440000002137014771520323014261 0ustar liggesusers subsetControl <- function(value = 1, subsets, subscenes = NULL, fullset = Reduce(union, subsets), accumulate = FALSE) { subsets <- lapply(subsets, as.integer) fullset <- as.integer(fullset) if (length(names(subsets))) labels <- names(subsets) else labels <- NULL structure(list(type = "subsetSetter", value = value - 1, subsets = unname(subsets), subscenes = subscenes, fullset = fullset, accumulate = accumulate, labels = labels), class = "rglControl") } propertyControl <- function(value = 0, entries, properties, objids = tagged3d(tags), tags, values = NULL, param = seq_len(NROW(values)) - 1, interp = TRUE) { objids <- as.integer(objids) structure(list(type = "propertySetter", value = value, values = values, entries = entries, properties = properties, objids = objids, param = param, interp = interp), class = "rglControl") } clipplaneControl <- function(a=NULL, b=NULL, c=NULL, d=NULL, plane = 1, clipplaneids = tagged3d(tag), tag, ...) { values <- cbind(a = a, b = b, c = c, d = d) col <- which(colnames(values) == letters[1:4]) - 1 propertyControl(values = values, entries = 4*(plane-1) + col, properties = "vClipplane", objids = clipplaneids, ...) } ageControl <- function(births, ages, objids = tagged3d(tags), tags, value = 0, colors = NULL, alpha = NULL, radii = NULL, vertices = NULL, normals = NULL, origins = NULL, texcoords = NULL, x = NULL, y = NULL, z = NULL, red = NULL, green = NULL, blue = NULL) { lengths <- c(colors = NROW(colors), alpha = length(alpha), radii = length(radii), vertices = NROW(vertices), normals = NROW(normals), origins = NROW(origins), texcoords = NROW(texcoords), x = length(x), y = length(y), z = length(z), red = length(red), green = length(green), blue = length(blue)) lengths <- lengths[lengths > 0] n <- unique(lengths) stopifnot(length(n) == 1, n == length(ages), all(diff(ages) >= 0)) ages <- c(-Inf, ages, Inf) rows <- c(1, 1:n, n) result <- list(type = "ageSetter", objids = as.integer(objids), value = value, births = births, ages = ages) if (!is.null(colors)) { colors <- col2rgb(colors)/255 colors <- as.numeric(colors[,rows]) result <- c(result, list(colors = colors)) } if (!is.null(alpha)) result <- c(result, list(alpha = alpha[rows])) if (!is.null(radii)) result <- c(result, list(radii = radii[rows])) if (!is.null(vertices)) { stopifnot(ncol(vertices) == 3) result <- c(result, list(vertices = as.numeric(t(vertices[rows,])))) } if (!is.null(normals)) { stopifnot(ncol(normals) == 3) result <- c(result, list(normals = as.numeric(t(normals[rows,])))) } if (!is.null(origins)) { stopifnot(ncol(origins) == 2) result <- c(result, list(origins = as.numeric(t(origins[rows,])))) } if (!is.null(texcoords)) { stopifnot(ncol(texcoords) == 2) result <- c(result, list(texcoords = as.numeric(t(texcoords[rows,])))) } if (!is.null(x)) result <- c(result, list(x = x[rows])) if (!is.null(y)) result <- c(result, list(y = y[rows])) if (!is.null(z)) result <- c(result, list(z = z[rows])) if (!is.null(red)) result <- c(result, list(red = red[rows])) if (!is.null(green)) result <- c(result, list(green = green[rows])) if (!is.null(blue)) result <- c(result, list(blue = blue[rows])) structure(result, class = "rglControl") } vertexControl <- function(value = 0, values = NULL, vertices = 1, attributes, objid = tagged3d(tag), tag, param = seq_len(NROW(values)) - 1, interp = TRUE) { attributes <- match.arg(attributes, choices = c("x", "y", "z", "red", "green", "blue", "alpha", "radii", "nx", "ny", "nz", "ox", "oy", "oz", "ts", "tt", "offset"), several.ok = TRUE) if (!is.null(values)) { ncol <- max(length(vertices), length(attributes)) if (is.matrix(values)) stopifnot(ncol == ncol(values)) else { stopifnot(ncol == 1) values <- matrix(values, ncol = 1) } # Repeat first and last values to make search simpler. param <- c(-Inf, param, Inf) values <- rbind(values[1,], values, values[nrow(values),]) } structure(list(type = "vertexSetter", value = value, values = values, vertices = vertices - 1, # Javascript 0-based indexing attributes = attributes, objid = as.integer(objid), param = param, # Javascript 0-based indexing interp = interp), class = "rglControl") } par3dinterpControl <- function(fn, from, to, steps, subscene = NULL, omitConstant = TRUE, ...) { rename <- character() times <- seq(from, to, length.out = steps+1) fvals <- lapply(times, fn) f0 <- fvals[[1]] entries <- numeric(0) properties <- character(0) values <- NULL props <- c("FOV", "userMatrix", "scale", "zoom") for (i in seq_along(props)) { prop <- props[i] propname <- rename[prop] if (is.na(propname)) propname <- prop if (!is.null(value <- f0[[prop]])) { newvals <- sapply(fvals, function(e) as.numeric(e[[prop]])) if (is.matrix(newvals)) newvals <- t(newvals) rows <- NROW(newvals) cols <- NCOL(newvals) stopifnot(rows == length(fvals)) entries <- c(entries, seq_len(cols)-1) properties <- c(properties, rep(propname, cols)) values <- cbind(values, newvals) } } if (omitConstant) keep <- apply(values, 2, var) > 0 else keep <- TRUE if (is.null(subscene)) subscene <- f0$subscene propertyControl(values = c(t(values[,keep])), entries = entries[keep], properties = properties[keep], objids = subscene, param = times, ...) } # This is a bridge to the old system # In the old system, the rglClass object was a global named # rgl, and controls install methods on it. In the # new system, the rglClass object is just a field of a
# element. The R code below creates an empty global for the # controls to modify, then the Javascript code in oldBridge # imports those into the real scene object. elementId2Prefix <- function(elementId, prefix = elementId) { .Deprecated("", msg = "This function is not needed if you use rglwidget().") cat(paste0("")) playwidget(elementId, structure(list(type = "oldBridge", prefix = prefix), class = "rglControl"), components = character(0)) } # This puts together a custom message for a more extensive change sceneChange <- function(elementId, x = scene3d(minimal), delete = NULL, add = NULL, replace = NULL, material = FALSE, rootSubscene = FALSE, delfromSubscenes = NULL, skipRedraw = FALSE, minimal = TRUE) { allSubscenes <- function() { result <- numeric() for (obj in scene$objects) if (obj$type == "subscene") result <- c(result, obj$id) result } inSubscenes <- function(id, subs) { result <- numeric() for (sub in subs) if (id %in% sub$objects) result <- c(result, sub$id) result } delete <- unique(c(delete, replace)) add <- unique(c(add, replace)) scene <- convertScene(x, useBuffer = FALSE) allsubids <- allSubscenes() allsubs <- scene$objects[as.character(allsubids)] for (id in add) scene$objects[[as.character(id)]]$inSubscenes <- inSubscenes(id, allsubs) scene$elementId <- elementId allIds <- names(scene$objects) dontSend <- setdiff(allIds, as.character(add)) scene$objects[dontSend] <- NULL if (!length(scene$objects)) scene$objects <- NULL if (!material) scene$material <- NULL if (!rootSubscene) scene$rootSubscene <- NULL scene$delete <- delete if (is.null(delfromSubscenes)) delfromSubscenes <- allsubids scene$delfromSubscenes <- as.numeric(delfromSubscenes) if (is.na(skipRedraw)) scene$redrawScene <- FALSE else { scene$redrawScene <- !skipRedraw scene$skipRedraw <- skipRedraw } scene } registerSceneChange <- function() { tags$script(rglDependency, ' Shiny.addCustomMessageHandler("sceneChange", rglwidgetClass.prototype.sceneChangeHandler); ') } rgl/R/buffer.R0000644000176200001440000004150214771520323012641 0ustar liggesuserstypeSignedByte <- 5120 typeUnsignedByte <- 5121 typeSignedShort <- 5122 typeUnsignedShort <- 5123 typeSignedInt <- 5124 # Not supported in glTF typeUnsignedInt <- 5125 typeFloat <- 5126 typeDouble <- 5130 # Not supported in glTF gltfTypes <- c(byte = 5120, ubyte = 5121, short = 5122, ushort = 5123, uint = 5125, float = 5126, int = 5124, double = 5130) getType <- function(x, types = "anyGLTF") { types <- match.arg(types, c(names(gltfTypes), c("anyGLTF", "any")), several.ok = TRUE) if ("anyGLTF" %in% types) types <- c(types, names(gltfTypes)[1:6]) if ("any" %in% types) types <- c(types, names(gltfTypes)) types <- unique(setdiff(types, c("anyGLTF", "any"))) r <- suppressWarnings(range(x, na.rm = TRUE)) if (is.integer(x) && !any(is.na(x)) && (r[1] >= 0 && any(c("byte", "short", "int", "ubyte", "ushort", "uint") %in% types) || (r[1] < 0 && any(c("byte", "short", "int") %in% types)))) { if (r[1] < 0 && ("byte" %in% types)) { if (-128 <= r[1] && r[2] <= 127) "byte" else if (-32768 <= r[1] && r[2] <= 32767 && ("short" %in% types)) "short" else "int" } else { if (r[2] <= 255 && ("ubyte" %in% types)) "ubyte" else if (r[2] <= 65535 && ("ushort" %in% types)) "ushort" else "uint" } } else if (is.numeric(x)) { if ((-32768 <= r[1] && r[2] <= 32767 || 0 <= r[1] && r[2] <= 65535) && isTRUE(all(x == as.integer(x))) && any(c("byte", "short", "ubyte", "ushort") %in% types)) getType(as.integer(x), types) else if ("float" %in% types) "float" else if ("double" %in% types) "double" } else stop('Unrecognized or disallowed type') } #' @title R6 Class for binary buffers in glTF files. #' #' @description #' These files typically have one buffer holding all the #' binary data for a scene. Buffer <- R6Class("Buffer", public = list( #' @param json #' list read from glTF file. #' @param binfile #' optional External binary filename, or raw vector #' initialize = function(json = NULL, binfile = NULL) { if (!is.null(json)) { private$buffers <- json$buffers private$bufferViews <- json$bufferViews private$accessors <- json$accessors } buffer <- self$getBuffer(0) if (is.null(buffer$uri)) { if (is.character(binfile)) buffer$uri <- binfile else if (is.raw(binfile)) buffer$bytes <- binfile } self$setBuffer(0, buffer) }, #' @description #' Load from file. #' #' @param uri Which file to load. #' @param buf Which buffer number to load. #' load = function(uri, buf = 0) { buffer <- self$getBuffer(buf) if (is.null(buffer)) buffer <- list(byteLength = 0) self$closeBuffer(buf) if (is.character(uri)) { bytes <- readBin(uri, "raw", n = file.size(uri)) buffer$uri <- uri } else if (is.raw(uri)) bytes <- uri buffer$byteLength <- length(bytes) buffer$con <- rawConnection(bytes, open = "r+b") self$setBuffer(buf, buffer) }, #' @description #' Write open buffer to connection. #' #' @param con #' Output connection. #' @param buf #' Buffer number. #' saveOpenBuffer = function(con, buf = 0) { buffer <- self$getBuffer(buf) if (is.null(buffer) || is.null(con0 <- buffer$con) || !inherits(con0, "connection") || !isOpen(con0)) stop("buffer ", buf, " is not open.") bytes <- rawConnectionValue(con0) writeBin(bytes, con) }, #' @description #' Get buffer object. #' #' @param buf Buffer number. #' @param default Default buffer object if `buf` not found. #' #' @return A list containing components described here: #' \url{https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-buffer}. #' getBuffer = function(buf, default = list(byteLength = 0)) { buffer <- if (buf + 1 <= length(private$buffers)) private$buffers[[buf + 1]] if (is.null(buffer)) default else structure(buffer, class = "gltfBuffer") }, #' @description #' Set buffer object. #' #' @param buf Buffer number. #' @param buffer New value to insert. #' setBuffer = function(buf, buffer) private$buffers[[buf + 1]] <- unclass(buffer), #' @description #' Open a connection for the data in a buffer. #' #' @param buf Buffer number. #' #' @return An open binary connection. #' openBuffer = function(buf) { buffer <- self$getBuffer(buf) if (is.null(buffer)) stop("no such buffer") if (is.null(buffer$con)) { if (!is.null(bytes <- buffer$bytes)) { buffer$con <- rawConnection(bytes, open = "r+b") buffer$bytes <- NULL self$setBuffer(buf, buffer) } else if (is.null(buffer$uri)) { buffer$con <- rawConnection(raw(0), open = "r+b") self$setBuffer(buf, buffer) } else self$load(buffer$uri, buf = buf) } self$getBuffer(buf)$con }, #' @description #' Write data to buffer. #' #' @param values Values to write. #' @param type Type to write. #' @param size Byte size of each value. #' @param buf Which buffer to write to. #' #' @return Byte offset of start of bytes written. #' writeBuffer = function(values, type, size, buf = 0) { if (is.null(buffer <- self$getBuffer(buf))) self$setBuffer(buf, buffer <- list(byteLength = 0)) byteLength <- buffer$byteLength byteOffset <- byteLength con <- self$openBuffer(buf) seek(con, byteOffset) byteOffset <- bitwAnd(byteOffset + size - 1, bitwNot(size - 1)) if (is.null(byteLength)) browser() if (byteOffset > byteLength) { writeBin(raw(byteOffset - byteLength), con) } if (type %in% c(typeFloat, typeDouble)) values <- as.numeric(values) else values <- as.integer(values) writeBin(values, con, size = size, endian = "little") buffer <- self$getBuffer(buf) buffer$byteLength <- byteOffset + length(values)*size self$setBuffer(buf, buffer) byteOffset }, #' @description #' Close the connection in a buffer. #' #' If there was a connection open, this will save the #' contents in the raw vector `bytes` within the buffer object. #' #' @param buf The buffer number. #' closeBuffer = function(buf) { buffer <- self$getBuffer(buf) if (!is.null(buffer) && !is.null(buffer$con)) { buffer$bytes <- rawConnectionValue(buffer$con) close(buffer$con) buffer$con <- NULL self$setBuffer(buf, buffer) } }, #' @description #' Close any open buffers. #' #' Call this after working with a GLTF file to avoid warnings #' from R about closing unused connections. #' closeBuffers = function() { for (i in seq_along(private$buffers)) { self$closeBuffer(i - 1) } }, #' @description #' Get `bufferView` object. #' #' @param bufv `bufferView` number. #' #' @return A list containing components described here: #' \url{https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-bufferview}. #' getBufferview = function(bufv) { bufferview <- private$bufferViews[[bufv+1]] if (is.null(bufferview)) stop("bufferView ", bufv, " not found.") structure(bufferview, class = "gltfBufferview") }, #' @description #' Add a new buffer view. #' #' @param values Values to put in the view. #' @param type Type of values. #' @param size Size of values in bytes. #' @param target Optional target use for values. #' @param buf Which buffer to write to. #' #' @return New `bufferView` number. #' addBufferView = function(values, type, size, target = NULL, buf = 0) { bufferview <- list() bufferview$buffer <- buf bufferview$byteLength <- size*length(values) buffer <- self$getBuffer(buf) bufferview$byteOffset <- self$writeBuffer(values, type, size, buf) if (!is.null(target)) bufferview$target <- target self$setBufferview(length(private$bufferViews), bufferview) length(private$bufferViews) - 1 }, #' @description #' Open a connection to a buffer view. #' #' @param bufv Which `bufferView`. #' #' @return A connection. openBufferview = function(bufv) { bufferview <- self$getBufferview(bufv) con <- self$openBuffer(bufferview$buffer) seek(con, bufferview$byteOffset) con }, #' @description #' Set `bufferView` object. #' #' @param bufv `bufferView` number. #' @param bufferView New value to insert. setBufferview = function(bufv, bufferView) private$bufferViews[[bufv + 1]] <- unclass(bufferView), #' @description #' Get accessor object #' #' @param acc Accessor number #' #' @return A list containing components described here: #' \url{https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-accessor} #' getAccessor = function(acc) structure(private$accessors[[acc + 1]], class = "gltfAccessor"), #' @description #' Set accessor object. #' #' @param acc Accessor number. #' @param accessor New value to insert. #' setAccessor = function(acc, accessor) private$accessors[[acc + 1]] <- unclass(accessor), #' @description #' Read data given by accessor number. #' #' @param acc Accessor number. #' #' @return A vector or array as specified in the accessor. For the `MATn` types, the 3rd index #' indexes the element. #' readAccessor = function(acc) { if (acc + 1 > length(private$accessors)) stop("No such accessor") accessor <- self$getAccessor(acc) self$readAccessor0(accessor) }, #' @description #' Read data given by accessor object. #' #' @param accessor Accessor object #' #' @return A vector or array as specified in the accessor. For the `MATn` types, the 3rd index #' indexes the element. #' readAccessor0 = function(accessor) { typenames <- c("5120" = "byte", "5121" = "unsigned_byte", "5122" = "short", "5123" = "unsigned_short", "5125" = "unsigned_int", "5126" = "float") types <- c("5120" = "int", "5121" = "int", "5122" = "int", "5123" = "int", "5125" = "int", "5126" = "double") sizes <- c("5120" = 1, "5121" = 1, "5122" = 2, "5123" = 2, "5125" = 4, "5126" = 4) signeds <- c("5120" = TRUE, "5121" = FALSE, "5122" = TRUE, "5123" = FALSE, "5125" = TRUE, # not really, but make readBin happy "5126" = TRUE) lens <- c(SCALAR = 1, VEC2 = 2, VEC3 = 3, VEC4 = 4, MAT2 = 4, MAT3 = 9, MAT4 = 16) ctype <- as.character(accessor$componentType) atype <- accessor$type type <- types[ctype] len <- lens[atype] size <- sizes[ctype] signed <- signeds[ctype] count <- accessor$count if (is.null(accessor$bufferView)) { values <- numeric(count*len) # initialized to zero } else { view <- self$getBufferview(accessor$bufferView) con <- self$openBufferview(accessor$bufferView) if (is.null(view$byteStride)) { skip <- 0 } else skip <- len*size - view$byteStride if (is.null(byteOffset <- accessor$byteOffset)) byteOffset <- 0 start <- seek(con) + byteOffset if (skip == 0) { seek(con, start) values <- readBin(con, type, n = len*count, size = size, signed = signed, endian = "little") } else { values <- numeric(count*len) for (i in seq_len(count)) { seek(con, start + (i-1)*view$byteStride) values[(i-1)*len + seq_len(len)] <- readBin(con, type, n = len, size = size, signed = signed, endian = "little") } } if (ctype == "5125") { # fix up unsigned integers values[is.na(values)] <- 2^31 values[values < 0] <- values[values < 0] + 2^32 } } if (!is.null(sparse <- accessor$sparse)) { indexobj <- sparse$indices indexobj$type <- "SCALAR" indexobj$count <- sparse$count index <- self$readAccessor0(indexobj) valueobj <- sparse$values valueobj$type <- "SCALAR" valueobj$componentType <- accessor$componentType valueobj$count <- len*sparse$count newvalues <- self$readAccessor0(valueobj) for (i in seq_len(sparse$count)) for (j in seq_len(len)) values[len*index[i] + j] <- newvalues[len*(i-1) + j] } if (!is.null(accessor$normalized) && accessor$normalized) values <- switch(ctype, "5120" = (values + 128)/255 - 1, # byte "5121" = values/255, # u byte "5122" = (values + 2^15)/65535 - 1, # short "5123" = values/65535, # u short values) # default if (len > 1) if (grepl("MAT", atype)) { values <- array(values, dim=c(sqrt(len), sqrt(len), count)) } else values <- matrix(values, ncol = len, byrow = TRUE) values }, #' @description #' Write values to accessor, not including `min` and `max`. #' #' @param values Values to write. #' @param target Optional target use for values. #' @param types Which types can be used? #' @param normalized Are normalized integers allowed? #' @param useDouble Whether to write doubles or singles. #' #' @return New accessor number addAccessor = function(values, target = NULL, types = "anyGLTF", normalized = FALSE) { componentTypeName <- getType(values, types) size <- switch(componentTypeName, "byte" =, # typeSignedByte "ubyte" = 1, # typeUnsignedByte = 1, "short" =, # typeSignedShort =, "ushort" = 2, # typeUnsignedShort = 2, "uint" =, # typeUnsignedInt =, "int" =, # typeSignedInt =, "float" = 4, # typeFloat = 4, "double" = 8) # typeDouble = 8) bufferView <- self$addBufferView(c(values), gltfTypes[componentTypeName], size = size, target = target) if (is.matrix(values) && nrow(values) > 1) { count <- ncol(values) type <- paste0("VEC", nrow(values)) } else { count <- length(values) type <- "SCALAR" } if (normalized && !(componentTypeName %in% c("byte", "ubyte", "short", "ushort"))) stop("Only bytes and short values can be normalized") accessor <- list(bufferView = bufferView, componentType = gltfTypes[[componentTypeName]], # double to drop name count = count, type = type) if (normalized) accessor$normalized <- TRUE private$accessors <- c(private$accessors, list(accessor)) length(private$accessors) - 1 }, #' @description #' Convert buffer to data URI. #' #' @param buf Buffer to convert. #' #' @return String containing data URI. dataURI = function(buf = 0) { self$closeBuffer(buf) buffer <- self$getBuffer(buf) if (is.null(buffer)) stop("Buffer ", buf, " does not exist.") bytes <- buffer$bytes if (is.null(bytes)) { if (is.null(buffer$uri)) return(base64enc::dataURI(raw(0), mime = "application/octet-stream")) else { self$load(buffer$uri, buf) self$closeBuffer(buf) buffer <- self$getBuffer(buf) bytes <- buffer$bytes } } base64enc::dataURI(bytes, mime = "application/octet-stream") }, #' @description Convert to list. #' @return List suitable for writing using JSON. as.list = function() { result <- list() for (n in names(private)) { thelist <- private[[n]] if (is.list(thelist) && length(thelist)) { for (i in seq_along(thelist)) thelist[[i]] <- unclass(thelist[[i]]) result[[n]] <- thelist } } result } ), private = list( buffers = list(), bufferViews = list(), accessors = list() # , # # finalize = function() { # self$closeBuffers() # } ) ) rgl/R/bgplot3d.R0000644000176200001440000000761115011677075013116 0ustar liggesuserssafe.dev.off <- function(which = dev.cur(), prev = dev.prev()) { if (which != 1) { force(prev) grDevices::dev.off(which) } if (length(dev.list())) dev.set(prev) else c("null device" = 1) } dev.off <- function(...) stop("Use safe.dev.off() instead!") legend3d <- function(...) { args <- list(...) bgargs <- setdiff(names(formals(bgplot3d)), c("expression", "...")) idx <- which(names(args) %in% c("sphere", "fogtype", bgargs)) if (length(idx)) { bgargs <- args[idx] args <- args[-idx] } else bgargs <- NULL do.call(bgplot3d, c(list(quote({ par(mar=c(0,0,0,0)) plot(0,0, type="n", xlim=0:1, ylim=0:1, xaxs="i", yaxs="i", axes=FALSE, bty="n") do.call(legend, args) })), bgargs)) } bgplot3d <- function(expression, bg.color = getr3dDefaults("bg", "color"), magnify = 1, ...) { viewport <- par3d("viewport") width <- magnify*viewport["width"] height <- magnify*viewport["height"] if (width > 0 && height > 0) { filename <- tempfile(fileext = ".png") png(filename = filename, width = width, height = height, bg = bg.color) grDevices::devAskNewPage(FALSE) value <- try(expression) safe.dev.off() result <- bg3d(texture = filename, col = "white", lit = FALSE, front = "filled", back = "filled", ...) } else { value <- NULL result <- bg3d(col = bg.color, ...) } lowlevel(structure(result, value = value)) } show2d <- function(expression, face = "z-", line = 0, reverse = FALSE, rotate = 0, x = NULL, y = NULL, z = NULL, width = 480, height = 480, filename = NULL, ignoreExtent = TRUE, color = "white", specular = "black", lit = FALSE, texmipmap = TRUE, texminfilter = "linear.mipmap.linear", expand = 1.03, texcoords = matrix(c(0,1,1,0,0,0,1,1), ncol=2), ...) { save <- par3d(ignoreExtent = ignoreExtent) on.exit(par3d(save)) if (is.null(filename)) { stopifnot(width > 0, height > 0) filename <- tempfile(fileext = ".png") png(filename = filename, width=width, height=height) value <- try(expression) safe.dev.off() } else value <- filename face <- c(strsplit(face, '')[[1]], '-')[1:2] coord <- tolower(face[1]) lower <- face[2] == '-' ranges <- .getRanges(expand = expand) switch(coord, x = { if (is.null(x)) x <- with(ranges, if (lower) x[1] - 0.075*line*diff(x) else x[2] + 0.075*line*diff(x)) if (is.null(y)) y <- with(ranges, c(y[1], y[2], y[2], y[1])) if (is.null(z)) z <- with(ranges, c(z[1], z[1], z[2], z[2])) }, y = { if (is.null(x)) x <- with(ranges, c(x[1], x[2], x[2], x[1])) if (is.null(y)) y <- with(ranges, if (lower) y[1] - 0.075*line*diff(y) else y[2] + 0.075*line*diff(y)) if (is.null(z)) z <- with(ranges, c(z[1], z[1], z[2], z[2])) }, z = { if (is.null(x)) x <- with(ranges, c(x[1], x[2], x[2], x[1])) if (is.null(y)) y <- with(ranges, c(y[1], y[1], y[2], y[2])) if (is.null(z)) z <- with(ranges, if (lower) z[1] - 0.075*line*diff(z) else z[2] + 0.075*line*diff(z)) }) x <- cbind(x, y, z) if (nrow(x) != 4) stop("Exactly 4 corners must be specified.") if (reverse) { temp <- x[2,] x[2,] <- x[4,] x[4,] <- temp } if (rotate) x <- x[(0:3 + rotate) %% 4 + 1, ] result <- quads3d(x, texture=filename, texcoords = texcoords, color = color, lit = lit, texmipmap = texmipmap, texminfilter = texminfilter, ...) lowlevel(structure(result, value = value, xyz = x, texcoords = texcoords, filename = filename)) } rgl/R/getBoundary.R0000644000176200001440000000220114771520323013644 0ustar liggesusersgetBoundary3d <- function(mesh, sorted = FALSE, simplify = TRUE, ...) { if (!inherits(mesh, "mesh3d")) stop(deparse(substitute(mesh)), " is not a mesh3d object.") edges <- NULL if (length(mesh$it)) edges <- cbind(edges, mesh$it[1:2,], mesh$it[2:3,], mesh$it[c(3,1),]) if (length(mesh$ib)) edges <- cbind(edges, mesh$ib[1:2,], mesh$ib[2:3,], mesh$ib[3:4,], mesh$ib[c(4,1),]) if (ncol(edges)) { # undirect the edges uedges <- t(apply(edges, 2, sort)) dup <- duplicated(uedges) | duplicated(uedges, fromLast = TRUE) edges <- edges[,!dup,drop=FALSE] if (sorted) { order <- rep(NA, ncol(edges)) order[1] <- 1 for (i in seq_len(length(order) - 1)) { j <- which(edges[1,] == edges[2, order[i]]) j <- setdiff(j, order[1:i]) if (length(j)) order[i+1] <- j[1] else order[i+1] <- setdiff(1:length(order), order[1:i]) } edges <- edges[, order, drop = FALSE] } } result <- mesh3d(vertices = mesh$vb, segments = edges, material = .fixMaterialArgs2(...)) if (simplify) result <- cleanMesh3d(result) result } rgl/R/persp3d.R0000644000176200001440000001450614771520323012754 0ustar liggesuserspersp3d <- function(x, ...) UseMethod("persp3d") persp3d.default <- function(x = seq(0, 1, length.out = nrow(z)), y = seq(0, 1, length.out = ncol(z)), z, xlim = NULL, ylim = NULL, zlim = NULL, xlab = NULL, ylab = NULL, zlab = NULL, add = FALSE, aspect = !add, forceClipregion = FALSE, ...) { if (!add) next3d() skip <- par3d(skipRedraw=TRUE) on.exit(par3d(skip)) if (is.null(xlab)) xlab <- if (!missing(x)) deparse(substitute(x)) else "X" if (is.null(ylab)) ylab <- if (!missing(y)) deparse(substitute(y)) else "Y" if (is.null(zlab)) zlab <- if (!missing(z)) deparse(substitute(z)) else "Z" ## labcex is disregarded since we do NOT yet put ANY labels... if (missing(z)) { if (!missing(x)) { if (is.list(x)) { z <- x$z y <- x$y x <- x$x } else { z <- x x <- seq(0, 1, length.out = nrow(z)) } } else stop("No 'z' matrix specified") } else if (is.list(x)) { y <- x$y x <- x$x } if ( (!is.matrix(x) && any(diff(x) <= 0)) || (!is.matrix(y) && any(diff(y) <= 0))) stop("Increasing 'x' and 'y' values expected") savesubscene <- currentSubscene3d() result <- setClipregion(xlim, ylim, zlim, forceClipregion) result <- c(result, surface=surface3d(x,y,z,...)) useSubscene3d(savesubscene) if (!add) { result <- c(result, decorate3d(xlim = xlim, ylim = ylim, zlim = zlim, xlab = xlab, ylab = ylab, zlab = zlab, aspect = aspect, ...)) highlevel(result) } else lowlevel(result) } setClipregion <- function(xlim = NULL, ylim = NULL, zlim = NULL, force = FALSE) { if (force || length(c(xlim, ylim, zlim))) { listeners <- par3d("listeners") result <- c(clipregion = newSubscene3d("inherit", "inherit", "inherit")) par3d(listeners = listeners) normals <- matrix(nrow = 0, ncol = 3) offsets <- numeric() if (length(xlim)) { normals <- rbind(normals, matrix(c(1, 0, 0, -1, 0, 0), nrow = 2, byrow = TRUE)) offsets <- c(offsets, -xlim[1], xlim[2]) } if (length(ylim)) { normals <- rbind(normals, matrix(c(0, 1, 0, 0, -1, 0), nrow = 2, byrow = TRUE)) offsets <- c(offsets, -ylim[1], ylim[2]) } if (length(zlim)) { normals <- rbind(normals, matrix(c(0, 0, 1, 0, 0, -1), nrow = 2, byrow = TRUE)) offsets <- c(offsets, -zlim[1], zlim[2]) } keep <- is.finite(offsets) if (length(offsets[keep])) result <- c(result, clipplanes = clipplanes3d(normals[keep,], d = offsets[keep])) } else result <- integer() lowlevel(result) } persp3d.function <- function(x, xlim = c(0,1), ylim = c(0,1), slim = NULL, tlim = NULL, n = 101, xvals = seq.int(min(xlim), max(xlim), length.out = n[1]), yvals = seq.int(min(ylim), max(ylim), length.out = n[2]), svals = seq.int(min(slim), max(slim), length.out = n[1]), tvals = seq.int(min(tlim), max(tlim), length.out = n[2]), xlab = NULL, ylab = NULL, zlab = NULL, col = "gray", otherargs = list(), normal = NULL, texcoords = NULL, ...) { f <- x n <- rep(n, length.out = 2) parametric <- !is.null(slim) || !is.null(tlim) if (!parametric) { n1 <- length(xvals) n2 <- length(yvals) xvals <- matrix(xvals, n1, n2) yvals <- matrix(yvals, n1, n2, byrow = TRUE) args <- c(list(c(xvals), c(yvals)), otherargs) zvals <- do.call(f, args) dim(zvals) <- dim(xvals) argnames <- names(as.list(f)) if (is.null(xlab)) xlab <- argnames[1] if (is.null(ylab)) ylab <- argnames[2] if (is.null(zlab)) zlab <- deparse(substitute(x)) } else { if (is.null(slim)) slim <- c(0,1) if (is.null(tlim)) tlim <- c(0,1) n1 <- length(svals) n2 <- length(tvals) svals <- matrix(svals, n1, n2) tvals <- matrix(tvals, n1, n2, byrow = TRUE) args <- c(list(as.numeric(svals), as.numeric(tvals)), otherargs) allvals <- do.call(f, args) xvals <- matrix(allvals[,1], n1, n2) yvals <- matrix(allvals[,2], n1, n2) zvals <- matrix(allvals[,3], n1, n2) if (!is.null(colnames <- colnames(allvals))) { if (is.null(xlab)) xlab <- colnames[1] if (is.null(ylab)) ylab <- colnames[2] if (is.null(zlab)) zlab <- colnames[3] } } if (is.function(col)) { zmin <- min(zvals, na.rm = TRUE) zscale <- 1/(max(zvals, na.rm = TRUE) - zmin) colfn <- colorRamp(col(100)) colrgba <- colfn(c((zvals - zmin)*zscale)) colrgba[is.na(colrgba)] <- 0 col <- rgb(colrgba, maxColorValue = 255) dim(col) <- dim(zvals) } if (is.function(normal)) normal <- do.call(normal, args) if (is.function(texcoords)) texcoords <- do.call(texcoords, args) args <- list(xvals, yvals, zvals, col = col, xlab = xlab, ylab = ylab, zlab = zlab, ...) if (is.matrix(normal)) args <- c(args, list(normal_x = matrix(normal[,1], n1, n2), normal_y = matrix(normal[,2], n1, n2), normal_z = matrix(normal[,3], n1, n2))) if (is.matrix(texcoords)) args <- c(args, list(texture_s = matrix(texcoords[,1], n1, n2), texture_t = matrix(texcoords[,2], n1, n2))) if (parametric) args <- c(args, list(xlim = if (!missing(xlim)) xlim, ylim = if (!missing(ylim)) ylim)) do.call(persp3d, args) } persp3d.deldir <- function(x, ..., add = FALSE) { plot3d(as.mesh3d(x, ...), add = add, ...) } persp3d.triSht <- persp3d.tri <- function(x, z, ..., add = FALSE) { plot3d(as.mesh3d(x, z, ...), add = add, ...) } persp3d.formula <- function(x, data=NULL, xlab = xyz$xlab, ylab = xyz$ylab, zlab = xyz$zlab, ...) { checkDeldir(error = TRUE) if (!is.null(data)) environment(x) <- list2env(data, envir = environment(x)) xyz <- xyz.coords(x, recycle = TRUE) dxyz <- with(xyz, deldir::deldir(x, y, z = z, suppressMsge = TRUE)) # nolint persp3d(dxyz, xlab = xlab, ylab = ylab, zlab = zlab, ...) } rgl/R/rglMouse.R0000644000176200001440000000420014771520323013157 0ustar liggesusersrglMouse <- function(sceneId, choices = c("trackball", "selecting", "xAxis", "yAxis", "zAxis", "polar", "zoom", "fov", "none"), labels = choices, button = 1, dev = cur3d(), subscene = currentSubscene3d(dev), default = par3d("mouseMode", dev = dev, subscene = subscene)[button + 1], stayActive = FALSE, height = 40, ...) { stopifnot(length(choices) == length(labels)) stopifnot(length(button == 1) && button %in% 1:3) options <- mapply(function(x, y) tags$option(x, value = y), labels, choices, SIMPLIFY = FALSE) for (i in seq_along(choices)) options[[i]] <- tags$option(labels[i], value = choices[i]) default <- which(choices == default) options[[default]] <- tagAppendAttributes(options[[default]], selected = NA) changecode <- 'document.getElementById(this.attributes.rglSceneId.value).rglinstance. setMouseMode(this.value, button = parseInt(this.attributes.rglButton.value), subscene = parseInt(this.attributes.rglSubscene.value), stayActive = parseInt(this.attributes.rglStayActive.value))' result <- tags$select(tagList(options), onchange = HTML(changecode), rglButton = button, rglSubscene = subscene, rglStayActive = as.numeric(stayActive), ...) if (!missing(sceneId) && !is.null(sceneId)) { upstream <- processUpstream(sceneId) if (!is.null(upstream$prevRglWidget)) result <- tagAppendAttributes(result, rglSceneId = upstream$prevRglWidget) } else upstream <- list() if (is.list(upstream$objects)) { if (requireNamespace("manipulateWidget", quietly = TRUE)) return(do.call(manipulateWidget::combineWidgets, c(upstream$objects, list(result, rowsize = c(upstream$rowsizes, height), ncol = 1)))) else warning("Combining widgets requires the 'manipulateWidget' package.", call. = FALSE) } browsable(result) } rgl/R/knitr.R0000644000176200001440000002215615011677075012530 0ustar liggesusersin_knitr <- function() isTRUE(getOption("knitr.in.progress")) in_knitr_with_altText_support <- function() in_knitr() && packageVersion("knitr") >= "1.42.12" ## ## knitr hook functions ## ## fns <- local({ newwindowdone <- FALSE closewindowsdone <- FALSE do_newwindow <- function(options) { if (!newwindowdone) { newwindow <- options$rgl.newwindow if (!is.null(newwindow) && newwindow) open3d() if (!is.null(options$rgl.keepopen)) warning("rgl.keepopen has been replaced by rgl.newwindow") newwindowdone <<- TRUE closewindowsdone <<- FALSE } } do_closewindows <- function(options) { if (!closewindowsdone) { closewindows <- options$rgl.closewindows if (!is.null(closewindows) && closewindows) while (cur3d()) close3d() newwindowdone <<- FALSE closewindowsdone <<- TRUE } } list(do_newwindow = do_newwindow, do_closewindows = do_closewindows) }) do_newwindow <- fns[["do_newwindow"]] do_closewindows <- fns[["do_closewindows"]] rm(fns) hook_webgl <- function(before, options, envir) { if (before) { do_newwindow(options) return() } res <- if (cur3d() != 0) { out_type <- opts_knit$get("out.format") if (!length(intersect(out_type, c("markdown", "html")))) stop("'hook_webgl' is for HTML only. ", "Use 'hook_rgl' instead, or 'setupKnitr(autoprint = TRUE)'.") knit_print(rglwidget(), options = options) } do_closewindows(options) m <- attr(res, 'knit_meta') knit_meta_add(m, if (missing(options)) '' else options$label) res } hook_rgl <- function(before, options, envir) { if (before) { do_newwindow(options) return() } res <- if (cur3d() != 0) { name <- fig_path("", options) margin <- options$rgl.margin if (is.null(margin)) margin <- 100 par3d(windowRect = margin + options$dpi * c(0, 0, options$fig.width, options$fig.height)) Sys.sleep(.05) # need time to respond to window size change dir <- knitr::opts_knit$get("base_dir") if (is.character(dir)) { if (!file_test("-d", dir)) dir.create(dir, recursive = TRUE) owd <- setwd(dir) on.exit(setwd(owd)) } save_rgl(name, options$dev) options$fig.num <- 1L # only one figure in total options$dev <- "png" hook_plot_custom(before, options, envir) } do_closewindows(options) res } hook_rglchunk <- function(before, options, envir) { if (before) do_newwindow(options) else if (is.null(options$webgl) && is.null(options$rgl)) do_closewindows(options) } save_rgl <- function(name, devices) { if (!file_test("-d", dirname(name))) dir.create(dirname(name), recursive = TRUE) # support 3 formats: eps, pdf and png (default) for (dev in devices) switch( dev, eps = , postscript = rgl.postscript(paste0(name, ".eps"), fmt = "eps"), pdf = rgl.postscript(paste0(name, '.pdf'), fmt = "pdf"), snapshot3d(paste0(name, ".png")) ) } # This code is mostly taken from Shiny, which has lots of authors: see # https://github.com/rstudio/shiny/blob/master/R/utils.R # Evaluate an expression using our own private stream of # randomness (not affected by set.seed). withPrivateSeed <- local({ ownSeed <- NULL function(expr) { # Save the old seed if present. if (exists(".Random.seed", envir = .GlobalEnv, inherits = FALSE)) { hasOrigSeed <- TRUE origSeed <- .GlobalEnv$.Random.seed } else { hasOrigSeed <- FALSE } # Swap in the private seed. if (is.null(ownSeed)) { if (hasOrigSeed) { # Move old seed out of the way if present. rm(.Random.seed, envir = .GlobalEnv, inherits = FALSE) } } else { .GlobalEnv$.Random.seed <- ownSeed } # On exit, save the modified private seed, and put the old seed back. on.exit({ ownSeed <<- .GlobalEnv$.Random.seed if (hasOrigSeed) { .GlobalEnv$.Random.seed <- origSeed } else { rm(.Random.seed, envir = .GlobalEnv, inherits = FALSE) } # Shiny had this workaround. I think we don't need it, and have # commented it out. # Need to call this to make sure that the value of .Random.seed gets put # into R's internal RNG state. (Issue #1763) # httpuv::getRNGState() # nolint }) expr } }) # Version of sample that runs with private seed p_sample <- function(...) { withPrivateSeed(sample(...)) } fns <- local({ saveopts <- NULL plotnum <- 0 setupDone <- NULL latex <- FALSE counter <- 0L rgl_counter <- function() { counter <<- counter + 1L counter } setupKnitr <- function(autoprint = FALSE, rgl.newwindow = autoprint, rgl.closewindows = autoprint) { # R produces multiple vignettes in the same session. # Watch out for leftovers if (!is.null(setupDone)) { options(saveopts) saveopts <<- NULL counter <<- 0L } setupDone <<- list(autoprint = autoprint, rgl.newwindow = rgl.newwindow, rgl.closewindows = rgl.closewindows) knitr::opts_chunk$set(rgl.newwindow = rgl.newwindow, rgl.closewindows = rgl.closewindows, rgl.chunk = TRUE) knit_hooks$set(webgl = hook_webgl) knit_hooks$set(webGL = hook_webgl) knit_hooks$set(rgl = hook_rgl) knit_hooks$set(rgl.chunk = hook_rglchunk) latex <<- identical(opts_knit$get("out.format"), "latex") || identical(opts_knit$get("rmarkdown.pandoc.to"), "latex") if (autoprint) saveopts <<- options(rgl.printRglwidget = TRUE) } knit_print.rglOpen3d <- function(x, options, ...) { print(x, ...) if (getOption("rgl.printRglwidget", FALSE)) { plotnum <<- plotnum + 1 } invisible(x) } knit_print.rglId <- function(x, options, ...) { if (getOption("rgl.printRglwidget", FALSE) && !par3d("skipRedraw")) { scene <- scene3d() args <- list(...) if (inherits(x, "rglHighlevel")) plotnum <<- plotnum + 1 structure(list(plotnum = plotnum, scene = scene, width = figWidth(), height = figHeight(), options = options, args = args), class = c("rglRecordedplot", "knit_other_plot")) } else invisible(x) } sew.rglRecordedplot <- function(x, options = list(), ...) { latex <- identical(opts_knit$get("out.format"), "latex") || identical(opts_knit$get("rmarkdown.pandoc.to"), "latex") scene <- x$scene doSnapshot <- knitrNeedsSnapshot(options) content <- rglwidget(scene, width = x$width, height = x$height, webgl = !doSnapshot) if (inherits(content, "knit_image_paths")) { # # We've done a snapshot, put it in the right place. name <- fig_path("-rgl.png", options, rgl_counter()) if (!file_test("-d", dirname(name))) dir.create(dirname(name), recursive = TRUE) file.copy(content, name, overwrite = TRUE) unlink(content) content <- structure(list(file = name, extension = "png"), class = "html_screenshot") } fig.align <- options$fig.align if (length(fig.align) == 1 && fig.align != "default") content <- prependContent(content, tags$style(sprintf( "#%s {%s}", content$elementId, switch(fig.align, center = "margin:auto;", left = "margin-left:0;margin-right:auto;", right = "margin-left:auto;margin-right:0;", "")))) result <- do.call("knit_print", c(list(x = content, options = options), x$args)) if (!latex) class(result) <- c(class(result), "knit_asis_htmlwidget") sew(result, options) } list( setupKnitr = setupKnitr, knit_print.rglOpen3d = knit_print.rglOpen3d, knit_print.rglId = knit_print.rglId, sew.rglRecordedplot = sew.rglRecordedplot) }) setupKnitr <- fns[["setupKnitr"]] knit_print.rglId <- fns[["knit_print.rglId"]] knit_print.rglOpen3d <- fns[["knit_print.rglOpen3d"]] sew.rglRecordedplot <- fns[["sew.rglRecordedplot"]] rm(fns) is_low_change.rglRecordedplot <- function(p1, p2) { inherits(p2, "rglRecordedplot") && p1$plotnum == p2$plotnum } figWidth <- function() { if (in_pkgdown_example()) return(pkgdown_dims()$width) else if (in_knitr()) opts <- opts_current$get(c("fig.width", "dpi", "fig.retina")) else opts <- NULL if (length(opts)) { result <- with(opts, fig.width*dpi/fig.retina) result[1] } else NULL } figHeight <- function() { if (in_pkgdown_example()) return(pkgdown_dims()$height) else if (in_knitr()) opts <- opts_current$get(c("fig.height", "dpi", "fig.retina")) else opts <- NULL if (length(opts)) { result <- with(opts, fig.height*dpi/fig.retina) result[1] } else NULL } rgl/R/testthat.R0000644000176200001440000000036314771520323013230 0ustar liggesusersexpect_known_scene <- function(name, close = TRUE, file = paste0("testdata/", name, ".rds"), ...) { testthat::local_edition(2) result <- testthat::expect_known_value(object = scene3d(), file = file, ...) if (close) close3d() result } rgl/R/ellipse3d.R0000644000176200001440000000447714555455305013275 0ustar liggesusersellipse3d <- function(x, ...) UseMethod("ellipse3d") ellipse3d.default <- function(x, scale = c(1, 1, 1), centre = c(0, 0, 0), level = 0.95, t = sqrt(qchisq(level, 3)), which = 1:3, subdivide = 3, smooth = TRUE, ...) { stopifnot(is.matrix(x)) cov <- x[which, which] chol <- chol(cov) sphere <- subdivision3d(cube3d(...), subdivide) norm <- sqrt( sphere$vb[1,]^2 + sphere$vb[2,]^2 + sphere$vb[3,]^2 ) for (i in 1:3) sphere$vb[i,] <- sphere$vb[i,]/norm sphere$vb[4,] <- 1 if (smooth) sphere$normals <- sphere$vb result <-scale3d(transform3d( sphere, chol), t,t,t) if (!missing(scale)) result <- scale3d(result, scale[1], scale[2], scale[3]) if (!missing(centre)) result <- translate3d(result, centre[1], centre[2], centre[3]) return(result) } ellipse3d.lm <- function(x, which = 1:3, level = 0.95, t = sqrt(3 * qf(level, 3, x$df.residual)), ...) { s <- summary(x) names <- names(x$coefficients[which]) structure(c(ellipse3d.default(s$sigma^2 * s$cov.unscaled[which, which], centre = x$coefficients[which], t = t, ...), xlab=names[1], ylab=names[2], zlab=names[3]), class="mesh3d") } ellipse3d.glm <- function(x, which = 1:3, level = 0.95, t, dispersion, ...) { s <- summary(x) est.disp <- missing(dispersion) & !(x$family$family %in% c('poisson','binomial')) if (missing(dispersion)) dispersion <- s$dispersion if (missing(t)) t <- ifelse(est.disp,sqrt(3 * qf(level, 3, s$df[2])), sqrt(qchisq(level, 3))) names <- names(x$coefficients[which]) structure(c(ellipse3d.default(dispersion * s$cov.unscaled[which, which], centre = x$coefficients[which], t = t, ...), xlab=names[1], ylab=names[2], zlab=names[3]), class="mesh3d") } ellipse3d.nls <- function(x, which = 1:3, level = 0.95, t = sqrt(3 * qf(level, 3, s$df[2])), ...) { s <- summary(x) names <- names(x$m$getPars()[which]) structure(c(ellipse3d.default(s$sigma^2 * s$cov.unscaled[which, which], centre = x$m$getPars()[which], t = t, ...), xlab=names[1], ylab=names[2], zlab=names[3]), class="mesh3d") } rgl/R/turn3d.R0000644000176200001440000000333514771520323012611 0ustar liggesusers turn3d <- function(x, y = NULL, n = 12, smooth = FALSE, ...) { xy <- xy.coords(x, y) x <- xy$x y <- zapsmall(xy$y) stopifnot(all(y >= 0)) len <- length(x) inds <- seq_len(len) if (smooth) { nx <- -diff(y) nx <- c(nx, 0) + c(0, nx) ny <- diff(x) ny <- c(ny, 0) + c(0, ny) nlen <- sqrt(nx^2 + ny^2) nlen[nlen == 0] <- 1 nx <- nx/nlen ny <- ny/nlen normals <- matrix(nrow=4, ncol=0) } zero <- y == 0 vb <- matrix(nrow=4, ncol=0) ib <- matrix(nrow=4, ncol=0) it <- matrix(nrow=3, ncol=0) theta <- seq(0, 2*pi, length.out = n + 1)[-(n + 1)] for (i in inds) { vb <- cbind(vb, rbind(x[i], sin(theta)*y[i], cos(theta)*y[i], 1)) if (smooth) normals <- cbind(normals, rbind(nx[i], sin(theta)*ny[i], cos(theta)*ny[i], 1)) if (i > 1) { if (zero[i] && zero[i-1]) { # do nothing } else if (!zero[i] && zero[i-1]) { # draw triangles prev <- ncol(vb) - n - 0:(n-1) curr <- ncol(vb) - 0:(n-1) curr2 <- curr + 1 curr2[1] <- curr2[1] - n it <- cbind(it, rbind(prev, curr, curr2)) } else if (zero[i] && !zero[i-1]) { # other triangles prev <- ncol(vb) - n - 0:(n-1) curr <- ncol(vb) - 0:(n-1) prev2 <- prev + 1 prev2[1] <- prev2[1] - n it <- cbind(it, rbind(prev, curr, prev2)) } else { # quads prev <- ncol(vb) - n - 0:(n-1) prev2 <- prev + 1 prev2[1] <- prev2[1] - n curr <- ncol(vb) - 0:(n-1) curr2 <- curr + 1 curr2[1] <- curr2[1] - n ib <- cbind(ib, rbind(prev, curr, curr2, prev2)) } } } result <- tmesh3d(vb, it, normals=if(smooth) t(normals), ...) if (length(ib)) result$ib <- ib result } rgl/R/rgl.bringtotop.R0000644000176200001440000000044014265301464014337 0ustar liggesusers ## ## bring device to top ## ## rgl.bringtotop <- function(stay = FALSE) { if ((.Platform$OS.type != "windows") && stay) warning("'stay' not implemented") ret <- .C( rgl_dev_bringtotop, success=FALSE, as.logical(stay) ) if (! ret$success) stop("'rgl.bringtotop' failed") } rgl/R/par3d.R0000644000176200001440000000630114771520323012377 0ustar liggesusersrgl.par3d.names <- c("antialias", "FOV", "ignoreExtent", "listeners", "mouseMode", "observer", "modelMatrix", "projMatrix", "skipRedraw", "userMatrix", "userProjection", "scale", "viewport", "zoom", "bbox", "windowRect", "family", "font", "cex", "useFreeType", "fontname", "maxClipPlanes", "glVersion", "activeSubscene" ) rgl.par3d.readonly <- c( "antialias", "observer", "modelMatrix", "projMatrix", "bbox", "fontname", "maxClipPlanes", "glVersion", "activeSubscene" ) par3d <- function(..., no.readonly = FALSE, dev = cur3d(), subscene = currentSubscene3d(dev)) { single <- FALSE args <- list(...) if (!length(args)) args <- as.list(if (no.readonly) rgl.par3d.names[-match(rgl.par3d.readonly, rgl.par3d.names)] else rgl.par3d.names) else { if (is.null(names(args)) && all(unlist(lapply(args, is.character)))) args <- as.list(unlist(args)) if (length(args) == 1) { if (is.list(args[[1]]) || is.null(args[[1]])) args <- args[[1]] else if(is.null(names(args))) single <- TRUE } } if ("dev" %in% names(args)) { if (!missing(dev) && dev != args[["dev"]]) stop("'dev' specified inconsistently") dev <- args[["dev"]] args[["dev"]] <- NULL } if (specifiedSubscene <- ("subscene" %in% names(args))) { if (!missing(subscene) && subscene != args[["subscene"]]) stop("'subscene' specified inconsistently") subscene <- args[["subscene"]] args[["subscene"]] <- NULL } dev <- as.integer(dev) if (!dev) dev <- open3d() subscene <- as.integer(subscene) if ("userMatrix" %in% names(args)) { m <- args$userMatrix svd <- svd(m[1:3, 1:3]) m[1:3, 1:3] <- svd$u %*% t(svd$v) theta <- atan2(-m[1,3], m[1,1]) m <- m %*% rotationMatrix(theta, 0,1,0) svd <- svd(m[1:3, 1:3]) m[1:3,1:3] <- svd$u %*% t(svd$v) phi <- atan2(-m[2,3], m[3,3]) args$.position <- c(theta, phi)*180/pi } if ("mouseMode" %in% names(args)) { m <- args$mouseMode if (is.null(names(m))) { if (length(m) < 5) args$mouseMode <- c("none", m) } else { m0 <- par3d("mouseMode") m0[names(m)] <- m args$mouseMode <- m0 } } if (forceViewport <- ("windowRect" %in% names(args) && !("viewport" %in% names(args)))) { if (specifiedSubscene) warning("Viewport for subscene ", subscene, " will be adjusted; other viewports will not be.") oldviewport <- .Call(rgl_par3d, dev, subscene, list("viewport","windowRect")) } value <- if (single) .Call(rgl_par3d, dev, subscene, args)[[1]] else .Call(rgl_par3d, dev, subscene, args) # The windowRect might be modified by the window manager (if # too large, for example), so we need to read it after the # change if (forceViewport) { oldsize <- oldviewport$windowRect[3:4] - oldviewport$windowRect[1:2] Sys.sleep(0.1) windowRect <- .Call(rgl_par3d, dev, subscene, list("windowRect"))$windowRect newsize <- windowRect[3:4] - windowRect[1:2] .Call(rgl_par3d, dev, subscene, list(viewport = round(oldviewport$viewport*newsize/oldsize))) } if(!is.null(names(args))) invisible(value) else value } rgl/R/plot3d.R0000644000176200001440000002525514771520323012604 0ustar liggesusersplot3d <- function(x, ...) UseMethod("plot3d") plot3d.default <- function(x, y = NULL, z = NULL, xlab = NULL, ylab = NULL, zlab = NULL, type = 'p', col = material3d("color")[1], size = material3d("size"), lwd = material3d("lwd"), radius = avgscale*size/60, add = FALSE, aspect = !add, xlim = NULL, ylim = NULL, zlim = NULL, forceClipregion = FALSE, decorate = !add, ...) { if (!add) next3d() skip <- par3d(skipRedraw=TRUE) on.exit(par3d(skip)) xlabel <- if (!missing(x)) deparse(substitute(x)) ylabel <- if (!missing(y)) deparse(substitute(y)) zlabel <- if (!missing(z)) deparse(substitute(z)) xyz <- xyz.coords(x,y,z, xlab=xlabel, ylab=ylabel, zlab=zlabel, recycle=TRUE) x <- xyz$x y <- xyz$y z <- xyz$z if (is.null(xlab)) xlab <- xyz$xlab if (is.null(ylab)) ylab <- xyz$ylab if (is.null(zlab)) zlab <- xyz$zlab if (type == "s" && missing(radius)) { xvals <- x yvals <- y zvals <- z if (add && diff(bbox <- par3d("bbox"))[1] > 0) { xvals <- c(x, bbox[1:2]) yvals <- c(y, bbox[3:4]) zvals <- c(z, bbox[5:6]) } if (!add) { if (!is.null(xlim)) xvals <- xlim if (!is.null(ylim)) yvals <- ylim if (!is.null(zlim)) zvals <- zlim } avgscale <- sqrt(sum(c(diff(range(xvals,na.rm=TRUE)), diff(range(yvals,na.rm=TRUE)), diff(range(zvals,na.rm=TRUE)))^2/3)) } savesubscene <- currentSubscene3d() result <- setClipregion(xlim, ylim, zlim, forceClipregion) result <- c(result, data=switch(type, p = points3d(x, y, z, color=col, size=size, ...), s = spheres3d(x, y, z, radius=radius, color=col, ...), l = lines3d(x, y, z, color=col, lwd=lwd, ...), h = segments3d(rep(x,rep(2,length(x))), rep(y,rep(2,length(y))), rbind(rep(0,length(z)),z), color = rep(col, rep(2,length(col))), lwd=lwd, ...), # this is a hack to plot invisible segments n = if (!add) segments3d(rep(range(x, na.rm=TRUE), c(2,2)), rep(range(y, na.rm=TRUE), c(2,2)), rep(range(z, na.rm=TRUE), c(2,2)))) ) useSubscene3d(savesubscene) if (decorate) result <- c(result, decorate3d(xlab=xlab, ylab=ylab, zlab=zlab, aspect = aspect, xlim=xlim, ylim=ylim, zlim=zlim, ...)) if (!add) highlevel(result) else lowlevel(result) } plot3d.mesh3d <- function(x, xlab = "x", ylab = "y", zlab = "z", type = c("shade", "wire", "dots"), add = FALSE, aspect = !add, ...) { if (!add) next3d() skip <- par3d(skipRedraw=TRUE) on.exit(par3d(skip)) if (missing(xlab) && !is.null(x$xlab)) xlab <- x$xlab if (missing(ylab) && !is.null(x$ylab)) ylab <- x$ylab if (missing(zlab) && !is.null(x$zlab)) zlab <- x$zlab result <- switch(match.arg(type), shade = shade3d(x, ...), wire = wire3d(x, ...), dots = dot3d(x, ...)) if (!add) { result <- c(result, decorate3d(xlab = xlab, ylab = ylab, zlab = zlab, aspect = aspect, ...)) highlevel(result) } else lowlevel(result) } decorate3d <- function(xlim = NULL, ylim = NULL, zlim = NULL, xlab = "x", ylab = "y", zlab = "z", box = TRUE, axes = TRUE, main = NULL, sub = NULL, top = TRUE, aspect = FALSE, expand = 1.03, tag = material3d("tag"), ...) { if (is.logical(aspect)) { autoscale <- aspect aspect <- c(1,1,1) } else autoscale <- TRUE result <- numeric(0) if (length(c(xlim, ylim, zlim))) { ranges <- .getRanges() if (is.null(xlim)) xlim <- ranges$xlim if (is.null(ylim)) ylim <- ranges$ylim if (is.null(zlim)) zlim <- ranges$zlim ind <- c(1,1,2,2) result <- c(result, strut=segments3d(xlim[ind], ylim[ind], zlim[ind], tag = tag)) } if (autoscale) aspect3d(aspect) if (axes) result <- c(result, axes=axes3d(box=box, expand=expand, tag = tag)) result <- c(result, title3d(xlab = xlab, ylab = ylab, zlab = zlab, main = main, sub = sub, tag = tag)) if (top) rgl.bringtotop() lowlevel(result) } plot3d.function <- function(x, ...) persp3d(x, ...) plot3d.deldir <- function(x, ...) persp3d(x, ...) plot3d.triSht <- plot3d.tri <- function(x, z, ...) persp3d(x, z, ...) plot3d.formula <- function(x, data = NULL, xlab = xyz$xlab, ylab = xyz$ylab, zlab = xyz$zlab, ...) { if (!is.null(data)) environment(x) <- list2env(data, envir = environment(x)) xyz <- xyz.coords(x) plot3d(xyz, xlab = xlab, ylab = ylab, zlab = zlab, ...) } plot3d.lm <- function(x, which = 1, plane.col = "gray", plane.alpha = 0.5, sharedMouse = TRUE, use_surface3d, do_grid = TRUE, grid.col = "black", grid.alpha = 1, grid.steps = 5, sub.steps = 4, vars = get_all_vars(terms(x), x$model), clip_to_density = 0, ...) { stopifnot(which %in% 1:3) dots <- list(...) n <- length(which) if (clip_to_density > 0) { if (!requireNamespace("MASS", quietly = TRUE)) { warning("'clip_to_density' requires the MASS package.") clip_to_density <- 0 } if (!requireNamespace("interp", quietly = TRUE)) { warning("'clip_to_density' requires the interp package.") clip_to_density <- 0 } } result <- NULL if (n > 1) { cols <- ceiling(sqrt(n)) rows <- ceiling(n/cols) mfrow3d(rows, cols, sharedMouse = sharedMouse) } fit <- x missing_vars <- missing(vars) cols <- ncol(vars) if (cols < 3) stop("Model has only ", cols, " variables.") if (cols > 3) warning("Model has ", cols, " variables; first 3 used.") observed <- vars[, c(2, 3, 1)] names <- colnames(observed) if (is.null(dots$xlab)) dots$xlab <- names[1] if (is.null(dots$ylab)) dots$ylab <- names[2] if (is.null(dots$zlab)) dots$zlab <- names[3] if (missing(use_surface3d)) use_surface3d <- !identical(class(fit), "lm") || ncol(as.matrix(model.frame(fit))) > 3 if (clip_to_density > 0) { densityVals <- MASS::kde2d(observed[,1], observed[,2]) densityVals$z <- with(densityVals, z/max(z)) # nolint density <- function(xyz) { with(densityVals, interp::bilinear(x, y, z, xyz[,1], xyz[,2])$z) # nolint } } plotGrid <- function(i, x, y, x0, y0, z) { dots$color <- grid.col dots$alpha <- grid.alpha dots$color <- grid.col dots$alpha <- grid.alpha dots$front <- dots$back <- dots$polygon_offset <- dots$type <- NULL lenx <- length(x) lenx0 <- length(x0) leny <- length(y) leny0 <- length(y0) x <- c(rep(x0, each = leny + 1), rep(c(x, NA), leny0)) y <- c(rep(c(y, NA), lenx0), rep(y0, each = lenx + 1)) if (missing(z)) { newdat <- data.frame(x, y) names(newdat) <- names[1:2] z <- predict(fit, newdata = newdat) } grid <- do.call(lines3d, c(list(x, y, z), dots)) if (clip_to_density > 0) grid <- clipObj3d(grid, density, clip_to_density, minVertices = 1000) names(grid) <- paste0("grid.", i) grid } plotPoints <- function(i, points, zlab) { dots$zlab <- zlab plot <- do.call(plot3d, c(list(x = points), dots)) names(plot) <- paste0(names(plot), ".", i) plot } plotSurface <- function(i) { bbox <- par3d("bbox") xlim <- c(bbox[1], bbox[2]) x0 <- pretty(xlim, grid.steps) ylim <- c(bbox[3], bbox[4]) y0 <- pretty(ylim, grid.steps) if (sub.steps > 1) { x <- rep(x0, each = sub.steps) + seq(0, diff(x0[1:2]), length.out = sub.steps + 1)[-(sub.steps + 1)] y <- rep(y0, each = sub.steps) + seq(0, diff(y0[1:2]), length.out = sub.steps + 1)[-(sub.steps + 1)] } else { x <- x0 y <- y0 } x <- c(xlim[1], x[xlim[1] < x & x < xlim[2]], xlim[2]) y <- c(ylim[1], y[ylim[1] < y & y < ylim[2]], ylim[2]) newdat <- expand.grid(x = x, y = y) names(newdat) <- names[1:2] z <- try(matrix(predict(fit, newdat), length(x), length(y))) if (inherits(z, "try-error") && !missing_vars) { stop("vars should be in order: response, pred1, pred2", call. = FALSE) } dots$color <- plane.col dots$alpha <- plane.alpha if (is.null(dots$polygon_offset)) dots$polygon_offset <- 1 dots$type <- NULL surface <- do.call("surface3d", c(list(x, y, z), dots)) if (clip_to_density > 0) surface <- clipObj3d(surface, density, clip_to_density, minVertices = 1000) names(surface) <- paste0("surface.", i) grid <- if (do_grid) { x0 <- x0[xlim[1] <= x0 & x0 <= xlim[2]] y0 <- y0[ylim[1] <= y0 & y0 <= ylim[2]] plotGrid(i, x, y, x0, y0) } c(surface, grid) } plotPlane <- function(i, a, b, d) { c <- -1 if (is.na(d)) d <- 0 dots$color <- plane.col dots$alpha <- plane.alpha if (is.null(dots$polygon_offset)) dots$polygon_offset <- 1 dots$type <- NULL plane <- do.call("planes3d", c(list(a = a, b = b, c = c, d = d), dots)) if (clip_to_density > 0) plane <- clipObj3d(plane, density, clip_to_density, minVertices = 1000) names(plane) <- paste0("plane.", i) grid <- if (do_grid) { bbox <- par3d("bbox") xlim <- c(bbox[1], bbox[2]) x0 <- pretty(xlim, grid.steps) ylim <- c(bbox[3], bbox[4]) y0 <- pretty(ylim, grid.steps) x0 <- x0[xlim[1] <= x0 & x0 <= xlim[2]] y0 <- y0[ylim[1] <= y0 & y0 <= ylim[2]] if (isTRUE(all.equal(c(a,b,d), c(0, 0, 0)))) plotGrid(i, xlim, ylim, x0, y0, z = 0) else plotGrid(i, xlim, ylim, x0, y0) } c(plane, grid) } for (i in seq_along(which)) { type <- which[i] if (type == 1L) { plot <- plotPoints(i, observed, dots$zlab) if (use_surface3d) { plane <- plotSurface(i) } else { coefs <- coef(fit) plane <- plotPlane(i, coefs[names[1]], coefs[names[2]], coefs["(Intercept)"]) } } else if (type == 2L) { plot <- plotPoints(i, cbind(observed[,1:2], residuals(fit)), "Residuals") plane <- plotPlane(i, 0, 0, 0) } else if (type == 3L) { plot <- plotPoints(i, cbind(observed[,1:2], predict(fit)), dots$zlab) if (use_surface3d) { plane <- plotSurface(i) } else { coefs <- coef(fit) plane <- plotPlane(i, coefs[names[1]], coefs[names[2]], coefs["(Intercept)"]) } } result <- c(result, plot, plane) } highlevel(result) } rgl/R/material.R0000644000176200001440000001721014771520323013165 0ustar liggesusers## ## R source file ## This file is part of rgl ## ## ## ## ===[ SECTION: generic appearance function ]================================ ## rgl.material0 <- function( color = "white", alpha = 1.0, lit = TRUE, ambient = "black", specular = "white", emission = "black", shininess = 50.0, smooth = TRUE, texture = NULL, textype = "rgb", texmode = "modulate", texmipmap = FALSE, texminfilter = "linear", texmagfilter = "linear", texenvmap = FALSE, front = "filled", back = "filled", size = 3.0, lwd = 1.0, fog = TRUE, point_antialias = FALSE, line_antialias = FALSE, depth_mask = TRUE, depth_test = "less", polygon_offset = c(0.0, 0.0), margin = "", floating = FALSE, tag = "", blend = c("src_alpha", "one_minus_src_alpha"), col, ... ) { # Allow compatibility with base graphics without relying # on abbreviated arguments if (missing(color) && !missing(col)) color <- col # solid or diffuse component color <- rgl.mcolor(color) if (length(color) < 1) stop("There must be at least one color") # light properties ambient <- rgl.color(ambient) specular <- rgl.color(specular) emission <- rgl.color(emission) # others rgl.bool(lit) rgl.bool(fog) rgl.bool(smooth) rgl.bool(point_antialias) rgl.bool(line_antialias) rgl.bool(depth_mask) rgl.clamp(shininess,0,128) rgl.numeric(size) rgl.numeric(lwd) depth_test <- rgl.enum.depthtest(depth_test) # side-dependant rendering front <- rgl.enum.polymode(front) back <- rgl.enum.polymode(back) # texture mapping rgl.bool(texmipmap) texture <- prepareTexture(texture) textype <- rgl.enum.textype( textype ) texmode <- rgl.enum.texmode( texmode ) texminfilter <- rgl.enum.texminfilter( texminfilter ) texmagfilter <- rgl.enum.texmagfilter( texmagfilter ) rgl.bool(texenvmap) texdelete <- !is.null(attr(texture, "rgl_source")) # polygon offset stopifnot(is.numeric(polygon_offset), length(polygon_offset) <= 2, length(polygon_offset) >= 1) if (length(polygon_offset) == 1) polygon_offset <- c(polygon_offset, polygon_offset) # blending stopifnot(length(blend) == 2) blend <- c(rgl.enum.blend(blend[1]), rgl.enum.blend(blend[2])) # vector length ncolor <- dim(color)[2] nalpha <- length(alpha) margin <- parseMargin(margin, floating = floating) # user data tag <- as.character(tag) rgl.string(tag) # pack data idata <- as.integer( c( ncolor, lit, smooth, front, back, fog, textype, texmipmap, texminfilter, texmagfilter, nalpha, ambient, specular, emission, texenvmap, point_antialias, line_antialias, depth_mask, depth_test, margin$coord - 1, margin$edge, floating, blend, texmode, texdelete, color) ) cdata <- as.character(c( tag, texture )) ddata <- as.numeric(c( shininess, size, lwd, polygon_offset, alpha )) ret <- .C( rgl_material, success = FALSE, idata, cdata, ddata ) } rgl.material <- function(...) { .Deprecated("material3d") rgl.material0(...) } rgl.getcolorcount <- function() .C( rgl_getcolorcount, count=integer(1) )$count rgl.getmaterial <- function(ncolors, id = NULL) { if (!length(id)) id <- 0L if (missing(ncolors)) ncolors <- if (id) rgl.attrib.count(id, "colors") else rgl.getcolorcount() idata <- rep(-1, 34+3*ncolors) idata[1] <- ncolors idata[11] <- ncolors cdata <- rep(paste(rep(" ", 512), collapse=""), 2) ddata <- rep(0, 5+ncolors) ret <- .C( rgl_getmaterial, success = FALSE, id = as.integer(id), idata = as.integer(idata), cdata = cdata, ddata = as.numeric(ddata) ) if (!ret$success) stop('rgl.getmaterial failed') polymodes <- c("filled", "lines", "points", "culled") textypes <- c("alpha", "luminance", "luminance.alpha", "rgb", "rgba") texmodes <- c("replace", "modulate", "decal", "blend", "add") minfilters <- c("nearest", "linear", "nearest.mipmap.nearest", "nearest.mipmap.linear", "linear.mipmap.nearest", "linear.mipmap.linear") magfilters <- c("nearest", "linear") depthtests <- c("never", "less", "equal", "lequal", "greater", "notequal", "gequal", "always") blendmodes <- c("zero", "one", "src_color", "one_minus_src_color", "dst_color", "one_minus_dst_color", "src_alpha", "one_minus_src_alpha", "dst_alpha", "one_minus_dst_alpha", "constant_color", "one_minus_constant_color", "constant_alpha", "one_minus_constant_alpha", "src_alpha_saturate") idata <- ret$idata ddata <- ret$ddata cdata <- ret$cdata list(color = rgb(idata[32 + 3*(seq_len(idata[1]))], idata[33 + 3*(seq_len(idata[1]))], idata[34 + 3*(seq_len(idata[1]))], maxColorValue = 255), alpha = if (idata[11]) ddata[seq(from=6, length.out = idata[11])] else 1, lit = idata[2] > 0, ambient = rgb(idata[12], idata[13], idata[14], maxColorValue = 255), specular = rgb(idata[15], idata[16], idata[17], maxColorValue = 255), emission = rgb(idata[18], idata[19], idata[20], maxColorValue = 255), shininess = ddata[1], smooth = idata[3] > 0, texture = if (cdata[2] == "") NULL else cdata[2], textype = textypes[idata[7]], texmipmap = idata[8] == 1, texminfilter = minfilters[idata[9] + 1], texmagfilter = magfilters[idata[10] + 1], texenvmap = idata[21] == 1, front = polymodes[idata[4]], back = polymodes[idata[5]], size = ddata[2], lwd = ddata[3], fog = idata[6] > 0, point_antialias = idata[22] == 1, line_antialias = idata[23] == 1, depth_mask = idata[24] == 1, depth_test = depthtests[idata[25] + 1], isTransparent = idata[26] == 1, polygon_offset = ddata[4:5], margin = deparseMargin(list(coord = idata[27] + 1, edge = idata[28:30])), floating = idata[31] == 1, blend = blendmodes[idata[32:33] + 1], texmode = texmodes[idata[34] + 1], tag = cdata[1] ) } prepareTexture <- function(texture) { arr <- NULL src <- NULL if (is.null(texture)) result <- "" else if (is.character(texture) && length(texture) == 1) { # Assume it's a filename ext <- tolower(file_ext(texture)) if (ext %in% c("jpg", "jpeg")) { if (requireNamespace("jpeg")) arr <- jpeg::readJPEG(texture) else stop("JPEG textures require the 'jpeg' package") } else result <- normalizePath(texture) } else { raster <- as.raster(texture) arr <- t(col2rgb(raster))/255 dim(arr) <- c(rev(dim(raster)), 3) arr <- aperm(arr, c(2,1,3)) } if (!is.null(arr)) { if (!requireNamespace("png")) stop("non-PNG textures require the 'png' package") result <- tempfile(fileext = ".png", tmpdir = .rglEnv$textureDir) src <- attr(texture, "src") png::writePNG(arr, target = result, text = c(rgl_source = deparse(src))) } structure(result, rgl_source = src) } textureSource <- function(texture) { if (missing(texture)) return(.rglEnv$textureDir) if (requireNamespace("png")) { png <- png::readPNG(texture, info = TRUE) if (!is.null(info <- attr(png, "info")) && !is.null(info$text) && !is.na(src <- info$text["rgl_source"])) return(parse(text = src)[[1]]) } texture } rgl/R/animate.R0000644000176200001440000002133514771520323013010 0ustar liggesusers# These quaternion functions are adapted from the orientlib package # Convert an array of rotation matrices to a matrix of unit quaternions toQuaternions <- function(x) { nicesqrt <- function(x) sqrt(pmax(x,0)) q4 <- nicesqrt((1 + x[1,1,] + x[2,2,] + x[3,3,])/4) # may go negative by rounding zeros <- zapsmall(q4) == 0 q1 <- ifelse(!zeros, (x[2,3,] - x[3,2,])/4/q4, nicesqrt(-(x[2,2,]+x[3,3,])/2)) q2 <- ifelse(!zeros, (x[3,1,] - x[1,3,])/4/q4, ifelse(zapsmall(q1) != 0, x[1,2,]/2/q1, nicesqrt((1-x[3,3,])/2))) q3 <- ifelse(!zeros, (x[1,2,] - x[2,1,])/4/q4, ifelse(zapsmall(q1) != 0, x[1,3,]/2/q1, ifelse(zapsmall(q2) != 0, x[2,3,]/2/q2, 1))) cbind(q1, q2, q3, q4) } # Convert a single quaternion to a rotation matrix toRotmatrix <- function(x) { x <- x/sqrt(sum(x^2)) matrix(c(1-2*x[2]^2-2*x[3]^2, 2*x[1]*x[2]-2*x[3]*x[4], 2*x[1]*x[3]+2*x[2]*x[4], 2*x[1]*x[2]+2*x[3]*x[4], 1-2*x[1]^2-2*x[3]^2, 2*x[2]*x[3] - 2*x[4]*x[1], 2*x[1]*x[3] - 2*x[2]*x[4], 2*x[2]*x[3] + 2*x[1]*x[4], 1 - 2*x[1]^2 - 2*x[2]^2), 3,3) } par3dinterp <- function(times=NULL, userMatrix, scale, zoom, FOV, method=c("spline", "linear"), extrapolate = c("oscillate","cycle","constant", "natural"), dev = cur3d(), subscene = par3d("listeners", dev = dev)) { force(dev) force(subscene) if (is.list(times)) { for (n in setdiff(names(times), "times")) assign(n, times[[n]]) if ("times" %in% names(times)) times <- times[["times"]] else times <- NULL } if (!missing(userMatrix) && is.list(userMatrix)) userMatrix <- do.call(cbind, userMatrix) if (!missing(scale) && is.list(scale)) scale <- do.call(rbind, scale) if (!missing(zoom) && is.list(zoom)) zoom <- unlist(zoom) if (!missing(FOV) && is.list(FOV)) FOV <- unlist(FOV) if (is.null(times)) { times <- if (!missing(userMatrix)) 0:(length(userMatrix)/16 - 1) else if (!missing(scale)) 0:(dim(scale)[1] - 1) else if (!missing(zoom)) 0:(length(zoom) - 1) else if (!missing(FOV)) 0:(length(FOV) - 1) } data <- matrix(0, length(times), 0) if (!missing(userMatrix)) { stopifnot( length(userMatrix) == 16*length(times) ) userMatrix <- array(userMatrix, c(4,4,length(times))) xlat <- ncol(data) + 1:4 data <- cbind(data, t(userMatrix[,4,, drop = TRUE])) persp <- ncol(data) + 1:3 data <- cbind(data, t(userMatrix[4,1:3,, drop = TRUE])) rot <- ncol(data) + 1:4 quat <- toQuaternions(userMatrix[1:3, 1:3, , drop = FALSE]) # Since q and -q are the same rotation, we want to interpolate # to the nearer one. for (i in seq_len(nrow(quat))[-1]) { if (sum((quat[i - 1, ] - quat[i, ])^2) > sum((quat[i - 1, ] + quat[i, ])^2)) quat[i, ] <- -quat[i, ] } data <- cbind(data, quat) } else { xlat <- NULL } if (!missing(scale)) { stopifnot( dim(scale)[1] == length(times) ) sc <- ncol(data) + 1:3 data <- cbind(data, log(scale)) } else sc <- NULL if (!missing(zoom)) { stopifnot( length(zoom) == length(times) ) zm <- ncol(data) + 1 data <- cbind(data, log(zoom)) } else zm <- NULL if (!missing(FOV)) { stopifnot( length(FOV) == length(times) ) fov <- ncol(data) + 1 data <- cbind(data, FOV) } else fov <- NULL method <- match.arg(method) extrapolate <- match.arg(extrapolate) if (extrapolate == "oscillate") { n <- length(times) times <- c(times[-n], -rev(times) + 2*times[length(times)]) data <- rbind(data[-n,,drop=FALSE], data[n:1,,drop=FALSE]) n <- 2*n - 1 extrapolate <- "cycle" } else if (extrapolate == "natural" && method != "spline") stop("'natural' extrapolation only supported for spline method") if (method == "spline") { fns <- apply(data, 2, function(col) splinefun(times, col, method = ifelse(extrapolate == "cycle", "periodic", "natural"))) } else { fns <- apply(data, 2, function(col) approxfun(times, col, rule=2)) } mintime <- min(times) maxtime <- max(times) function(time) { if (time < mintime || time > maxtime) { if (extrapolate == "constant" || mintime == maxtime) time <- ifelse(time < mintime, mintime, maxtime) else if (extrapolate == "cycle") time <- (time - mintime) %% (maxtime - mintime) + mintime } data <- sapply(fns, function(f) f(time)) result <- list(dev = dev, subscene = subscene) if (!is.null(xlat)) { userMatrix <- matrix(0, 4,4) userMatrix[,4] <- data[xlat] userMatrix[4,1:3] <- data[persp] userMatrix[1:3,1:3] <- toRotmatrix(data[rot]) result$userMatrix <- userMatrix } if (!is.null(sc)) result$scale <- exp(data[sc]) if (!is.null(zm)) result$zoom <- exp(data[zm]) if (!is.null(fov)) result$FOV <- data[fov] result } } spin3d <- function(axis = c(0, 0, 1), rpm = 5, dev = cur3d(), subscene = par3d("listeners", dev = dev)) { force(axis) force(rpm) force(dev) force(subscene) M <- par3d("userMatrix", dev = dev, subscene = subscene) function(time, base = M) list(userMatrix = rotate3d(base, time*rpm*pi/30, axis[1], axis[2], axis[3]), dev = dev, subscene = subscene) } play3d <- function(f, duration = Inf, dev = cur3d(), ..., startTime = 0) { # Don't want to start timing until args are known: they may be obtained # interactively force(f) force(duration) force(dev) start <- proc.time()[3] - startTime rgl.setselectstate("none") repeat { if(!missing(dev) && cur3d() != dev) set3d(dev) time <- proc.time()[3] - start if (time > duration || rgl.selectstate()$state == msABORT) return(invisible(NULL)) stopifnot(cur3d() != 0) args <- f(time, ...) subs <- args$subscene if (is.null(subs)) subs <- currentSubscene3d(dev) else args$subscene <- NULL for (s in subs) par3d(args, subscene = s) } } movie3d <- function(f, duration, dev = cur3d(), ..., fps=10, movie = "movie", frames = movie, dir = tempdir(), convert = NULL, clean = TRUE, verbose=TRUE, top = !rgl.useNULL(), type = "gif", startTime = 0, webshot = TRUE) { olddir <- setwd(dir) on.exit(setwd(olddir)) for (i in round(startTime*fps):(duration*fps)) { time <- i/fps if(cur3d() != dev) set3d(dev) stopifnot(cur3d() != 0) args <- f(time, ...) subs <- args$subscene if (is.null(subs)) subs <- currentSubscene3d(dev) else args$subscene <- NULL for (s in subs) par3d(args, subscene = s) filename <- sprintf("%s%03d.png",frames,i) if (verbose) { cat(gettextf("Writing '%s'\r", filename)) flush.console() } if (top) rgl.bringtotop() snapshot3d(filename = filename, webshot = webshot) } cat("\n") if (.Platform$OS.type == "windows") system <- shell # nolint if (is.null(convert) && requireNamespace("magick", quietly = TRUE)) { m <- NULL for (i in round(startTime*fps):(duration*fps)) { filename <- sprintf("%s%03d.png",frames,i) frame <- magick::image_read(filename) if (is.null(m)) m <- frame else m <- c(m, frame) if (clean) unlink(filename) } m <- magick::image_animate(m, fps = fps, loop = 1, dispose = "previous") magick::image_write(m, paste0(movie, ".", type)) return(invisible(m)) } else if (is.null(convert)) { warning("R package 'magick' is not installed; trying external package.") convert <- TRUE } if (is.logical(convert) && convert) { # Check for ImageMagick progname <- "magick" version <- try(system2(progname, "--version", stdout = TRUE, stderr = TRUE), silent = TRUE) if (inherits(version, "try-error") || !length(grep("ImageMagick", version))) { progname <- "convert" version <- try(system2(progname, "--version", stdout = TRUE, stderr = TRUE), silent = TRUE) } if (inherits(version, "try-error") || !length(grep("ImageMagick", version))) stop("'ImageMagick' not found") filename <- paste0(movie, ".", type) if (verbose) cat(gettextf("Will create: %s\n", file.path(dir, filename))) convert <- paste(progname, "-delay 1x%d %s*.png %s.%s") } if (is.character(convert)) { convert <- sprintf(convert, fps, frames, movie, type, duration, dir) if (verbose) { cat(gettextf("Executing: '%s'\n", convert)) flush.console() } system(convert) if (clean) { if (verbose) cat(gettext("Deleting frames\n")) for (i in 0:(duration*fps)) { filename <- sprintf("%s%03d.png",frames,i) unlink(filename) } } } invisible(convert) } rgl/R/r3d.rgl.R0000644000176200001440000010117515026315057012646 0ustar liggesusers# # R3D rendering functions - rgl implementation # # Node Management getr3dDefaults <- function(class = NULL, value = NULL) { result <- r3dDefaults if (exists("r3dDefaults", envir = globalenv())) { user <- get("r3dDefaults", envir=.GlobalEnv) for (n in names(user)) { if (is.list(result[[n]])) result[[n]][names(user[[n]])] <- user[[n]] else result[[n]] <- user[[n]] } } if (!is.null(class)) result <- result[[class]] if (!is.null(result) && !is.null(value)) result <- result[[value]] result } clear3d <- function(type = c("shapes", "bboxdeco", "material"), defaults=getr3dDefaults(), subscene = 0) { .check3d() if (is.na(subscene)) subscene <- currentSubscene3d() typeid0 <- rgl.enum.nodetype(type) userviewpoint <- 4 %in% typeid0 material <- 5 %in% typeid0 modelviewpoint <- 8 %in% typeid0 drop <- typeid0 %in% c(4:5, 8) typeid <- typeid0[!drop] type <- names(typeid) if (subscene == 0) { nobg <- setdiff(typeid, 6) idata <- as.integer(c(length(nobg), nobg)) ret <- .C( rgl_clear, success = FALSE, idata )$success if (6 %in% typeid) rgl.incrementID() # for back compatibility if (! ret) stop("'rgl_clear' failed") } else { sceneids <- ids3d(type=type, subscene = 0)$id thisids <- ids3d(type=type, subscene = subscene)$id if (length(thisids)) { delFromSubscene3d(ids = thisids, subscene = subscene) gc3d(protect = setdiff(sceneids, thisids)) } } if ( userviewpoint || modelviewpoint) view3d(type = c("userviewpoint", "modelviewpoint")[c(userviewpoint, modelviewpoint)]) if ( material ) rgl.material0() if ( 4 %in% typeid0 ) { # userviewpoint do.call("par3d", defaults["FOV"]) } if ( 8 %in% typeid0 ) { # modelviewpoint do.call("par3d", defaults["userMatrix"]) } if ( 5 %in% typeid0 ) { # material if (length(defaults$material)) do.call("material3d", defaults$material) } if ( 6 %in% typeid0 ) { # background do.call("bg3d", as.list(defaults$bg)) } lowlevel() } # Environment rgl.material.names <- c("color", "alpha", "lit", "ambient", "specular", "emission", "shininess", "smooth", "front", "back", "size", "lwd", "fog", "point_antialias", "line_antialias", "texture", "textype", "texmode", "texmipmap", "texminfilter", "texmagfilter", "texenvmap", "depth_mask", "depth_test", "isTransparent", "polygon_offset", "margin", "floating", "tag", "blend") rgl.material.readonly <- "isTransparent" # Warn about putting a texture on a black surface, but only # if the surface is black because that's the default. warnBlackTexture <- function(..., defaults = material3d(), color = col, col = "missing", texture = defaults$texture, texmode = defaults$texmode) { if (!is.null(texture)) { if (length(color) == 1 && !is.na(color) && color == "missing" && !is.na(texmode) && texmode == "modulate" && isTRUE(getOption("rgl.warnBlackTexture", TRUE)) && length(defaults$color) && !is.na(defaults$color[1]) && defaults$color[1] %in% c("#000000", "black")) warning("Texture will be invisible on black surface", call. = FALSE) } } # Attach the expression for the source of a texture if # it is not already there addTextureSource <- function(texture, ...) { if (!is.null(texture) && is.null(attr(texture, "src"))) attr(texture, "src") <- substitute(texture) texture } # This function expands a list of arguments by putting # all entries from Params (i.e. the current settings by default) # in place for any entries that are not listed. # Unrecognized args are left in place. .fixMaterialArgs <- function(..., Params = material3d(), col) { f <- function(...) list(...) dots <- list(...) if (!is.null(dots$texture)) { warnBlackTexture(..., col = if (missing(col)) "missing" else col, defaults = Params) dots$texture <- addTextureSource(...) } if (!missing(col)) Params$color <- col formals(f) <- c(Params, formals(f)) names <- as.list(names(Params)) names(names) <- names names <- lapply(names, as.name) b <- as.list(body(f)) body(f) <- as.call(c(b[1], names, b[-1])) do.call(f, dots) } # This one just expands the argument names to match the # standard names .fixMaterialArgs2 <- function(..., col) { call <- do.call(call, list("rgl.material0", ...)) result <- as.list(match.call(rgl.material0, call))[-1] if (!missing(col) && is.null(result$color)) result$color <- col result } # This one just gets the material args # If warn is TRUE, give a warning instead of ignoring extras. .getMaterialArgs <- function(..., material = list(), warn = FALSE, col = material[["col"]]) { fullyNamed <- as.list(match.call(rgl.material0, as.call(c(list(as.name("rgl.material0"), ...), material))))[-1] if (!is.null(col) && !("color" %in% names(fullyNamed))) fullyNamed$color <- col good <- names(fullyNamed) %in% rgl.material.names if (warn && !all(good)) warning("Argument(s) ", paste(names(fullyNamed)[!good], collapse = ", "), " not matched.") fullyNamed[good] } material3d <- function(..., id = NULL) { args <- list(...) argnames <- names(args) if (length(argnames) && !is.null(id)) stop("Material properties cannot be set on existing objects.") if (length(id) > 1) stop("Material properties may only be queried for single objects.") argnames <- setdiff(argnames, rgl.material.readonly) if (!length(args)) argnames <- rgl.material.names else { if (is.null(names(args)) && all(unlist(lapply(args, is.character)))) { argnames <- unlist(args) args <- NULL } if (length(args) == 1) { if (is.list(args[[1]]) | is.null(args[[1]])) { args <- args[[1]] argnames <- names(args) } } } value <- rgl.getmaterial(id = id)[argnames] if (length(args)) { save <- options(rgl.warnBlackTexture = FALSE) on.exit(options(save)) args <- do.call(".fixMaterialArgs", args) do.call("rgl.material0", args) return(invisible(value)) } else if (length(argnames) == 1) return(value[[1]]) else return(value) } bg3d <- function(color, sphere=FALSE, back="lines", fogtype="none", fogScale = 1, col, ... ) { .check3d(); save <- material3d(); on.exit(material3d(save)) bgid <- ids3d("background")$id if (length(bgid) && nrow(flags <- rgl.attrib(bgid[1], "flags"))) { if (missing(sphere)) sphere <- flags["sphere", 1] if (missing(fogtype)) fogtype <- if (flags["linear_fog", 1]) "linear" else if (flags["exp_fog", 1]) "exp" else if (flags["exp2_fog", 1]) "exp2" else "none" if (currentSubscene3d() == rootSubscene()) rgl.incrementID() # for back compatibility } dots <- list(...) if (!missing(color)) { dots$color <- color if (!missing(col)) warning("'color' specified, so 'col' is ignored.") } else if (!missing(col)) dots$color <- col if ("fogtype" %in% names(dots)) fogtype <- dots$fogtype if ("fogScale" %in% names(dots)) fogScale <- dots$fogScale else fogScale <- 1 if ("color" %in% names(dots)) color <- dots$color else if ("col" %in% names(dots)) color <- dots$col else color <- getr3dDefaults("bg", "color") if (is.null(color)) color <- "white" new <- .fixMaterialArgs(sphere = sphere, fogtype = fogtype, fogScale = fogScale, color = color, back = back, lit = FALSE, Params = save) do.call("rgl.material0", .fixMaterialArgs(..., Params = new)) fogtype <- rgl.enum.fogtype(fogtype) idata <- as.integer(c(sphere,fogtype)) fogScale <- as.numeric(fogScale) stopifnot(length(fogScale) == 1, fogScale > 0) ret <- .C( rgl_bg, success = as.integer(FALSE), idata, fogScale ) if (! ret$success) stop("'rgl_bg' failed") if (length(bgid)) pop3d(type = "background", id = bgid) lowlevel(ret$success) } light3d <- function(theta=0, phi=15, x=NULL, y = NULL, z = NULL, viewpoint.rel = TRUE, ambient = "#FFFFFF", diffuse = "#FFFFFF", specular = "#FFFFFF") { .check3d() ambient <- rgl.color(ambient) diffuse <- rgl.color(diffuse) specular <- rgl.color(specular) # if a complete set of x, y, z is given, the light source is assumed to be part of the scene, theta and phi are ignored # else the light source is infinitely far away and its direction is determined by theta, phi (default) if ( !is.null(x) ) { if ( !missing(theta) || !missing(phi) ) warning("'theta' and 'phi' ignored when 'x' is present") xyz <- xyz.coords(x,y,z, recycle = TRUE) x <- xyz$x y <- xyz$y z <- xyz$z if (length(x) > 1) stop("A light can only be in one place at a time") finite.pos <- TRUE } else { if ( !is.null(y) || !is.null(z) ) warning("'y' and 'z' ignored, 'theta' and 'phi' used") finite.pos <- FALSE x <- 0 y <- 0 z <- 0 } idata <- as.integer(c(viewpoint.rel, ambient, diffuse, specular, finite.pos)) ddata <- as.numeric(c(theta, phi, x, y, z)) ret <- .C( rgl_light, success = as.integer(FALSE), idata, ddata ) if (! ret$success) stop("Error in 'rgl_light'. Too many lights? maximum is 8 sources per scene") lowlevel(ret$success) } view3d <- function(theta = 0.0, phi = 15.0, fov = 60.0, zoom = 1.0, scale = par3d("scale"), interactive = TRUE, userMatrix, type = c("userviewpoint", "modelviewpoint")) { .check3d() zoom <- rgl.clamp(zoom,0,Inf) phi <- rgl.clamp(phi,-90,90) fov <- rgl.clamp(fov,0,179) type <- match.arg(type, several.ok = TRUE) polar <- missing(userMatrix) if (polar) userMatrix <- diag(4) idata <- as.integer(c(interactive,polar, "userviewpoint" %in% type, "modelviewpoint" %in% type)) ddata <- as.numeric(c(theta,phi,fov,zoom,scale,userMatrix[1:16])) ret <- .C( rgl_viewpoint, success = FALSE, idata, ddata ) if (! ret$success) stop("'rgl_viewpoint' failed") lowlevel() } bbox3d <- function(xat = NULL, yat = NULL, zat = NULL, xunit = "pretty", yunit = "pretty", zunit = "pretty", expand = 1.03, draw_front = FALSE, xlab=NULL, ylab=NULL, zlab=NULL, xlen=5, ylen=5, zlen=5, marklen=15.0, marklen.rel=TRUE, ...) { .check3d(); save <- material3d(); on.exit(material3d(save)) # Force evaluation of args as in old bbox3d list(xat=xat, yat=yat, zat=zat, xunit=xunit, yunit=yunit, zunit=zunit, expand=expand, draw_front=draw_front) do.call(rgl.material0, .fixMaterialArgs(..., Params = save)) if (is.null(xat)) xlab <- NULL else { xlen <- length(xat) if (is.null(xlab)) xlab <- format(xat) else xlab <- rep(xlab, length.out=xlen) } if (is.null(yat)) ylab <- NULL else { ylen <- length(yat) if (is.null(ylab)) ylab <- format(yat) else ylab <- rep(ylab, length.out=ylen) } if (is.null(zat)) zlab <- NULL else { zlen <- length(zat) if (is.null(zlab)) zlab <- format(zat) else zlab <- rep(zlab,length.out=length(zat)) } xticks <- length(xat) yticks <- length(yat) zticks <- length(zat) if (identical(xunit, "pretty")) xunit <- -1 if (identical(yunit, "pretty")) yunit <- -1 if (identical(zunit, "pretty")) zunit <- -1 length(xlen) <- 1 length(ylen) <- 1 length(zlen) <- 1 length(marklen.rel) <- 1 length(draw_front) <- 1 length(xunit) <- 1 length(yunit) <- 1 length(zunit) <- 1 length(marklen) <- 1 length(expand) <- 1 idata <- as.integer(c(xticks,yticks,zticks, xlen, ylen, zlen, marklen.rel, draw_front)) ddata <- as.numeric(c(xunit, yunit, zunit, marklen, expand)) ret <- .C( rgl_bbox, success = as.integer(FALSE), idata, ddata, as.numeric(xat), as.character(xlab), as.numeric(yat), as.character(ylab), as.numeric(zat), as.character(zlab) ) if (! ret$success) stop("'rgl_bbox' failed") lowlevel(ret$success) } dummyBbox <- function() bbox3d(xat = numeric(), yat = numeric(), zat = numeric(), front = "cull", back = "cull") observer3d <- function(x, y=NULL, z=NULL, auto=FALSE) { if (missing(x)) location <- c(NA, NA, NA) else { xyz <- xyz.coords(x,y,z, recycle = TRUE) location <- c(xyz$x, xyz$y, xyz$z) if (length(location) != 3) stop("A single point must be specified for the observer location") } prev <- .C(rgl_getObserver, success=integer(1), ddata=numeric(3), NAOK = TRUE)$ddata .C(rgl_setObserver, success=as.integer(auto), ddata=as.numeric(location), NAOK = TRUE) lowlevel(prev) } # Shapes points3d <- function(x,y=NULL,z=NULL,...) { .check3d(); save <- material3d(); on.exit(material3d(save)) do.call("rgl.primitive0", c(list(type = "points", x=x,y=y,z=z), .fixMaterialArgs(..., Params = save))) } lines3d <- function(x,y=NULL,z=NULL,...) { .check3d(); save <- material3d(); on.exit(material3d(save)) do.call("rgl.primitive0", c(list(type = "linestrips", x=x,y=y,z=z), .fixMaterialArgs(..., Params = save))) } segments3d <- function(x,y=NULL,z=NULL,...) { .check3d(); save <- material3d(); on.exit(material3d(save)) do.call("rgl.primitive0", c(list(type = "lines", x=x,y=y,z=z), .fixMaterialArgs(..., Params = save))) } triangles3d <- function(x,y=NULL,z=NULL,...) { .check3d(); save <- material3d(); on.exit(material3d(save)) do.call("rgl.primitive0", c(list(type = "triangles", x=x, y=y, z=z), .fixMaterialArgs(..., Params = save))) } quads3d <- function(x,y=NULL,z=NULL,...) { .check3d(); save <- material3d(); on.exit(material3d(save)) do.call("rgl.primitive0", c(list(type = "quadrangles", x=x,y=y,z=z), .fixMaterialArgs(..., Params = save))) } text3d <- function(x, y = NULL, z = NULL, texts, adj = 0.5, pos = NULL, offset = 0.5, usePlotmath = is.language(texts), family = par3d("family"), font = par3d("font"), cex = par3d("cex"), useFreeType = par3d("useFreeType"), ...) { if (usePlotmath) return(plotmath3d(x = x, y = y, z = z, text = texts, adj = adj, pos = pos, offset = offset, cex = cex, ...)) .check3d(); save <- material3d(); on.exit(material3d(save)) do.call("rgl.material0", .fixMaterialArgs(..., Params = save)) # Force evaluation list(x = x, y = y, z = z, text = texts, adj = adj, pos = pos, offset = offset) vertex <- rgl.vertex(x,y,z) nvertex <- rgl.nvertex(vertex) if (!is.null(pos)) { npos <- length(pos) stopifnot(all(pos %in% 0:6)) stopifnot(length(offset) == 1) adj <- offset } else { pos <- 0 npos <- 1 } if (length(adj) > 3) warning("Only the first three entries of 'adj' are used") adj <- c(adj, 0.5, 0.5, 0.5)[1:3] if (!length(texts)) { if (nvertex) warning("No text to plot") return(invisible(integer(0))) } if (nvertex) { texts <- rep(texts, length.out=nvertex) idata <- as.integer(nvertex) nfonts <- max(length(family), length(font), length(cex)) family <- rep(family, length.out = nfonts) font <- rep(font, length.out = nfonts) cex <- rep(cex, length.out = nfonts) family[font == 5] <- "symbol" font <- ifelse( font < 0 | font > 4, 1, font) ret <- .C( rgl_texts, success = as.integer(FALSE), idata, as.double(adj), as.character(texts), as.numeric(vertex), as.integer(nfonts), as.character(family), as.integer(font), as.numeric(cex), as.integer(useFreeType), as.integer(npos), as.integer(pos), NAOK=TRUE ) if (! ret$success) stop("'rgl_texts' failed") lowlevel(ret$success) } } texts3d <- text3d spheres3d <- function(x, y = NULL, z = NULL, radius = 1, fastTransparency = TRUE, ...) { .check3d(); save <- material3d(); on.exit(material3d(save)) # Force evaluation of args list(x = x, y = y, z = z, radius = radius, fastTransparency = fastTransparency) do.call("rgl.material0", .fixMaterialArgs(..., Params = save)) vertex <- rgl.vertex(x,y,z) nvertex <- rgl.nvertex(vertex) radius <- rgl.attr(radius, nvertex) nradius <- length(radius) if (nvertex && nradius) { idata <- as.integer( c( nvertex, nradius ) ) ret <- .C( rgl_spheres, success = as.integer(FALSE), idata, as.numeric(vertex), as.numeric(radius), as.integer(fastTransparency), NAOK=TRUE ) if (! ret$success) stop("'rgl_spheres' failed") lowlevel(ret$success) } } planes3d <- function(a,b=NULL,c=NULL,d=0,...) { .check3d(); save <- material3d(); on.exit(material3d(save)) # Force evaluation of args list(a=a,b=b,c=c,d=d) do.call("rgl.material0", .fixMaterialArgs(..., Params = save)) normals <- rgl.vertex(a, b, c) nnormals <- rgl.nvertex(normals) noffsets <- length(d) if (nnormals && noffsets) { idata <- as.integer( c( nnormals, noffsets ) ) ret <- .C( rgl_planes, success = as.integer(FALSE), idata, as.numeric(normals), as.numeric(d), NAOK=TRUE ) if (! ret$success) stop("'rgl_planes' failed") lowlevel(ret$success) } } clipplanes3d <- function(a,b=NULL,c=NULL,d=0) { .check3d() normals <- rgl.vertex(a, b, c) nnormals <- rgl.nvertex(normals) noffsets <- length(d) if (nnormals && noffsets) { idata <- as.integer( c( nnormals, noffsets ) ) ret <- .C( rgl_clipplanes, success = as.integer(FALSE), idata, as.numeric(normals), as.numeric(d), NAOK=TRUE ) if (! ret$success) stop("'rgl_clipplanes' failed") lowlevel(ret$success) } } abclines3d <- function(x,y=NULL,z=NULL,a,b=NULL,c=NULL,...) { .check3d(); save <- material3d(); on.exit(material3d(save)) # Force evaluation of args list(x=x,y=y,z=z,a=a,b=b,c=c) do.call("rgl.material0", .fixMaterialArgs(..., Params = save)) bases <- rgl.vertex(x, y, z) nbases <- rgl.nvertex(bases) directions <- rgl.vertex(a, b, c) ndirs <- rgl.nvertex(directions) if (nbases && ndirs) { idata <- as.integer( c( nbases, ndirs ) ) ret <- .C( rgl_abclines, success = as.integer(FALSE), idata, as.numeric(bases), as.numeric(directions), NAOK=TRUE ) if (! ret$success) stop("'rgl_abclines' failed") lowlevel(ret$success) } } sprites3d <- function(x, y = NULL, z = NULL, radius = 1, shapes = NULL, userMatrix, fixedSize = FALSE, adj = 0.5, pos = NULL, offset = 0.25, rotating = FALSE, ...) { .check3d(); save <- material3d(); on.exit(material3d(save)) do.call("rgl.material0", .fixMaterialArgs(..., Params = save)) if (missing(userMatrix)) { userMatrix <- getr3dDefaults()$userMatrix if (is.null(userMatrix)) userMatrix <- diag(4) } savepar <- par3d(skipRedraw=TRUE, ignoreExtent=TRUE) on.exit(par3d(savepar), add=TRUE) par3d(ignoreExtent=savepar$ignoreExtent) # Force evaluation of args list(x=x,y=y,z=z,radius=radius,shapes=shapes, userMatrix=userMatrix, fixedSize = fixedSize, rotating = rotating, adj = adj, pos = pos, offset = offset) center <- rgl.vertex(x,y,z) ncenter <- rgl.nvertex(center) radius <- rgl.attr(radius, ncenter) nradius <- length(radius) if (is.list(shapes)) { nshapelens <- length(shapes) if (!nshapelens) stop("Must have at least one shape") shapelens <- vapply(shapes, length, 1L) shapes <- unlist(shapes) } else if (length(shapes)) { nshapelens <- 1 shapelens <- length(shapes) } else { nshapelens <- 0 shapelens <- NULL } if (any(is.na(shapes))) stop("shapes must not be NA") nshapes <- length(shapes) pos <- as.integer(pos) npos <- length(pos) if (npos) { pos <- rep(pos, length.out = ncenter) adj <- offset } adj <- c(adj, 0.5, 0.5, 0.5)[1:3] if (ncenter && nradius) { if (length(shapes) && length(userMatrix) != 16) stop("Invalid 'userMatrix'") if (length(fixedSize) != 1) stop("Invalid 'fixedSize'") idata <- as.integer( c(ncenter,nradius,nshapes, fixedSize, npos, rotating, nshapelens, shapelens ) ) ret <- .C( rgl_sprites, success = as.integer(FALSE), idata, as.numeric(center), as.numeric(radius), as.integer(shapes), as.numeric(t(userMatrix)), as.numeric(adj), pos, as.numeric(offset), NAOK=TRUE ) if (! ret$success) stop("'rgl_sprites' failed") lowlevel(ret$success) } } surface3d <- function(x, y = NULL, z = NULL, ..., normal_x = NULL, normal_y = NULL, normal_z = NULL, texture_s = NULL, texture_t=NULL, flip = FALSE) { .check3d(); save <- material3d(); on.exit(material3d(save)) # Evaluate args list(x=x,y=z,z=y,coords=c(1,3,2), normal_x=normal_x,normal_y=normal_z,normal_z=normal_y) do.call("rgl.material0", .fixMaterialArgs(..., Params = save)) flags <- rep(FALSE, 4) nrows <- NA ncols <- NA if (is.matrix(x)) { nrows <- nrow(x) ncols <- ncol(x) flags[1] <- TRUE } else nrows <- length(x) if (is.matrix(y)) { if (is.na(ncols)) ncols <- ncol(y) if ( any(dim(y) != c(nrows, ncols))) stop(gettextf("Bad dimension for %s", "y"), domain = NA) flags[2] <- TRUE } else { if (is.na(ncols)) ncols <- length(y) else if (ncols != length(y)) stop(gettextf("Bad length for %s", "y"), domain = NA) } if (is.matrix(z)) { if (any(dim(z) != c(nrows, ncols))) stop(gettextf("Bad dimension for %s", "z")) } else if (!flags[1] && !flags[2] && length(z) == nrows*ncols) { z <- matrix(z, nrows, ncols) } else if (!flags[2]) { if (!flags[1]) stop("At least one coordinate must be a matrix") if (nrows != length(z)) stop(gettextf("Bad length for %s", "z")) z <- matrix(z, nrows, ncols) } else { if (ncols != length(z)) stop(gettextf("Bad length for %s", "z")) z <- matrix(z, nrows, ncols, byrow = TRUE) } nz <- length(z) if ( nrows < 2 ) stop("rows < 2") if ( ncols < 2 ) stop("cols < 2") coords <- c(1,3,2) nulls <- c(is.null(normal_x), is.null(normal_y), is.null(normal_z)) if (!all( nulls ) ) { if (any( nulls )) stop("All normals must be supplied") if ( !identical(dim(z), dim(normal_x)) || !identical(dim(z), dim(normal_y)) || !identical(dim(z), dim(normal_z)) ) stop(gettextf("Bad dimension for %s", "normals"), domain = NA) flags[3] <- TRUE } nulls <- c(is.null(texture_s), is.null(texture_t)) if (!all( nulls ) ) { if (any( nulls )) stop("Both texture coordinates must be supplied") if ( !identical(dim(z), dim(texture_s)) || !identical(dim(z), dim(texture_t)) ) stop(gettextf("Bad dimension for %s", "textures"), domain = NA) flags[4] <- TRUE } idata <- as.integer( c( nrows, ncols ) ) xdecreasing <- diff(x[!is.na(x)][1:2]) < 0 ydecreasing <- diff(y[!is.na(y)][1:2]) < 0 parity <- (perm_parity(coords) + xdecreasing + ydecreasing + flip) %% 2 if (is.na(parity)) parity <- 0 ret <- .C( rgl_surface, success = as.integer(FALSE), idata, as.numeric(x), as.numeric(y), as.numeric(z), as.numeric(normal_x), as.numeric(normal_y), as.numeric(normal_z), as.numeric(texture_s), as.numeric(texture_t), as.integer(coords), as.integer(parity), as.integer(flags), NAOK=TRUE ) if (! ret$success) stop("'rgl_surface' failed") lowlevel(ret$success) } terrain3d <- surface3d # Interaction select3d <- function(button = c("left", "middle", "right"), dev = cur3d(), subscene = currentSubscene3d(dev)) { .check3d() rect <- rgl.select(button = button, dev = dev, subscene = subscene) if (is.null(rect)) return(NULL) proj <- rgl.projection(dev = dev, subscene = subscene) llx <- rect[1] lly <- rect[2] urx <- rect[3] ury <- rect[4] selectionFunction3d(proj, region = c(llx, lly, urx, ury)) } # 3D Generic Object Rendering Attributes dot3d <- function(x,...) UseMethod("dot3d") wire3d <- function(x,...) UseMethod("wire3d") shade3d <- function(x,...) UseMethod("shade3d") # 3D Generic transformation translate3d <- function(obj,x,y,z,...) UseMethod("translate3d") scale3d <- function(obj,x,y,z,...) UseMethod("scale3d") rotate3d <- function(obj,angle,x,y,z,matrix,...) UseMethod("rotate3d") transform3d <- function(obj,matrix,...) rotate3d(obj, matrix = matrix, angle = NA, x = NA, y = NA, z = NA) subdivision3d <- function(x,...) UseMethod("subdivision3d") # 3D Custom shapes particles3d <- function(x,y=NULL,z=NULL,radius=1,...) sprites3d( x=x,y=y,z=z,radius=radius, lit=FALSE,alpha=0.2, textype="alpha", texture=system.file("textures/particle.png",package="rgl"), ... ) # r3d default settings for new windows r3dDefaults <- list(userMatrix = rotationMatrix(290*pi/180, 1, 0, 0), mouseMode = c("none", "trackball", "zoom", "fov", "pull"), FOV = 30, bg = list(color="white",fogtype = "none"), family = "sans", material = list(color="black", fog = TRUE)) if (.Platform$OS.type == "windows") r3dDefaults$useFreeType <- FALSE open3d <- function(..., params = getr3dDefaults(), useNULL = rgl.useNULL(), silent = FALSE ) { register_pkgdown_methods() args <- list(...) if (missing(useNULL) && !is.null(params$useNULL)) { useNULL <- params$useNULL params$useNULL <- NULL } if (missing(silent) && !is.null(params$silent)) { silent <- params$silent params$silent <- NULL } antialias <- -1L if (!is.null(args$antialias) || !is.null(args$antialias <- r3dDefaults$antialias)) { saveopt <- options(rgl.antialias = args$antialias) antialias <- args$antialias on.exit(options(saveopt)) args$antialias <- NULL } ret <- .C( rgl_dev_open, success=FALSE, useNULL=useNULL, antialias = as.integer(antialias)) if (! ret$success) stop("open failed") if (!is.null(args$material)) { params$material <- do.call(.fixMaterialArgs, c(args$material, Params=list(params$material))) args$material <- NULL } if (length(args) && (is.null(names(args)) || any(nchar(names(args)) == 0))) stop("open3d parameters must be named") params[names(args)] <- args clear3d("material", defaults = params) params$material <- NULL if (!is.null(params$bg)) { do.call("bg3d", params$bg) params$bg <- NULL } do.call("par3d", params) result <- structure(cur3d(), class = "rglOpen3d") if (silent) invisible(result) else result } print.rglOpen3d <- function(x, ...) { print(unclass(x)) } close3d <- function(dev = cur3d(), silent = TRUE) { for (d in dev[dev != 0]) { devname <- paste0("dev", d) rgl.callback.env[[devname]] <- NULL set3d(d, silent = silent) if (length(hook <- getHook("on.rgl.close"))) { if (is.list(hook)) hook <- hook[[1]] # test is for compatibility with R < 3.0.0 hook() } ret <- .C( rgl_dev_close, success=FALSE ) if (! ret$success) stop("close failed") if (!silent) message("Closed device ", d) } invisible(cur3d()) } cur3d <- function() .Call( rgl_dev_getcurrent ) rgl.cur <- cur3d set3d <- function(dev, silent = FALSE) { prev <- cur3d() idata <- c( as.integer(dev), as.integer(silent) ) ret <- .C( rgl_dev_setcurrent, success=FALSE, idata ) if (! ret$success) stop(gettextf("No device opened with id %s", dev), domain = NA) prev } .check3d <- function() { if (result<-cur3d()) return(result) else return(open3d()) } requireWebshot2 <- function() { suppressMessages(res <- requireNamespace("webshot2", quietly = TRUE)) if (res) res <- requireNamespace("chromote") && !is.null(path <- chromote::find_chrome()) && nchar(path) > 0 && file.exists(path) res } snapshot3d <- function(filename = tempfile(fileext = ".png"), fmt = "png", top = TRUE, ..., scene, width = NULL, height = NULL, webshot = as.logical(Sys.getenv("RGL_USE_WEBSHOT", "TRUE"))) { force(filename) if (webshot && !requireWebshot2()) { warning("webshot = TRUE requires the webshot2 package and Chrome browser; using rgl.snapshot() instead") webshot <- FALSE } saveopts <- options(rgl.useNULL = webshot) on.exit(options(saveopts)) # The logic here is a little convoluted: # scene resize webshot getscene1 plot resize getscene2 # no no no # no no yes X # no yes no X # no yes yes X X X X # yes no no X # yes no yes # yes yes no X X # yes yes yes X X X resize <- !is.null(width) || !is.null(height) havescene <- !missing(scene) if (havescene) { if (inherits(scene, "rglWebGL")) { snapshot <- scene$x$snapshot if (!is.null(snapshot) && is.null(width) && is.null(height)) return(saveURI(snapshot, filename)) else scene <- attr(scene, "origScene") } } if (!havescene && webshot) scene <- scene3d() if ((!havescene && resize && webshot) || (havescene && (resize || !webshot))) { open3d() plot3d(scene) on.exit(close3d(), add = TRUE) } if (resize) { saverect <- rect <- par3d("windowRect") on.exit(par3d(windowRect = saverect), add = TRUE) if (!is.null(width)) rect[3] <- rect[1] + width if (!is.null(height)) rect[4] <- rect[2] + height par3d(windowRect = rect) } if (webshot) { if (resize) scene <- scene3d() rect <- par3d("windowRect") f1 <- tempfile(fileext = ".html") # Work around path issue in webshot2: f1 <- normalizePath(f1, winslash = "/", mustWork = FALSE) on.exit(unlink(f1), add = TRUE) width <- rect[3] - rect[1] height <- rect[4] - rect[2] saveWidget(rglwidget(scene, elementId = "webshot", width = width, height = height, webgl = TRUE), f1, selfcontained = FALSE) unlink(filename) res <- try(capture.output(webshot2::webshot(f1, file = filename, selector = "#webshot", vwidth = width + 100, vheight = height, ...), type = "message")) if (!inherits(res, "try-error") && file.exists(filename) && file.size(filename) > 0) return(invisible(filename)) warning("webshot2::webshot() failed; trying rgl.snapshot()") } rgl.snapshot(filename, fmt, top) } rgl.incrementID <- function(n = 1L) { .C(rgl_incrementID, n = as.integer(n))$n } rgl/R/rglwidget.R0000644000176200001440000004517215011677075013374 0ustar liggesusers rmarkdownOutput <- function() { if (requireNamespace("rmarkdown", quietly = TRUE)) { output <- rmarkdown::metadata$output if (length(output)) if (is.character(output)) return(output[1]) else if (is.list(output) && length(names(output))) return(names(output)[1]) } NULL } rglShared <- function(id, key = NULL, group = NULL, deselectedFade = 0.1, deselectedColor = NULL, selectedColor = NULL, selectedIgnoreNone = TRUE, filteredFade = 0, filteredColor = NULL) { if (!requireNamespace("crosstalk")) stop("This function requires crosstalk.") data <- as.data.frame(rgl.attrib(id, "vertices")) attr(data, "rglId") <- as.integer(id) attr(data, "rglOptions") <- list(deselectedFade = deselectedFade, deselectedColor = if (!is.null(deselectedColor)) as.numeric(col2rgb(deselectedColor, alpha = TRUE)/255), selectedColor = if (!is.null(selectedColor)) as.numeric(col2rgb(selectedColor, alpha = TRUE)/255), selectedIgnoreNone = selectedIgnoreNone, filteredFade = filteredFade, filteredColor = if (!is.null(filteredColor)) as.numeric(col2rgb(filteredColor, alpha = TRUE)/255)) n <- nrow(data) if (!n) stop("No vertices in object ", id) if (!is.null(key) && (n != length(key) || anyDuplicated(key))) stop("'key' must have exactly one unique value for each vertex") result <- if (is.null(group)) crosstalk::SharedData$new(data, key) else crosstalk::SharedData$new(data, key, group) structure(result, class = c("rglShared", class(result))) } CSStoPixels <- function(x, DPI = 100) { if (is.null(x)) return(x) num <- function(x) as.numeric(sub("[^[:digit:].]*$", "", x)) units <- function(x) sub("^[[:digit:].]+", "", x) if (!is.numeric(x)) { units <- units(x) if (units == "auto") stop("Only fixed CSS sizes allowed") val <- num(x) if (units != "") val <- switch(units, "px" = val, "in" = val * DPI, "cm" = val * DPI / 2.54, "mm" = val * DPI / 254, "pt" = val * DPI / 72, "pc" = val * DPI / 6, stop("Only fixed CSS sizes allowed") ) } else val <- x val } # These sizes are taken from htmlwidgets/R/sizing.R DEFAULT_WIDTH <- 960 DEFAULT_HEIGHT <- 500 DEFAULT_PADDING <- 40 DEFAULT_WIDTH_VIEWER <- 450 DEFAULT_HEIGHT_VIEWER <- 350 DEFAULT_PADDING_VIEWER <- 15 # For widgets, we use the sizingPolicy to see how it would be # displayed resolveHeight <- function(x, inViewer = TRUE, default = 40) { if (inViewer) refsize <- DEFAULT_HEIGHT_VIEWER else refsize <- DEFAULT_HEIGHT result <- x$height if (is.null(result) && !is.null(policy <- x$sizingPolicy)) { if (inViewer) { viewer <- policy$viewer if (isTRUE(viewer$fill)) result <- refsize else result <- viewer$defaultHeight } else result <- NULL if (is.null(result) && isTRUE(policy$fill)) result <- refsize if (is.null(result)) result <- policy$defaultHeight if (is.null(result)) result <- refsize } if (is.null(result)) result <- default CSStoPixels(result, refsize) } getWidgetId <- function(widget) { if (inherits(widget, "htmlwidget")) widget$elementId else { NULL } } # Get information from previous objects being piped into # this one, and modify a copy of them as necessary getHeights <- function(objects, defaultHeight = 40) { if (inherits(objects, "combineWidgets")) heights <- objects$params$rowsize else { if (inherits(objects, c("shiny.tag", "htmlwidget")) || !is.list(objects)) objects <- tagList(objects) heights <- rep(defaultHeight, length(objects)) for (i in seq_along(objects)) { tag <- objects[[i]] if (inherits(tag, "rglWebGL") && is.null(tag$height)) heights[i] <- tag$x$height else if (inherits(tag, "htmlwidget")) heights[i] <- resolveHeight(tag) else if (is.list(tag) && !is.null(tag$height) && !is.na(height <- suppressWarnings(as.numeric(tag$height)))) heights[i] <- height } } heights } processUpstream <- function(upstream, elementId = NULL, playerId = NULL) { rowsizes <- getHeights(upstream) if (inherits(upstream, "combineWidgets")) upstream <- upstream$widgets if (inherits(upstream, "knit_image_paths") && length(upstream)) upstream <- img(src = image_uri(upstream[1])) if (inherits(upstream, c("shiny.tag", "htmlwidget"))) upstream <- tagList(upstream) if (is.character(upstream) && !is.na(upstream[1])) return(list(prevRglWidget = upstream)) if (is.list(upstream)) { # Objects upstream of the current one may need to know about an rgl widget, # or this object may need to know about an upstream rgl widget. Stop when # you find one. lookForRglWidget <- function(upstream) { prevRglWidget <- NULL players <- character() for (i in rev(seq_along(upstream))) { tag <- upstream[[i]] if (inherits(tag, "rglWebGL")) { prevRglWidget <- tag$elementId if (is.null(prevRglWidget)) prevRglWidget <- tag$elementId <- upstream[[i]]$elementId <- newElementId("rgl") if (!is.null(playerId) && !(playerId %in% tag$x$players)) upstream[[i]]$x$players <- c(tag$x$players, playerId) } else if (inherits(tag, "rglPlayer") && is.null(tag$x$sceneId)) { players <- c(players, tag$elementId) if (!is.null(elementId)) upstream[[i]]$x$sceneId <- elementId } else if (inherits(tag, "shiny.tag") && !tagHasAttribute(tag, "rglSceneId")) { upstream[[i]] <- tagAppendAttributes(tag, rglSceneId = elementId) } else if (inherits(tag, "combineWidgets")) { temp <- lookForRglWidget(tag$widgets) players <- c(players, temp$players) prevRglWidget <- temp$prevRglWidget upstream[[i]]$widgets <- temp$objects } if (!is.null(prevRglWidget)) break } list(objects = upstream, players = players, prevRglWidget = prevRglWidget) } result <- lookForRglWidget(upstream) result$rowsizes <- rowsizes } else result <- list(objects = upstream, players = if (is.character(upstream)) upstream else character(), prevRglWidget = if (is.character(upstream)) upstream, rowsizes = rowsizes) result } asRow <- function(..., last = NA, height = NULL, colsize = 1) { if (!requireNamespace("manipulateWidget", quietly = TRUE)) { warning("asRow requires the 'manipulateWidget' package.", call. = FALSE) last <- NA } args <- list(...) if ((length(args) == 1 && inherits(args[[1]], "combineWidgets")) || !requireNamespace("manipulateWidget", quietly = TRUE)) { orig <- args[[1]] } else { orig <- do.call(manipulateWidget::combineWidgets, c(args, list(ncol = 1, rowsize = getHeights(args)))) } origlen <- length(orig$widgets) for (i in seq_len(origlen)) if (inherits(orig$widgets[[i]], "knit_image_paths")) orig$widgets[[i]] <- img(src = image_uri(orig$widgets[[i]])) if (is.na(last)) last <- origlen else if (last > origlen) stop("'last' must be no more than the number of widgets") keep <- seq_len(origlen - last) inrow <- seq_len(last) + origlen - last origRowsizes <- rep_len(orig$params$rowsize, origlen) if (length(inrow)) { maxinrow <- max(origRowsizes[inrow]) if (is.null(height)) height <- maxinrow } else if (is.null(height)) height <- 0 orig$params$rowsize <- c(origRowsizes[keep], height) if (requireNamespace("manipulateWidget", quietly = TRUE)) { row <- do.call(manipulateWidget::combineWidgets, c(orig$widgets[inrow], list(nrow = 1, colsize = colsize))) orig$widgets <- c(orig$widgets[keep], list(row)) } orig } newElementId <- function(prefix) paste0(prefix, p_sample(100000, 1)) isMarkdownHTMLformat <- function() { output <- rmarkdown::metadata$output if (is.list(output)) output <- names(output) is.character(output) && length(output) >= 1 && output[1] == "markdown::html_format" } knitrNeedsSnapshot <- function(options = knitr::opts_current$get()) { if (!is.null(options$snapshot)) return(options$snapshot) if (isFALSE(options$screenshot.force)) return(FALSE) force <- isTRUE(options$screenshot.force) if (isMarkdownHTMLformat()) return(FALSE) fmt <- pandoc_to() if (!length(fmt) || force) return(TRUE) html_format <- fmt %in% c("html", "html4", "html5", "revealjs", "s5", "slideous", "slidy") !html_format } rglwidget <- local({ function(x = scene3d(minimal), width = figWidth(), height = figHeight(), controllers = NULL, elementId = NULL, reuse = FALSE, webGLoptions = list(preserveDrawingBuffer = TRUE), shared = NULL, minimal = TRUE, webgl, snapshot, shinyBrush = NULL, altText = "3D plot", ..., oldConvertBBox = FALSE, fastTransparency = getOption("rgl.fastTransparency", TRUE)) { if (missing(snapshot)) { if (missing(webgl)) { if (in_knitr()) snapshot <- knitrNeedsSnapshot() else snapshot <- FALSE } else snapshot <- !webgl } else { if (!is.logical(snapshot)) { stop("snapshot must be TRUE or FALSE") } } if (missing(webgl)) webgl <- !snapshot if (webgl == snapshot || is.na(webgl) || is.na(snapshot)) stop("Must specify either 'snapshot' or 'webgl' but not both") origScene <- x force(shared) # It might plot something... if (is.null(elementId) && (!inShiny() || # If in Shiny, all of the classes below need the ID inherits(controllers, c("combineWidgets", "shiny.tag", "htmlwidget")))) elementId <- newElementId("rgl") if (!is.null(shinyBrush)) { if (!is.character(shinyBrush) || length(shinyBrush) != 1) stop("'shinyBrush' must be a single character value") if (!inShiny()) warning("'shinySelectionInput' is only used in Shiny") else x$selectionInput <- shinyBrush } if (!inherits(x, "rglscene")) stop("First argument should be an rgl scene.") if (!is.null(shared) && !is.list(shared)) shared <- list(shared) if (length(shared) && !requireNamespace("crosstalk", quietly = TRUE)) stop("'shared' requires the crosstalk package.") dependencies <- list(rglDependency, CanvasMatrixDependency) if (length(shared) && isNamespaceLoaded("crosstalk")) { x$crosstalk <- list(key = vector("list", length(shared)), group = character(length(shared)), id = integer(length(shared)), options = vector("list", length(shared))) dependencies <- c(dependencies, crosstalk::crosstalkLibs()) } else { x$crosstalk <- list(key = list(), group = character(), id = integer(), options = list()) } for (i in seq_along(shared)) { s <- shared[[i]] if (crosstalk::is.SharedData(s) && inherits(s, "rglShared")) { x$crosstalk$key[[i]] <- s$key() x$crosstalk$group[i] <- s$groupName() x$crosstalk$id[i] <- attr(s$origData(), "rglId") x$crosstalk$options[[i]] <- attr(s$origData(), "rglOptions") } else if (!is.null(s)) stop("'shared' must be an object produced by rglShared() or a list of these") } if (!is.null(width)) width <- CSStoPixels(width) if (!is.null(height)) height <- CSStoPixels(height) x <- convertScene(x, width, height, elementId = elementId, webgl = webgl, snapshot = snapshot, oldConvertBBox = oldConvertBBox) upstream <- processUpstream(controllers, elementId = elementId) if (webgl) { x$vertexShader <- paste(readLines(system.file("htmlwidgets/lib/rglClass/shaders/rgl_vertex.glsl", package = "rgl")), collapse = "\n") x$fragmentShader <- paste(readLines(system.file("htmlwidgets/lib/rglClass/shaders/rgl_fragment.glsl", package = "rgl")), collapse = "\n") x$players <- upstream$players x$webGLoptions <- webGLoptions x$fastTransparency <- fastTransparency if (inShiny()) x$altText <- altText # create widget attr(x, "TOJSON_ARGS") <- list(na = "string") result <- structure(htmlwidgets::createWidget( name = 'rglWebGL', x = x, width = width, height = height, package = 'rgl', elementId = elementId, dependencies = dependencies, ... ), origScene = origScene) # We always emit aria-labelledby. We need to # choose here whether to write the label, or rely # on other code to write it. We let other code write it # in new knitr and Shiny, and otherwise do it ourselves. if (!in_knitr_with_altText_support() && !inShiny()) result <- htmlwidgets::prependContent(result, tags$p(altText, id = ariaLabelId(elementId), hidden = NA)) } else { if (is.list(upstream$objects)) { result <- img(src = image_uri(x), width = width, height = height) } else result <- x } if (is.list(upstream$objects)) { if (requireNamespace("manipulateWidget", quietly = TRUE)) result <- do.call(manipulateWidget::combineWidgets, c(upstream$objects, list(result, rowsize = c(upstream$rowsizes, height), ncol = 1))) else warning("Combining widgets requires the 'manipulateWidget' package.", call. = FALSE) } result }}) ariaLabelId <- function(id) paste0(id, "-aria") widget_html.rglWebGL <- function(id, style, class, ...){ result <- tags$div(id = id, style = style, class = class, role = "img", "aria-labelledby" = ariaLabelId(id)) # In shiny, we need to write the alt text label. if (inShiny()) result <- tags$div(tags$p("3D plot 1", id = ariaLabelId(id), hidden = NA), result) result } print.rglMouseSelection <- function(x, verbose = FALSE, ...) { if (!is.null(x$region)) { cat("Mouse selection:\n") if (verbose) { cat("p1=[", x$region[1], ",", x$region[2], "] p2=[", x$region[3], ",", x$region[4],"]\n") cat("Projection data included: ", !is.null(x$model) && !is.null(x$proj) && !is.null(x$view), "\n") } } else cat("Inactive mouse selection.\n") invisible(x) } # Create the local dependencies makeDependency <- function(name, src, script = NULL, package, version = packageVersion(package), minifile = paste0(basename(src), ".min.js"), debugging = FALSE, ...) { javascript <- vapply(script, function(x) !is.list(x), FALSE) if (any(javascript) && requireNamespace("js", quietly = TRUE) && packageVersion("js") >= "1.2") { if (debugging) { for (f in script[javascript]) { hints <- js::jshint(readLines(file.path(system.file(src, package = package), f)), undef = TRUE, bitwise = TRUE, eqeqeq = TRUE, latedef = TRUE, browser = TRUE, devel = TRUE, globals = list(CanvasMatrix4 = FALSE, WebGLFloatArray = FALSE, rglwidgetClass = FALSE, rgltimerClass = FALSE, Shiny = FALSE )) for (i in seq_len(NROW(hints))) warning(f, "#", hints[i, "line"], ": ", hints[i, "reason"], call. = FALSE, immediate. = TRUE) } } minified <- js::uglify_files(file.path(system.file(src, package = package), script[javascript])) writeLines(minified, file.path(system.file(src, package = package), minifile)) if (!debugging) script <- c(minifile, script[!javascript]) } htmlDependency(name = name, src = src, package = package, version = version, script = script, all_files = FALSE, ...) } CanvasMatrixDependency <- makeDependency("CanvasMatrix4", src = "htmlwidgets/lib/CanvasMatrix", script = "CanvasMatrix.src.js", package = "rgl", debugging = isTRUE(as.logical(Sys.getenv("RGL_DEBUGGING", "FALSE")))) local({ shaders <- c('rglwidgetClass.rgl_vertex_shader = function() {', paste('return ', paste0('"', readLines(system.file("htmlwidgets/lib/rglClass/shaders/rgl_vertex.glsl", package = "rgl")), '\\n"', collapse = "+\n"), ';};'), 'rglwidgetClass.rgl_fragment_shader = function() {', paste('return ', paste0('"', readLines(system.file("htmlwidgets/lib/rglClass/shaders/rgl_fragment.glsl", package = "rgl")), '\\n"', collapse = "+\n"), ';};')) writeLines(paste(shaders, collapse = "\n"), file.path(system.file("htmlwidgets/lib/rglClass", package = "rgl"), "shadersrc.src.js")) }) rglDependency <- makeDependency("rglwidgetClass", src = "htmlwidgets/lib/rglClass", script = c("rglClass.src.js", "utils.src.js", "buffer.src.js", "subscenes.src.js", "shaders.src.js", "shadersrc.src.js", "textures.src.js", "projection.src.js", "mouse.src.js", "init.src.js", "pieces.src.js", "draw.src.js", "controls.src.js", "selection.src.js", "rglTimer.src.js", "pretty.src.js", "axes.src.js", "animation.src.js"), stylesheet = "rgl.css", package = "rgl", debugging = isTRUE(as.logical(Sys.getenv("RGL_DEBUGGING", "FALSE")))) image_uri <- function(filename) { paste0("data:", mime::guess_type(filename), ";base64,", base64encode(filename)) } rgl/R/drape3d.R0000644000176200001440000001266214771520323012717 0ustar liggesusersdrape3d <- function(obj, ...) UseMethod("drape3d") drape3d.default <- function(obj, ...) drape3d(as.mesh3d(obj), ...) drape3d.mesh3d <- function(obj, x, y = NULL, z = NULL, plot = TRUE, up = c(0, 0, 1), P = projectDown(up), ...) { # Takes segment number as input; returns # NULL if in no triangle, otherwise matrix of projected locations and triangle numbers. ztri <- function(i) { p <- psegs[,i] oo <- p[1] < TRI[1,1,] | p[1] > TRI[2,1,] | p[2] < TRI[1,2,] | p[2] > TRI[2,2,] result <- NULL lam <- numeric(3) for(j in which(!oo)) { ## get barycentric coords of p in projected triangle v <- pverts[,obj$it[,j]] ## v[i,] vertices of projected triangle i D <- (v[2,2]-v[2,3]) * (v[1,1]-v[1,3]) + (v[1,3]-v[1,2]) * (v[2,1]-v[2,3]) if (D == 0) next l <- (v[2,2]-v[2,3]) * (p[1] -v[1,3]) + (v[1,3]-v[1,2]) * (p[2] -v[2,3]) lam[1] <- l/D if (lam[1] < 0 || lam[1] > 1) next ## not in this triangle l <- (v[2,3]-v[2,1]) * (p[1] -v[1,3]) + (v[1,1]-v[1,3]) * (p[2] -v[2,3]) lam[2] <- l/D if (lam[2] < 0 || lam[2] > 1) next ## not in this triangle lam[3] <- 1-sum(lam[1:2]) if (lam[3] < 0 || lam[3] > 1) next ## not in this triangle v <- matrix(verts[,obj$it[,j]], 3,3) ## Now v is vertices of original triangle result <- rbind(result, c(v %*% lam, j)) } result } op <- function(v) v[if(v[1] > v[2]) c(2,1) else c(1,2)] ## orders pair obj <- as.tmesh3d(obj) verts <- obj$vb segs <- xyz.coords(x, y, z, recycle=TRUE) segs <- rbind(segs$x, segs$y, segs$z, 1) if (length(dim(P)) != 2 || !all(dim(P) == 4)) stop("P should be a homogeneous coordinate matrix.") P <- t(P) # The convention in rgl is row vectors on the left # but we'll be using column vectors on the right # Project the vertices, then get 1st two Euclidean coords pverts <- P %*% verts pverts <- pverts[1:2,]/rep(pverts[4,], each = 2) # and switch verts to Euclidean: verts <- verts[1:3,]/rep(verts[4,], each = 3) psegs <- P %*% segs # projected segments psegs <- psegs[1:2,]/rep(psegs[4,], each = 2) ## get unique point pairs making a triangle side tri <- matrix(NA,nrow=3*ncol(obj$it),ncol=2) n <- 0 for (j in seq_len(ncol(obj$it))) { v <- obj$it[,j] tri[n<-n+1,] <- v[c(1,2)] tri[n<-n+1,] <- v[c(2,3)] tri[n<-n+1,] <- v[c(3,1)] } TRI <- array(NA,c(2,2,ncol(obj$it))) for(j in seq_len(ncol(obj$it))) { v <- obj$it[,j] ## vertices of triangle TRI[,,j] <- matrix(c(range(pverts[1,v]),range(pverts[2,v])),2,2) } ## now TRI[,1,i] is x coord range for projected triangle i ## now TRI[,2,i] is y coord range for projected triangle i result <- matrix(numeric(), ncol = 3) p2 <- NA p2tri <- NULL for (i in seq_len(ncol(psegs))) { p1 <- p2 p1tri <- p2tri if (!length(p1tri)) zs <- NULL else zs <- cbind(p1tri, 0) # First point p2 <- psegs[,i] if (any(is.na(p2))) { p2tri <- NULL next } else { p2tri <- ztri(i) zs <- rbind(zs, cbind(p2tri, 1)) # Last point } if (any(is.na(p1))) next ## add middle points p21 <- p2 - p1 s <- matrix(c(p1,p2),2,2) ## speedup: winnow futile intersection calcs s <- t(apply(s,1,op)) ## triangle seg x extent is all below or above line seg x extent sx <- (pverts[1,tri[,1]] < s[1,1] & pverts[1,tri[,2]] < s[1,1]) | (pverts[1,tri[,1]] > s[1,2] & pverts[1,tri[,2]] > s[1,2]) ## triangle seg y extent is all below or above line seg y extent sy <- (pverts[2,tri[,1]] < s[2,1] & pverts[2,tri[,2]] < s[2,1]) | (pverts[2,tri[,1]] > s[2,2] & pverts[2,tri[,2]] > s[2,2]) for(j in which(!sx & !sy)) { ## possible intersections p3 <- pverts[,tri[j,1]] p4 <- pverts[,tri[j,2]] p43 <- p4-p3 p31 <- p3-p1 D <- -p21[1]*p43[2] + p21[2]*p43[1] if (D == 0) next ## parallel line segs T1<- -p31[1]*p43[2] + p31[2]*p43[1] t1 <- T1/D if (t1 < 0 || t1 > 1) next ## not within p1 ... p2 T2<- p21[1]*p31[2] - p21[2]*p31[1] t2 <- T2/D if (t2 < 0 || t2 > 1) next ## not within p3 ... p4 v3 <- verts[,tri[j,1]] v43 <- verts[,tri[j,2]] - v3 k <- (j+2)%/%3 # triangle number zs <- rbind(zs, c(v3+t2*v43, k, t1))## t1 along line seg & point value } if (length(zs)) { # Order by triangle to group them, then by t # within triangle o <- order(zs[,4], zs[,5]) zs <- zs[o, , drop = FALSE] # Only keep cases that are on the same triangle # Rounding may give us 1 or 3 intersections with a # triangle; discard singletons, use first and last # for triples. k <- zs[,4] dup <- duplicated(k) nextdup <- c(dup[-1], FALSE) keep <- xor(dup, nextdup) # The first or last for a triangle zs <- zs[keep,,drop = FALSE] # Order by t value finish <- 2*seq_len(nrow(zs)/2) start <- finish - 1 o <- order(zs[start, 5]) start <- start[o] finish <- finish[o] # Drop zero length segments keep <- zs[start, 5] < zs[finish, 5] start <- start[keep] finish <- finish[keep] both <- as.numeric(rbind(start, finish)) result <- rbind(result, zs[both, -(4:5), drop = FALSE]) } } if (plot) segments3d(result, ...) else result } rgl/R/pkgchecks.R0000644000176200001440000000055414771520323013334 0ustar liggesusers# Suggested package checks checkDeldir <- function(error = FALSE) { result <- requireNamespace("deldir", quietly = TRUE) && (packageVersion("deldir") < "1.0.2" || packageVersion("deldir") >= "1.0.4") if (error && !result) stop("This function requires the 'deldir' package (but is not compatible with version 1.0-2).", call. = FALSE) result } rgl/R/callbacks.R0000644000176200001440000000242114771520323013304 0ustar liggesusersrgl.setMouseCallbacks <- function(button, begin=NULL, update=NULL, end=NULL, dev = cur3d(), subscene = currentSubscene3d(dev)) { invisible(.Call(rgl_setMouseCallbacks, as.integer(button), begin, update, end, as.integer(dev), as.integer(subscene))) } rgl.getMouseCallbacks <- function(button, dev = cur3d(), subscene = currentSubscene3d(dev)) .Call(rgl_getMouseCallbacks, as.integer(button), as.integer(dev), as.integer(subscene)) rgl.setWheelCallback <- function(rotate=NULL, dev = cur3d(), subscene = currentSubscene3d(dev)) { invisible(.Call(rgl_setWheelCallback, rotate, as.integer(dev), as.integer(subscene))) } rgl.getWheelCallback <- function(dev = cur3d(), subscene = currentSubscene3d(dev)) .Call(rgl_getWheelCallback, as.integer(dev), as.integer(subscene)) rgl.setAxisCallback <- function(axis, draw = NULL, dev = cur3d(), subscene = currentSubscene3d(dev)) { .Deprecated("setAxisCallbacks") stopifnot(length(axis) == 1, axis %in% 1:3) .Call(rgl_setAxisCallback, draw, as.integer(dev), as.integer(subscene), as.integer(axis - 1)) invisible(NULL) } rgl.getAxisCallback <- function(axis, dev = cur3d(), subscene = currentSubscene3d(dev)) { .Call(rgl_getAxisCallback, as.integer(dev), as.integer(subscene), as.integer(axis - 1)) } rgl/R/device.R0000644000176200001440000000641715011677075012642 0ustar liggesusers## ## R source file ## This file is part of rgl ## ## ## ## ===[ SECTION: device management ]========================================== ## rgl.useNULL <- function() { if (noOpenGL) return(TRUE) opt <- getOption("rgl.useNULL", Sys.getenv("RGL_USE_NULL")) if (is.logical(opt)) return(opt) opt <- as.character(opt) if (nchar(opt)) { opt <- pmatch(tolower(opt), c("yes", "true"), nomatch=3) return(c(TRUE, TRUE, FALSE)[opt]) } FALSE } ## ## open device ## ## rgl.open <- function(useNULL = rgl.useNULL()) { .Deprecated("open3d") ret <- .C( rgl_dev_open, success=FALSE, useNULL=useNULL, antialias = as.integer(getOption("rgl.antialias", -1L))) if (! ret$success) stop("'rgl.open' failed") } ## ## close device ## ## rgl.close <- function() { .Deprecated("close3d") if (length(hook <- getHook("on.rgl.close"))) { if (is.list(hook)) hook <- hook[[1]] # test is for compatibility with R < 3.0.0 hook() } ret <- .C( rgl_dev_close, success=FALSE ) if (! ret$success) stop("No device opened") } ## ## get all devices ## ## rgl.dev.list <- function() .Call( rgl_dev_list ) ## ## set current device ## ## rgl.set <- function(which, silent = FALSE) { .Deprecated("set3d") idata <- c( as.integer(which), as.integer(silent) ) ret <- .C( rgl_dev_setcurrent, success=FALSE, idata ) if (! ret$success) stop(gettextf("No device opened with id %s", which), domain = NA) } ## ## export image ## ## rgl.snapshot <- function( filename, fmt="png", top=TRUE ) { if (top) rgl.bringtotop() idata <- as.integer(rgl.enum.pixfmt(fmt)) if (length(filename) != 1) stop("filename is length ", length(filename)) filename <- normalizePath(filename, mustWork = FALSE) ret <- .C( rgl_snapshot, success=FALSE, idata, filename ) if (! ret$success) warning("'rgl.snapshot' failed") invisible(filename) } ## ## export postscript image ## ## rgl.postscript <- function( filename, fmt="eps", drawText=TRUE ) { idata <- as.integer(c(rgl.enum.gl2ps(fmt), as.logical(drawText))) if (length(filename) != 1) stop("filename is length ", length(filename)) ret <- .C( rgl_postscript, success=FALSE, idata, normalizePath(filename, mustWork = FALSE, winslash = "/") ) if (! ret$success) warning("Postscript conversion failed") } ## ## read image ## ## rgl.pixels <- function(component = c("red", "green", "blue"), viewport = par3d("viewport"), top=TRUE ) { if (top) rgl.bringtotop() compnum <- as.integer(sapply(component, rgl.enum.pixelcomponent)) stopifnot(length(viewport) == 4) ll <- as.integer(viewport[1:2]) stopifnot(all(!is.na(ll)), all(ll >= 0)) size <- as.integer(viewport[3:4]) stopifnot(all(!is.na(size), all(size >= 0))) result <- array(NA_real_, dim=c(size[1], size[2], length(component))) dimnames(result) <- list(NULL, NULL, component) if (length(result) > 0) for (i in seq_along(compnum)) { ret <- .C( rgl_pixels, success=FALSE, ll, size, compnum[i], values = double(size[1]*size[2])) if (! ret$success) warning(gettextf("Error reading component '%s'", component[i]), domain = NA) result[,,i] <- ret$values } if (length(component) > 1) return(result) else return(result[,,1]) } rgl/R/tkspin3d.R0000644000176200001440000001563214771520323013134 0ustar liggesusers tkspinControl <- function(base, dev = cur3d(), continue=FALSE, speed=30, scale=100, ...) { if (!requireNamespace("tcltk", quietly = TRUE)) stop("This function requires 'tcltk'.") slider <- tcltk::tclVar(speed) getZooms <- function() { old <- cur3d() on.exit(set3d(old)) result <- numeric(max(dev)) for (device in dev) { set3d(device) result[device] <- par3d("zoom") } result } zooms <- getZooms() scale <- tcltk::tclVar(scale) continuous <- tcltk::tclVar(as.numeric(continue)) buttonPress <- NULL direction <- NULL lastTime <- proc.time()[3] timeDiff <- 0 rotateUp <- function() { angle <- timeDiff*as.numeric(tcltk::tclObj(slider))*pi/180 par3d(userMatrix = rotationMatrix(-angle, 1,0,0) %*% par3d("userMatrix")) } rotateLeft <- function() { angle <- timeDiff*as.numeric(tcltk::tclObj(slider))*pi/180 par3d(userMatrix = rotationMatrix(-angle, 0,1,0) %*% par3d("userMatrix")) } rotateRight <- function() { angle <- timeDiff*as.numeric(tcltk::tclObj(slider))*pi/180 par3d(userMatrix = rotationMatrix(angle, 0,1,0) %*% par3d("userMatrix")) } rotateSpin <- function() { angle <- timeDiff*as.numeric(tcltk::tclObj(slider))*pi/180 par3d(userMatrix = rotationMatrix(-angle, 0,0,1) %*% par3d("userMatrix")) } rotateDown <- function() { angle <- timeDiff*as.numeric(tcltk::tclObj(slider))*pi/180 par3d(userMatrix = rotationMatrix(angle, 1,0,0) %*% par3d("userMatrix")) } rotate <- function() { old <- cur3d() on.exit(set3d(old)) if (buttonPress) { if ((currentTime <- proc.time()[3]) > lastTime) { timeDiff <<- currentTime - lastTime lastTime <<- currentTime for (device in dev) { set3d(device) if (direction == "up") rotateUp() if (direction == "left") rotateLeft() if (direction == "spin") rotateSpin() if (direction == "right") rotateRight() if (direction == "down") rotateDown() } } tcltk::tcl("after",5,rotate) } } # rotation button callback functions # note that "..." argument is necessary upButtonPress <- function(...) { buttonPress <<- TRUE lastTime <<- proc.time()[3] direction <<- "up" rotate() } leftButtonPress <- function(...) { buttonPress <<- TRUE lastTime <<- proc.time()[3] direction <<- "left" rotate() } spinButtonPress <- function(...) { buttonPress <<- TRUE lastTime <<- proc.time()[3] direction <<- "spin" rotate() } rightButtonPress <- function(...) { buttonPress <<- TRUE lastTime <<- proc.time()[3] direction <<- "right" rotate() } downButtonPress <- function(...) { buttonPress <<- TRUE lastTime <<- proc.time()[3] direction <<- "down" rotate() } onIdle <- function(...) { buttonPress <<- TRUE rotate() buttonPress <<- FALSE if (as.numeric(tcltk::tclObj(continuous))) tcltk::tcl("after", "idle", onIdle) } buttonRelease <- function(...) { buttonPress <<- FALSE if (as.numeric(tcltk::tclObj(continuous))) tcltk::tcl("after", "idle", onIdle) } resetAxis <- function(...) { old <- cur3d() on.exit(set3d(old)) for (device in dev) { set3d(device) par3d(userMatrix = diag(4)) } } setScale <- function(...) { old <- cur3d() on.exit(set3d(old)) scale <- as.numeric(tcltk::tclObj(scale)) for (device in dev) { set3d(device) par3d(zoom = 10^((scale - 100)/50)*zooms[device]) } } spec.frm <- tcltk::tkframe(base, ...) first.frm <- tcltk::tkframe(spec.frm) second.frm <- tcltk::tkframe(spec.frm) third.frm <- tcltk::tkframe(spec.frm) fourth.frm <- tcltk::tkframe(spec.frm) # rotations buttons upButton <- tcltk::tkbutton(first.frm, text=" ^ ") leftButton <- tcltk::tkbutton(first.frm, text=" < ") spinButton <- tcltk::tkbutton(first.frm, text=" O ") rightButton <- tcltk::tkbutton(first.frm, text=" > ") downButton <- tcltk::tkbutton(first.frm, text=" v ") tcltk::tkgrid(tcltk::tklabel(first.frm, text=" "), upButton, tcltk::tklabel(first.frm, text=" ")) tcltk::tkgrid(leftButton,spinButton,rightButton) tcltk::tkgrid(tcltk::tklabel(first.frm, text=" "), downButton, tcltk::tklabel(first.frm, text=" ")) tcltk::tkbind(upButton, "", upButtonPress) tcltk::tkbind(leftButton, "", leftButtonPress) tcltk::tkbind(spinButton, "", spinButtonPress) tcltk::tkbind(rightButton, "", rightButtonPress) tcltk::tkbind(downButton, "", downButtonPress) tcltk::tkbind(upButton,"", buttonRelease) tcltk::tkbind(leftButton,"", buttonRelease) tcltk::tkbind(spinButton,"", buttonRelease) tcltk::tkbind(rightButton,"", buttonRelease) tcltk::tkbind(downButton,"", buttonRelease) # control buttons frameAxis <- tcltk::tkframe(second.frm,borderwidth=2) tcltk::tkpack(frameAxis) buttonAxis <- tcltk::tkbutton(frameAxis,text=" Reset Axis ",command=resetAxis) contBox <- tcltk::tkcheckbutton(frameAxis,text="Continue rotating", variable=continuous) tcltk::tkpack(contBox, buttonAxis,fill="x") #control scale frame frameControl <- tcltk::tkframe(third.frm,borderwidth=4) tcltk::tkpack(frameControl) frameControlSpeed <- tcltk::tkframe(frameControl) sliderSpeed <- tcltk::tkscale(frameControlSpeed, showvalue=FALSE, orient="horiz", from=0, to=400,resolution=1,variable=slider) tcltk::tkpack(tcltk::tklabel(frameControlSpeed,text="Speed:"),sliderSpeed,side="left") frameControlScale <- tcltk::tkframe(frameControl) sliderScale <- tcltk::tkscale(frameControlScale,showvalue=FALSE,orient="horiz", from=0, to=200,resolution=1, variable=scale, command=setScale) tcltk::tkpack(tcltk::tklabel(frameControlScale,text="Scale:"),sliderScale,side="left") tcltk::tkpack(frameControlSpeed,frameControlScale) tcltk::tkpack(first.frm, second.frm, third.frm, fourth.frm) tcltk::tkpack(spec.frm,expand=TRUE) spec.frm } tkspin3d <- function(dev = cur3d(), ...) { if (!requireNamespace("tcltk", quietly = TRUE)) stop("This function requires 'tcltk'.") args <- list(...) controlargs <- list() if (length(args)) { controlargindices <- which(names(args) %in% names(formals(tkspinControl))) if (length(controlargindices)) { args <- args[-controlargindices] controlargs <- args[controlargindices] } } base <- do.call(tcltk::tktoplevel, args) tcltk::tkwm.title(base, "Spin") spin <- do.call(tkspinControl, c(list(base = base, dev = dev), controlargs)) quit <- tcltk::tkbutton(base,text="Quit", command=function()tcltk::tkdestroy(base)) tcltk::tkpack(spin, quit) } rgl/R/Sweave.R0000644000176200001440000000372114771520323012623 0ustar liggesusers## ## Sweave device ## ## rgl.Sweave <- function(name, width, height, options, ...) { if (length(hook <- getHook("on.rgl.close"))) { # test is for compatibility with R < 3.0.0 if (is.list(hook)) hook <- hook[[1]] dev <- environment(hook)$dev set3d(dev) } else { wr <- c(0, 0, width*options$resolution, height*options$resolution) open3d(windowRect=wr) if (is.null(delay <- options$delay)) delay <- 0.1 Sys.sleep(as.numeric(delay)) wrnew <- par3d("windowRect") if (wr[3] - wr[1] != wrnew[3] - wrnew[1] || wr[4] - wr[2] != wrnew[4] - wrnew[2]) stop("rgl window creation error; try reducing resolution, width or height") dev <- cur3d() } snapshotDone <- FALSE # stayOpen is used below in rgl.Sweave.off stayOpen <- isTRUE(options$stayopen) type <- options$outputtype if (is.null(type)) type <- "png" setHook("on.rgl.close", action="replace", function(remove=TRUE) { prev.dev <- cur3d() on.exit(set3d(prev.dev)) if (!snapshotDone) { set3d(dev) switch(type, png = snapshot3d(filename=paste(name, "png", sep=".")), pdf = rgl.postscript(filename=paste(name, "pdf", sep="."), fmt="pdf"), eps = rgl.postscript(filename=paste(name, "eps", sep="."), fmt="eps"), stop(gettextf("Unrecognized rgl outputtype: '%s'", type), domain = NA) ) snapshotDone <<- TRUE } if (remove) setHook("on.rgl.close", action="replace", NULL) }) } rgl.Sweave.off <- function() { if (length(hook <- getHook("on.rgl.close"))) { if (is.list(hook)) hook <- hook[[1]] # test is for R pre-3.0.0 compatibility stayOpen <- environment(hook)$stayOpen if (stayOpen) hook(FALSE) else close3d() } } ## ## Sweave snapshot ## ## Sweave.snapshot <- function() { if (length(hook <- getHook("on.rgl.close"))) { if (is.list(hook)) hook <- hook[[1]] # test is for R pre-3.0.0 compatibility hook(remove = FALSE) } } rgl/R/merge.mesh3d.R0000644000176200001440000000654414771520323013660 0ustar liggesusersmerge.mesh3d <- function(x, y, ..., attributesMustMatch = FALSE) { fixmesh <- function(m) { stopifnot(inherits(m, "mesh3d")) if (nrow(m$vb) == 3) m$vb <- rbind(m$vb, 1) if (!length(m$ip)) m$ip <- matrix(numeric(), nrow=1, ncol=0) if (!length(m$is)) m$is <- matrix(numeric(), nrow=2, ncol=0) if (!length(m$it)) m$it <- matrix(numeric(), nrow=3, ncol=0) if (!length(m$ib)) m$ib <- matrix(numeric(), nrow=4, ncol=0) if (!is.null(m$normals) && nrow(m$normals) == 3) m$normals <- rbind(m$normals, 1) if (is.null(m$meshColor)) m$meshColor <- "vertices" if (!is.null(m$material)) { n <- switch(m$meshColor, vertices = ncol(m$vb), edges = NCOL(m$is), faces = NCOL(m$it) + NCOL(m$ib), legacy = 3*NCOL(m$it) + 4*NCOL(m$ib)) if (length(m$material$color) == 1) m$material$color <- rep(m$material$color, n) if (length(m$material$alpha) == 1) m$material$alpha <- rep(m$material$alpha, n) } else m$material <- list() m } z <- fixmesh(x) ylist <- list(...) if (!missing(y)) ylist <- c(list(y), ylist) for (i in seq_along(ylist)) { x <- z y <- fixmesh(ylist[[i]]) if (!attributesMustMatch) { common <- intersect(names(x), names(y)) x <- x[common] y <- y[common] } stopifnot(is.null(x$normals) == is.null(y$normals), is.null(x$texcoords) == is.null(y$texcoords), is.null(x$values) == is.null(y$values)) stopifnot(x$meshColor == y$meshColor) nx <- ncol(x$vb) z <- list(vb = cbind(x$vb, y$vb), ip = if (length(x$ip) || length(y$ip)) cbind(x$ip, y$ip + nx), is = if (length(x$is) || length(y$is)) cbind(x$is, y$is + nx), it = if (length(x$it) || length(y$it)) cbind(x$it, y$it + nx), ib = if (length(x$ib) || length(y$ib)) cbind(x$ib, y$ib + nx), normals = cbind(x$normals, y$normals), texcoords = cbind(x$texcoords, y$texcoords), values = c(x$values, y$values), meshColor = x$meshColor) if (!attributesMustMatch) { common <- intersect(names(x$material), names(y$material)) x$material <- x$material[common] y$material <- y$material[common] for (n in common) { if (!(n %in% c("color", "alpha")) && !identical(x$material[[n]], y$material[[n]])) x$material[[n]] <- NULL } } else { stopifnot(setequal(names(x$material), names(y$material))) for (n in names(x$material)) if (!identical(x$material[[n]], y$material[[n]])) stop("Material ", n, " values don't match") } z$material <- x$material z$material$color <- c(x$material$color, y$material$color) z$material$alpha <- c(x$material$alpha, y$material$alpha) class(z) <- "mesh3d" } if (!is.null(z$material)) { if (length(unique(z$material$color)) == 1) z$material$color <- z$material$color[1] if (length(unique(z$material$alpha)) == 1) z$material$alpha <- z$material$alpha[1] } if (!length(z$material$color)) z$material$color <- NULL if (!length(z$material)) z$material <- NULL if (!length(z$ip)) z$ip <- NULL if (!length(z$is)) z$is <- NULL if (!length(z$it)) z$it <- NULL if (!length(z$ib)) z$ib <- NULL z } rgl/cleanup0000755000176200001440000000023315026603605012414 0ustar liggesusers#! /bin/sh rm -f config.* src/Makevars src/Makedeps src/*.o src/*.so src/*.dll rm -rf autom4te.cache rm -rf R/noOpenGL.R src/useNULL/*.o inst/useNULL/*.so rgl/demo/0000755000176200001440000000000014771520323011766 5ustar liggesusersrgl/demo/simpleShinyRgl.R0000644000176200001440000000125614771520323015066 0ustar liggesusers# A simple Shiny demo written by Dieter Menne options(rgl.useNULL = TRUE) if (!require(shiny)) stop("This demo requires shiny.") library(rgl) app <- shinyApp( ui = bootstrapPage( checkboxInput("rescale", "Rescale"), rglwidgetOutput("rglPlot") ), server = function(input, output) { output$rglPlot <- renderRglwidget({ try(close3d(), silent = TRUE) if (input$rescale) aspect3d(1,1,10) else aspect3d(1,1,1) altText <- if (input$rescale) "rescaled" else "not rescaled" spheres3d(rnorm(100), rnorm(100), rnorm(100,sd = 0.1), col = "red", radius = 0.1) axes3d() rglwidget(altText = altText) }) }) runApp(app) rgl/demo/shinyToggle.R0000644000176200001440000000132214771520323014403 0ustar liggesusersif (!require("shiny")) stop("This demo requires shiny.") library(rgl) open3d(useNULL = TRUE) ids <- plot3d(rnorm(100), rnorm(100), rnorm(100))["data"] scene <- scene3d() close3d() ui <- fluidPage( checkboxInput("chk", label = "Display", value = FALSE), playwidgetOutput("control"), rglwidgetOutput("wdg") ) server <- function(input, output, session) { options(rgl.useNULL = TRUE) save <- options(rgl.inShiny = TRUE) on.exit(options(save)) output$wdg <- renderRglwidget({ rglwidget(scene, controllers = "control") }) output$control <- renderPlaywidget({ toggleWidget("wdg", respondTo = "chk", ids = ids) }) } if (interactive()) shinyApp(ui = ui, server = server) rgl/demo/shinyTabs.R0000644000176200001440000000144014771520323014054 0ustar liggesusersif (!require("shiny")) stop("This demo requires shiny.") library(rgl) options(rgl.useNULL = TRUE) ui <- fluidPage( mainPanel( tabsetPanel( tabPanel("red", rglwidgetOutput('thewidget1')), tabPanel("green", rglwidgetOutput('thewidget2')) )) ) server <- function(input, output, session) { x <- rnorm(100) y <- 2*rnorm(100) z <- 10*rnorm(100) open3d() plot3d(x, y, z, col = "red") scene1 <- scene3d() plot3d(z, y, x, col = "green") scene2 <- scene3d() close3d() save <- options(rgl.inShiny = TRUE) on.exit(options(save)) output$thewidget1 <- renderRglwidget( rglwidget(scene1) ) output$thewidget2 <- renderRglwidget( rglwidget(scene2) ) } if (interactive()) shinyApp(ui = ui, server = server)rgl/demo/shinyDemo.R0000644000176200001440000001137614771520323014060 0ustar liggesusersif (!require("shiny")) stop("This demo requires shiny.") library(rgl) library(misc3d) options(rgl.useNULL = TRUE) set.seed(123) ui <- fluidPage( registerSceneChange(), titlePanel("Nelder-Mead"), sidebarLayout( sidebarPanel( helpText("The Nelder-Mead algorithm evaluates the function", "on the vertices of a simplex. At each step it", "moves one vertex of the simplex to a better value."), sliderInput("Slider", min=0, max=59, step=1, value=0, label="Steps", animate=animationOptions(200, loop=TRUE)), sliderInput("Slider2", min=0, max=59, step=1, value=0, label="Cumulative", animate=animationOptions(200, loop=TRUE)), playwidgetOutput('thecontroller'), playwidgetOutput('thecontroller2'), actionButton('newStart', 'Restart')), mainPanel( rglwidgetOutput('thewidget', width = "100%", height = 512)) ) ) u1 <- runif(1) u2 <- runif(1)*(1-u1) u3 <- 1 - u1 - u2 # Example modified from ?contour3d #Example 2: Nested contours of mixture of three tri-variate normal densities nmix3 <- function(x, y, z, m, s) { u1 * dnorm(x, m, s) * dnorm(y, m, s) * dnorm(z, m, s) + u2 * dnorm(x, -m, s) * dnorm(y, -m, s) * dnorm(z, -m, s) + u3 * dnorm(x, m, s) * dnorm(y, -1.5 * m, s) * dnorm(z, m, s) } f <- function(x,y,z) nmix3(x,y,z,.5,.5) g <- function(n = 40, k = 5, alo = 0.1, ahi = 0.5, cmap = heat.colors) { th <- seq(0.05, 0.2, len = k) col <- rev(cmap(length(th))) al <- seq(alo, ahi, len = length(th)) x <- seq(-2, 2, len=n) bg3d(col="white") contour3d(f,th,x,x,x,color=col,alpha=al) # nolint } f3 <- function(x) -f(x[1], x[2], x[3]) g(20,3) surface <- scene3d() close3d() neldermead <- function(x, f) { n <- nrow(x) p <- ncol(x) if (n != p + 1) stop(paste('Need', p + 1, 'starting points')) fx <- rep(NA, n) for (i in 1:n) fx[i] <- f(x[i,]) o <- order(fx) fx <- fx[o] x <- x[o,] xmid <- apply(x[1:p,], 2, mean) z1 <- xmid - (x[n,] - xmid) fz1 <- f(z1) if (fz1 < fx[1]) { z2 <- xmid - 2*(x[n,] - xmid) fz2 <- f(z2) if (fz2 < fz1) { x[n,] <- z2 } else { x[n,] <- z1 } } else if (fz1 < fx[p]) { x[n,] <- z1 } else { if (fz1 < fx[n]) { x[n,] <- z1 fx[n] <- fz1 } z3 <- xmid + (x[n,] - xmid)/2 fz3 <- f(z3) if (fz3 < fx[n]) { x[n,] <- z3 } else { for (i in 2:n) { x[i,] <- x[1,] + (x[i,] - x[1,])/2 } } } return(x) } showsimplex <- function(x, f, col="blue") { n <- nrow(x) z <- numeric(n) for (i in 1:n) z[i] <- f(x[i,]) xyz <- cbind(x, z) # This is tricky: # 1. draw all lines, taking vertices two at a time: c(segments3d(xyz[as.numeric(combn(n, 2)),], col="black", depth_test = "lequal"), # 2. draw all faces, taking vertices three at a time: triangles3d(xyz[as.numeric(combn(n, 3)),], col=col, alpha=0.3)) } setStartPoint <- function() { xyz <- matrix(rnorm(12, sd=0.1) + rep(rnorm(3,sd=2), each=4), 4, 3) subsets <-list() for (i in 1:60) { xyz <- neldermead(xyz,f3) subset <- showsimplex(xyz,f3) subsets <-c(subsets,list(subset)) } names(subsets) <- seq_along(subsets) subsets } server <- function(input, output, session) { plot3d(surface) dev <- cur3d() save <- options(rgl.inShiny = TRUE) on.exit(options(save)) session$onSessionEnded(function() { set3d(dev) close3d() }) path <- reactiveValues(subsets = setStartPoint()) observeEvent(input$newStart, { set3d(dev) deletes <- unique(unlist(path$subsets)) if (length(deletes)) delFromSubscene3d(deletes) subsets <- setStartPoint() adds <- unique(unlist(subsets)) session$sendCustomMessage("sceneChange", sceneChange("thewidget", delete = deletes, add = adds, skipRedraw = TRUE)) path$subsets <- subsets updateSliderInput(session, "Slider", value=0) updateSliderInput(session, "Slider2", value=0) session$onFlushed(function() session$sendCustomMessage("sceneChange", sceneChange("thewidget", skipRedraw = FALSE))) }) output$thewidget <- renderRglwidget({ rglwidget(controllers=c("thecontroller", "thecontroller2")) }) output$thecontroller <- renderPlaywidget({ if (length(path$subsets)) playwidget("thewidget", respondTo = "Slider", subsetControl(1, path$subsets), start = 1, stop = length(path$subsets)) }) output$thecontroller2 <- renderPlaywidget({ if (length(path$subsets)) playwidget("thewidget", respondTo = "Slider2", subsetControl(1, path$subsets, accumulate = TRUE)) }) } if (interactive()) shinyApp(ui = ui, server = server) rgl/demo/mouseCallbacks.R0000644000176200001440000002134614555455305015056 0ustar liggesusersxprod <- function(a, b) c(a[2]*b[3] - a[3]*b[2], a[3]*b[1] - a[1]*b[3], a[1]*b[2] - a[2]*b[1]) vlen <- function(a) sqrt(sum(a^2)) angle <- function(a,b) { dot <- sum(a*b) acos(dot/vlen(a)/vlen(b)) } clamp <- function(x, min, max) pmin(pmax(x, min), max) mouseNone <- function(button = 1, dev = cur3d() ) { cur <- cur3d() for (i in dev) { set3d(i, TRUE) rgl.setMouseCallbacks(button, begin = NULL, update = NULL, end = NULL, dev = dev) } set3d(cur) } mouseTrackball <- function(button = 1, dev = cur3d() ) { width <- height <- rotBase <- NULL userMatrix <- list() cur <- cur3d() screenToVector <- function(x, y) { radius <- max(width, height)/2 centre <- c(width, height)/2 pt <- (c(x, y) - centre)/radius len <- vlen(pt) if (len > 1.e-6) pt <- pt/len maxlen <- sqrt(2) angle <- (maxlen - len)/maxlen*pi/2 z <- sin(angle) len <- sqrt(1 - z^2) pt <- pt * len return(c(pt, z)) } trackballBegin <- function(x, y) { vp <- par3d("viewport") width <<- vp[3] height <<- vp[4] cur <<- cur3d() for (i in dev) { if (inherits(try(set3d(i, TRUE)), "try-error")) dev <<- dev[dev != i] else userMatrix[[i]] <<- par3d("userMatrix") } set3d(cur, TRUE) rotBase <<- screenToVector(x, height - y) } trackballUpdate <- function(x,y) { rotCurrent <- screenToVector(x, height - y) angle <- angle(rotBase, rotCurrent) axis <- xprod(rotBase, rotCurrent) mouseMatrix <- rotationMatrix(angle, axis[1], axis[2], axis[3]) for (i in dev) { if (inherits(try(set3d(i, TRUE)), "try-error")) dev <<- dev[dev != i] else par3d(userMatrix = mouseMatrix %*% userMatrix[[i]]) } set3d(cur, TRUE) } for (i in dev) { set3d(i, TRUE) rgl.setMouseCallbacks(button, begin = trackballBegin, update = trackballUpdate, end = NULL, dev = dev) } set3d(cur, TRUE) } mouseXAxis<- function(button = 1, dev = cur3d() , left=TRUE) { mouseOneAxis(button, dev, axis=c(1,0,0), left=left) } mouseYAxis<- function(button = 1, dev = cur3d(), left = TRUE ) { mouseOneAxis(button, dev, axis=c(0,1,0), left=left) } mouseZAxis<- function(button = 1, dev = cur3d(), left=TRUE) { mouseOneAxis(button, dev, axis=c(0,0,1), left=left) } mouseOneAxis <- function(button = 1, dev = cur3d(), axis = c(1,0,0), left = TRUE ) { width <- height <- rotBase <- NULL userMatrix <- list() cur <- cur3d() screenToVector <- function(x, y) { radius <- max(width, height)/2 centre <- c(width, height)/2 pt <- (c(x, y) - centre)/radius len <- vlen(pt) if (len > 1.e-6) pt <- pt/len maxlen <- sqrt(2) angle <- (maxlen - len)/maxlen*pi/2 z <- sin(angle) len <- sqrt(1 - z^2) pt <- pt * len return(c(pt, z)) } oneAxisBegin <- function(x, y) { vp <- par3d("viewport") width <<- vp[3] height <<- vp[4] cur <<- cur3d() for (i in dev) { if (inherits(try(set3d(i, TRUE)), "try-error")) dev <<- dev[dev != i] else userMatrix[[i]] <<- par3d("userMatrix") } set3d(cur, TRUE) rotBase <<- screenToVector(x, height/2) } oneAxisUpdate <- function(x,y) { rotCurrent <- screenToVector(x, height/2) angle <- rotCurrent[1] - rotBase[1] mouseMatrix <- rotationMatrix(angle, axis[1], axis[2], axis[3]) for (i in dev) { if (inherits(try(set3d(i, TRUE)), "try-error")) dev <<- dev[dev != i] else { if (left) par3d(userMatrix = mouseMatrix %*% userMatrix[[i]]) else par3d(userMatrix = userMatrix[[i]] %*% mouseMatrix) } } set3d(cur, TRUE) } for (i in dev) { set3d(i, TRUE) rgl.setMouseCallbacks(button, begin = oneAxisBegin, update = oneAxisUpdate, end = NULL, dev = dev) } set3d(cur, TRUE) } mousePolar <- function(button = 1, dev = cur3d()) { screenToPolar <- function(x,y) { r <- min(width, height)/2 dx <- clamp(x - width/2, -r, r) dy <- clamp(y - height/2, -r, r) return( asin( c(dx, -dy)/r ) ) } cur <- cur3d() width <- height <- dragBase <- dragCurrent <- NULL camBase <- list() polarBegin <- function(x, y) { vp <- par3d("viewport") width <<- vp[3] height <<- vp[4] dragBase <<- screenToPolar(x, y) cur <<- cur3d() for (i in dev) { if (inherits(try(set3d(i, TRUE)), "try-error")) dev <<- dev[dev != i] else { m <- par3d("userMatrix") svd <- svd(m[1:3, 1:3]) m[1:3, 1:3] <- svd$u %*% t(svd$v) theta <- atan2(-m[1,3], m[1,1]) m <- m %*% rotationMatrix(theta, 0,1,0) svd <- svd(m[1:3, 1:3]) m[1:3,1:3] <- svd$u %*% t(svd$v) phi <- atan2(-m[2,3], m[3,3]) camBase[[i]] <<- c(theta, phi) } } set3d(cur, TRUE) } polarUpdate <- function(x,y) { dragCurrent <<- screenToPolar(x, y) for (i in dev) { if (inherits(try(set3d(i, TRUE)), "try-error")) dev <<- dev[dev != i] else { newpos <- camBase[[i]] - ( dragCurrent - dragBase ) newpos[2] <- clamp(newpos[2], -pi/2, pi/2) mouseMatrix <- rotationMatrix(newpos[2], 1, 0, 0) %*% rotationMatrix(-newpos[1], 0, 1, 0) par3d(userMatrix = mouseMatrix) } } set3d(cur, TRUE) } for (i in dev) { set3d(i, TRUE) rgl.setMouseCallbacks(button, begin = polarBegin, update = polarUpdate, end = NULL, dev = dev) } set3d(cur, TRUE) } # Set background colour based on x,y position in the window mouseBG <- function(button = 1, dev = cur3d(), init = "white", rate = cbind(c(1,0,1),c(0,1,1)), space = c("rgb", "hsv")) { cur <- cur3d() space <- match.arg(space) init <- col2rgb(init)/255 if (space == "hsv") init <- rgb2hsv(init*255) width <- height <- lambda0 <- lambda <- NULL bgBegin <- function(x, y) { lambda0 <<- c(x/width, 1-y/height) # nolint vp <- par3d("viewport") width <<- vp[3] height <<- vp[4] } bgUpdate <- function(x,y) { lambda <<- c(x/width, 1-y/height) - lambda0 color <- clamp(init + rate %*% lambda, 0, 1) x <- color[1] y <- color[2] z <- color[3] if (space == "rgb") color <- rgb(x,y,z) else color <- hsv(x,y,z) for (i in dev) { if (inherits(try(set3d(i, TRUE)), "try-error")) dev <<- dev[dev != i] else bg3d(color=color) } set3d(cur, TRUE) } bgEnd <- function() { init <<- clamp(init + rate %*% lambda, 0, 1) } for (i in dev) { set3d(i, TRUE) rgl.setMouseCallbacks(button, begin = bgBegin, update = bgUpdate, end = bgEnd, dev = dev) } set3d(cur, TRUE) } # Set time using an arbitrary par3dinterp function mouseInterp <- function(button = 1, dev = cur3d(), fn, init = 0, range = NULL, direction=c(1,0)) { cur <- cur3d() time <- init x0 <- width <- NULL interpBegin <- function(x, y) { vp <- par3d("viewport") width <<- vp[3] x0 <<- sum(direction*c(x,y)) } interpUpdate <- function(x,y) { time <<- init + (sum(direction*c(x,y)) - x0)/width if (!is.null(range)) time <<- clamp(time, range[1], range[2]) for (i in dev) { if (inherits(try(set3d(i, TRUE)), "try-error")) dev <<- dev[dev != i] else par3d(fn(time)) } set3d(cur, TRUE) } interpEnd <- function() { init <<- time } for (i in dev) { set3d(i, TRUE) rgl.setMouseCallbacks(button, begin = interpBegin, update = interpUpdate, end = interpEnd, dev = dev) } set3d(cur, TRUE) } mouseZoom <- function(button = 1, dev = cur3d()) mouseInterp(button,dev=dev,fn=par3dinterp(times=c(-4,4)/4, zoom=c(10^(-4),10^4),method="linear"), init=log10(par3d("zoom"))/4,range=c(-4,4)/4,direction=c(0,-1)) mouseFOV <- function(button = 1, dev = cur3d()) mouseInterp(button,dev=dev,fn=par3dinterp(times=c(1,179)/180, FOV=c(1,179),method="linear"), init=par3d("FOV")/180, range = c(1,179)/180, direction=c(0,1)) # Synchronize mouse control of two windows for stereo view example(surface3d, echo = FALSE) par3d(windowRect= c(0,32,512,544), userMatrix = rotationMatrix(5*pi/180, 0,1,0) %*% par3d("userMatrix") ) w1 <- cur3d() example(surface3d, echo = FALSE) par3d(windowRect = c(512,32,1024,544)) w2 <- cur3d() mouseTrackball(dev=c(w1,w2)) mouseZoom(2,dev=c(w1,w2)) mouseFOV(3,dev=c(w1,w2)) rgl/demo/00Index0000644000176200001440000000066714771520323013131 0ustar liggesusersrgl RGL Interactive Demonstration flag play3d() function that waves a flag mouseCallbacks Standard mouse handlers implemented in R, for a stereo view stereo Stereo views using a random dot stereogram & an anaglyph simpleShinyRgl Shiny demo with checkbox shinyToggle Shiny with togglewidget shinyTabs Shiny with tabs shinyDemo rglwidget in Shiny: Nelder-Mead demonstration shinyMouse Mouse selection in Shiny rgl/demo/shinyMouse.R0000644000176200001440000000656714771520323014272 0ustar liggesusers# Use the mouse to select points # Original version written by Yohann Demont if (!require("shiny")) stop("This demo requires shiny.") if (!requireNamespace("crosstalk")) stop("This demo requires crosstalk.") library(rgl) ui <- fluidPage( sidebarLayout( mainPanel(tabsetPanel(id = "navbar", selected = "3D", tabPanel(title = "2D", plotOutput("plot_2D", brush = brushOpts(id = "plot_2D_brush", resetOnNew = TRUE, direction = "xy")), verbatimTextOutput("brush_info_2D")), tabPanel(title = "3D", uiOutput("plot_3D_mousemode"), rglwidgetOutput("plot_3D"), verbatimTextOutput("brush_info_3D"), verbatimTextOutput("selected")) )), sidebarPanel(selectInput("plot_x", label = "x feature", choices = colnames(iris)[-5], selected = colnames(iris)[1]), selectInput("plot_y", label = "y feature", choices = colnames(iris)[-5], selected = colnames(iris)[2]), selectInput("plot_z", label = "z feature", choices = colnames(iris)[-5], selected = colnames(iris)[3]), actionButton(inputId = "reset_brush", label = "reset brush")) )) server <- function(input, output, session) { # 2D output$plot_2D <- renderPlot({ plot(x = iris[, input$plot_x], y = iris[, input$plot_y], col = as.integer(iris[, "Species"])) }) output$brush_info_2D <- renderPrint(str(input$plot_2D_brush)) # 3D sharedData <- NULL output$brush_info_3D <- renderPrint(print(input$rgl_3D_brush, verbose = TRUE)) # How to use selectionFunction3d ? output$selected <- renderPrint({ if(length(input$rgl_3D_brush) == 0 || input$rgl_3D_brush$state == "inactive") return(NULL) cat("Selections from crosstalk:\n") # Need as.logical because selection() might return NULL print(which(as.logical(sharedData$selection()))) cat("Selections using function:\n") f <- selectionFunction3d(input$rgl_3D_brush) which(f(iris[, c(input$plot_x, input$plot_y, input$plot_z)])) }) output$plot_3D_mousemode <- renderUI({ rglMouse( default = "trackball", stayActive = FALSE, choices = c("trackball", "selecting"), sceneId = "plot_3D") }) open3d(useNULL = TRUE) output$plot_3D <- renderRglwidget({ clear3d() dat <- iris[, c(input$plot_x, input$plot_y, input$plot_z, "Species")] dat$id <-as.character(seq_len(nrow(iris))) plot3d(x = dat[, 1:3], type = "s", size = 1, col = as.integer(iris[, "Species"]), aspect = TRUE) sharedData <<- rglShared(id = text3d(dat[, 1:3], text = dat[, "id"], adj = -0.5), group = "SharedData_plot_3D_ids", deselectedFade = 0, selectedIgnoreNone = FALSE) shinyResetBrush(session, "rgl_3D_brush") rglwidget(shared = sharedData, shinyBrush = "rgl_3D_brush") }) observeEvent(input$reset_brush, { session$resetBrush("plot_2D_brush") shinyResetBrush(session, "rgl_3D_brush") }) } shinyApp(ui, server) rgl/demo/rgl.r0000644000176200001440000000026014771520323012733 0ustar liggesusers# all rgl interactive demos demo(flag) demo(mouseCallbacks) demo(shapes3d) demo(shinyDemo) demo(shinyMouse) demo(shinyTabs) demo(shinyToggle) demo(simpleShinyRgl) demo(stereo) rgl/demo/flag.R0000644000176200001440000000137114555455305013033 0ustar liggesusers wave <- function(time) { x <- seq(0,2, len=100) wavefn <- function(x) x * sin(-5*time + 1.5 * (x/2) * 2*pi)/10 deriv <- function(x) (wavefn(x + 0.01) - wavefn(x - 0.01))/0.02 arclen <- cumsum(sqrt(1 + deriv(x)^2))*(x[2]-x[1]) keep <- arclen < 2 x <- x[keep] y <- matrix(wavefn(x), length(x),20) z <- matrix(seq(0,1, len=20), length(x), 20, byrow=TRUE) arclen <- arclen[keep] par3d(skipRedraw = TRUE) if (nrow(ids3d())) pop3d() surface3d(x,y,z, texture_s=matrix(arclen/2, length(x), 20), texture_t=z, col="white") c(list(skipRedraw = FALSE), spin(time)) } open3d() material3d(texture = system.file("textures","rgl2.png", package="rgl")) spin <- spin3d(rpm=6,axis=c(0,0,1)) if (!rgl.useNULL()) play3d(wave, 10, startTime = 5) rgl/demo/stereo.R0000644000176200001440000001246514555455305013431 0ustar liggesusersrandomDot <- function(left, right, rightOffset=c(200, 0), n=3000, ...) { old <- cur3d() on.exit(set3d(old)) force(left) force(right) set3d(left) leftViewport <- par3d("viewport") leftSize <- leftViewport[3:4] leftProj <- rgl.projection() leftDepth <- rgl.pixels("depth") leftUR <- leftViewport[1:2] + leftSize - 1 set3d(right) rightViewport <- par3d("viewport") rightSize <- rightViewport[3:4] rightProj <- rgl.projection() rightDepth <- rgl.pixels("depth") rightUR <- rightViewport[1:2] + rightSize - 1 size <- pmax(leftViewport[3:4], rightViewport[3:4]+rightOffset) pts <- matrix(c(sample(leftSize[1], n, replace=TRUE), sample(leftSize[2], n, replace=TRUE)), n, 2) cols <- 1:n startpt <- pts startcols <- cols keep <- startpt[,1] < leftSize[1] & startpt[,2] < leftSize[2] pt <- startpt[keep,,drop=FALSE] cl <- startcols[keep] while (length(pt)) { depth <- leftDepth[pt] user <- rgl.window2user((pt[,1]-0.5)/leftSize[1], (pt[,2]-0.5)/leftSize[2], depth, projection=leftProj) win <- rgl.user2window(user, projection=rightProj) bkgd <- cbind((pt[,1] - 0.5)/rightSize[1], (pt[,2] - 0.5)/rightSize[2], 1) usewin <- rep(depth < 1, 3) rightPt <- structure(ifelse(usewin, win, bkgd), dim=dim(win)) rightPti <- round(cbind(rightSize[1]*rightPt[,1], rightSize[2]*rightPt[,2]) + 0.5) keep <- rightPti[,1] >= 1 & rightPti[,1] <= rightUR[1] & rightPti[,2] >= 1 & rightPti[,2] <= rightUR[2] rightPti <- rightPti[keep,,drop=FALSE] rightPt <- rightPt[keep,,drop=FALSE] cl <- cl[keep] keep <- TRUE | rightPt[,3] <= rightDepth[ rightPti ]+0.001 rightPti <- rightPti[keep,,drop=FALSE] cl <- cl[keep] pt <- cbind(rightPti[,1] + rightOffset[1], rightPti[,2] + rightOffset[2]) pts <- rbind(pts, pt) cols <- c(cols, cl) keep <- apply(pt, 1, min) >= 1 & pt[,1] <= leftUR[1] & pt[,2] <= leftUR[2] pt <- pt[keep,,drop=FALSE] cl <- cl[keep] } pt <- cbind(startpt[,1] - rightOffset[1], startpt[,2] - rightOffset[2]) keep <- pt[,1] > 1 & pt[,1] < rightSize[1] & pt[,2] > 1 & pt[,2] < rightSize[2] pt <- pt[ keep,,drop=FALSE ] cl <- startcols[ keep ] while (length(pt)) { depth <- rightDepth[pt] user <- rgl.window2user((pt[,1]-0.5)/rightSize[1], (pt[,2]-0.5)/rightSize[2], depth, projection=rightProj) win <- rgl.user2window(user, projection=leftProj) bkgd <- cbind((pt[,1] - 0.5)/leftSize[1], (pt[,2] - 0.5)/leftSize[2], 1) usewin <- rep(depth < 1, 3) leftPt <- structure(ifelse(usewin, win, bkgd), dim=dim(win)) leftPti <- round(cbind(leftSize[1]*leftPt[,1], leftSize[2]*leftPt[,2]) + 0.5) keep <- leftPti[,1] >= 1 & leftPti[,1] <= leftUR[1] & leftPti[,2] >= 1 & leftPti[,2] <= leftUR[2] leftPti <- leftPti[keep,,drop=FALSE] leftPt <- leftPt[keep,,drop=FALSE] cl <- cl[keep] keep <- TRUE | leftPt[,3] <= leftDepth[ leftPti ]+0.001 leftPti <- leftPti[keep,,drop=FALSE] cl <- cl[keep] pt <- leftPti pts <- rbind(pts, pt) cols <- c(cols, cl) pt <- cbind(pt[,1] - rightOffset[1], pt[,2] - rightOffset[2]) keep <- apply(pt, 1, min) >= 1 & pt[,1] <= rightUR[1] & pt[,2] <= rightUR[2] pt <- pt[keep,,drop=FALSE] cl <- cl[keep] } plot(pts, col = cols, pch=16, axes=FALSE,cex=0.25+cols/n/2,xlab="",ylab="",...) rug((size[1] + c(-1,1)*rightOffset[1])/2, side=1) rug((size[1] + c(-1,1)*rightOffset[1])/2, side=3) rug((size[2] + c(-1,1)*rightOffset[2])/2, side=2) rug((size[2] + c(-1,1)*rightOffset[2])/2, side=4) } #red #cyan anaglyph <- function(left, right, leftColor = c(1,0,0), rightColor = c(0,1,1), dimens = dim(leftPixels)) { old <- cur3d() on.exit(set3d(old)) force(left) force(right) set3d(left) vp <- par3d("viewport") leftPixels <- rgl.pixels(viewport=vp) leftPixels <- t((leftPixels[,,1]+leftPixels[,,2]+leftPixels[,,3])/3) leftPixels <- leftPixels[rev(seq_len(dimens[1])), seq_len(dimens[2])] set3d(right) rightPixels <- rgl.pixels(viewport=vp) rightPixels <- t((rightPixels[,,1]+rightPixels[,,2]+rightPixels[,,3])/3) rightPixels <- rightPixels[rev(seq_len(dimens[1])), seq_len(dimens[2])] red <- pmin(leftPixels*leftColor[1] + rightPixels*rightColor[1], 1) green <- pmin(leftPixels*leftColor[2] + rightPixels*rightColor[2], 1) blue <- pmin(leftPixels*leftColor[3] + rightPixels*rightColor[3], 1) z <- as.raster(array(c(red, green, blue), dim = c(dimens, 3))) if (length(z)) { par(mar = c(0,0,0,0)) plot(z) } else { cat("Unable to read pixels:\nstr(leftPixels):\n") str(leftPixels) cat("str(rightPixels):\n") str(rightPixels) } } if (!rgl.useNULL()) { source(system.file("demo/mouseCallbacks.R", package="rgl"), echo=FALSE ) # This version assumes the eyes diverge for the stereo view. # Reverse the two arguments for the cross-eyed view. dev.new(width=9, height=7) randomDot(cur3d()-1, cur3d()) # A red-cyan anaglyph (for 3D glasses). Use optional args to anaglyph for other glasses. dev.new() anaglyph(cur3d()-1, cur3d()) } else cat("Can't read pixels from a NULL device\n") rgl/COPYING0000644000176200001440000004311214265301464012077 0ustar liggesusers GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. rgl/vignettes/0000755000176200001440000000000015026603601013045 5ustar liggesusersrgl/vignettes/transparency.Rmd0000644000176200001440000001504015011677075016234 0ustar liggesusers--- title: "A Note on Transparency" author: "Duncan Murdoch" date: "24/10/2020" output: rmarkdown::html_vignette: fig_height: 5 fig_width: 5 toc: true pdf_document: fig_height: 5 fig_width: 5 toc: true html_document: default vignette: > %\VignetteIndexEntry{A Note on Transparency} %\VignetteEngine{knitr::rmarkdown} --- ```{r setup, include=FALSE} if (!requireNamespace("rmarkdown", quietly = TRUE) || !rmarkdown::pandoc_available("1.14")) { warning(call. = FALSE, "These vignettes assume rmarkdown and Pandoc version 1.14. These were not found. Older versions will not work.") knitr::knit_exit() } knitr::opts_chunk$set(echo = TRUE, snapshot = FALSE, screenshot.force = FALSE) library(rgl) options(rgl.useNULL = TRUE) setupKnitr(autoprint = TRUE) M <- structure(c(0.997410774230957, 0.0707177817821503, -0.0130676832050085, 0, -0.0703366547822952, 0.99714070558548, 0.02762770652771, 0, 0.0149840852245688, -0.0266370177268982, 0.999532878398895, 0, 0, 0, 0, 1), .Dim = c(4L, 4L)) ``` ## Introduction When drawing transparent surfaces, `rgl` tries to sort objects from back to front to get better rendering of transparency. However, it doesn't sort each pixel separately, so some pixels end up drawn in the incorrect order. This note describes the consequences of that error, and suggests remedies. ## Correct Drawing We'll assume that the standard `glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)` blending is used. That is, when drawing with transparency $\alpha$, the new colour is mixed at proportion $\alpha$ with the colour previously drawn (which gets weight $1-\alpha$.) This note is concerned with what happens when two transparent objects are drawn at the same location. We suppose the further one has transparency $\alpha_1$, and the closer one has transparency $\alpha_2$. If they are drawn in the correct order (further first), the three colours (background, further object, closer object) should end up mixed in proportions $C = [(1-\alpha_1)(1-\alpha_2), \alpha_1(1-\alpha_2), \alpha_2]$ respectively. ## Incorrect sorting If the objects are drawn in the wrong order, the actual proportions of each colour will be $N = [(1-\alpha_1)(1-\alpha_2),\alpha_1, \alpha_2(1-\alpha_1)]$ if no masking occurs. `rgl` currently defaults to depth masking using `glDepthMask(GL_TRUE)`. This means that depths are saved when the objects are drawn, and if an attempt is made to draw the further object after the closer one (i.e. as here), the further object will be culled, and the proportions will be $M = [(1-\alpha_2), 0, \alpha_2]$. ## Mask or Not? The question is: which is better, `glDepthMask(GL_TRUE)` or `glDepthMask(GL_FALSE)`? One way to measure this is to measure the distance between $C$ and the incorrect proportions. (This is unlikely to match perceptual distance, which will depend on the colours as well, but we need something. Some qualitative comments below.) So we have $$|C-N|^2 = 2\alpha_1^2\alpha_2^2,$$ and $$|C-M|^2 = 2\alpha_1^2(1-\alpha_2)^2.$$ Thus the error is larger with $N$ when $\alpha_2 > 1 / 2$, and larger with $M$ when $\alpha_2 < 1 / 2$. The value of $\alpha_1$ doesn't affect the preference, though small values of $\alpha_1$ will be associated with smaller errors. Depending on the colours of the background and the two objects, this recommendation could be modified. For example, if the two objects are the same colour (or very close), it doesn't really matter how the 2nd and 3rd proportions are divided up, and $N$ will be best because it gets the background proportion exactly right. ## Recommendation Typically in `rgl` we don't know which object will be closer and which one will be further, so we can't base our choice on a single $\alpha_i$. The recommendation would be to use all small levels of `alpha` and disable masking, or use all large values of `alpha` and retain masking. ## Example The classic example of an impossible to sort scene involves three triangles arranged cyclicly so each one is behind one and in front of one of the others (based on https://paroj.github.io/gltut/Positioning/Tut05%20Overlap%20and%20Depth%20Buffering.html). ```{r} theta <- 2*pi*c(0:2, 4:6, 8:10)/12 x <- cos(theta) y <- sin(theta) z <- rep(c(0,0,1), 3) xyz <- cbind(x, y, z) xyz <- xyz[c(1,2,6, 4,5,9, 7,8,3),] open3d() par3d(userMatrix = M) triangles3d(xyz, col = rep(c("red", "green", "blue"), each = 3)) ``` To see the effect of the calculations above, consider the following four displays. ```{r fig.width=8} open3d() par3d(userMatrix = M) layout3d(matrix(1:9, ncol = 3, byrow=TRUE), widths = c(1,2,2), heights = c(1, 3,3), sharedMouse = TRUE) text3d(0,0,0, " ") next3d() text3d(0,0,0, "depth_mask = TRUE") next3d() text3d(0,0,0, "depth_mask = FALSE") next3d() text3d(0,0,0, "alpha = 0.7") next3d() triangles3d(xyz, col = rep(c("red", "green", "blue"), each = 3), alpha = 0.7, depth_mask = TRUE) next3d() triangles3d(xyz, col = rep(c("red", "green", "blue"), each = 3), alpha = 0.7, depth_mask = FALSE) next3d() text3d(0,0,0, "alpha = 0.3") next3d() triangles3d(xyz, col = rep(c("red", "green", "blue"), each = 3), alpha = 0.3, depth_mask = TRUE) next3d() triangles3d(xyz, col = rep(c("red", "green", "blue"), each = 3), alpha = 0.3, depth_mask = FALSE) ``` As you rotate the figures, you can see imperfections in rendering. On the right, the last drawn appears to be on top, while on the left, the first drawn appears more opaque than it should. In the figure below, the three triangles each have different transparency, and each use the recommended setting: ```{r} open3d() par3d(userMatrix = M) triangles3d(xyz[1:3,], col = "red", alpha = 0.3, depth_mask = FALSE) triangles3d(xyz[4:6,], col = "green", alpha = 0.7, depth_mask = TRUE) triangles3d(xyz[7:9,], col = "blue", depth_mask = TRUE) ``` In this figure, all three triangles are the same colour, only lighting affects the display: ```{r fig.width=8} open3d() par3d(userMatrix = M) layout3d(matrix(1:9, ncol = 3, byrow=TRUE), widths = c(1,2,2), heights = c(1, 3,3), sharedMouse = TRUE) text3d(0,0,0, " ") next3d() text3d(0,0,0, "depth_mask = TRUE") next3d() text3d(0,0,0, "depth_mask = FALSE") next3d() text3d(0,0,0, "alpha = 0.7") next3d() triangles3d(xyz, col = "red", alpha = 0.7, depth_mask = TRUE) next3d() triangles3d(xyz, col = "red", alpha = 0.7, depth_mask = FALSE) next3d() text3d(0,0,0, "alpha = 0.3") next3d() triangles3d(xyz, col = "red", alpha = 0.3, depth_mask = TRUE) next3d() triangles3d(xyz, col = "red", alpha = 0.3, depth_mask = FALSE) ``` Here `depth_mask = FALSE` seems to be the right choice in both cases.rgl/vignettes/pkgdown.Rmd0000644000176200001440000000571315011677075015202 0ustar liggesusers--- title: "Using RGL in pkgdown web sites" author: "Duncan Murdoch" output: rmarkdown::html_vignette: fig_height: 5 fig_width: 5 toc: true pdf_document: fig_height: 5 fig_width: 5 toc: true html_document: default vignette: > %\VignetteIndexEntry{Using RGL in pkgdown web sites} %\VignetteEngine{knitr::rmarkdown} --- ```{r setup, include=FALSE} if (!requireNamespace("rmarkdown", quietly = TRUE) || !rmarkdown::pandoc_available("1.14")) { warning(call. = FALSE, "These vignettes assume rmarkdown and Pandoc version 1.14. These were not found. Older versions will not work.") knitr::knit_exit() } knitr::opts_chunk$set(echo = TRUE, snapshot = FALSE, screenshot.force = FALSE) library(rgl) options(rgl.useNULL = TRUE) setupKnitr(autoprint = TRUE) ``` ## What is the problem? [pkgdown](https://pkgdown.r-lib.org/) is an R package that makes it easy to build a web site for your package. However, the previous version 1.6.1 on CRAN didn't work so well for packages whose examples use RGL or other packages like [leaflet](http://rstudio.github.io/leaflet/) that use [htmlwidgets](http://www.htmlwidgets.org). This document described changes that support both of these. The changes are now incorporated into `pkgdown` 2.0.0, so everything but user instructions has been removed. ## Using `RGL in examples. If you use RGL in example code, they should appear automatically in examples. The RGL output is set up to mimic what would happen in a `knitr` document that uses ```{r eval=FALSE} setupKnitr(autoprint = TRUE) ``` i.e. the output RGL commands will automatically be included in the display. Low-level changes will be collected into a single display: ```{r} # Show regression plane with z as dependent variable library(rgl) open3d() x <- rnorm(100) y <- rnorm(100) z <- 0.2*x - 0.3*y + rnorm(100, sd = 0.3) fit <- lm(z ~ x + y) plot3d(x, y, z, type = "s", col = "red", size = 1) # No plot here, because of the planes3d() call below coefs <- coef(fit) a <- coefs["x"] b <- coefs["y"] c <- -1 d <- coefs["(Intercept)"] planes3d(a, b, c, d, alpha = 0.5) ``` ## Specifying the size of figures By default, pkgdown generates standard plots which are wider than they are high (according to the golden ratio). Often RGL plots look better with equal width and height, since the contents may be rotated by the user. To specify the size of plots in pkgdown, you use the `figures` entry in `_pkgdown.yml`. The defaults are similar to ``` figures: dev: ragg::agg_png dpi: 96 dev.args: [] fig.ext: png fig.width: 7 fig.height: ~ fig.retina: 2 fig.asp: 1.618 bg: NA other.parameters: [] ``` By default RGL uses these parameters as well, but allows you to override any of `fig.width`, `fig.height` and `fig.asp` by specifying an `rgl` entry in `other.parameters`. For example: ``` figures: fig.width: 5 other.parameters: rgl: fig.asp: 1 ``` This will make all plots have a width of 5 inches and will make RGL plots square. rgl/vignettes/rgl.Rmd0000644000176200001440000013563015011677075014317 0ustar liggesusers--- title: "rgl Overview" author: "Duncan Murdoch" date: "`r format(Sys.time(), '%B %d, %Y')`" output: rmarkdown::html_vignette: fig_height: 5 fig_width: 5 toc: true html_document: df_print: paged toc: true pdf_document: fig_height: 5 fig_width: 5 toc: true vignette: > %\VignetteIndexEntry{rgl Overview} %\VignetteEngine{knitr::rmarkdown} --- ```{r setup, echo=FALSE, results="asis"} source("setup.R") setupKnitr(autoprint = TRUE) set.seed(123) ``` ## Introduction The `rgl` package is used to produce interactive 3-D plots. It contains high-level graphics commands modelled loosely after classic R graphics, but working in three dimensions. It also contains low level structure inspired by (but incompatible with) the `grid` package. This document gives an overview. See the help pages for details. For installation instructions, see the `README` file in the top level directory of the source tarball `r paste0("rgl_", packageVersion("rgl"), ".tar.gz")` (or a later version). ### About this document This document was written in R Markdown, using the `knitr` package for production. It corresponds to `rgl` version `r packageVersion("rgl")`. Most of the highlighted function names are HTML links. The internal links should work in any browser; the links to help topics should work if you view the vignette from within the R help system. The document includes WebGL figures. To view these, you must have Javascript and WebGL enabled in your browser. Some older browsers may not support this -- see https://get.webgl.org for tests and links to a discussion. ## Basics and High Level Functions The `r indexfns("plot3d")` function plots points within an RGL window. It is similar to the classic `r linkfn("plot", pkg="graphics")` function, but works in 3 dimensions. For example ```{r "plot3d()"} with(iris, plot3d(Sepal.Length, Sepal.Width, Petal.Length, type="s", col=as.numeric(Species))) ``` can be used to plot three columns of the `iris` data. Allowed plot types include `"p", "l", "h", "s"`, meaning points, lines, segments from z=0, and spheres. There's a lot of flexibility in specifying the coordinates; the `r linkfn("xyz.coords", pkg = "grDevices")` function from the `grDevices` package is used for this. You can use your mouse to manipulate the plot. The default is that if you click and hold with the left mouse button, you can rotate the plot by dragging it. The right mouse button is used to resize it, and the middle button changes the perspective in the point of view. If you call `r linkfn("plot3d")` again, it will overwrite the current plot. To open a new graphics window, use `r linkfn("open3d")`. The other high level function is `r indexfns("persp3d")` to draw surfaces. It is similar to the classic `r linkfn("persp", pkg = "graphics")` function, but with greater flexibility. First, any of `x`, `y` or `z` can be specified using matrices, not just `z`. This allows parametric surfaces to be plotted. An even simpler specification is possible: `x` may be a function, in which case `persp3d` will work out the grid itself. See `r linkfn("persp3d.function", text="?persp3d.function", pkg="rgl")` for details. For example, the `MASS` package estimates Gamma parameters using maximum likelihood in a `r linkfn("fitdistr", text="?MASS::fitdistr", pkg="MASS")` example. Here we show the log likelihood surface. ```{r "persp3d()", fig.height=3, fig.width=6, fig.keep="last", eval=requireNamespace("MASS",quietly=TRUE)} # This example requires the MASS package library(MASS) # from the fitdistr example set.seed(123) x <- rgamma(100, shape = 5, rate = 0.1) fit <- fitdistr(x, dgamma, list(shape = 1, rate = 0.1), lower = 0.001) loglik <- function(shape, rate) sum(dgamma(x, shape=shape, rate=rate, log=TRUE)) loglik <- Vectorize(loglik) xlim <- fit$estimate[1]+4*fit$sd[1]*c(-1,1) ylim <- fit$estimate[2]+4*fit$sd[2]*c(-1,1) mfrow3d(1, 2, sharedMouse = TRUE) persp3d(loglik, xlim = xlim, ylim = ylim, n = 30) zlim <- fit$loglik + c(-qchisq(0.99, 2)/2, 0) next3d() persp3d(loglik, xlim = xlim, ylim = ylim, zlim = zlim, n = 30) ``` On the left, the whole surface over a range of the parameters; on the right, only the parts of the surface with log likelihood values near the maximum. Note: this example used the `knitr` hook functions (see `r linkfn("setupKnitr")`) to insert the scene into this vignette; the previous example used the `rglwidget` function. We generally recommend the newer `r linkfn("rglwidget")` approach. Note that both `plot3d` and `persp3d` are generic functions, with the following methods defined: ```{r} methods(plot3d) methods(persp3d) ``` ## Adding Graphical Elements ### Primitive shapes Just as we have `r linkfn("points", pkg="graphics")` and `r linkfn("lines", pkg="graphics")` in classic graphics, there are a number of low level functions in `rgl` to add graphical elements to the currently active plot. The "primitive" shapes are those that are native to OpenGL: Function | Description ----------------------------- | ----------- `r indexfns("points3d")`: | adds points `r indexfns("lines3d")`: | adds lines `r indexfns("segments3d")`: | adds line segments `r indexfns("triangles3d")`: | adds triangles `r indexfns("quads3d")`: | adds quadrilaterals Each of the above functions takes arguments `x`, `y` and `z`, again using `r linkfn("xyz.coords", pkg="grDevices")` for flexibility. They group successive entries as necessary. For example, the `r linkfn("triangles3d")` function takes each successive triple of points as the vertices of a triangle. You can use these functions to annotate the current graph, or to construct a figure from scratch. ### Constructed shapes `rgl` also has a number of objects which it constructs from the primitives. Function | Description ----------------------------- | ----------- `r indexfns(c("text3d", "texts3d"))`: | adds text `r indexfns("abclines3d")`: | adds straight lines to plot (like `abline`) `r indexfns("arc3d")`: | adds spherical arcs or spirals to plot `r indexfns("planes3d")`: | adds planes to plot `r indexfns("clipplanes3d")`: | add clipping planes to plot `r indexfns(c("sprites3d", "particles3d"))`: | add sprites (fixed shapes or images) to plot `r indexfns("spheres3d")`: | adds spheres `r indexfns(c("surface3d", "terrain3d"))`: | a surface (as used in `r linkfn("persp3d")`) `r indexfns("drape3d")`: | drapes lines on a surface or object(s) `r indexfns("shadow3d")`: | projects mesh onto a surface `r indexfns("arrow3d")`: | add an arrow to a scene `r indexfns("pch3d")`: | draw base-style plotting symbols `r indexfns("plotmath3d")`: | used by `r linkfn("text3d")` for math text ### Axes and other "decorations" The following low-level functions control the look of the graph: Function | Description ------------------------------------ | ----------- `r indexfns(c("axes3d", "axis3d"))`: | add axes to plot `r indexfns(c("box3d", "bbox3d"))`: | add box around plot `r indexfns("title3d")`: | add title to plot `r indexfns("mtext3d")`: | add marginal text to plot `r indexfns("decorate3d")`: | add multiple "decorations" (scales, etc.) to plot `r indexfns("aspect3d")`: | set the aspect ratios for the plot `r indexfns(c("bg3d", "bgplot3d"))`: | set the background of the scene `r indexfns("show2d")`: | show a 2D plot or image in a 3D scene `r indexfns("legend3d")`: | set a legend for the scene `r indexfns("grid3d")`: | add a reference grid to a graph `r indexfns("thigmophobe3d")`: | choose label positions to avoid overlap `r indexfns("setAxisCallbacks")`: | set user-defined axis annotations For example, to plot three random triangles, one could use ```{r "triangles3d()", fig.width=3, fig.height=3} triangles3d(cbind(x=rnorm(9), y=rnorm(9), z=rnorm(9)), col = "green") decorate3d() bg3d("lightgray") aspect3d(1,1,1) ``` Besides the `*3d` functions mentioned above, there are deprecated functions `r deprecated(c("rgl.abclines", "rgl.bbox", "rgl.bg", "rgl.clipplanes", "rgl.lines", "rgl.linestrips", "rgl.planes", "rgl.points", "rgl.primitive", "rgl.quads", "rgl.setAxisCallback", "rgl.spheres", "rgl.sprites", "rgl.surface", "rgl.texts", "rgl.triangles"))`. You should avoid using all of these functions, which do not work properly with the `*3d` functions and will soon be removed from `rgl`. See the `r linkfn("r3d", text="?r3d", pkg="rgl")` help topic for details. The function `r indexfns(c("rgl.getAxisCallback"))` provides low-level support for `r linkfn("setAxisCallbacks")`. ## Controlling the Look of the Scene ### Camera angle By default when you open a new plot with `r linkfn("open3d")`: * The x axis goes from left to right. * The y axis goes from near the camera to far away. * The z axis goes from down to up. You can change the camera angle simply by dragging the picture with the mouse. To set the camera angle programmatically, use `r indexfns("view3d")`. This uses polar coordinates: * `theta` sets the rotation around the vertical axis, in degrees. * `phi` sets the "vertical" rotation around the horizontal axis, from -90 to 90 degrees. The default angle is roughly `theta = 0, phi = -70`. Starting from this position: * As you increase `theta`, the graph will spin anticlockwise from your point of view. * As you increase `phi` to 0, you start to look down at the scene from the top. If you increase `phi` above 0, you continue over and start to see the graph from the "back" (and upside down). You can also use `r indexfns("observer3d")` to change the camera location using `x,y,z` coordinates. In particular, increasing the `z` coordinate lets you zoom out, and decreasing it zooms you in. One useful approach is to use the mouse to find a nice viewing angle. You can then save it using `par3d("userMatrix")` and restore the same view later: ```{r, eval = FALSE} myview <- par3d("userMatrix") # ... later ... par3d(userMatrix = myview) ``` ### Lighting In most scenes, objects are "lit", meaning that their appearance depends on their position and orientation relative to lights in the scene. The lights themselves don't normally show up, but their effect on the objects does. Use the `r indexfns("light3d")` function to specify the position and characteristics of a light. Lights may be infinitely distant, or may be embedded within the scene. Their characteristics include `ambient`, `diffuse`, and `specular` components, all defaulting to white. The `ambient` component appears the same from any direction. The `diffuse` component depends on the angle between the surface and the light, while the `specular` component also takes the viewer's position into account. The deprecated `r deprecated("rgl.light")` function should no longer be used; use `r linkfn("light3d")` instead. ### Materials The mental model used in `rgl` is that the objects being shown in scenes are physical objects in space, with material properties that affect how light reflects from them (or is emitted by them). These are mainly controlled by the `r indexfns("material3d")` function, or by arguments to other functions that are passed to it. The material properties that are recognized in calls to `material3d` are described in detail in the `r linkfn("material3d", text="?material3d", pkg="rgl")` help page, and listed in the `r indexfns("rgl.material.names")` variable. All of them can be set except the ones in `r indexfns("rgl.material.readonly")`. Here we give an overview. Property | Default | Meaning --------- | ------- | ------------------ color | white | vector of surface colors to apply to successive vertices for diffuse light alpha | 1 | transparency: 0 is invisible, 1 is opaque lit | TRUE | whether lighting calculations should be done ambient | black | color in ambient light specular | white | color in specular light emission | black | color emitted by the surface shininess | 50 | controls the specular lighting: high values look shiny smooth | TRUE | whether shading should be interpolated between vertices texture | NULL | optional path to a "texture" bitmap to be displayed on the surface front, back | fill | should polygons be filled, or outlined? size | 3 | size of points in pixels lwd | 1 | width of lines in pixels Other properties include "texmipmap", "texmagfilter", "texminfilter", "texenvmap", "fog", "point\_antialias", "line\_antialias", "depth\_mask", "depth\_test", "polygon_offset", "margin", "floating", "tag" and "blend"; see `r linkfn("material3d", "the help page", pkg = "rgl")` for details. There is also a deprecated `r deprecated("rgl.material")` function that works at a lower level; users should avoid it. ### Textures As described in the previous section, one of the material properties is `texture`, the name of a bitmap file (in `.png` format) containing an image to be displayed on the surface. This section gives more details about textures. In `OpenGL`, each vertex in a polygon may be associated with a particular location in the bitmap. The interior of the polygon interpolates within the bitmap. There are two conventions in `rgl` functions for specifying these coordinates. Functions which specify primitives (`r linkfn("triangles3d")`, etc.) accept an optional matrix argument `texcoords` which gives `s` (horizontal) and `t` (vertical) locations within the bitmap in columns with one row per vertex. The coordinates are `(0,0)` for the lower left, and `(1,1)` for the upper right. If values outside this range are given, the image repeats, i.e. `(1.1, 1.2)` would specify the same point in the image as `(0.1, 0.2)`. Other functions such as `r linkfn("surface3d")` that take matrices for each vertex coordinate accept texture coordinates as matrices as well, in arguments `texture_s` and `texture_t`. For example, the following code displays four copies of a 2D plot on a quad, because the texture coordinates run from 0 to 2 in both `s` and `t`: ```{r Texture} filename <- tempfile(fileext = ".png") png(filename = filename) plot(rnorm(1000), rnorm(1000)) safe.dev.off() open3d() xyz <- cbind(c(0,1,1,0), 0, c(0,0,1,1)) quads3d(xyz, texture = filename, texcoords = xyz[,c(1, 3)]*2, col = "white", specular = "black") ``` Some other notes: - The color in `quads3d()` above was specified to be white. By default, the colors in the bitmap will modify the color of the surface. If `col` is black (a common default), you won't see anything, so a warning may be issued. - You usually don't want specular reflections (which show up as glare). Setting `specular` to black prevents those. - The material property `"texmode"` allows texture colors to be used differently. The default is `"modulate"`, where the texture values combine multiplicatively with the underlying values. - Another aspect of how the bitmap is handled is controlled by the material property `"textype"`. The default is `"rgb"`, which takes the red-green-blue colors from the bitmap and uses them to modify the corresponding colors in the polygon. - Other possibilities for `"textype"` and `"texmode"` are described in `r linkfn("material3d", "the material3d help page", pkg = "rgl")`. - The other `"tex*"` material properties control how the interpolation within the image is done. - Modern `OpenGL` supports 1- and 3-dimensional textures; these are not currently supported in `rgl`. ### Fonts `rgl` uses the same ideas as base graphics for drawing text: there are font families named `"sans"`, `"serif"`, and `"mono"` for drawing text of those types. In `rgl`, the `"symbol"` family is not supported. New font families can be defined using the low-level function `r indexfns("rglFonts")`, or more simply using the higher level function `r indexfns("rglExtrafonts")`. The latter function requires the `extrafont` package to be installed. ### par3d: Miscellaneous graphical parameters The `r indexfns("par3d")` function, modelled after the classic graphics `r linkfn("par", pkg="graphics")` function, sets or reads a variety of different `rgl` internal parameters, listed in the `r indexfns("rgl.par3d.names")` variable. All of them can be set except the ones in `r indexfns("rgl.par3d.readonly")`. Some parameters are completely read-only; others are fixed at the time the window is opened, and others may be changed at any time. Name | Changeable? | Description ----------- | ----- | ----------- antialias | fixed | Amount of hardware antialiasing cex | | Default size for text family | | Device-independent font family name; see `r linkfn("text3d", text="?text3d", pkg="rgl")` font | | Integer font number useFreeType | | Should FreeType fonts be used if available? fontname | read-only | System-dependent font name set by `r linkfn("rglFonts")` FOV | | Field of view, in degrees. Zero means isometric perspective ignoreExtent | | Should `rgl` ignore the size of new objects when computing the bounding box? skipRedraw | | Should `rgl` suppress updates to the display? maxClipPlanes | read-only | How many clip planes can be defined? modelMatrix | read-only | The OpenGL ModelView matrix; partly set by `r indexfns("view3d")` projMatrix | read-only | The OpenGL Projection matrix bbox | read-only | Current bounding-box of the scene viewport | | Dimensions in pixels of the scene within the window windowRect | | Dimensions in pixels of the window on the whole screen listeners | | Which subscenes respond to mouse actions in the current one mouseMode | | What the mouse buttons do. See `r linkfn("mouseMode", '"mouseMode"')` observer | read-only | The position of the observer; set by `r indexfns("observer3d")` scale | | Rescaling for each coordinate; see `r linkfn("aspect3d")` zoom | | Magnification of the scene The deprecated `r deprecated("rgl.viewpoint")` function should not be used. ### Default settings The `r indexfns("r3dDefaults")` list and the `r indexfns("getr3dDefaults")` function control defaults in new windows opened by `r linkfn("open3d")`. The function looks for the variable in the user's global environment, and if not found there, finds the one in the `rgl` namespace. This allows the user to override the default settings for new windows. Once found, the `r3dDefaults` list provides initial values for `r linkfn("par3d")` parameters, as well as defaults for `r linkfn("material3d")` and `r linkfn("bg3d")` in components `"material"` and `"bg"` respectively. ## Meshes: Constructing Shapes `rgl` includes a number of functions to construct and display various solid shapes. These generate objects of class `"shape3d"`, `"mesh3d"` or `"shapelist3d"`. The details of the classes are described below. We start with functions to generate them. ### Specific solids These functions generate specific shapes. Optional arguments allow attributes such as color or transformations to be specified. Function | Description ------------------------------------ | ----------- `r indexfns(c("tetrahedron3d", "cube3d", "octahedron3d", "dodecahedron3d", "icosahedron3d"))`: | Platonic solids `r indexfns(c("cuboctahedron3d", "oh3d"))`: | other solids ```{r Solids} cols <- rainbow(7) layout3d(matrix(1:16, 4,4), heights=c(1,3,1,3)) text3d(0,0,0,"tetrahedron3d"); next3d() shade3d(tetrahedron3d(col=cols[1])); next3d() text3d(0,0,0,"cube3d"); next3d() shade3d(cube3d(col=cols[2])); next3d() text3d(0,0,0,"octahedron3d"); next3d() shade3d(octahedron3d(col=cols[3])); next3d() text3d(0,0,0,"dodecahedron3d"); next3d() shade3d(dodecahedron3d(col=cols[4])); next3d() text3d(0,0,0,"icosahedron3d"); next3d() shade3d(icosahedron3d(col=cols[5])); next3d() text3d(0,0,0,"cuboctahedron3d"); next3d() shade3d(cuboctahedron3d(col=cols[6])); next3d() text3d(0,0,0,"oh3d"); next3d() shade3d(oh3d(col=cols[7])) ``` A very large collection of polyhedra is contained in the `r linkfn("Rpolyhedra-package", text = "Rpolyhedra", pkg = "Rpolyhedra")` package. ### Generating new shapes These functions generate new shapes: Function | Description ------------------------------------ | ----------- `r indexfns("cylinder3d")`: | generate a tube or cylinder `r indexfns("polygon3d")`: | generate a flat polygon by triangulation `r indexfns("extrude3d")`: | generate an "extrusion" of a polygon `r indexfns("turn3d")`: | generate a solid of rotation `r indexfns("ellipse3d")`: | generate an ellipsoid in various ways `r indexfns("mesh3d")`: | generate a shape from indexed vertices `r indexfns("shapelist3d")`: | generate a shape by combining other shapes `r linkfn("as.mesh3d")`: | a generic function; see below A related function is `r indexfns("triangulate")`, which takes a two dimensional polygon and divides it up into triangles using the "ear-clipping" algorithm. The generic function `r indexfns("as.mesh3d")` is provided to allow data structures produced by other code to be converted to mesh structures. Currently the following classes are supported: Class | Package | Description ----- | ------- | ----------- `r indexfns("deldir", pkg = "deldir")` | `deldir` | Delaunay triangulations of irregular point clouds `r indexfns("triSht", pkg = "interp")` | `interp` | Also Delaunay triangulations `r indexfns("tri", pkg = "tripack")` | `tripack` | Generalized Delaunay triangulations `r indexfns("ashape3d", pkg = "alphashape3d")` | `alphashape3d` | Alpha-shapes `r linkfn("rglId")` | `rgl` | `rgl` object identifiers The `r indexfns("checkDeldir")` function checks that a compatible version of the `deldir` package is installed. The default `r indexfns("as.mesh3d.default")` method is a simple way to construct a mesh from a matrix of vertices; it can use `r indexfns("mergeVertices")` (which can also be used on its own) to merge repeated vertices within the matrix, allowing `r linkfn("addNormals")` to be used to give a smooth appearance. The `r indexfns("as.tmesh3d")` generic is a variation that guarantees the resulting object will have no quad entries. Functions `r indexfns(c("tmesh3d","qmesh3d"))` are now obsolete; use `r linkfn("mesh3d")` instead. ### The underlying class structure for shapes `"shape3d"` is the basic abstract type. Objects of this class can be displayed by `r indexfns("shade3d")` (which shades faces), `r indexfns("wire3d")` (which draws edges), or `r indexfns("dot3d")` (which draws points at each vertex.) `"mesh3d"` is a descendant type. Objects of this type contain the following fields: Field | Meaning ------------ | --------------- vb | A 4 by n matrix of vertices in homogeneous coordinates. Each column is a point. ip | (optional) A vector of vertex indices for points. is | (optional) A 2 by s matrix of vertex indices. Each column is a line segment. it | (optional) A 3 by t matrix of vertex indices. Each column is a triangle. ib | (optional) A 4 by q matrix of vertex indices. Each column is a quadrilateral. material | (optional) A list of material properties. normals | (optional) A matrix of the same shape as vb, containing normal vectors at each vertex. texcoords | (optional) A 2 by n matrix of texture coordinates corresponding to each vertex. values | (optional) A vector of length n holding values at each vertex meshColor | (optional) A text value indicating how colors and texture coordinates should be interpreted. tags | (optional) A vector added by some functions (e.g. `r linkfn("clipMesh3d")`) to relate output parts to input parts. ### Contouring and clipping shapes These functions compute and plot contours of functions on surfaces, or clip objects along a contour of a function. Function | Description -------------------------------- | ----------- `r indexfns("contourLines3d")`: | draw contour lines on surface `r indexfns("filledContour3d")`: | fill between contours on surface `r indexfns("clipMesh3d")`: | clip mesh object using curved boundary `r indexfns("clipObj3d")`: | clip general object using curved boundary ### Manipulating shapes These functions manipulate and modify mesh objects: Function | Description ------------------------------------ | ----------- `r indexfns("addNormals")`: | add normal vectors to make a shape look smooth `r indexfns("subdivision3d")`: | add extra vertices to make it look even smoother `r indexfns("merge.mesh3d", backticked("merge"))`: | merge mesh objects `r indexfns("facing3d")`: | subset of mesh facing "up" `r indexfns("getBoundary3d")`: | get the boundary of a mesh object The individual steps in `r linkfn("subdivision3d")` are also available: `r indexfns(c("deform.mesh3d", "divide.mesh3d", "normalize.mesh3d"))`. These are mainly intended for internal use. ## Multi-figure Layouts `rgl` has several functions to support displaying multiple different "subscenes" in the same window. The high level functions are Function | Description ------------------------- | ----------- `r indexfns("mfrow3d")`: | Multiple figures (like `r linkfn("par", text = 'par("mfrow")', pkg="graphics")` `r indexfns("layout3d")`: | Multiple figures (like `r linkfn("layout", pkg="graphics")`) `r indexfns("next3d")`: | Move to the next figure (like `r linkfn("plot.new", pkg="graphics")` or `r linkfn("frame", pkg="graphics")`) `r indexfns("subsceneList")`: | List all the subscenes in the current layout `r indexfns("clearSubsceneList")`: | Clear the current list and revert to the previous one There are also lower level functions. Function | Description ---------------------------------- | ----------- `r indexfns("newSubscene3d")`: | Create a new subscene, with fine control over what is inherited from the parent `r indexfns("currentSubscene3d")`: | Report on the active subscene `r indexfns("subsceneInfo")`: | Get information on current subscene `r indexfns("useSubscene3d")`: | Make a different subscene active `r indexfns(c("addToSubscene3d", "delFromSubscene3d"))`: | Add objects to a subscene, or delete them `r indexfns("gc3d")`: | Do "garbage collection": delete objects that are not displayed in any subscene ## Documents with `rgl` Scenes The `rgl` package can produce output that can be embedded in other documents. The recommended way to do this has changed several times over the years. We will start with the current recommendation, then list older methods. ### The recommended method Currently the best way to embed an `rgl` scene in a document is to produce the document in HTML using R Markdown. Early in the document, you should have code like this in one of the setup code chunks: ````markdown `r ''````{r echo=FALSE, include=FALSE} library(rgl) setupKnitr(autoprint = TRUE) ``` ```` The call to `setupKnitr()` will install a number of hooks and set options in `knitr` so that `rgl` code is handled properly. The `autoprint = TRUE` argument makes `rgl` act in the document almost the same way it would act in the console, or the way base graphics are handled by `knitr`: If you print the value of high level `rgl` functions, a plot will be inserted into the output, but maybe only after low level modifications to it are complete. For example, this code block prints both triangles and spheres in a single plot at the end: ```{r Autoprint} xyz <- matrix(rnorm(27), ncol = 3) triangles3d(xyz, col = rainbow(9)) spheres3d(xyz, col = rainbow(9), radius = 0.1) ``` There are a few differences if you have a complicated situation: - The mechanism depends on the result of the `rgl` function calls being automatically printed. If the calls are in a loop or other code block where automatic printing doesn't happen, you'll need some trickery to get things to print. For example, this will print three plots: ```{r eval = FALSE} plots <- NULL for (i in 1:3) { plot3d(rnorm(10), rnorm(10), rnorm(10)) plots <- htmltools::tagList(plots, rglwidget()) close3d() } plots ``` - It also depends on the fact that `rgl` functions return results using `lowlevel()` or `highlevel()` to mark which kind of plot they are. If you are using a function from another package to produce the plot, you may need to insert an explicit call to one of those to get it to print. Use `lowlevel()` if the function just modifies an existing plot, `highlevel()` if it starts a new one. For example, ```{r eval = FALSE} foreignHigh() # Produces a high level plot, but doesn't return # an appropriate value highlevel() foreignLow() # Modifies the previous plot lowlevel() ``` This should display the output at the end of the code chunk, when modifications are assumed complete. ### Producing PDF output While some PDF previewers support interactive 3D graphics, most don't. To produce a screenshot of an `rgl` scene in an R Markdown document with PDF output, simply follow the directions given above. The auto-printing will detect PDF output and use `snapshot3d` to produce a PNG file to insert. (See below if you want to insert a different format of graphic.) If you really need interactive output, see the `r linkfn("writeASY")` function. ### Manual insertion of plots You may not want to use the `setupKnitr(autoprint = TRUE)` method described above. It is very new, and may still have bugs; you may have an older document and not want to edit it to work that way. In this case, you can insert plots manually. Use setup code ````markdown `r ''````{r echo=FALSE, include=FALSE} library(rgl) setupKnitr() ``` ```` and call `rglwidget()` at top level whenever you want to insert a plot. There are a couple of other differences in default behaviour if you are not using `autoprint`: - By default, each code chunk continues the `rgl` scene from earlier chunks. You'll need an explicit `r linkfn("open3d")` call to get a clean window. - Also by default, the `rgl` window is not closed at the end of the chunk. This probably doesn't matter, but you may find you run out of memory if your scenes are really big. ### Older methods The original way to insert an `rgl` scene in a document was to use the deprecated `r deprecated("writeWebGL")` function to write HTML code to insert in a document. Later, `Sweave` and `knitr` hooks were added. These are no longer supported, and you should update old documents to use the newer methods. If you are reading documents that suggest using those methods, let the author know they need updating! ## Utility Functions ### User interaction By default, `rgl` detects and handles mouse clicks within your scene, and uses these to control its appearance. You can find out the current handlers using the following code: ```{r} par3d("mouseMode") ``` The labels `c("left", "right", "middle")` refer to the buttons on a three button mouse, or simulations of them on other mice. `"wheel"` refers to the mouse wheel, and `"none"` refers to actions that take place when the mouse is moved without pressing any button. The button actions generally correspond to click and drag operations. Possible values for `r indexfns("mouseMode", '"mouseMode"')` for the mouse pointer or wheel are as follows: Mode | Description -------------- | --------- `"none"` | No action `"trackball"` | The mouse acts as a virtual trackball. Clicking and dragging rotates the scene `"xAxis"`, `"yAxis"`, `"zAxis"` | Like `"trackball"`, but restricted to rotation about one axis `"polar"` | The mouse affects rotations by controlling polar coordinates directly `"selecting"` | The mouse is being used by the `r linkfn("select3d")` function `"zoom"` | The mouse zooms the display `"fov"` | The mouse affects perspective by changing the field of view `"pull"` | Rotating the mouse wheel towards the user "pulls the scene closer" `"push"` | The same rotation "pushes the scene away" `"user"` | A user action set by `r indexfns(c("setUserCallbacks", "rgl.setMouseCallbacks", "rgl.setWheelCallback"))`. Use `r indexfns("rgl.getMouseCallbacks")` and `r indexfns("rgl.getWheelCallback")` to retrieve. The following functions make use of the mouse for selection within a scene. Function | Description ---------------------------- | ----------- `r indexfns("identify3d")`: | like the classic graphics `r linkfn("identify", pkg="graphics")` function `r indexfns("select3d")`: | returns a function that tests whether a coordinate was selected `r indexfns("selectpoints3d")`: | selects from specific objects `r indexfns("hover3d")`: | displays "hover" info about points `r indexfns("selectionFunction3d")` produces the selection function from information about the projection and mouse selection region; it is used internally in the functions above. The deprecated `r deprecated("rgl.select3d")` function is an obsolete version of `select3d`, and `r indexfns("rgl.select")` is a low-level support function. ### Animations `rgl` has several functions that can be used to construct animations. These are based on functions that update the scene according to the current real-world time, and repeated calls to those. The functions are: Function | Description ---------------------- | ------------- `r indexfns("play3d")`: | Repeatedly call the update function `r indexfns("spin3d")`: | Update the display by rotating at a constant rate `r indexfns("par3dinterp")`: | Compute new values of some `r linkfn("par3d")` parameters by interpolation over time See the `r linkfn("movie3d")` function for a way to output an animation to a file on disk. Animations are not currently supported in the HTML written by `r linkfn("rglwidget")`, though the `playwidget` function provides equivalent functionality. ### Integration with TCL/TK There are three functions in `rgl` that support control of an `rgl` scene using the TCL/TK framework. Function | Description ---------------------- | ------------- `r indexfns("tkspin3d")`: | Set up buttons in a window to control a scene `r indexfns("tkspinControl")`: | Embed the control buttons in a separate TCL/TK frame `r indexfns("tkpar3dsave")`: | Create a dialog to interactively save mouse actions These functions were formerly contained (without the `tk` prefixes on their names) in the `tkrgl` package. That package is now deprecated. ### Exporting and importing scenes `rgl` contains several functions to write scenes to disk for use by other software, or to read them in. In order from highest fidelity to lowest, the functions are: Function | Description ----------- | ------------- `r indexfns("scene3d")`: | Save a scene to an R variable, which can be saved and reloaded `r indexfns("rglwidget")`: | Prints as HTML and Javascript to display a scene in a web browser. (See also [User Interaction in WebGL](WebGL.html).) `r indexfns("writeASY")`: | Write files for Asymptote `r indexfns("writePLY")`: | Write PLY files (commonly used in 3D printing) `r indexfns(c("readOBJ", "writeOBJ"))`: | Read or write OBJ files (commonly used in 3D graphics) `r indexfns(c("readSTL", "writeSTL"))`: | Read or write STL files (also common in 3D printing) `r indexfns("as.rglscene")`: | Generic function, no methods in `rgl` The [`rgl2gltf`](https://dmurdoch.github.io/rgl2gltf/dev/) package can read or write GLTF and GLB files. It includes an `as.rglscene` method to convert GLTF objects to `rgl` scenes. The code in `rgl`'s `r indexfns("Buffer")` R6 class is based on the GLTF format. It is used by `r linkfn("rglwidget")` to make output webpages somewhat smaller than they were previously. There are also functions to save snapshots or other recordings of a scene, without any 3D information being saved: Function | Description ------------ | ------------- `r indexfns("snapshot3d")`: | Save a PNG file bitmap of the scene `r indexfns("rgl.postscript")`: | Save a Postscript, LaTeX, PDF, SVG or PGF vector rendering of the scene `r indexfns("movie3d")`: | Save a series of bitmaps to be assembled into a movie `r indexfns("rgl.pixels")`: | Obtain pixel-level information about the scene in an R variable `r indexfns("rgl.Sweave")`: | Driver function for inserting a snapshot into a Sweave document. `r indexfns(c("hook_rgl", "hook_webgl"))`: | `knitr` hook functions for inserting images into a document. `r indexfns("setupKnitr")`: | Function to set up `knitr` hooks The `r indexfns("rgl.snapshot")` function is a low level version of `snapshot3d()`; it requires that the `rgl` display be onscreen and copies from there. `snapshot3d()` tries to use the `webshot2` package so it will work even with no display. The functions `r indexfns(c("rgl.Sweave.off", "Sweave.snapshot"))` are involved in Sweave processing and not normally called by users. ### Default display There are two ways in which `rgl` scenes are normally displayed within R. The older one is in a dedicated window. In Unix-alikes this is an X11 window; it is a native window in Microsoft Windows. On macOS, the XQuartz system (see https://www.xquartz.org) needs to be installed to support this. To suppress this display, set `options(rgl.useNULL = TRUE)` before opening a new `rgl` window. See the help page for the `r indexfns("rgl.useNULL")` function for how to set this before starting R. The newer way to display a scene is by using WebGL in a browser window or in the Viewer pane in RStudio. To select this, set `options(rgl.printRglwidget = TRUE)`. Each operation that would change the scene will return a value which triggers a new WebGL display when printed. ### Working with WebGL scenes You should use the following scheme for exporting a scene to a web page. There's also an older scheme, which is no longer supported. The recommended approach works with the `htmlwidgets` framework (see http://www.htmlwidgets.org/). In an R Markdown document in `knitr`, use the `r linkfn("rglwidget")` function. (You can also use chunk option `webgl=TRUE`; we recommend the explicit use of `rglwidget`.) This approach also allows display of `rgl` scenes in [RStudio](https://posit.co/). Besides `rgl` scenes, various controls for them can be displayed, and there are a few utility functions that can be useful: Function | Description ------------------------------------ | ------------- `r indexfns("propertyControl")`: | set individual properties `r indexfns("clipplaneControl")`: | control a clipping plane `r indexfns("subsetControl")`: | control which objects are displayed `r indexfns("ageControl")`: | "age" vertices of an object `r indexfns("vertexControl")`: | control properties of vertices `r indexfns("par3dinterpControl")`: | WebGL control like `r linkfn("par3dinterp")` `r indexfns("playwidget")`: | display and automate controls `r indexfns("toggleWidget")`: | display a button to toggle some items `r documentedfns <- c(documentedfns, "%>%");indexfns("pipe", text="%>%")`: | `magrittr` pipe `r indexfns(c("figHeight", "figWidth"))`: | Dimensions of figures in R Markdown document `r indexfns("rglShared")`: | share data using `crosstalk` package `r indexfns("rglMouse")`: | change mouse mode in RGL scene `r indexfns("asRow")`: | arrange multiple objects in an HTML display `r indexfns("getWidgetId")`: | get the `elementId` from a widget These functions work with the above scheme in Shiny apps: Function | Description ------------------------------------ | ------------- `r indexfns("sceneChange")`: | used in `Shiny` for large scene changes `r indexfns(c("shinyGetPar3d", "shinySetPar3d"))`: | get or set `r linkfn("par3d")` values from Shiny `r indexfns("shinyResetBrush")`: | reset the mouse brush in Shiny The `r linkfn("selectionFunction3d")` function is also likely to be involved in mouse interactions when using Shiny. Some functions are mainly for internal use: `r indexfns(c("elementId2Prefix", "playwidgetOutput", "renderPlaywidget", "rglwidgetOutput", "renderRglwidget", "registerSceneChange"))`. More details are given in the vignette [User Interaction in WebGL](WebGL.html). The functions `r indexfns(c("lowlevel", "highlevel", "rglId"))` are also for internal use, marking function results for automatic printing. Finally, the function `r indexfns("setUserShaders")` allows you to use hand-written shaders in WebGL, and `r indexfns("getShaders")` allows you to see what shader would be used. ### Working with the scene `rgl` maintains internal structures for all the scenes it displays. The following functions allow users to find information about them and manipulate them. In cases where there are both `*3d` and `rgl.*` versions of functions, most users should use the `*3d` version: the `rgl.*` functions are more primitive and are mainly intended for internal use. Function | Description ------------------------------------ | ----------- `r indexfns("open3d")`: | open a new window `r indexfns("close3d")`: | close the current window `r indexfns("cur3d")`: | id of the active device `r indexfns("set3d")`: | set a particular device to be active `r indexfns("pop3d")`: | delete objects from the scene `r indexfns(c("clear3d"))`: | delete all objects of certain classes `r indexfns("ids3d")`: | ids, types and tags of current objects `r indexfns("tagged3d")`: | find tags or objects with tags Some of these functions have alternate names for back compatibility: `r deprecated(c("rgl.cur", "rgl.ids", "rgl.pop"))`. Either name will work, but the `*3d` version is recommended for new code. Some have deprecated versions: `r deprecated(c("rgl.clear", "rgl.set"))`. Those should not be called. These functions are mainly intended for programming, and have no corresponding `*3d` counterparts: Function | Description ------------- | ----------- `r indexfns("rgl.bringtotop")`: | bring the current window to the top `r indexfns("rgl.dev.list")`: | ids of all active devices `r indexfns(c("rgl.attrib", "rgl.attrib.info", "rgl.attrib.count"))`: | attributes of objects in the scene `r indexfns("rgl.projection")`: | return information about the current projection `r indexfns(c("rgl.user2window", "rgl.window2user"))`: | convert between coordinates in the current projection The `r indexfns("as.triangles3d")` generic function is intended to extract coordinates in a form suitable for passing to `r linkfn("triangles3d")`. Currently a method is provided for `r linkfn("rglId")` objects. In addition to these, there are some deprecated functions which should not be called: `r deprecated(c("rgl.init", "rgl.open", "rgl.close", "rgl.quit"))`. ### Working with 3-D vectors Most `rgl` functions work internally with "homogeneous" coordinates. In this system, 3-D points are represented with 4 coordinates, generally called (x, y, z, w). The corresponding Euclidean point is (x/w, y/w, z/w), if w is nonzero; zero values of w correspond to "points at infinity". The advantage of this system is that affine transformations including translations and perspective shifts become linear transformations, with multiplication by a 4 by 4 matrix. `rgl` has the following functions to work with homogeneous coordinates: Function | Description ------------------------------------ | ----------- `r indexfns(c("asEuclidean", "asHomogeneous"))`: | convert between homogeneous and Euclidean coordinates when x, y and z are columns `r indexfns(c("asEuclidean2", "asHomogeneous2"))`: | convert when x, y and z are rows `r indexfns(c("rotate3d", "scale3d", "translate3d"))`: | apply a transformation `r indexfns("transform3d")`: | apply a general transformation `r indexfns(c("rotationMatrix", "scaleMatrix", "translationMatrix"))`: | compute the transformation matrix `r indexfns("identityMatrix")`: | return a 4 x 4 identity matrix `r indexfns("projectDown")`: | a 3D to 2D projection down a vector There is also a function `r indexfns("GramSchmidt")`, mainly for internal use: it does a Gram-Schmidt orthogonalization of a 3x3 matrix, with some specializations for its use in `r linkfn("cylinder3d")`. ### Working with other packages Sometimes it may be convenient to interactively rotate a scene to a particular view, then display it in `lattice` or base graphics. The `r indexfns("rglToLattice")` and `r indexfns("rglToBase")` functions support this. For example, we first display the volcano data in `rgl`: ```{r fig.alt="Volcano in rgl", echo = 2:3} close3d() persp3d(volcano, col = "green") ``` This display is interactive, but we can reproduce the initial view using the `lattice` `r linkfn("wireframe", pkg = "lattice")` or base graphics `r linkfn("persp", pkg = "graphics")` functions: ```{r eval=requireNamespace("orientlib", quietly = TRUE) && requireNamespace("lattice", quietly = TRUE), fig.alt=paste0("Volcano in ", c("lattice", "base"), "graphics.")} # Only evaluated if the lattice & orientlib packages are installed lattice::wireframe(volcano, col = "green", screen = rglToLattice()) angles <- rglToBase() persp(volcano, col = "green", shade = TRUE, theta = angles$theta, phi = angles$phi) ``` Note that the `orientlib` package must be available for these functions to work. ### Creating `pkgdown` websites The ["Using RGL in pkgdown web sites"](pkgdown.html) vignette describes how to use `rgl` in a `pkgdown` web site. The utility function `r indexfns("in_pkgdown_example")` can be used to detect that `pkgdown` is being used. ### Working with `testthat` The `testthat` package is widely used for unit tests in packages. Such tests are hard to write with `rgl`, because the output is visual and interactive rather than a simple value. The `r indexfns("expect_known_scene")`, `r indexfns("compare_proxy.mesh3d")` and `r indexfns("all.equal.mesh3d")` functions help with this by removing system-dependent features of `rgl` output. ### Working with Javascript The WebGL displays created using `r linkfn("rglwidget")` rely on a large body of Javascript code included in this package. To help in development of this code, the `r indexfns("makeDependency")` function was written. It may be useful in other packages that include Javascript. ### Other functions and objects This section is for miscellaneous functions and objects that don't fall in any of the other categories in this document. The `r indexfns("setGraphicsDelay")` function is designed to work around what appears to be a bug on macOS: if a standard plot window is opened too quickly after an `rgl` window, R can crash. This function inserts a one second delay when it appears to be needed. The `r indexfns("gltfTypes")` vector contains constants used in OpenGL and glTF. ## Warning: Work in Progress! This vignette is always a work in progress. Some aspects of the `rgl` package are not described, or do not have examples. There may even be functions that are missed completely, if the following list is not empty: ```{r echo=FALSE} setdiff(ls("package:rgl"), c(documentedfns, deprecatedfns)) ``` ## Index of Functions The following functions and constants are described in this document:
```{r echo=FALSE, results="asis"} writeIndex(cols = if (knitr::is_html_output()) 5 else 4) ``` rgl/vignettes/deprecation.Rmd0000644000176200001440000001756215000743766016032 0ustar liggesusers--- title: "Deprecating the `rgl.*` interface" author: "Duncan Murdoch" date: "`r Sys.Date()`" output: rmarkdown::html_vignette: toc: true vignette: > %\VignetteIndexEntry{Deprecating the `rgl.*` interface} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` # Introduction Since at least 2004, `rgl` has had two interfaces for many of the primitive functions: `rgl.*` and `*3d`. For example, to draw points you could use `rgl.points()` or `points3d()`. With the upcoming version 1.0.0 release of `rgl`, most of the duplication will be removed. The first step will be to deprecate a large number of `rgl.*` functions so they give warnings when they are called, and a few months later they will be removed from the package exports. This document describes the differences and changes needed by users of the `rgl.*` interface. # Differences between the interfaces ## Opening a window The `rgl.open()` function has a single argument, `useNULL`. If set to `TRUE`, the NULL `rgl` device will be used. The `par3d()` settings will be set to their defaults. The `open3d()` function has arguments ```r function(..., params = getr3dDefaults(), useNULL = rgl.useNULL(), silent = FALSE ) ``` and allows `par3d()` values to be specified, and uses the `r3dDefaults` variable to set default values for `par3d()`, `material3d()`, and `bg3d()`. Initially `r3dDefaults` is defined as ```r list(userMatrix = rotationMatrix(290*pi/180, 1, 0, 0), mouseMode = c("none", "trackball", "zoom", "fov", "pull"), FOV = 30, family = "sans", bg = list(color="white", fogtype = "none"), material = list(color="black", fog = TRUE) ) ``` Users can create their own default lists; e.g. to get the same result as `rgl.open()` would give, use ```r open3d(params = list()) ``` or ```r r3dDefaults <- list() open3d() ``` ## Material properties The `rgl.material()` function has a large number of parameters. The pre-deprecation arguments were: ```r function( color = "white", alpha = 1.0, lit = TRUE, ambient = "black", specular = "white", emission = "black", shininess = 50.0, smooth = TRUE, texture = NULL, textype = "rgb", texmipmap = FALSE, texminfilter = "linear", texmagfilter = "linear", texenvmap = FALSE, front = "filled", back = "filled", size = 3.0, lwd = 1.0, fog = TRUE, point_antialias = FALSE, line_antialias = FALSE, depth_mask = TRUE, depth_test = "less", polygon_offset = c(0.0, 0.0), margin = "", floating = FALSE, tag = "", blend = c("src_alpha", "one_minus_src_alpha"), col, ... ) ``` Thus a call like `rgl.material(color = "black")` will set the color to black, and will also set all of the other parameters to the default values listed above. On the other hand, the arguments to `material3d()` are ```r function (..., id = NULL) ``` Calling `material3d(color = "black")` will set the color to black and leave all other parameters unchanged. ## Primitive shapes The primitive shapes (points etc.) can be set using calls like `rgl.points(x, y, z, color = "black")` or `points3d(x, y, z, color = "black")`. The first difference is that `rgl.*` primitives will call `rgl.material()` to set the material properties: in this example `color` will be set to `black`, and all other parameters will be set to their defaults. The `*3d` versions of the primitives use `material3d()` to set material properties, so only those that were specified will be changed, and the original values will be restored afterwards. The second difference is what happens if there is no window already open. The `rgl.*` functions will call `rgl.open()` (ignoring `r3dDefaults`), whereas the `*3d` functions will call `open3d()`. # Why deprecate `rgl.*`? Both of the systems worked, but they do not work together. For example, calling `rgl.points()` will have carry-on effects on later `points3d()` calls, whereas each `points3d()` call will just draw the points, it won't affect future calls. Users have found this confusing, and it makes their code hard to debug, and the `rgl` package hard to maintain. The `*3d` interface is more flexible, and more similar to the base graphics interface in R, so I've decided it will be the only one available going forward. ## Some `rgl.*` functions are not deprecated There will still be some `rgl.*` functions in the package. These are functions that are mainly intended for programming, such as `rgl.attrib()` and `rgl.user2window()`, and a few legacy functions like `rgl.Sweave()` supporting older approaches of using `rgl`. In a few cases both function versions are identical (`rgl.cur`, `rgl.ids`, and `rgl.pop` are identical to `cur3d`, `ids3d` and `pop3d` respectively), and for those the `rgl.*` versions will be kept, but the documentation will concentrate on the `*3d` functions. # My package uses `rgl.*`. What do I need to do? If your package is using `rgl.*` functions, the first step is to just make the substitutions suggested by the deprecation warning message. For example, if you use `rgl.points(rnorm(10), rnorm(10), rnorm(10))` try using `points3d(rnorm(10), rnorm(10), rnorm(10))` instead. In most cases this will give you what you want. In some cases more changes will be needed. ## `rgl.open` and `rgl.material` See above if you were using these. ## Textures The default color after `rgl.open()` was white, whereas with `open3d()` the default color is black, with a white background. Textures multiplicatively modify the color of the object, so after `open3d()`, a texture on an object will still appear black. Explicitly specifying `color = "white"` when a texture is used will fix this. ## `rgl.surface()` The arguments to `rgl.surface()` and `surface3d()` functions are different. The argument lists are ```r rgl.surface( x, z, y, coords = 1:3, ..., normal_x = NULL, normal_y = NULL, normal_z = NULL, texture_s = NULL, texture_t = NULL) surface3d(x, y = NULL, z = NULL, ..., normal_x = NULL, normal_y = NULL, normal_z = NULL, texture_s = NULL, texture_t=NULL) ``` Notice that the arguments are in a different order. Another difference is that `rgl.surface()` expects the surface to be defined in the `y` coordinate and viewed in the orientation produced by `rgl.open()`, not the one produced by `open3d()`. Up until very recently, `surface3d()` didn't allow both `x` and `z` to be vectors. The excellent [`rayshader` package](https://www.rayshader.com) used the convention that the `y` argument held the surface, so the `y` direction should point up. Using `view3d(theta = 45, phi = 45)` (which it was already doing) gives a reasonable view. ## Lists of material names and par3d properties Many functions in `rgl` and other packages use `...` to set material or `par3d` properties in a call, and for some, `...` will contain other optional arguments. Some packages used the argument list of `rgl.material()` to identify the material property names. Going forward, packages should use the variables ```r rgl.material.names rgl.material.readonly ``` These are character variables holding all the material property names. (`rgl.material.names` contains all names; `rgl.material.readonly` is the read-only subset of that list.) There are also variables ```r rgl.par3d.names rgl.par3d.readonly ``` which give the same information for `par3d`. Since these variables are recently added, you will need to add a dependence on `rgl (>= 0.111.5)` if you use them. ## Others If you have particular problems adapting other `rgl.*` to the `*3d` interface, please post them as issues on https://github.com/dmurdoch/rgl/issues . I'll explain how to get what you want or fix things in `rgl` so you can do it. rgl/vignettes/WebGL.Rmd0000644000176200001440000004035715013106241014454 0ustar liggesusers--- title: "User Interaction in WebGL" author: "Duncan Murdoch" date: "`r format(Sys.time(), '%B %d, %Y')`" output: rmarkdown::html_vignette: toc: true fig_width: 5 fig_height: 5 vignette: > %\VignetteIndexEntry{User Interaction in WebGL} %\VignetteEngine{knitr::rmarkdown} %\VignetteDepends{crosstalk} --- ```{r setup, echo=FALSE, results="asis"} source("setup.R") setupKnitr(autoprint = FALSE) set.seed(123) ``` ## Introduction This document describes how to embed `rgl` scenes in HTML documents and use embedded Javascript to control a WebGL display in an HTML document. For more general information about `rgl`, see [rgl Overview](rgl.html). We assume that the HTML document is produced from R markdown source using `knitr` or `rmarkdown`. This format mixes text with Markdown markup with chunks of R code. There is a limited amount of discussion of other methods. There are two ways to embed an `rgl` scene in the document. The newest one is recommended: call `r linkfn("setupKnitr")` with argument `autoprint = TRUE` early in the document. This will set things up to be quite similar to the way standard 2D graphics are included by `knitr`, i.e. it will detect the fact that you've drawn something, and just include it automatically. If `autoprint = FALSE` is used or no call is made to `setupKnitr()`, an explicit call to `r linkfn("rglwidget")` will produce a "widget" which can be embedded into your document by printing it. This document uses that method. Older methods (e.g. `writeWebGL` or various hooks) that were used before `rgl` version 0.102.0 are no longer supported. ## Browser support Most browsers now support WebGL, but in some browsers it may be disabled by default. See https://get.webgl.org for help on a number of different browsers. ## Examples We start with a simple plot of the iris data. We insert a code chunk and call the `r linkfn("rglwidget")` function with optional argument `elementId`. This allows later Javascript code to refer to the image. We also save the object ids from the plot, so that they can be manipulated later. (The first example in [Controls](#controls) uses tags instead of saving the ids.) ```{r elementId} library(rgl) plotids <- with(iris, plot3d(Sepal.Length, Sepal.Width, Petal.Length, type="s", col=as.numeric(Species))) rglwidget(elementId = "plot3drgl") ``` Next we insert a button to toggle the display of the data. ```{r} toggleWidget(sceneId = "plot3drgl", ids = plotids["data"], label = "Data") ``` The `sceneId` is the same as the `elementId` we used in `rglwidget()`, the `ids` are the object ids of the objects that we'd like to toggle, and the `label` is the label shown on the button. To find the names in the `plotids` variable, apply `names()` or `unclass()`: ```{r} names(plotids) unclass(plotids) ``` ## Using `magrittr` or base pipes It can be error-prone to set the `elementId` in the `rglwidget()` to match the `sceneId` in the `toggleWidget()` (or `playwidget()`, described below). In the usual case where both are intended to appear together, [`magrittr`](https://CRAN.R-project.org/package=magrittr)-style pipes can be used quite flexibly: the first argument of the control widget accepts the result of `rglwidget()` (or other control widgets), and the `controllers` argument of `rglwidget()` accepts control widgets. In R 4.1.0, the new base pipe operator `|>` should be usable in the same way. For example, ```{r Pipes} rglwidget() %>% toggleWidget(ids = plotids["data"], label = "Data") ``` If you have R 4.1.0 or greater, this should do the same: ```{r eval=FALSE} rglwidget() |> toggleWidget(ids = plotids["data"], label = "Data") ``` You can swap the order of button and scene; use the `magrittr` dot (or the `=>` syntax in base pipes) to pass the `toggleWidget` to `rglwidget` in the `controllers` argument: ```{r "Control before widget"} toggleWidget(NA, ids = plotids["data"], label = "Data") %>% rglwidget(controllers = .) ``` or using R 4.1.0 or later, ```{r eval=FALSE} toggleWidget(NA, ids = plotids["data"], label = "Data") |> w => rglwidget(controllers = w) ``` ## Controls We have seen how to change the contents of the plot using `r indexfns("toggleWidget")`. We can do more elaborate displays. For example, we can redo the previous plot, but with the three species as separate "spheres" objects and buttons to toggle them: ```{r "Toggle subsets"} clear3d() # Remove the earlier display with(subset(iris, Species == "setosa"), spheres3d(Sepal.Length, Sepal.Width, Petal.Length, col=as.numeric(Species), radius = 0.211, tag = "setosa")) with(subset(iris, Species == "versicolor"), spheres3d(Sepal.Length, Sepal.Width, Petal.Length, col=as.numeric(Species), radius = 0.211, tag = "versicolor")) with(subset(iris, Species == "virginica"), spheres3d(Sepal.Length, Sepal.Width, Petal.Length, col=as.numeric(Species), radius = 0.211, tag = "virginica")) aspect3d(1,1,1) decorate3d(tag = "axes") rglwidget() %>% toggleWidget(tags = "setosa") %>% toggleWidget(tags = "versicolor") %>% toggleWidget(tags = "virginica") %>% toggleWidget(tags = "axes") %>% asRow(last = 4) ``` Since we skipped the `label` argument, the buttons are labelled with the values of the tags. The `asRow` function is discussed `r linkfn("asRow", "below")`. `toggleWidget()` is actually a convenient wrapper for two functions: `r indexfns("playwidget")` and `r indexfns("subsetControl")`. `playwidget()` adds the button to the web page (and can also add sliders, do animations, etc.), while `subsetControl()` chooses a subset of objects to display. ### `subsetControl` For a more general example, we could use a slider to select several subsets of the data in the iris display. For example, ```{r Slider} rglwidget() %>% playwidget(start = 0, stop = 3, interval = 1, subsetControl(1, subsets = list( Setosa = tagged3d("setosa"), Versicolor = tagged3d("versicolor"), Virginica = tagged3d("virginica"), All = tagged3d(c("setosa", "versicolor", "virginica")) ))) ``` There are several other "control" functions. ### `par3dinterpControl` `r indexfns("par3dinterpControl")` approximates the result of `r linkfn("par3dinterp")`. For example, the following code (similar to the `r linkfn("play3d")` example) rotates the scene in a complex way. ```{r "par3dinterpControl()"} M <- r3dDefaults$userMatrix fn <- par3dinterp(time = (0:2)*0.75, userMatrix = list(M, rotate3d(M, pi/2, 1, 0, 0), rotate3d(M, pi/2, 0, 1, 0)) ) rglwidget() %>% playwidget(par3dinterpControl(fn, 0, 3, steps=15), step = 0.01, loop = TRUE, rate = 0.5) ``` Some things to note: The generated Javascript slider has 300 increments, so that motion appears smooth. However, storing 300 `userMatrix` values would take up a lot of space, so we use interpolation in the Javascript code. However, the Javascript code can only do linear interpolation, not the more complex spline-based SO(3) interpolation done by `r linkfn("par3dinterp")`. Because of this, we need to output 15 steps from `r linkfn("par3dinterpControl")` so that the distortions of linear interpolation are not visible. ### `propertyControl` `r indexfns("propertyControl")` is a more general function to set the value of properties of the scene. Currently most properties are supported, but use does require knowledge of the internal implementation. ### `clipplaneControl` `r indexfns("clipplaneControl")` allows the user to control the location of a clipping plane by moving a slider. ### `vertexControl` Less general than `r linkfn("propertyControl")` is `r indexfns("vertexControl")`. This function sets attributes of individual vertices in a scene. For example, to set the x-coordinate of the closest point in the setosa group, and modify its colour from black to white, ```{r "vertexControl()"} setosavals <- subset(iris, Species == "setosa") which <- which.min(setosavals$Sepal.Width) init <- setosavals$Sepal.Length[which] rglwidget() %>% playwidget( vertexControl(values = matrix(c(init, 0, 0, 0, 8, 1, 1, 1), nrow = 2, byrow = TRUE), attributes = c("x", "red", "green", "blue"), vertices = which, tag = "setosa"), step = 0.01) ``` ### `ageControl` A related function is `r indexfns("ageControl")`, though it uses a very different specification of the attributes. It is used when the slider controls the "age" of the scene, and attributes of vertices change with their age. To illustrate we will show a point moving along a curve. We give two `ageControl` calls in a list; the first one controls the colour of the trail, the second controls the position of the point: ```{r "ageControl()"} time <- 0:500 xyz <- cbind(cos(time/20), sin(time/10), time) lineid <- plot3d(xyz, type="l", col = "black")["data"] sphereid <- spheres3d(xyz[1, , drop=FALSE], radius = 8, col = "red") rglwidget() %>% playwidget(list( ageControl(births = time, ages = c(0, 0, 50), colors = c("gray", "red", "gray"), objids = lineid), ageControl(births = 0, ages = time, vertices = xyz, objids = sphereid)), start = 0, stop = max(time) + 20, rate = 50, components = c("Reverse", "Play", "Slower", "Faster", "Reset", "Slider", "Label"), loop = TRUE) ``` ### `rglMouse` While not exactly a control in the sense of the other functions in this section, the `r indexfns("rglMouse")` function is used to add an HTML control to a display to allow the user to select the mouse mode. For example, the display below initially allows selection of particular points, but the mouse mode may be changed to let the user rotate the display for a another view of the scene. ```{r crosstalk,eval = requireNamespace("crosstalk", quietly=TRUE)} # This example requires the crosstalk package # We skip it if crosstalk is not available. ids <- with(iris, plot3d(Sepal.Length, Sepal.Width, Petal.Length, type="s", col=as.numeric(Species))) par3d(mouseMode = "selecting") rglwidget(shared = rglShared(ids["data"])) %>% rglMouse() ``` The `rglShared()` call used here is described `r linkfn("rglShared", "below")`. ## Layout of the display Many `rgl` displays will contain several elements: one or more `rgl` scenes and controls. Internally `rgl` uses the `combineWidgets` function from the [`manipulateWidget`](https://github.com/rte-antares-rpackage/manipulateWidget) package. The `rgl` package provides 3 convenience functions for arranging displays. We have already met the first: the `magrittr` pipe, `%>%`. When the display is constructed as a single object using pipes, the objects in the pipeline will be arranged in a single column. The second convenience function is `r indexfns("asRow")`. This takes as input a list of objects or a `combineWidgets` object (perhaps the result of a pipe), and rearranges (some of) them into a horizontal row. As in the `r linkfn("toggleWidget", "toggleWidget example")`, the `last` argument can be used to limit the actions of `asRow` to the specified number of components. (If `last = 0`, all objects are stacked: this can be useful if some of them are not from the `rgl` package, so piping doesn't work for them.) Finally, `r indexfns("getWidgetId")` can be used to extract the HTML element ID from an HTML widget. This is useful when combining widgets that are not all elements of the same pipe, as in the `crosstalk` example below. If these convenience functions are not sufficient, you can call `r linkfn("combineWidgets", text = "manipulateWidget::combineWidgets", pkg = "manipulateWidget")` or other functions from `manipulateWidget` for more flexibility in the display arrangements. ## Integration with `crosstalk` The [`crosstalk`](https://rstudio.github.io/crosstalk/) package allows widgets to communicate with each other. Currently it supports selection and filtering of observations. `rgl` can send, receive and display these messages. An `rgl` display may have several subscenes, each displaying different datasets. Each object in the scene is potentially a shared dataset in the `crosstalk` sense. The linking depends on the `r indexfns("rglShared")` function. Calling `rglShared(id)`, where `id` is the `rgl` id value for an object in the current scene, creates a shared data object containing the coordinates of the vertices of the `rgl` object. This object is passed to `r linkfn("rglwidget")` in the `shared` argument. It can also be passed to other widgets that accept shared data, linking the two displays. If a shared data object has been created in some other way, it can be linked to a particular `rgl` `id` value by copying its `key` and `group` properties as shown in the example below. ```{r "rglShared()",eval=requireNamespace("crosstalk", quietly = TRUE)} # This example requires the crosstalk package. # We skip it if crosstalk is not available. library(crosstalk) sd <- SharedData$new(mtcars) ids <- plot3d(sd$origData(), col = mtcars$cyl, type = "s") # Copy the key and group from existing shared data rglsd <- rglShared(ids["data"], key = sd$key(), group = sd$groupName()) rglwidget(shared = rglsd) %>% asRow("Mouse mode: ", rglMouse(getWidgetId(.)), "Subset: ", filter_checkbox("cylinderselector", "Cylinders", sd, ~ cyl, inline = TRUE), last = 4, colsize = c(1,2,1,2), height = 60) ``` If multiple objects in the `rgl` scene need to be considered as shared data, you can pass the results of several `rglShared()` calls in a list, i.e. `rglwidget(shared = )`. The key values will be assumed to be shared across datasets; if this is not wanted, use a prefix or some other means to make sure they differ between objects. If the same `rgl` id is used in more than one `rglShared()` object, it will respond to messages from all of them. This may lead to undesirable behaviour as one message cancels the previous one. ## Low level controls We repeat the initial plot from this document: ```{r plot3d2} plotids <- with(iris, plot3d(Sepal.Length, Sepal.Width, Petal.Length, type="s", col=as.numeric(Species))) subid <- currentSubscene3d() rglwidget(elementId="plot3drgl2") ``` We might like a button on the web page to cause a change to the display, e.g. a rotation of the plot. First we add buttons, with the "onclick" event set to a function described below: which produces these buttons: We stored the subscene number that is currently active in `subid` in the code chunk above, and use it as `r rinline("subid")` in the script below. `knitr` substitutes the value when it processes the document. The `rotate()` function uses the Javascript function `document.getElementById` to retrieve the `
` component of the web page containing the scene. It will have a component named `rglinstance` which contains information about the scene that we can modify: If we had used `webGL=TRUE` in the chunk header, the `knitr` WebGL support would create a global object with a name of the form `rgl`. For example, if the code chunk was named `plot3d2`, the object would be called `plot3d2rgl`, and this code would work: ## Index The following functions are described in this document:
```{r echo=FALSE, results="asis"} writeIndex(cols = 5) ``` rgl/vignettes/demos.Rmd0000644000176200001440000005142415011677075014640 0ustar liggesusers--- title: "rgl Demos" date: "`r Sys.Date()`" output: rmarkdown::html_vignette: toc: true fig_height: 5 fig_width: 5 vignette: > %\VignetteIndexEntry{rgl Demos} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = FALSE, # Bug in knitr 1.42 requires FALSE here comment = "#>", snapshot = FALSE, screenshot.force = FALSE) library(rgl) setupKnitr(autoprint = TRUE) ``` ## Introduction This vignette holds code that was previously included as "demos" in `rgl`. Some of the demos require R to be running; those remain available via `demo(package = "rgl")`. ## hist3d: 3D histogram using basic building blocks ```{r} ########## ### 3D HIST EXAMPLE: ########## ################################################################################ ##### Required functions 'binplot' and 'hist3d': binplot.3d<-function(x,y,z,alpha=1,topcol="#ff0000",sidecol="#aaaaaa") { save <- par3d(skipRedraw=TRUE) on.exit(par3d(save)) x1<-c(rep(c(x[1],x[2],x[2],x[1]),3),rep(x[1],4),rep(x[2],4)) z1<-c(rep(0,4),rep(c(0,0,z,z),4)) y1<-c(y[1],y[1],y[2],y[2],rep(y[1],4),rep(y[2],4),rep(c(y[1],y[2],y[2],y[1]),2)) x2<-c(rep(c(x[1],x[1],x[2],x[2]),2),rep(c(x[1],x[2],rep(x[1],3),rep(x[2],3)),2)) z2<-c(rep(c(0,z),4),rep(0,8),rep(z,8) ) y2<-c(rep(y[1],4),rep(y[2],4),rep(c(rep(y[1],3),rep(y[2],3),y[1],y[2]),2) ) quads3d(x1,z1,y1,col=rep(sidecol,each=4),alpha=alpha) quads3d(c(x[1],x[2],x[2],x[1]),rep(z,4),c(y[1],y[1],y[2],y[2]), col=rep(topcol,each=4),alpha=1) segments3d(x2,z2,y2,col="#000000") } hist3d<-function(x,y=NULL,nclass="auto",alpha=1,col="#ff0000",scale=10) { save <- par3d(skipRedraw=TRUE) on.exit(par3d(save)) xy <- xy.coords(x,y) x <- xy$x y <- xy$y n<-length(x) if (nclass == "auto") nclass<-ceiling(sqrt(nclass.Sturges(x))) breaks.x <- seq(min(x),max(x),length=(nclass+1)) breaks.y <- seq(min(y),max(y),length=(nclass+1)) z<-matrix(0,(nclass),(nclass)) for (i in seq_len(nclass)) { for (j in seq_len(nclass)) { z[i, j] <- (1/n)*sum(x < breaks.x[i+1] & y < breaks.y[j+1] & x >= breaks.x[i] & y >= breaks.y[j]) binplot.3d(c(breaks.x[i],breaks.x[i+1]),c(breaks.y[j],breaks.y[j+1]), scale*z[i,j],alpha=alpha,topcol=col) } } } ################################################################################ open3d() bg3d(color="gray") light3d(0, 0) # Drawing a 'bin' for given coordinates: binplot.3d(c(-0.5,0.5),c(4.5,5.5),2,alpha=0.6) # Setting the viewpoint ('theta' and 'phi' have the same meaning as in persp): view3d(theta=40,phi=40) ##### QUADS FORMING BIN open3d() # Defining transparency and colors: alpha<-0.7; topcol<-"#ff0000"; sidecol<-"#aaaaaa" # Setting up coordinates for the quads and adding them to the scene: y<-x<-c(-1,1) ; z<-4; of<-0.3 x12<-c(x[1],x[2],x[2],x[1]); x11<-rep(x[1],4); x22<-rep(x[2],4) z00<-rep(0,4); z0z<-c(0,0,z,z); zzz<-rep(z,4); y11<-rep(y[1],4) y1122<-c(y[1],y[1],y[2],y[2]); y12<-c(y[1],y[2],y[2],y[1]); y22<-rep(y[2],4) quads3d(c(x12,x12,x11-of,x12,x22+of,x12), c(z00-of,rep(z0z,4),zzz+of), c(y1122,y11-of,y12,y22+of,y12,y1122), col=rep(c(rep(sidecol,5),topcol),each=4),alpha=c(rep(alpha,5),1)) # Setting up coordinates for the border-lines of the quads and drawing them: yl1<-c(y[1],y[2],y[1],y[2]); yl2<-c(y[1]-of,y[1]-of) xl<-c(rep(x[1],8),rep(x[1]-of,8),rep(c(x[1],x[2]),8),rep(x[2],8),rep(x[2]+of,8)) zl<-c(0,z,0,z,z+of,z+of,-of,-of,0,0,z,z,0,z,0,z,rep(0,4),rep(z,4),rep(-of,4), rep(z+of,4),z+of,z+of,-of,-of,rep(c(0,z),4),0,0,z,z) yl<-c(yl2,y[2]+of,y[2]+of,rep(c(y[1],y[2]),4),y[1],y[1],y[2],y[2],yl2, rep(y[2]+of,4),yl2,y[2],y[2],rep(y[1],4),y[2],y[2],yl1,yl2,y[2]+of, y[2]+of,y[1],y[1],y[2],y[2],yl1) lines3d(xl,zl,yl,col="#000000") view3d(theta=40,phi=40) ##### COMPLETE HISTOGRAM: open3d() # Setting the rng to a fixed value: set.seed(1000) # Drawing a 3d histogramm of 2500 normaly distributed observations: hist3d(rnorm(2500),rnorm(2500),alpha=0.4,nclass=7,scale=30) # Choosing a lightgrey background: bg3d(col="#cccccc") view3d(theta=40,phi=40) ``` ## bivar: Bivariate densities: kernel smoothing using surface3d and alpha-channel (requires MASS package) ```{r} # rgl demo: rgl-bivar.r # author: Daniel Adler rgl.demo.bivar <- function() { if (!requireNamespace("MASS", quietly = TRUE)) stop("This demo requires MASS") # parameters: n<-50; ngrid<-40 # generate samples: set.seed(31415) x<-rnorm(n); y<-rnorm(n) # estimate non-parameteric density surface via kernel smoothing denobj <- MASS::kde2d(x, y, n=ngrid) den.z <-denobj$z # generate parametric density surface of a bivariate normal distribution xgrid <- denobj$x ygrid <- denobj$y bi.z <- dnorm(xgrid)%*%t(dnorm(ygrid)) # visualize: zscale<-20 # New window open3d() # clear scene: clear3d("all") # setup env: bg3d(color="#887777") light3d() # Draws the simulated data as spheres on the baseline spheres3d(x,y,rep(0,n),radius=0.1,color="#CCCCFF") # Draws non-parametric density surface3d(xgrid,ygrid,den.z*zscale,color="#FF2222",alpha=0.5) # Draws parametric density surface3d(xgrid,ygrid,bi.z*zscale,color="#CCCCFF",front="lines") } rgl.demo.bivar() ``` ## Abundance: Animal abundance, visualization of multi-dimension data using multiple techniques ```{r} # RGL-Demo: animal abundance # Authors: Oleg Nenadic, Daniel Adler rgl.demo.abundance <- function() { open3d() clear3d("all") # remove all shapes, lights, bounding-box, and restore viewpoint # Setup environment: bg3d(col="#cccccc") # setup background light3d() # setup head-light # Importing animal data (created with wisp) terrain<-dget(system.file("demodata/region.dat",package="rgl")) pop<-dget(system.file("demodata/population.dat",package="rgl")) # Define colors for terrain zlim <- range(terrain) colorlut <- terrain.colors(82) col1 <- colorlut[9*sqrt(3.6*(terrain-zlim[1])+2)] # Set color to (water-)blue for regions with zero 'altitude' col1[terrain==0]<-"#0000FF" # Add terrain surface shape (i.e. population density): surface3d( 1:100,seq(1,60,length=100),terrain, col=col1,spec="#000000", ambient="#333333", back="lines" ) # Define colors for simulated populations (males:blue, females:red): col2<-pop[,4] col2[col2==0]<-"#3333ff" col2[col2==1]<-"#ff3333" # Add simulated populations as sphere-set shape spheres3d( pop[,1], pop[,2], terrain[cbind( ceiling(pop[,1]),ceiling(pop[,2]*10/6) )]+0.5, radius=0.2*pop[,3], col=col2, alpha=(1-(pop[,5])/10 ) ) } rgl.demo.abundance() ``` ## lsystem: Plant modelling using a turtle and L-system ```{r} # demo: lsystem.r # author: Daniel Adler # # geometry # deg2rad <- function( degree ) { return( degree*pi/180 ) } rotZ.m3x3 <- function( degree ) { kc <- cos(deg2rad(degree)) ks <- sin(deg2rad(degree)) return( matrix( c( kc, -ks, 0, ks, kc, 0, 0, 0, 1 ),ncol=3,byrow=TRUE ) ) } rotX.m3x3 <- function( degree ) { kc <- cos(deg2rad(degree)) ks <- sin(deg2rad(degree)) return( matrix( c( 1, 0, 0, 0, kc, -ks, 0, ks, kc ),ncol=3,byrow=TRUE ) ) } rotY.m3x3 <- function( degree ) { kc <- cos(deg2rad(degree)) ks <- sin(deg2rad(degree)) return( matrix( c( kc, 0, ks, 0, 1, 0, -ks, 0, kc ),ncol=3,byrow=TRUE ) ) } rotZ <- function( v, degree ) { return( rotZ.m3x3(degree) %*% v) } rotX <- function( v, degree ) { return( rotX.m3x3(degree) %*% v) } rotY <- function( v, degree ) { return( rotY.m3x3(degree) %*% v) } # # turtle graphics, rgl implementation: # turtle.init <- function(pos=c(0,0,0),head=0,pitch=90,roll=0,level=0) { clear3d("all") bg3d(color="gray") light3d() return( list(pos=pos,head=head,pitch=pitch,roll=roll,level=level) ) } turtle.move <- function(turtle, steps, color) { rm <- rotX.m3x3(turtle$pitch) %*% rotY.m3x3(turtle$head) %*% rotZ.m3x3(turtle$roll) from <- as.vector( turtle$pos ) dir <- rm %*% c(0,0,-1) to <- from + dir * steps x <- c( from[1], to[1] ) y <- c( from[2], to[2] ) z <- c( from[3], to[3] ) lines3d(x,y,z,col=color,size=1.5,alpha=0.5) turtle$pos <- to return(turtle) } turtle.pitch <- function(turtle, degree) { turtle$pitch <- turtle$pitch + degree return(turtle) } turtle.head <- function(turtle, degree) { turtle$head <- turtle$head + degree return(turtle) } turtle.roll <- function(turtle, degree) { turtle$roll <- turtle$roll + degree return(turtle) } # # l-system general # lsystem.code <- function( x ) substitute( x ) lsystem.gen <- function( x, grammar, levels=0 ) { code <- eval( substitute( substitute( REPLACE , grammar ), list(REPLACE=x) ) ) if (levels) return( lsystem.gen( code , grammar , levels-1 ) ) else return( code ) } # # l-system plot # lsystem.plot <- function( expr, level ) { turtle <- turtle.init(level=level) lsystem.eval( expr, turtle ) } lsystem.eval <- function( expr, turtle ) { if ( length(expr) == 3 ) { turtle <- lsystem.eval( expr[[2]], turtle ) turtle <- lsystem.eval( expr[[3]], turtle ) turtle <- lsystem.eval( expr[[1]], turtle ) } else if ( length(expr) == 2 ) { saved <- turtle turtle <- lsystem.eval( expr[[1]], turtle ) turtle <- lsystem.eval( expr[[2]], turtle ) turtle <- saved } else if ( length(expr) == 1 ) { if ( as.name(expr) == "stem" ) turtle <- turtle.move(turtle, 5, "brown") else if ( as.name(expr) == "short") turtle <- turtle.move(turtle, 5, "brown") else if ( as.name(expr) == "leaf" ) { spheres3d(turtle$pos[1],turtle$pos[2],turtle$pos[3],radius=0.1+turtle$level*0.3,color="green") sprites3d(turtle$pos[1],turtle$pos[2],turtle$pos[3],radius=0.5+turtle$level*0.3 ,color="green",texture=system.file("textures/particle.png",package="rgl"),textype="alpha",alpha=0.5) } else if ( as.name(expr) == "roll" ) turtle <- turtle.head(turtle, 60) else if ( as.name(expr) == "down" ) turtle <- turtle.pitch(turtle,10) else if ( as.name(expr) == "up" ) turtle <- turtle.pitch(turtle,-10) else if ( as.name(expr) == "left" ) turtle <- turtle.head(turtle, 1) else if ( as.name(expr) == "right") turtle <- turtle.head(turtle,-1.5) else if ( as.name(expr) == "turnleft") turtle <- turtle.head(turtle,20) else if ( as.name(expr) == "turnright") turtle <- turtle.head(turtle,-20) else if ( as.name(expr) == "turn") turtle <- turtle.roll(turtle,180) } return(turtle) } # # example # simple <- function(level=0) { grammar <- list( stem=lsystem.code( stem-(up-stem-leaf)-stem-(down-stem-leaf)-stem-leaf ) ) plant <- lsystem.gen(lsystem.code(stem), grammar, level ) lsystem.plot(plant,level) } rgl.demo.lsystem <- function(level=0) { gen <- list( stem=lsystem.code( stem-left-stem-branch( turnleft-down-short-turnleft-down-stem-leaf)-right-right-stem--branch( turnright-up-short-turnright-up-short-turnright-short-stem-leaf)-left-left-left-stem-branch( turnleft-down-short-turnright-down-stem-leaf )-branch( up-turnright-short-up-turnleft-up-stem-leaf ) ) ) plant <- lsystem.gen(lsystem.code(stem), gen, level ) lsystem.plot(plant,level) } open3d() rgl.demo.lsystem(level=1) rglwidget() ``` ## subdivision: Subdivision surfaces using generic meshes (preview of generic 3D interface) ```{r} # RGL-demo: subdivision surfaces # author: Daniel Adler rgl.demo.subdivision <- function() { # setup environment clear3d("all") view3d() bg3d(color="gray") light3d() # generate basic mesh obj <- oh3d() part <- function( level, tx, ... ) { shade3d( translate3d( obj, tx, 0, 0 ) , color="gray30", front="lines",alpha=0.5,back="lines", override=TRUE ) shade3d( translate3d( subdivision3d( obj, depth=level ), tx, 0, 0 ) , override=TRUE, ... ) } part(0, -5.50, color="blue" ) part(1, -1.75, color="yellow" ) part(2, 1.75, color="red" ) part(3, 5.50, color="green" ) } open3d() rgl.demo.subdivision() ``` ## envmap: Environment mapping ```{r} # RGL-Demo: environment mapping # Author: Daniel Adler rgl.demo.envmap <- function() { open3d() # Clear scene: clear3d("all") light3d() bg3d(sphere=TRUE, color="white", back="filled" , texture=system.file("textures/refmap.png",package="rgl") ) data(volcano) surface3d( 10*seq_len(nrow(volcano)),10*seq_len(ncol(volcano)),5*volcano , texture=system.file("textures/refmap.png",package="rgl") , texenvmap=TRUE , texmode="modulate" , color = "white" ) } rgl.demo.envmap() ``` ## shapes3d: 3D shape primitives (cones, ellipsoids, cubes), some taken from qmesh3d ```{r} cone3d <- function(base=c(0,0,0),tip=c(0,0,1),rad=1,n=30,draw.base=TRUE,qmesh=FALSE, trans = par3d("userMatrix"), ...) { ax <- tip-base if (missing(trans) && !cur3d()) trans <- diag(4) ### is there a better way? if (ax[1]!=0) { p1 <- c(-ax[2]/ax[1],1,0) p1 <- p1/sqrt(sum(p1^2)) if (p1[1]!=0) { p2 <- c(-p1[2]/p1[1],1,0) p2[3] <- -sum(p2*ax) p2 <- p2/sqrt(sum(p2^2)) } else { p2 <- c(0,0,1) } } else if (ax[2]!=0) { p1 <- c(0,-ax[3]/ax[2],1) p1 <- p1/sqrt(sum(p1^2)) if (p1[1]!=0) { p2 <- c(0,-p1[3]/p1[2],1) p2[3] <- -sum(p2*ax) p2 <- p2/sqrt(sum(p2^2)) } else { p2 <- c(1,0,0) } } else { p1 <- c(0,1,0); p2 <- c(1,0,0) } degvec <- seq(0,2*pi,length=n+1)[-1] ecoord2 <- function(theta) { base+rad*(cos(theta)*p1+sin(theta)*p2) } i <- rbind(1:n,c(2:n,1),rep(n+1,n)) v <- cbind(sapply(degvec,ecoord2),tip) if (qmesh) ## minor kluge for quads -- draw tip twice i <- rbind(i,rep(n+1,n)) if (draw.base) { v <- cbind(v,base) i.x <- rbind(c(2:n,1),1:n,rep(n+2,n)) if (qmesh) ## add base twice i.x <- rbind(i.x,rep(n+2,n)) i <- cbind(i,i.x) } if (qmesh) v <- rbind(v,rep(1,ncol(v))) ## homogeneous if (!qmesh) triangles3d(v[1,i],v[2,i],v[3,i],...) else return(rotate3d(qmesh3d(v,i,material=list(...)), matrix=trans)) } ellipsoid3d <- function(rx=1,ry=1,rz=1,n=30,ctr=c(0,0,0), qmesh=FALSE, trans = par3d("userMatrix"),...) { if (missing(trans) && !cur3d()) trans <- diag(4) degvec <- seq(0,pi,length=n) ecoord2 <- function(p) c(rx*cos(p[1])*sin(p[2]),ry*sin(p[1])*sin(p[2]),rz*cos(p[2])) v <- apply(expand.grid(2*degvec,degvec),1,ecoord2) if (qmesh) v <- rbind(v,rep(1,ncol(v))) ## homogeneous e <- expand.grid(1:(n-1),1:n) i1 <- apply(e,1,function(z)z[1]+n*(z[2]-1)) i2 <- i1+1 i3 <- (i1+n-1) %% n^2 + 1 i4 <- (i2+n-1) %% n^2 + 1 i <- rbind(i1,i2,i4,i3) if (!qmesh) quads3d(v[1,i],v[2,i],v[3,i],...) else return(rotate3d(qmesh3d(v,i,material=list(...)),matrix=trans)) } ############ open3d() ellipsoid3d(ctr=c(2,2,2),rx=3,ry=2,col="red",alpha=0.4) cone3d(base=c(-2,-2,-2),rad=0.5,tip=c(-3,0,-4),col="blue",front="lines",back="lines") shade3d(translate3d(cube3d(),3,-2,3,col="purple")) ### now with qmesh() open3d() q1 <- cone3d(qmesh=TRUE,trans=diag(4)) ## the "unit cone"; ## height=1,radius=1, base at (0,0,0) shade3d(q1) ## various transformations and rotations wire3d(translate3d(q1,3,0,0),col="green") wire3d(translate3d(scale3d(q1,1,1,2),6,0,0),col="green") dot3d(translate3d(q1,0,3,0),col="green") dot3d(translate3d(scale3d(q1,2,1,1),0,6,0),col="green") shade3d(translate3d(q1,0,0,3),col="red") shade3d(translate3d(rotate3d(scale3d(q1,1,1,2),pi/4,0,1,0),0,0,6),col="red") axes3d() open3d() s1 <- ellipsoid3d(qmesh=TRUE,trans=diag(4)) ## the "unit sphere"; ## radius=1, ctr at (0,0,0) shade3d(s1) ## various transformations and rotations wire3d(translate3d(s1,3,0,0),col="green") wire3d(translate3d(scale3d(s1,1,1,2),6,0,0),col="green") dot3d(translate3d(s1,0,3,0),col="green") dot3d(translate3d(scale3d(s1,2,1,1),0,6,0),col="green") shade3d(translate3d(s1,0,0,3),col="red") shade3d(translate3d(rotate3d(scale3d(s1,1,1,2),pi/4,0,1,0),0,0,6),col="red") axes3d() ``` ## lollipop3d: "Lollipop" plots (3D scatterplot with lines between points and a surface) ```{r} cone3d <- function(base,tip,rad,n=30,...) { degvec <- seq(0,2*pi,length=n) ax <- tip-base ## what do if ax[1]==0? if (ax[1]!=0) { p1 <- c(-ax[2]/ax[1],1,0) p1 <- p1/sqrt(sum(p1^2)) if (p1[1]!=0) { p2 <- c(-p1[2]/p1[1],1,0) p2[3] <- -sum(p2*ax) p2 <- p2/sqrt(sum(p2^2)) } else { p2 <- c(0,0,1) } } else if (ax[2]!=0) { p1 <- c(0,-ax[3]/ax[2],1) p1 <- p1/sqrt(sum(p1^2)) if (p1[1]!=0) { p2 <- c(0,-p1[3]/p1[2],1) p2[3] <- -sum(p2*ax) p2 <- p2/sqrt(sum(p2^2)) } else { p2 <- c(1,0,0) } } else { p1 <- c(0,1,0); p2 <- c(1,0,0) } ecoord2 <- function(theta) { base+rad*(cos(theta)*p1+sin(theta)*p2) } for (i in seq_len(n-1)) { li <- ecoord2(degvec[i]) lj <- ecoord2(degvec[i+1]) triangles3d(c(li[1],lj[1],tip[1]),c(li[2],lj[2],tip[2]),c(li[3],lj[3],tip[3]),...) } } lollipop3d <- function(data.x,data.y,data.z,surf.fun,surf.n=50, xlim=range(data.x), ylim=range(data.y), zlim=range(data.z), asp=c(y=1,z=1), xlab=deparse(substitute(x)), ylab=deparse(substitute(y)), zlab=deparse(substitute(z)), alpha.surf=0.4, col.surf=fg,col.stem=c(fg,fg), col.pt="gray",type.surf="line",ptsize, lwd.stem=2,lit=TRUE,bg="white",fg="black", col.axes=fg,col.axlabs=fg, axis.arrow=TRUE,axis.labels=TRUE, box.col=bg, axes=c("lines","box")) { axes <- match.arg(axes) col.stem <- rep(col.stem,length=2) x.ticks <- pretty(xlim) x.ticks <- x.ticks[x.ticks>=min(xlim) & x.ticks<=max(xlim)] x.ticklabs <- if (axis.labels) as.character(x.ticks) else NULL y.ticks <- pretty(ylim) y.ticks <- y.ticks[y.ticks>=min(ylim) & y.ticks<=max(ylim)] y.ticklabs <- if (axis.labels) as.character(y.ticks) else NULL z.ticks <- pretty(zlim) z.ticks <- z.ticks[z.ticks>=min(zlim) & z.ticks<=max(zlim)] z.ticklabs <- if (axis.labels) as.character(z.ticks) else NULL if (!missing(surf.fun)) { surf.x <- seq(xlim[1],xlim[2],length=surf.n) surf.y <- seq(ylim[1],ylim[2],length=surf.n) surf.z <- outer(surf.x,surf.y,surf.fun) ## requires surf.fun be vectorized z.interc <- surf.fun(data.x,data.y) zdiff <- diff(range(c(surf.z,data.z))) } else { z.interc <- rep(min(data.z),length(data.x)) zdiff <- diff(range(data.z)) } xdiff <- diff(xlim) ydiff <- diff(ylim) y.adj <- if (asp[1]<=0) 1 else asp[1]*xdiff/ydiff data.y <- y.adj*data.y y.ticks <- y.adj*y.ticks ylim <- ylim*y.adj ydiff <- diff(ylim) z.adj <- if (asp[2]<=0) 1 else asp[2]*xdiff/zdiff data.z <- z.adj*data.z if (!missing(surf.fun)) { surf.y <- y.adj*surf.y surf.z <- z.adj*surf.z } z.interc <- z.adj*z.interc z.ticks <- z.adj*z.ticks zlim <- z.adj*zlim open3d() clear3d("all") light3d() bg3d(color=c(bg,fg)) if (!missing(surf.fun)) surface3d(surf.x,surf.y,surf.z,alpha=alpha.surf, front=type.surf,back=type.surf, col=col.surf,lit=lit) if (missing(ptsize)) ptsize <- 0.02*xdiff ## draw points spheres3d(data.x,data.y,data.z,r=ptsize,lit=lit,color=col.pt) ## draw lollipops apply(cbind(data.x,data.y,data.z,z.interc),1, function(X) { lines3d(x=rep(X[1],2), y=rep(X[2],2), z=c(X[3],X[4]), col=ifelse(X[3]>X[4],col.stem[1], col.stem[2]),lwd=lwd.stem) }) if (axes=="box") { bbox3d(xat=x.ticks,xlab=x.ticklabs, yat=y.ticks,ylab=y.ticklabs, zat=z.ticks,zlab=z.ticklabs,lit=lit) } else if (axes=="lines") { ## set up axis lines axis3d(edge="x",at=x.ticks,labels=x.ticklabs, col=col.axes,arrow=axis.arrow) axis3d(edge="y",at=y.ticks,labels=y.ticklabs, col=col.axes,arrow=axis.arrow) axis3d(edge="z",at=z.ticks,labels=z.ticklabs, col=col.axes,arrow=axis.arrow) box3d(col=col.axes) } decorate3d(xlab=xlab, ylab=ylab, zlab=zlab, box=FALSE, axes=FALSE, col=col.axlabs) } x <- 1:5 y <- x*10 z <- (x+y)/20 open3d() spheres3d(x,y,z) axes3d() set.seed(1001) x <- runif(30) y <- runif(30,max=2) dfun <- function(x,y) 2*x+3*y+2*x*y+3*y^2 z <- dfun(x,y)+rnorm(30,sd=0.5) ## lollipops only lollipop3d(x,y,z) ## lollipops plus theoretical surface open3d() lollipop3d(x,y,z,dfun,col.pt="red",col.stem=c("red","blue")) ## lollipops plus regression fit linmodel <- lm(z~x+y) dfun <- function(x,y) predict(linmodel,newdata=data.frame(x=x,y=y)) open3d() lollipop3d(x,y,z,dfun,col.pt="red",col.stem=c("red","blue")) #### ```rgl/vignettes/setup.R0000644000176200001440000000737615013106241014337 0ustar liggesusersoptions(rgl.useNULL=FALSE) suppressPackageStartupMessages(library(rgl)) options(rgl.useNULL=TRUE) options(rgl.printRglwidget=FALSE) open3d() if (!requireNamespace("rmarkdown", quietly = TRUE) || !rmarkdown::pandoc_available("1.14")) { warning(call. = FALSE, "These vignettes assume rmarkdown and Pandoc version 1.14. These were not found. Older versions will not work.") knitr::knit_exit() } # If Pandoc is not installed, the output format won't be set. # knitr uses it to determine whether to do # screenshots; we don't want those. see https://github.com/rstudio/markdown/issues/115 knitr::opts_chunk$set(screenshot.force = FALSE, snapshot = FALSE) # knitr::opts_chunk$set(snapshot = TRUE) # for snapshots instead of dynamic documentedfns <- c() deprecatedfns <- c() backticked <- function(s) paste0("`", s, "`") indexfns <- function(fns, text = backticked(fns), show = TRUE, pkg = "rgl") { documentedfns <<- c(documentedfns, fns) anchors <- paste0('', if (show) linkfn(fns, text, pkg = pkg), '') paste(anchors, collapse=if (show) ", " else "") } deprecated <- function(fns, text = backticked(fns), show = TRUE, pkg = "rgl") { deprecatedfns <<- c(deprecatedfns, fns) if (show) paste(text, collapse = ", ") } indexclass <- indexproperties <- function(fns, text = backticked(fns), show = TRUE) { documentedfns <<- c(documentedfns, fns) anchors <- paste0('', if (show) text, '') paste(anchors, collapse=if (show) ", " else "") } indexmethods <- function(fns, text = backticked(paste0(fns, "()")), show = TRUE) { documentedfns <<- c(documentedfns, fns) anchors <- paste0('', if (show) text, '') paste(anchors, collapse=if (show) ", " else "") } linkfn <- function(fn, text = backticked(fn), pkg = NA) { if (is.na(pkg)) paste0('', text, '') else { text <- rep_len(text, length(fn)) url <- rep_len(NA, length(fn)) for (i in seq_along(fn)) { if (pkg == "rgl") { rdpath <- Sys.getenv("VignetteRdPath", unset = "../html/") url[i] <- paste0(rdpath, basename(help(fn[i])), ".html") } else if (requireNamespace("downlit", quietly = TRUE)) url[i] <- downlit::autolink_url(paste0(pkg, "::", fn[i])) if (is.na(url[i])) url[i] <- paste0('../../', pkg, '/help/', fn[i], ".html") } paste0('', text, '') } } # Write this once at the start of the document. cat(' ') writeIndex <- function(cols = 4) { if (!is.null(documentedfns)) { documentedfns <- sort(documentedfns) entries <- paste0('', documentedfns, '  ') len <- length(entries) padding <- ((len + cols - 1) %/% cols) * cols - len if (padding) entries <- c(entries, rep("", length.out=padding)) cat('\n
\n') print(knitr::kable(matrix(entries, ncol=cols), format="pandoc")) cat("
\n") } } # This displays the string code as `r code` when entered # as `r rinline(code)`. Due to Stephane Laurent rinline <- function(code, script = FALSE){ if (script) html <- "`r CODE`" else html <- '``` `r CODE` ```' sub("CODE", code, html) } # This sets up default "alt text" for screen readers. defaultAltText <- function() { paste(knitr::opts_current$get("label"), "example.") } knitr::opts_chunk$set(fig.alt = quote(defaultAltText())) rgl/src/0000755000176200001440000000000015026603601011624 5ustar liggesusersrgl/src/subscene.h0000644000176200001440000002416514771520323013621 0ustar liggesusers#ifndef SUBSCENE_H #define SUBSCENE_H #include "Shape.h" #include "ClipPlane.h" #include "Viewpoint.h" #include "Background.h" #include "BBoxDeco.h" #include "Light.h" #include namespace rgl { enum Embedding { EMBED_INHERIT=1, EMBED_MODIFY, EMBED_REPLACE }; enum Embedded { EM_VIEWPORT = 0, EM_PROJECTION, EM_MODEL, EM_MOUSEHANDLERS}; enum ButtonID {bnNOBUTTON = 0, bnLEFT, bnRIGHT, bnMIDDLE, bnWHEEL}; enum MouseModeID {mmNONE = 0, mmTRACKBALL, mmXAXIS, mmYAXIS, mmZAXIS, mmPOLAR, mmSELECTING, mmZOOM, mmFOV, mmUSER, wmPUSH, wmPULL, wmUSER2}; enum MouseSelectionID {msNONE=1, msCHANGING, msDONE, msABORT}; typedef void (*userControlPtr)(void *userData, int mouseX, int mouseY); typedef void (*userControlEndPtr)(void *userData); typedef void (*userCleanupPtr)(void **userData); typedef void (*userWheelPtr)(void *userData, int dir); typedef void (Subscene::*viewControlPtr)(int mouseX,int mouseY); typedef void (Subscene::*viewControlEndPtr)(); typedef void (Subscene::*viewWheelPtr)(int dir); class Subscene : public SceneNode { /* Subscenes do their own projection. They can inherit, modify or replace the viewport, projection and model matrices. The root viewport always replaces them, since it doesn't have anything to inherit. */ private: Sphere getViewSphere(); void setupViewport(RenderContext* rctx); void setupProjMatrix(RenderContext* rctx); void setupModelMatrix(RenderContext* rctx); void setupModelViewMatrix(RenderContext* rctx); void setDefaultMouseMode(); void disableLights(RenderContext* rctx); void setupLights(RenderContext* rctx); void newEmbedding(); /* These lists contain pointers to lights and shapes, but don't actually manage them: the Scene does that. */ std::vector lights; std::vector shapes; std::vector unsortedShapes; std::vector zsortShapes; std::vector clipPlanes; /* Subscenes form a tree; this is the parent subscene. The root has a NULL parent. */ Subscene* parent; /* Here are the children */ std::vector subscenes; UserViewpoint* userviewpoint; ModelViewpoint* modelviewpoint; /** * bounded background **/ Background* background; /** * bounded decorator **/ BBoxDeco* bboxdeco; /** * How is this subscene embedded in its parent? **/ Embedding do_viewport, do_projection, do_model, do_mouseHandlers; /** * This viewport on the (0,0) to (1,1) scale **/ Rect2d viewport; public: Subscene(Embedding in_viewport, Embedding in_projection, Embedding in_model, Embedding in_mouseHandlers, bool in_ignoreExtent); virtual ~Subscene( ); bool add(SceneNode* node); void addBackground(Background* newbackground); void addBBoxDeco(BBoxDeco* bboxdeco); void addShape(Shape* shape); void addLight(Light* light); void addSubscene(Subscene* subscene); void addBBox(const AABox& bbox, bool changes); void intersectClipplanes(void); /** * hide shape or light or bboxdeco **/ void hideShape(int id); void hideLight(int id); void hideBBoxDeco(int id); void hideBackground(int id); Subscene* hideSubscene(int id, Subscene* current); void hideViewpoint(int id); /** * recursive search for subscene; could return self, or NULL if not found **/ Subscene* getSubscene(int id); Subscene* whichSubscene(int id); /* which subscene holds this */ Subscene* whichSubscene(int mouseX, int mouseY); /* coordinates are pixels within the window */ /* And here is the root */ Subscene* getRootSubscene(); /** * get parent, or NULL for the root **/ Subscene* getParent() const { return parent; } /** * get children **/ size_t getChildCount() const { return subscenes.size(); } Subscene* getChild(int which) const { return subscenes[which]; } /** * get the bbox */ BBoxDeco* get_bboxdeco(); /** * get a bbox */ BBoxDeco* get_bboxdeco(int id); /** * get the background */ Background* get_background() const { return background; } /** * get a background */ Background* get_background(int id); /** * obtain subscene's axis-aligned bounding box. **/ const AABox& getBoundingBox(); /** * get information about stacks */ int get_id_count(TypeID type, bool recursive); int get_ids(TypeID type, int* ids, char** types, bool recursive); virtual int getAttributeCount(SceneNode* subscene, AttribID attrib); virtual void getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result); virtual std::string getTextAttribute(SceneNode* subscene, AttribID attrib, int index); /* Update matrices etc. in preparation for rendering */ void update(RenderContext* renderContext); /* load the matrices into OpenGL */ void loadMatrices(); /* Do the OpenGL rendering */ void render(RenderContext* renderContext, bool opaquePass); void renderClipplanes(RenderContext* renderContext); void disableClipplanes(RenderContext* renderContext); void renderUnsorted(RenderContext* renderContext); void renderZsort(RenderContext* renderContext); /** * Get and set flag to ignore elements in bounding box **/ int getIgnoreExtent(void) const { return (int) ignoreExtent; } void setIgnoreExtent(int in_ignoreExtent); void setEmbedding(int which, Embedding value); /* which is 0=viewport, 1=projection, 2=model */ Embedding getEmbedding(Embedded which); Subscene* getMaster(Embedded which); void setUserMatrix(double* src); void setUserProjection(double* src); void setScale(double* src); void setViewport(double x, double y, double width, double height); /* Sets relative (i.e. [0,1]x[0,1]) viewport size */ void setPosition(double* src); void getUserMatrix(double* dest); void getUserProjection(double* dest); void getScale(double* dest); void getPosition(double* dest); double* getMousePosition(); void clearMouseListeners(); void addMouseListener(Subscene* sub); void deleteMouseListener(Subscene* sub); void getMouseListeners(size_t max, int* ids); float getDistance(const Vertex& v) const; // Translate from OpenGL window-relative coordinates (relative to bottom left corner of window) to // viewport relative (relative to bottom left corner of viewport) void translateCoords(int* mouseX, int* mouseY) const { *mouseX = *mouseX - pviewport.x; *mouseY = *mouseY - pviewport.y; } UserViewpoint* getUserViewpoint(); ModelViewpoint* getModelViewpoint(); virtual std::string getTypeName() { return "subscene"; }; Background* get_background(); /* This vector lists other subscenes that will be controlled by mouse actions on this one. We need to delete those entries if the subscene is deleted! */ std::vector mouseListeners; // These are set after rendering the scene Vec4 Zrow; Vec4 Wrow; Matrix4x4 modelMatrix, projMatrix; Rect2 pviewport; // viewport in pixels /** * mouse support */ void buttonBegin(int button, int mouseX, int mouseY); void buttonUpdate(int button, int mouseX, int mouseY); void buttonEnd(int button); MouseModeID needsBegin; bool mouseNeedsWatching(); void wheelRotate(int dir); MouseModeID getMouseMode(int button); void setMouseMode(int button, MouseModeID mode); void setMouseCallbacks(int button, userControlPtr begin, userControlPtr update, userControlEndPtr end, userCleanupPtr cleanup, void** user); void getMouseCallbacks(int button, userControlPtr *begin, userControlPtr *update, userControlEndPtr *end, userCleanupPtr *cleanup, void** user); void setWheelCallback(userWheelPtr wheel, void* user); void getWheelCallback(userWheelPtr *wheel, void** user); // o DRAG FEATURE: mouseSelection int drag; double mousePosition[4]; void mouseSelectionBegin(int mouseX,int mouseY); void mouseSelectionUpdate(int mouseX,int mouseY); void mouseSelectionEnd(); MouseSelectionID getSelectState(); void setSelectState(MouseSelectionID state); private: /** * compute bounding-box **/ void calcDataBBox(); /** * Need to recalc bbox **/ void newBBox(); /** * bounding box of subscene **/ AABox data_bbox; bool ignoreExtent; bool bboxChanges; /** * mouse support */ viewControlPtr ButtonBeginFunc[5], ButtonUpdateFunc[5]; viewControlEndPtr ButtonEndFunc[5]; viewWheelPtr WheelRotateFunc; viewControlPtr getButtonBeginFunc(int button); viewControlPtr getButtonUpdateFunc(int button); viewControlEndPtr getButtonEndFunc(int button); MouseModeID mouseMode[5]; MouseSelectionID selectState; void noneBegin(int mouseX, int mouseY) {}; void noneUpdate(int mouseX, int mouseY) {}; void noneEnd() {}; // o DRAG FEATURE: adjustDirection void polarBegin(int mouseX, int mouseY); void polarUpdate(int mouseX, int mouseY); void polarEnd(); void trackballBegin(int mouseX, int mouseY); void trackballUpdate(int mouseX, int mouseY); void trackballEnd(); void oneAxisBegin(int mouseX, int mouseY); void oneAxisUpdate(int mouseX, int mouseY); void wheelRotateNone(int dir) {}; void wheelRotatePull(int dir); void wheelRotatePush(int dir); PolarCoord camBase, dragBase, dragCurrent; Vertex rotBase, rotCurrent, axis[3]; // o DRAG FEATURE: adjustZoom void adjustZoomBegin(int mouseX, int mouseY); void adjustZoomUpdate(int mouseX, int mouseY); void adjustZoomEnd(); int zoomBaseY; // o DRAG FEATURE: adjustFOV (field of view) void adjustFOVBegin(int mouseX, int mouseY); void adjustFOVUpdate(int mouseX, int mouseY); void adjustFOVEnd(); int fovBaseY; // o DRAG FEATURE: user supplied callback void userBegin(int mouseX, int mouseY); void userUpdate(int mouseX, int mouseY); void userEnd(); bool busy; int activeButton; void* wheelData; userWheelPtr wheelCallback; void userWheel(int dir); void* userData[15]; userControlPtr beginCallback[5], updateCallback[5]; userControlEndPtr endCallback[5]; userCleanupPtr cleanupCallback[5]; }; } // namespace rgl #endif // SUBSCENE_H rgl/src/types.h0000644000176200001440000000562714555455305013167 0ustar liggesusers#ifndef RGL_TYPES_H #define RGL_TYPES_H #include #include "pragma.h" // C++ header file // This file is part of RGL // namespace rgl { // // // constants // // #ifndef NULL #define NULL 0UL #endif // // // fundamental data types // // typedef unsigned char u8; typedef long u32; // // memory management objects // class AutoDestroy { public: AutoDestroy() { refcount = 0; } virtual ~AutoDestroy() { } void ref() { refcount++; } void unref() { if ( !(--refcount) ) delete this; } private: int refcount; }; template class Ref { public: Ref() : ptr(NULL) { } Ref(T* in_ptr) : ptr(in_ptr) { if (ptr) ptr->ref(); } Ref(const Ref& ref) : ptr(ref.ptr) { if (ptr) ptr->ref(); } ~Ref() { if (ptr) ptr->unref(); } Ref& operator = (T* in_ptr) { if (ptr) ptr->unref(); ptr = in_ptr; if (ptr) ptr->ref(); return *this; } T* operator -> () { return ptr; } operator bool () { return (ptr) ? true : false; } private: T* ptr; }; // // CLASS // DestroyHandler // class DestroyHandler { public: virtual ~DestroyHandler(); virtual void notifyDestroy(void* userdata) = 0; }; // // mem copy // template inline void copy(A* from, B* to, int size) { memcpy( (void*) to, (const void*) from, size*sizeof(A) ); } // // TEMPLATE // ARRAY // template struct ARRAY { int _size; T* ptr; inline int size() { return _size; } inline ARRAY(int in_size) : _size(in_size), ptr(new T [_size]) { } template inline ARRAY(int in_size, SRC* src) : _size(in_size), ptr(new T [_size]) { copy(src, ptr,_size); } inline ~ARRAY() { delete [] ptr; } inline T& get(int index) { return ptr[index]; } inline T& getRecycled(int index) { return ptr[index%_size]; }; }; // // cast-copy doubles to floats // template<> inline void copy(double* from, float* to, int size) { while(size--) { *to = (float) *from; from++; to++; } } /** * get most significant bit * @param x unsigned value * @return bit position between 1..32 or 0 if value was 0 **/ inline int msb(unsigned int x) { if (x) { int bit = sizeof(int)*8; unsigned int mask = 1<<((sizeof(int)*8)-1); while ( !(x & mask) ) { --bit; mask >>= 1; } return bit; } else return 0; } // template T getMax(T a, T b) { return (a > b) ? a : b; } // template T getMin(T a, T b) { return (a < b) ? a : b; } inline int getMin(int a, int b) { return (a <= b) ? a : b; } inline float getMin(float a, float b) { return (a <= b) ? a : b; } inline int getMax(int a, int b) { return (a >= b) ? a : b; } inline float getMax(float a, float b) { return (a >= b) ? a : b; } inline float clamp(float v, float floor, float ceil) { return (vceil) ? ceil : v ); } inline int clamp(int v, int floor, int ceil) { return (vceil) ? ceil : v ); } } // namespace rgl #endif /* RGL_TYPES_H */ rgl/src/pngpixmap.h0000644000176200001440000002405714771520323014015 0ustar liggesusers#include "lib.h" #include "types.h" #include // C++ header file // This file is part of RGL // namespace rgl { class PNGPixmapFormat : public PixmapFormat { public: PNGPixmapFormat() { } bool checkSignature(std::FILE* fd) { unsigned char buf[8]; if (fread(buf, 1, 8, fd) < 8) return false; fseek(fd, 0, SEEK_SET); return !png_sig_cmp(buf, 0, 8); } bool load(std::FILE* fd, Pixmap* pixmap) { Load load(fd, pixmap); if (load.init()) { bool success; success = load.process(); if (!success) printMessage("pixmap png loader: process failed"); return success; } else { printMessage("pixmap png loader: init failed"); return false; } } bool save(std::FILE* fd, Pixmap* pixmap) { Save save(fd, pixmap); if (save.init()) return save.process(); else return false; } private: // // CLASS // Load // class Load { public: Load(std::FILE* _file, Pixmap* _pixmap) { file = _file; pixmap = _pixmap; png_ptr = NULL; info_ptr = NULL; finish = false; error = false; } bool init(void) { bool success = false; png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, (png_voidp)this, error_callback, warning_callback); if (png_ptr) { info_ptr = png_create_info_struct(png_ptr); if (info_ptr) { png_set_progressive_read_fn(png_ptr, (void *)this, info_callback, row_callback, end_callback); success = true; } } return success; } bool process() { while ((!feof(file)) && (!error)) { size_t size = fread(buffer,1,sizeof(buffer),file); if (ferror(file)) { printError("file read error"); return false; } png_process_data(png_ptr, info_ptr, buffer, size); } return finish; } ~Load() { if (png_ptr) png_destroy_read_struct(&png_ptr, (info_ptr) ? &info_ptr : NULL, (png_infopp)NULL); } private: static void printError(const char* error_msg) { char buf[256]; snprintf(buf, 256, "PNG Pixmap Loader Error: %s", error_msg); printMessage(buf); } static void printWarning(const char* warning_msg) { char buf[256]; snprintf(buf, 256, "PNG Pixmap Loader Warning: %s", warning_msg); printMessage(buf); } static void error_callback(png_structp png_ptr, png_const_charp error_msg) { // Load* load = (Load*) png_get_error_ptr(png_ptr); printError( (const char*) error_msg ); } static void warning_callback(png_structp png_ptr, png_const_charp warning_msg) { // Load* load = (Load*) png_get_error_ptr(png_ptr); printWarning( (const char*) warning_msg ); } static void info_callback(png_structp png_ptr, png_infop info) { char buffer[256]; Load* load = (Load*) png_get_progressive_ptr(png_ptr); png_uint_32 width, height; int bit_depth, color_type, interlace_type, compression_type, filter_type; png_get_IHDR(load->png_ptr, load->info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type); char* color_type_name; switch(color_type) { case PNG_COLOR_TYPE_RGB: color_type_name = (char*)"RGB"; break; case PNG_COLOR_TYPE_GRAY: color_type_name = (char*)"GRAY"; break; case PNG_COLOR_TYPE_PALETTE: color_type_name = (char*)"INDEX"; break; case PNG_COLOR_TYPE_RGB_ALPHA: color_type_name = (char*)"RGBALPHA"; break; case PNG_COLOR_TYPE_GRAY_ALPHA: color_type_name = (char*)"GRAYALPHA"; break; default: color_type_name = (char*)"unknown"; break; }; const char* interlace_string = (interlace_type == PNG_INTERLACE_ADAM7) ? "adam7 interlace " : ""; if (bit_depth == 16) png_set_strip_16(png_ptr); else if (bit_depth < 8 && color_type == PNG_COLOR_TYPE_GRAY) png_set_expand_gray_1_2_4_to_8(png_ptr); else if (bit_depth != 8) /* this should never happen with current formats... */ goto unsupported; if (interlace_type == PNG_INTERLACE_ADAM7) goto unsupported; PixmapTypeID typeID; switch(color_type) { case PNG_COLOR_TYPE_RGB: typeID = RGB24; goto init; case PNG_COLOR_TYPE_GRAY: typeID = GRAY8; goto init; case PNG_COLOR_TYPE_RGB_ALPHA: typeID = RGBA32; goto init; case PNG_COLOR_TYPE_PALETTE: png_set_palette_to_rgb(png_ptr); typeID = RGB24; goto init; case PNG_COLOR_TYPE_GRAY_ALPHA: png_set_gray_to_rgb(png_ptr); typeID = RGBA32; goto init; default: goto unsupported; break; }; init: if (typeID == RGB24 && png_get_valid(png_ptr, info, PNG_INFO_tRNS)) { png_set_tRNS_to_alpha(png_ptr); typeID = RGBA32; } load->pixmap->init(typeID, width,height,bit_depth); png_read_update_info(load->png_ptr,load->info_ptr); return; unsupported: snprintf(buffer, sizeof(buffer), "%s%s format unsupported: %lux%lu (%d bits per channel)", interlace_string, color_type_name, (long unsigned int)width, (long unsigned int)height, bit_depth); printMessage(buffer); load->error = true; png_read_update_info(load->png_ptr,load->info_ptr); return; /* Do any setup here, including setting any of the transformations mentioned in the Reading PNG files section. For now, you _must_ call either png_start_read_image() or png_read_update_info() after all the transformations are set (even if you don't set any). You may start getting rows before png_process_data() returns, so this is your last chance to prepare for that. */ } static void row_callback(png_structp png_ptr, png_bytep new_row, png_uint_32 row_num, int pass) { Load* load = (Load*) png_get_progressive_ptr(png_ptr); void* rowptr = load->pixmap->data + load->pixmap->bytesperrow * (load->pixmap->height-1-row_num); memcpy(rowptr, new_row, load->pixmap->bytesperrow); } static void end_callback(png_structp png_ptr, png_infop info) { Load* load = (Load*) png_get_progressive_ptr(png_ptr); load->finish = true; /* This function is called after the whole image has been read, including any chunks after the image (up to and including the IEND). You will usually have the same info chunk as you had in the header, although some data may have been added to the comments and time fields. Most people won't do much here, perhaps setting a flag that marks the image as finished. */ } /* static void end_callback(void) { } */ typedef void (PNGAPI *png_error_ptr) PNGARG((png_structp, png_const_charp)); std::FILE* file; Pixmap* pixmap; png_structp png_ptr; png_infop info_ptr; unsigned char buffer[4096]; bool error; bool finish; }; // // CLASS // Save // class Save { public: Save(std::FILE* in_file, Pixmap* in_pixmap) { file = in_file; pixmap = in_pixmap; png_ptr = NULL; info_ptr = NULL; } bool init(void) { bool success = false; png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, (png_voidp)this, error_callback, warning_callback); if (png_ptr) { info_ptr = png_create_info_struct(png_ptr); if (info_ptr) { png_init_io(png_ptr, file); success = true; } } return success; } bool process(void) { if (setjmp(png_jmpbuf(png_ptr))) { printError("an error occured"); png_destroy_write_struct(&png_ptr, &info_ptr); return false; } png_set_filter(png_ptr, 0, PNG_FILTER_NONE); const int color_type = PNG_COLOR_TYPE_RGB; const int interlace_type = PNG_INTERLACE_NONE; const int compression_type = PNG_COMPRESSION_TYPE_DEFAULT; const int filter_type = PNG_FILTER_TYPE_DEFAULT; png_set_IHDR(png_ptr, info_ptr, pixmap->width, pixmap->height, pixmap->bits_per_channel, color_type, interlace_type, compression_type, filter_type); png_text text[1]; text[0].key = (png_charp)"Software"; text[0].text = (png_charp)"R/RGL package/libpng"; text[0].compression = PNG_TEXT_COMPRESSION_NONE; png_set_text(png_ptr, info_ptr, text, sizeof(text)/sizeof(png_text) ); png_write_info(png_ptr, info_ptr); png_bytep rowptr = (png_bytep) ( ((u8*)pixmap->data) + (pixmap->height - 1) * pixmap->bytesperrow ); for(unsigned int i=0;iheight;i++) { png_write_row(png_ptr, rowptr); rowptr -= pixmap->bytesperrow; } png_write_end(png_ptr, info_ptr); return true; } ~Save() { if (png_ptr) png_destroy_write_struct(&png_ptr, (info_ptr) ? &info_ptr : NULL); } private: static void printError(const char* error_msg) { char buf[256]; snprintf(buf, 256, "PNG Pixmap Saver Error: %s", error_msg); printMessage(buf); } static void printWarning(const char* warning_msg) { char buf[256]; snprintf(buf, 256, "PNG Pixmap Saver Warning: %s", warning_msg); printMessage(buf); } static void error_callback(png_structp png_ptr, png_const_charp error_msg) { // Save* save = (Save*) png_get_error_ptr(png_ptr); printError( (const char*) error_msg ); } static void warning_callback(png_structp png_ptr, png_const_charp warning_msg) { // Save* save = (Save*) png_get_error_ptr(png_ptr); printWarning( (const char*) warning_msg ); } std::FILE* file; Pixmap* pixmap; png_structp png_ptr; png_infop info_ptr; }; }; } // namespace rgl rgl/src/rgl-win.def0000644000176200001440000000004414265301465013670 0ustar liggesusersLIBRARY rgl.dll EXPORTS R_init_rglrgl/src/LineSet.cpp0000644000176200001440000000140514771520323013700 0ustar liggesusers#include "PrimitiveSet.h" using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // LineSet // LineSet::LineSet(Material& in_material, int in_nvertices, double* in_vertices, bool in_ignoreExtent, int in_nindices, int* in_indices, bool in_bboxChange) : PrimitiveSet(in_material, in_nvertices, in_vertices, GL_LINES, 2, in_ignoreExtent, in_nindices, in_indices, in_bboxChange) { material.lit = false; if (material.line_antialias) blended = true; } LineSet::LineSet(Material& in_material, bool in_ignoreExtent, bool in_bboxChange) : PrimitiveSet(in_material, GL_LINES, 2, in_ignoreExtent, in_bboxChange) { material.lit = false; if (material.line_antialias) blended = true; } rgl/src/PlaneSet.h0000644000176200001440000000212214771520323013512 0ustar liggesusers#ifndef PLANESET_H #define PLANESET_H #include "scene.h" #include "geom.h" #include "Shape.h" #include "PrimitiveSet.h" #include namespace rgl { class PlaneSet : public TriangleSet { private: /* Use parametrization ax + by + cz + d = 0 */ int nPlanes; ARRAY normal; /* (a,b,c) */ ARRAY offset; /* d */ public: PlaneSet(Material& in_material, int in_nnormal, double* in_normal, int in_noffset, double* in_offset); // ~PlaneSet(); /** * tell type. **/ virtual std::string getTypeName() { return "planes"; }; /** * overload to update triangles first. */ virtual AABox& getBoundingBox(Subscene* subscene); /** * overload to update triangles first. */ virtual void renderBegin(RenderContext* renderContext); /** * update mesh */ void updateTriangles(Subscene* subscene); /** * update then get attributes */ int getAttributeCount(SceneNode* subscene, AttribID attrib); void getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result); }; } // namespace rgl #endif // PLANESET_H rgl/src/ClipPlane.cpp0000644000176200001440000000731114771520323014206 0ustar liggesusers#include "ClipPlane.h" #include "Viewpoint.h" #include "R.h" #include using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // ClipPlaneSet // int ClipPlaneSet::num_planes = 0; ClipPlaneSet::ClipPlaneSet(Material& in_material, int in_nnormal, double* in_normal, int in_noffset, double* in_offset) : Shape(in_material,true), nPlanes(std::max(in_nnormal, in_noffset)), normal(in_nnormal, in_normal), offset(in_noffset, in_offset) { } int ClipPlaneSet::getAttributeCount(SceneNode* subscene, AttribID attrib) { switch (attrib) { case NORMALS: case OFFSETS: return nPlanes; } return 0; } void ClipPlaneSet::getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result) { int n = getAttributeCount(subscene, attrib); if (first + count < n) n = first + count; if (first < n) { if (attrib == NORMALS) { while (first < n) { *result++ = normal.getRecycled(first).x; *result++ = normal.getRecycled(first).y; *result++ = normal.getRecycled(first).z; first++; } } else if (attrib == OFFSETS) { while (first < n) *result++ = offset.getRecycled(first++); } } } void ClipPlaneSet::renderBegin(RenderContext* renderContext) { firstPlane = GL_CLIP_PLANE0 + num_planes; num_planes += nPlanes; } void ClipPlaneSet::drawPrimitive(RenderContext* renderContext, int index) { #ifndef RGL_NO_OPENGL GLdouble eqn[4]; eqn[0] = normal.getRecycled(index).x; eqn[1] = normal.getRecycled(index).y; eqn[2] = normal.getRecycled(index).z; eqn[3] = offset.getRecycled(index); glClipPlane(firstPlane + index, eqn); glEnable(firstPlane + index); #endif } void ClipPlaneSet::enable(bool show) { #ifndef RGL_NO_OPENGL for (int i=0; i 0) bbox.vmin.x = getMax(bbox.vmin.x, b1*(b1 > 0 ? bbox.vmin.y : bbox.vmax.y) +c1*(c1 > 0 ? bbox.vmin.z : bbox.vmax.z) +d1); else if (a < 0) bbox.vmax.x = getMin(bbox.vmax.x, b1*(b1 > 0 ? bbox.vmax.y : bbox.vmin.y) +c1*(c1 > 0 ? bbox.vmax.z : bbox.vmin.z) +d1); a1 = -a/b; c1 = -c/b; d1 = -d/b; if (b > 0) bbox.vmin.y = getMax(bbox.vmin.y, a1*(a1 > 0 ? bbox.vmin.x : bbox.vmax.x) +c1*(c1 > 0 ? bbox.vmin.z : bbox.vmax.z) +d1); else if (b < 0) bbox.vmax.y = getMin(bbox.vmax.y, a1*(a1 > 0 ? bbox.vmax.x : bbox.vmin.x) +c1*(c1 > 0 ? bbox.vmax.z : bbox.vmin.z) +d1); a1 = -a/c; b1 = -b/c; d1 = -d/c; if (c > 0) bbox.vmin.z = getMax(bbox.vmin.z, a1*(a1 > 0 ? bbox.vmin.x : bbox.vmax.x) +b1*(b1 > 0 ? bbox.vmin.y : bbox.vmax.y) +d1); else if (c < 0) bbox.vmax.z = getMin(bbox.vmax.z, a1*(a1 > 0 ? bbox.vmax.x : bbox.vmin.x) +b1*(b1 > 0 ? bbox.vmax.y : bbox.vmin.y) +d1); } } rgl/src/init.h0000644000176200001440000000053114771520323012744 0ustar liggesusers#ifndef RGL_INIT_H #define RGL_INIT_H #include "R.h" #include namespace rgl { #ifdef __cplusplus extern "C" { #endif /* // RGL initialization // */ /* library service */ SEXP rgl_init (SEXP initValue, SEXP onlyNULL, SEXP in_namespace, SEXP debug); #ifdef __cplusplus } #endif } // namespace rgl #endif /* RGL_INIT_H */ rgl/src/Texture.cpp0000644000176200001440000001570214771520323014002 0ustar liggesusers #include "Texture.h" #include "pixmap.h" #include "config.h" #include "platform.h" #include "RenderContext.h" using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // Texture // Texture::Texture( const char* in_filename , Type in_type , Mode in_mode , bool in_mipmap , unsigned int in_minfilter , unsigned int in_magfilter , bool in_envmap , bool in_deleteFile ) { texName = 0; pixmap = new Pixmap(); type = in_type; mode = in_mode; mipmap = in_mipmap; envmap = in_envmap; deleteFile = in_deleteFile; magfilter = (in_magfilter) ? GL_LINEAR : GL_NEAREST; if (mipmap) { switch(in_minfilter) { case 0: minfilter = GL_NEAREST; break; case 1: minfilter = GL_LINEAR; break; case 2: minfilter = GL_NEAREST_MIPMAP_NEAREST; break; case 3: minfilter = GL_NEAREST_MIPMAP_LINEAR; break; case 4: minfilter = GL_LINEAR_MIPMAP_NEAREST; break; default: minfilter = GL_LINEAR_MIPMAP_LINEAR; break; } } else { switch(in_minfilter) { case 0: minfilter = GL_NEAREST; break; default: minfilter = GL_LINEAR; break; } } filename = in_filename; if ( !pixmap->load(filename.c_str()) ) { delete pixmap; pixmap = NULL; } } Texture::~Texture() { #ifndef RGL_NO_OPENGL if (texName) { glDeleteTextures(1, &texName); } #endif if (pixmap) delete pixmap; if (filename.size() && deleteFile) std::remove(filename.c_str()); } bool Texture::isValid() const { return (pixmap) ? true : false; } void Texture::getParameters(Type *out_type, Mode *out_mode, bool *out_mipmap, unsigned int *out_minfilter, unsigned int *out_magfilter, std::string *out_filename) { *out_type = type; *out_mode = mode; *out_mipmap = mipmap; switch(minfilter) { case GL_NEAREST: *out_minfilter = 0; break; case GL_LINEAR: *out_minfilter = 1; break; case GL_NEAREST_MIPMAP_NEAREST: *out_minfilter = 2; break; case GL_NEAREST_MIPMAP_LINEAR: *out_minfilter = 3; break; case GL_LINEAR_MIPMAP_NEAREST: *out_minfilter = 4; break; case GL_LINEAR_MIPMAP_LINEAR: *out_minfilter = 5; break; default: *out_minfilter = 6; break; } *out_magfilter = (magfilter == GL_LINEAR) ? 1 : 0; *out_filename = filename; } #ifndef RGL_NO_OPENGL static unsigned int texsize(unsigned int s) { return 1U << msb(s-1); } #include "lib.h" static void printGluErrorMessage(GLint error) { const GLubyte* gluError; char buf[256]; gluError = gluErrorString (error); snprintf(buf, 256, "GLU Library Error : %s", (const char*) gluError); printMessage(buf); } #endif void Texture::init(RenderContext* renderContext) { #ifndef RGL_NO_OPENGL glGenTextures(1, &texName); glBindTexture(GL_TEXTURE_2D, texName); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minfilter); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magfilter); GLint internalFormat = 0; GLenum format = 0; GLint ualign; unsigned int bytesperpixel = 0; switch(type) { case ALPHA: internalFormat = GL_ALPHA; break; case LUMINANCE: internalFormat = GL_LUMINANCE; break; case LUMINANCE_ALPHA: internalFormat = GL_LUMINANCE_ALPHA; break; case RGB: internalFormat = GL_RGB; break; case RGBA: internalFormat = GL_RGBA; break; } switch(mode) { case REPLACE: internalMode = GL_REPLACE; break; case MODULATE: internalMode = GL_MODULATE; break; case DECAL: internalMode = GL_DECAL; break; case BLEND: internalMode = GL_BLEND; break; case ADD: internalMode = GL_ADD; break; } switch(pixmap->typeID) { case GRAY8: ualign = 1; bytesperpixel = 1; switch(internalFormat) { case GL_ALPHA: format = GL_ALPHA; break; default: format = GL_LUMINANCE; break; } break; case RGB24: ualign = 1; format = GL_RGB; bytesperpixel = 3; break; case RGB32: ualign = 2; format = GL_RGB; bytesperpixel = 4; break; case RGBA32: ualign = 2; format = GL_RGBA; bytesperpixel = 4; break; default: // INVALID return; } glPixelStorei(GL_UNPACK_ALIGNMENT, ualign); GLenum gl_type = GL_UNSIGNED_BYTE; GLint glTexSize; glGetIntegerv(GL_MAX_TEXTURE_SIZE, &glTexSize ); if (GLAD_GL_VERSION_3_0) { glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, pixmap->width, pixmap->height, 0, format, gl_type , pixmap->data); if (mipmap) glGenerateMipmap(GL_TEXTURE_2D); } else { unsigned int maxSize = static_cast(glTexSize); if (mipmap) { int gluError = gluBuild2DMipmaps(GL_TEXTURE_2D, internalFormat, pixmap->width, pixmap->height, format, gl_type, pixmap->data); if (gluError) printGluErrorMessage(gluError); } else { unsigned int width = texsize(pixmap->width); unsigned int height = texsize(pixmap->height); if ( (width > maxSize) || (height > maxSize) ) { char buf[256]; snprintf(buf, 256, "GL Library : Maximum texture size of %dx%d exceeded.\n(Perhaps enabling mipmapping could help.)", maxSize,maxSize); printMessage(buf); } else if ( (pixmap->width != width) || ( pixmap->height != height) ) { char* data = new char[width * height * bytesperpixel]; int gluError = gluScaleImage(format, pixmap->width, pixmap->height, gl_type, pixmap->data, width, height, gl_type, data); if (gluError) printGluErrorMessage(gluError); glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, gl_type , data); delete[] data; } else { glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, pixmap->width, pixmap->height, 0, format, gl_type , pixmap->data); } } } if (envmap) { glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glEnable(GL_TEXTURE_GEN_S); glEnable(GL_TEXTURE_GEN_T); } #endif if (pixmap) { delete pixmap; pixmap = NULL; } } void Texture::beginUse(RenderContext* renderContext) { #ifndef RGL_NO_OPENGL if (!texName) { init(renderContext); } glPushAttrib(GL_TEXTURE_BIT|GL_ENABLE_BIT|GL_CURRENT_BIT); glEnable(GL_TEXTURE_2D); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, internalMode); glBindTexture(GL_TEXTURE_2D, texName); if (type == ALPHA) { glEnable(GL_BLEND); } #endif } void Texture::endUse(RenderContext* renderContext) { #ifndef RGL_NO_OPENGL glPopAttrib(); #endif } rgl/src/geom.h0000644000176200001440000000241014771520323012726 0ustar liggesusers#ifndef GEOM_H #define GEOM_H #include "rglmath.h" namespace rgl { // // CLASS // AABox (axis-aligned box) // class Sphere; class AABox { public: AABox(); AABox(const AABox& that) : vmin(that.vmin), vmax(that.vmax) { } void invalidate(void); bool isValid(void) const; /* use +Max, -Max to indicate it needs recalc */ bool isEmpty(void) const; /* use 1, -1 to indicate empty */ void setEmpty(void); void operator += (const AABox& aabox); void operator += (const Sphere& sphere); void operator += (const Vertex& vertex); bool operator < (const AABox& aabox) const; AABox transform(Matrix4x4& M); Vertex getCenter(void) const; Vertex vmin, vmax; }; // // CLASS // Sphere // class Sphere { public: Sphere() : center(0,0,0), radius(1) {}; Sphere(const Vertex& center, const float radius); Sphere(const float radius); Sphere(const AABox& aabox); Sphere(const AABox& aabox, const Vertex& scale); Vertex center; float radius; }; // // CLASS // Frustum // class Frustum { public: Frustum() : ortho(false) {}; void enclose(float sphere_radius, float fovangle, int win_width, int win_height); Matrix4x4 getMatrix(); float left, right, bottom, top, znear, zfar, distance; bool ortho; }; } // namespace rgl #endif // GEOM_H rgl/src/PrimitiveSet.cpp0000644000176200001440000002610514771520323014765 0ustar liggesusers#include "PrimitiveSet.h" #include "BBoxDeco.h" #include "subscene.h" #include "R.h" using namespace rgl; // ===[ PRIMITIVE SET ]======================================================= PrimitiveSet::PrimitiveSet ( Material& in_material, int in_type, int in_nverticesperelement, bool in_ignoreExtent, bool in_bboxChange ) : Shape(in_material, in_ignoreExtent, SHAPE, in_bboxChange) { type = in_type; nverticesperelement = in_nverticesperelement; nvertices = 0; nindices = 0; } void PrimitiveSet::initPrimitiveSet( int in_nvertices, double* in_vertices, int in_nindices, int* in_indices ) { nvertices = in_nvertices; nindices = in_nindices; if (nindices) nprimitives = nindices / nverticesperelement; else nprimitives = nvertices / nverticesperelement; vertexArray.alloc(nvertices); hasmissing = false; for(int i=0;i= 0) { Subscene* subscene = renderContext->subscene; bboxdeco = subscene->get_bboxdeco(); } if (bboxdeco) { invalidateDisplaylist(); verticesTodraw.alloc(vertexArray.size()); for (int i=0; i < vertexArray.size(); i++) verticesTodraw.setVertex(i, bboxdeco->marginVecToDataVec(vertexArray[i], renderContext, &material) ); verticesTodraw.beginUse(); } else vertexArray.beginUse(); SAVEGLERROR; } // --------------------------------------------------------------------------- void PrimitiveSet::drawAll(RenderContext* renderContext) { #ifndef RGL_NO_OPENGL if (!hasmissing) { if (!nindices) glDrawArrays(type, 0, nverticesperelement*nprimitives ); else glDrawElements(type, nindices, GL_UNSIGNED_INT, indices); } else { bool missing = true; for (int i=0; i= 0) { Subscene* subscene = renderContext->subscene; bboxdeco = subscene->get_bboxdeco(); } if (bboxdeco) { normalsToDraw.alloc(normalArray.size()); for (int i=0; i < normalArray.size(); i++) normalsToDraw.setVertex(i, bboxdeco->marginNormalToDataNormal(normalArray[i], renderContext, &material) ); normalsToDraw.beginUse(); } else normalArray.beginUse(); } texCoordArray.beginUse(); } // --------------------------------------------------------------------------- void FaceSet::drawEnd(RenderContext* renderContext) { texCoordArray.endUse(); if (material.lit) normalArray.endUse(); PrimitiveSet::drawEnd(renderContext); } int FaceSet::getAttributeCount(SceneNode* subscene, AttribID attrib) { switch (attrib) { case NORMALS: return nvertices; case TEXCOORDS: return texCoordArray.size(); } return PrimitiveSet::getAttributeCount(subscene, attrib); } void FaceSet::getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result) { int n = getAttributeCount(subscene, attrib); if (first + count < n) n = first + count; if (first < n) { switch (attrib) { case NORMALS: { if (normalArray.size() < n) initNormals(NULL); while (first < n) { *result++ = normalArray[first].x; *result++ = normalArray[first].y; *result++ = normalArray[first].z; first++; } return; } case TEXCOORDS: { while (first < n) { *result++ = texCoordArray[first].s; *result++ = texCoordArray[first].t; first++; } return; } } PrimitiveSet::getAttribute(subscene, attrib, first, count, result); } } rgl/src/select.cpp0000644000176200001440000000117014555455305013622 0ustar liggesusers// C++ source // This file is part of RGL. // #include "select.h" #include using namespace rgl; void SELECT::render(double* position) { #ifndef RGL_NO_OPENGL GLdouble llx, lly, urx, ury; llx = *position; lly = *(position+1); urx = *(position+2); ury = *(position+3); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0.0f,1.0f,0.0f,1.0f,0.0f,1.0f); glColor3f(0.5f,0.5f,0.5f); glLineWidth(2.0); glBegin(GL_LINE_LOOP); glVertex2d(llx, lly); glVertex2d(llx, ury); glVertex2d(urx, ury); glVertex2d(urx, lly); glEnd(); #endif } rgl/src/gl2ps.c0000644000176200001440000060644215011677075013045 0ustar liggesusers/* * GL2PS, an OpenGL to PostScript Printing Library * Copyright (C) 1999-2020 C. Geuzaine * * This program is free software; you can redistribute it and/or * modify it under the terms of either: * * a) the GNU Library General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your * option) any later version; or * * b) the GL2PS License as published by Christophe Geuzaine, either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either * the GNU Library General Public License or the GL2PS License for * more details. * * You should have received a copy of the GNU Library General Public * License along with this library in the file named "COPYING.LGPL"; * if not, write to the Free Software Foundation, Inc., 51 Franklin * Street, Fifth Floor, Boston, MA 02110-1301, USA. * * You should have received a copy of the GL2PS License with this * library in the file named "COPYING.GL2PS"; if not, I will be glad * to provide one. * * For the latest info about gl2ps and a full list of contributors, * see http://www.geuz.org/gl2ps/. * * Please report all bugs and problems to . */ #ifdef RGL_NO_OPENGL typedef int make_iso_compiler_happy; #else #include "gl2ps.h" #include #include #include #include #include #include #if defined(GL2PS_HAVE_ZLIB) #include #endif #if defined(GL2PS_HAVE_LIBPNG) #include #endif /********************************************************************* * * Private definitions, data structures and prototypes * *********************************************************************/ /* Magic numbers (assuming that the order of magnitude of window coordinates is 10^3) */ #define GL2PS_EPSILON 5.0e-3F #define GL2PS_ZSCALE 1000.0F #define GL2PS_ZOFFSET 5.0e-2F #define GL2PS_ZOFFSET_LARGE 20.0F #define GL2PS_ZERO(arg) (fabs(arg) < 1.e-20) /* BSP tree primitive comparison */ #define GL2PS_COINCIDENT 1 #define GL2PS_IN_FRONT_OF 2 #define GL2PS_IN_BACK_OF 3 #define GL2PS_SPANNING 4 /* 2D BSP tree primitive comparison */ #define GL2PS_POINT_COINCIDENT 0 #define GL2PS_POINT_INFRONT 1 #define GL2PS_POINT_BACK 2 /* Internal feedback buffer pass-through tokens */ #define GL2PS_BEGIN_OFFSET_TOKEN 1 #define GL2PS_END_OFFSET_TOKEN 2 #define GL2PS_BEGIN_BOUNDARY_TOKEN 3 #define GL2PS_END_BOUNDARY_TOKEN 4 #define GL2PS_BEGIN_STIPPLE_TOKEN 5 #define GL2PS_END_STIPPLE_TOKEN 6 #define GL2PS_POINT_SIZE_TOKEN 7 #define GL2PS_LINE_CAP_TOKEN 8 #define GL2PS_LINE_JOIN_TOKEN 9 #define GL2PS_LINE_WIDTH_TOKEN 10 #define GL2PS_BEGIN_BLEND_TOKEN 11 #define GL2PS_END_BLEND_TOKEN 12 #define GL2PS_SRC_BLEND_TOKEN 13 #define GL2PS_DST_BLEND_TOKEN 14 #define GL2PS_IMAGEMAP_TOKEN 15 #define GL2PS_DRAW_PIXELS_TOKEN 16 #define GL2PS_TEXT_TOKEN 17 typedef enum { T_UNDEFINED = -1, T_CONST_COLOR = 1, T_VAR_COLOR = 1<<1, T_ALPHA_1 = 1<<2, T_ALPHA_LESS_1 = 1<<3, T_VAR_ALPHA = 1<<4 } GL2PS_TRIANGLE_PROPERTY; typedef GLfloat GL2PSplane[4]; typedef struct GL2PSbsptree2d_ GL2PSbsptree2d; struct GL2PSbsptree2d_ { GL2PSplane plane; GL2PSbsptree2d *front, *back; }; typedef struct { GLint nmax, size, incr, n; char *array; } GL2PSlist; typedef struct GL2PSbsptree_ GL2PSbsptree; struct GL2PSbsptree_ { GL2PSplane plane; GL2PSlist *primitives; GL2PSbsptree *front, *back; }; typedef struct { GL2PSvertex vertex[3]; int prop; } GL2PStriangle; typedef struct { GLshort fontsize; char *str, *fontname; /* Note: for a 'special' string, 'alignment' holds the format (PostScript, PDF, etc.) of the special string */ GLint alignment; GLfloat angle; } GL2PSstring; typedef struct { GLsizei width, height; /* Note: for an imagemap, 'type' indicates if it has already been written to the file or not, and 'format' indicates if it is visible or not */ GLenum format, type; GLfloat zoom_x, zoom_y; GLfloat *pixels; } GL2PSimage; typedef struct GL2PSimagemap_ GL2PSimagemap; struct GL2PSimagemap_ { GL2PSimage *image; GL2PSimagemap *next; }; typedef struct { GLshort type, numverts; GLushort pattern; char boundary, offset, culled; GLint factor, linecap, linejoin, sortid; GLfloat width, ofactor, ounits; GL2PSvertex *verts; union { GL2PSstring *text; GL2PSimage *image; } data; } GL2PSprimitive; typedef struct { #if defined(GL2PS_HAVE_ZLIB) Bytef *dest, *src, *start; uLongf destLen, srcLen; #else int dummy; #endif } GL2PScompress; typedef struct{ GL2PSlist* ptrlist; int gsno, fontno, imno, shno, maskshno, trgroupno; int gsobjno, fontobjno, imobjno, shobjno, maskshobjno, trgroupobjno; } GL2PSpdfgroup; typedef struct { /* General */ GLint format, sort, options, colorsize, colormode, buffersize; GLint lastlinecap, lastlinejoin; char *title, *producer, *filename; GLboolean boundary, blending; GLfloat *feedback, lastlinewidth; GLint viewport[4], blendfunc[2], lastfactor; GL2PSrgba *colormap, lastrgba, threshold, bgcolor; GLushort lastpattern; GL2PSvertex lastvertex; GL2PSlist *primitives, *auxprimitives; FILE *stream; GL2PScompress *compress; GLboolean header; GL2PSvertex rasterpos; GLboolean forcerasterpos; /* BSP-specific */ GLint maxbestroot; /* Occlusion culling-specific */ GLboolean zerosurfacearea; GL2PSbsptree2d *imagetree; GL2PSprimitive *primitivetoadd; /* PDF-specific */ int streamlength; GL2PSlist *pdfprimlist, *pdfgrouplist; int *xreflist; int objects_stack; /* available objects */ int extgs_stack; /* graphics state object number */ int font_stack; /* font object number */ int im_stack; /* image object number */ int trgroupobjects_stack; /* xobject numbers */ int shader_stack; /* shader object numbers */ int mshader_stack; /* mask shader object numbers */ /* for image map list */ GL2PSimagemap *imagemap_head; GL2PSimagemap *imagemap_tail; /* for TEX scaling */ GLfloat tex_scaling; } GL2PScontext; typedef struct { void (*printHeader)(void); void (*printFooter)(void); void (*beginViewport)(GLint viewport[4]); GLint (*endViewport)(void); void (*printPrimitive)(void *data); void (*printFinalPrimitive)(void); const char *file_extension; const char *description; } GL2PSbackend; /* The gl2ps context. gl2ps is not thread safe (we should create a local GL2PScontext during gl2psBeginPage) */ static GL2PScontext *gl2ps = NULL; /* Need to forward-declare this one */ static GLint gl2psPrintPrimitives(void); /********************************************************************* * * Utility routines * *********************************************************************/ static void gl2psMsg(GLint level, const char *fmt, ...) { /* Avoid R check complaints: GL2PS_SILENT is always set va_list args; if(!(gl2ps->options & GL2PS_SILENT)){ switch(level){ case GL2PS_INFO : fprintf(stderr, "GL2PS info: "); break; case GL2PS_WARNING : fprintf(stderr, "GL2PS warning: "); break; case GL2PS_ERROR : fprintf(stderr, "GL2PS error: "); break; } va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); fprintf(stderr, "\n"); } */ /* if(level == GL2PS_ERROR) exit(1); */ } static void *gl2psMalloc(size_t size) { void *ptr; if(!size) return NULL; ptr = malloc(size); if(!ptr){ gl2psMsg(GL2PS_ERROR, "Couldn't allocate requested memory"); return NULL; } return ptr; } static void *gl2psRealloc(void *ptr, size_t size) { void *orig = ptr; if(!size) return NULL; ptr = realloc(orig, size); if(!ptr){ gl2psMsg(GL2PS_ERROR, "Couldn't reallocate requested memory"); free(orig); return NULL; } return ptr; } static void gl2psFree(void *ptr) { if(!ptr) return; free(ptr); } static int gl2psWriteBigEndian(unsigned long data, int bytes) { int i; int size = sizeof(unsigned long); for(i = 1; i <= bytes; ++i){ fputc(0xff & (data >> (size - i) * 8), gl2ps->stream); } return bytes; } /* zlib compression helper routines */ #if defined(GL2PS_HAVE_ZLIB) static void gl2psSetupCompress(void) { gl2ps->compress = (GL2PScompress*)gl2psMalloc(sizeof(GL2PScompress)); gl2ps->compress->src = NULL; gl2ps->compress->start = NULL; gl2ps->compress->dest = NULL; gl2ps->compress->srcLen = 0; gl2ps->compress->destLen = 0; } static void gl2psFreeCompress(void) { if(!gl2ps->compress) return; gl2psFree(gl2ps->compress->start); gl2psFree(gl2ps->compress->dest); gl2ps->compress->src = NULL; gl2ps->compress->start = NULL; gl2ps->compress->dest = NULL; gl2ps->compress->srcLen = 0; gl2ps->compress->destLen = 0; } static int gl2psAllocCompress(unsigned int srcsize) { gl2psFreeCompress(); if(!gl2ps->compress || !srcsize) return GL2PS_ERROR; gl2ps->compress->srcLen = srcsize; gl2ps->compress->destLen = (int)ceil(1.001 * gl2ps->compress->srcLen + 12); gl2ps->compress->src = (Bytef*)gl2psMalloc(gl2ps->compress->srcLen); gl2ps->compress->start = gl2ps->compress->src; gl2ps->compress->dest = (Bytef*)gl2psMalloc(gl2ps->compress->destLen); return GL2PS_SUCCESS; } static void *gl2psReallocCompress(unsigned int srcsize) { if(!gl2ps->compress || !srcsize) return NULL; if(srcsize < gl2ps->compress->srcLen) return gl2ps->compress->start; gl2ps->compress->srcLen = srcsize; gl2ps->compress->destLen = (int)ceil(1.001 * gl2ps->compress->srcLen + 12); gl2ps->compress->src = (Bytef*)gl2psRealloc(gl2ps->compress->src, gl2ps->compress->srcLen); gl2ps->compress->start = gl2ps->compress->src; gl2ps->compress->dest = (Bytef*)gl2psRealloc(gl2ps->compress->dest, gl2ps->compress->destLen); return gl2ps->compress->start; } static int gl2psWriteBigEndianCompress(unsigned long data, int bytes) { int i; int size = sizeof(unsigned long); for(i = 1; i <= bytes; ++i){ *gl2ps->compress->src = (Bytef)(0xff & (data >> (size-i) * 8)); ++gl2ps->compress->src; } return bytes; } static int gl2psDeflate(void) { /* For compatibility with older zlib versions, we use compress(...) instead of compress2(..., Z_BEST_COMPRESSION) */ return compress(gl2ps->compress->dest, &gl2ps->compress->destLen, gl2ps->compress->start, gl2ps->compress->srcLen); } #endif static int gl2psPrintf(const char* fmt, ...) { int ret; va_list args; #if defined(GL2PS_HAVE_ZLIB) static char buf[1024]; char *bufptr = buf; GLboolean freebuf = GL_FALSE; unsigned int oldsize = 0; #if !defined(GL2PS_HAVE_NO_VSNPRINTF) /* Try writing the string to a 1024 byte buffer. If it is too small to fit, keep trying larger sizes until it does. */ int bufsize = sizeof(buf); #endif if(gl2ps->options & GL2PS_COMPRESS){ va_start(args, fmt); #if defined(GL2PS_HAVE_NO_VSNPRINTF) ret = vsprintf(buf, fmt, args); #else ret = vsnprintf(bufptr, bufsize, fmt, args); #endif va_end(args); #if !defined(GL2PS_HAVE_NO_VSNPRINTF) while(ret >= (bufsize - 1) || ret < 0){ /* Too big. Allocate a new buffer. */ bufsize *= 2; if(freebuf == GL_TRUE) gl2psFree(bufptr); bufptr = (char *)gl2psMalloc(bufsize); freebuf = GL_TRUE; va_start(args, fmt); ret = vsnprintf(bufptr, bufsize, fmt, args); va_end(args); } #endif oldsize = gl2ps->compress->srcLen; gl2ps->compress->start = (Bytef*)gl2psReallocCompress(oldsize + ret); memcpy(gl2ps->compress->start + oldsize, bufptr, ret); if(freebuf == GL_TRUE) gl2psFree(bufptr); ret = 0; } else{ #endif va_start(args, fmt); ret = vfprintf(gl2ps->stream, fmt, args); va_end(args); #if defined(GL2PS_HAVE_ZLIB) } #endif return ret; } static void gl2psPrintGzipHeader(void) { #if defined(GL2PS_HAVE_ZLIB) char tmp[10] = {'\x1f', '\x8b', /* magic numbers: 0x1f, 0x8b */ 8, /* compression method: Z_DEFLATED */ 0, /* flags */ 0, 0, 0, 0, /* time */ 2, /* extra flags: max compression */ '\x03'}; /* OS code: 0x03 (Unix) */ if(gl2ps->options & GL2PS_COMPRESS){ gl2psSetupCompress(); /* add the gzip file header */ fwrite(tmp, 10, 1, gl2ps->stream); } #endif } static void gl2psPrintGzipFooter(void) { #if defined(GL2PS_HAVE_ZLIB) int n; uLong crc, len; char tmp[8]; if(gl2ps->options & GL2PS_COMPRESS){ if(Z_OK != gl2psDeflate()){ gl2psMsg(GL2PS_ERROR, "Zlib deflate error"); } else{ /* determine the length of the header in the zlib stream */ n = 2; /* CMF+FLG */ if(gl2ps->compress->dest[1] & (1<<5)){ n += 4; /* DICTID */ } /* write the data, without the zlib header and footer */ fwrite(gl2ps->compress->dest+n, gl2ps->compress->destLen-(n+4), 1, gl2ps->stream); /* add the gzip file footer */ crc = crc32(0L, gl2ps->compress->start, gl2ps->compress->srcLen); for(n = 0; n < 4; ++n){ tmp[n] = (char)(crc & 0xff); crc >>= 8; } len = gl2ps->compress->srcLen; for(n = 4; n < 8; ++n){ tmp[n] = (char)(len & 0xff); len >>= 8; } fwrite(tmp, 8, 1, gl2ps->stream); } gl2psFreeCompress(); gl2psFree(gl2ps->compress); gl2ps->compress = NULL; } #endif } /* The list handling routines */ static void gl2psListRealloc(GL2PSlist *list, GLint n) { if(!list){ gl2psMsg(GL2PS_ERROR, "Cannot reallocate NULL list"); return; } if(n <= 0) return; if(!list->array){ list->nmax = n; list->array = (char*)gl2psMalloc(list->nmax * list->size); } else{ if(n > list->nmax){ list->nmax = ((n - 1) / list->incr + 1) * list->incr; list->array = (char*)gl2psRealloc(list->array, list->nmax * list->size); } } } static GL2PSlist *gl2psListCreate(GLint n, GLint incr, GLint size) { GL2PSlist *list; if(n < 0) n = 0; if(incr <= 0) incr = 1; list = (GL2PSlist*)gl2psMalloc(sizeof(GL2PSlist)); list->nmax = 0; list->incr = incr; list->size = size; list->n = 0; list->array = NULL; gl2psListRealloc(list, n); return list; } static void gl2psListReset(GL2PSlist *list) { if(!list) return; list->n = 0; } static void gl2psListDelete(GL2PSlist *list) { if(!list) return; gl2psFree(list->array); gl2psFree(list); } static void gl2psListAdd(GL2PSlist *list, void *data) { if(!list){ gl2psMsg(GL2PS_ERROR, "Cannot add into unallocated list"); return; } list->n++; gl2psListRealloc(list, list->n); memcpy(&list->array[(list->n - 1) * list->size], data, list->size); } static int gl2psListNbr(GL2PSlist *list) { if(!list) return 0; return list->n; } static void *gl2psListPointer(GL2PSlist *list, GLint idx) { if(!list){ gl2psMsg(GL2PS_ERROR, "Cannot point into unallocated list"); return NULL; } if((idx < 0) || (idx >= list->n)){ gl2psMsg(GL2PS_ERROR, "Wrong list index in gl2psListPointer"); return NULL; } return &list->array[idx * list->size]; } static void gl2psListSort(GL2PSlist *list, int (*fcmp)(const void *a, const void *b)) { if(!list) return; qsort(list->array, list->n, list->size, fcmp); } /* Must be a list of GL2PSprimitives. */ static void gl2psListAssignSortIds(GL2PSlist *list) { GLint i; for(i = 0; i < gl2psListNbr(list); i++){ (*(GL2PSprimitive**)gl2psListPointer(list, i))->sortid = i; } } static void gl2psListAction(GL2PSlist *list, void (*action)(void *data)) { GLint i; for(i = 0; i < gl2psListNbr(list); i++){ (*action)(gl2psListPointer(list, i)); } } static void gl2psListActionInverse(GL2PSlist *list, void (*action)(void *data)) { GLint i; for(i = gl2psListNbr(list); i > 0; i--){ (*action)(gl2psListPointer(list, i-1)); } } #if defined(GL2PS_HAVE_LIBPNG) static void gl2psListRead(GL2PSlist *list, int index, void *data) { if((index < 0) || (index >= list->n)) gl2psMsg(GL2PS_ERROR, "Wrong list index in gl2psListRead"); memcpy(data, &list->array[index * list->size], list->size); } static void gl2psEncodeBase64Block(unsigned char in[3], unsigned char out[4], int len) { static const char cb64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; out[0] = cb64[ in[0] >> 2 ]; out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ]; out[2] = (len > 1) ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '='; out[3] = (len > 2) ? cb64[ in[2] & 0x3f ] : '='; } static void gl2psListEncodeBase64(GL2PSlist *list) { unsigned char *buffer, in[3], out[4]; int i, n, index, len; n = list->n * list->size; buffer = (unsigned char*)gl2psMalloc(n * sizeof(unsigned char)); memcpy(buffer, list->array, n * sizeof(unsigned char)); gl2psListReset(list); index = 0; while(index < n) { len = 0; for(i = 0; i < 3; i++) { if(index < n){ in[i] = buffer[index]; len++; } else{ in[i] = 0; } index++; } if(len) { gl2psEncodeBase64Block(in, out, len); for(i = 0; i < 4; i++) gl2psListAdd(list, &out[i]); } } gl2psFree(buffer); } #endif /* Helpers for rgba colors */ static GLboolean gl2psSameColor(GL2PSrgba rgba1, GL2PSrgba rgba2) { if(!GL2PS_ZERO(rgba1[0] - rgba2[0]) || !GL2PS_ZERO(rgba1[1] - rgba2[1]) || !GL2PS_ZERO(rgba1[2] - rgba2[2])) return GL_FALSE; return GL_TRUE; } static GLboolean gl2psVertsSameColor(const GL2PSprimitive *prim) { int i; for(i = 1; i < prim->numverts; i++){ if(!gl2psSameColor(prim->verts[0].rgba, prim->verts[i].rgba)){ return GL_FALSE; } } return GL_TRUE; } static GLboolean gl2psSameColorThreshold(int n, GL2PSrgba rgba[], GL2PSrgba threshold) { int i; if(n < 2) return GL_TRUE; for(i = 1; i < n; i++){ if(fabs(rgba[0][0] - rgba[i][0]) > threshold[0] || fabs(rgba[0][1] - rgba[i][1]) > threshold[1] || fabs(rgba[0][2] - rgba[i][2]) > threshold[2]) return GL_FALSE; } return GL_TRUE; } static void gl2psSetLastColor(GL2PSrgba rgba) { int i; for(i = 0; i < 3; ++i){ gl2ps->lastrgba[i] = rgba[i]; } } static GLfloat gl2psGetRGB(GL2PSimage *im, GLuint x, GLuint y, GLfloat *red, GLfloat *green, GLfloat *blue) { GLsizei width = im->width; GLsizei height = im->height; GLfloat *pixels = im->pixels; GLfloat *pimag; /* OpenGL image is from down to up, PS image is up to down */ switch(im->format){ case GL_RGBA: pimag = pixels + 4 * (width * (height - 1 - y) + x); break; case GL_RGB: default: pimag = pixels + 3 * (width * (height - 1 - y) + x); break; } *red = *pimag; pimag++; *green = *pimag; pimag++; *blue = *pimag; pimag++; return (im->format == GL_RGBA) ? *pimag : 1.0F; } /* Helper routines for pixmaps */ static GL2PSimage *gl2psCopyPixmap(GL2PSimage *im) { int size; GL2PSimage *image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage)); image->width = im->width; image->height = im->height; image->format = im->format; image->type = im->type; image->zoom_x = im->zoom_x; image->zoom_y = im->zoom_y; switch(image->format){ case GL_RGBA: size = image->height * image->width * 4 * sizeof(GLfloat); break; case GL_RGB: default: size = image->height * image->width * 3 * sizeof(GLfloat); break; } image->pixels = (GLfloat*)gl2psMalloc(size); memcpy(image->pixels, im->pixels, size); return image; } static void gl2psFreePixmap(GL2PSimage *im) { if(!im) return; gl2psFree(im->pixels); gl2psFree(im); } #if defined(GL2PS_HAVE_LIBPNG) #if !defined(png_jmpbuf) # define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) #endif static void gl2psUserWritePNG(png_structp png_ptr, png_bytep data, png_size_t length) { unsigned int i; GL2PSlist *png = (GL2PSlist*)png_get_io_ptr(png_ptr); for(i = 0; i < length; i++) gl2psListAdd(png, &data[i]); } static void gl2psUserFlushPNG(png_structp png_ptr) { (void) png_ptr; /* not used */ } static void gl2psConvertPixmapToPNG(GL2PSimage *pixmap, GL2PSlist *png) { png_structp png_ptr; png_infop info_ptr; unsigned char *row_data; GLfloat dr, dg, db; int row, col; if(!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) return; if(!(info_ptr = png_create_info_struct(png_ptr))){ png_destroy_write_struct(&png_ptr, NULL); return; } if(setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); return; } png_set_write_fn(png_ptr, (void *)png, gl2psUserWritePNG, gl2psUserFlushPNG); png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION); png_set_IHDR(png_ptr, info_ptr, pixmap->width, pixmap->height, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png_ptr, info_ptr); row_data = (unsigned char*)gl2psMalloc(3 * pixmap->width * sizeof(unsigned char)); for(row = 0; row < pixmap->height; row++){ for(col = 0; col < pixmap->width; col++){ gl2psGetRGB(pixmap, col, row, &dr, &dg, &db); row_data[3*col] = (unsigned char)(255. * dr); row_data[3*col+1] = (unsigned char)(255. * dg); row_data[3*col+2] = (unsigned char)(255. * db); } png_write_row(png_ptr, (png_bytep)row_data); } gl2psFree(row_data); png_write_end(png_ptr, info_ptr); png_destroy_write_struct(&png_ptr, &info_ptr); } #endif /* Helper routines for text strings */ static GLint gl2psAddText(GLint type, const char *str, const char *fontname, GLshort fontsize, GLint alignment, GLfloat angle, GL2PSrgba color, GLboolean setblpos, GLfloat blx, GLfloat bly) { GLfloat pos[4]; GL2PSprimitive *prim; GLboolean valid; if(!gl2ps || !str || !fontname) return GL2PS_UNINITIALIZED; if(gl2ps->options & GL2PS_NO_TEXT) return GL2PS_SUCCESS; if (gl2ps->forcerasterpos) { pos[0] = gl2ps->rasterpos.xyz[0]; pos[1] = gl2ps->rasterpos.xyz[1]; pos[2] = gl2ps->rasterpos.xyz[2]; pos[3] = 1.f; } else { glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid); if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */ glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); } prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); prim->type = (GLshort)type; prim->boundary = 0; prim->numverts = setblpos ? 2 : 1; prim->verts = (GL2PSvertex*)gl2psMalloc(sizeof(GL2PSvertex) * prim->numverts); prim->verts[0].xyz[0] = pos[0]; prim->verts[0].xyz[1] = pos[1]; prim->verts[0].xyz[2] = pos[2]; if (setblpos) { prim->verts[1].xyz[0] = blx; prim->verts[1].xyz[1] = bly; prim->verts[1].xyz[2] = 0; } prim->culled = 0; prim->offset = 0; prim->ofactor = 0.0; prim->ounits = 0.0; prim->pattern = 0; prim->factor = 0; prim->width = 1; prim->linecap = 0; prim->linejoin = 0; if (color) { memcpy(prim->verts[0].rgba, color, 4 * sizeof(float)); } else { if (gl2ps->forcerasterpos) { prim->verts[0].rgba[0] = gl2ps->rasterpos.rgba[0]; prim->verts[0].rgba[1] = gl2ps->rasterpos.rgba[1]; prim->verts[0].rgba[2] = gl2ps->rasterpos.rgba[2]; prim->verts[0].rgba[3] = gl2ps->rasterpos.rgba[3]; } else { glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba); } } prim->data.text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring)); prim->data.text->str = (char*)gl2psMalloc((strlen(str)+1)*sizeof(char)); strcpy(prim->data.text->str, str); prim->data.text->fontname = (char*)gl2psMalloc((strlen(fontname)+1)*sizeof(char)); strcpy(prim->data.text->fontname, fontname); prim->data.text->fontsize = fontsize; prim->data.text->alignment = alignment; prim->data.text->angle = angle; gl2ps->forcerasterpos = GL_FALSE; /* If no OpenGL context, just add directly to primitives */ if (gl2ps->options & GL2PS_NO_OPENGL_CONTEXT) { gl2psListAdd(gl2ps->primitives, &prim); } else { gl2psListAdd(gl2ps->auxprimitives, &prim); glPassThrough(GL2PS_TEXT_TOKEN); } return GL2PS_SUCCESS; } static GL2PSstring *gl2psCopyText(GL2PSstring *t) { GL2PSstring *text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring)); text->str = (char*)gl2psMalloc((strlen(t->str)+1)*sizeof(char)); strcpy(text->str, t->str); text->fontname = (char*)gl2psMalloc((strlen(t->fontname)+1)*sizeof(char)); strcpy(text->fontname, t->fontname); text->fontsize = t->fontsize; text->alignment = t->alignment; text->angle = t->angle; return text; } static void gl2psFreeText(GL2PSstring *text) { if(!text) return; gl2psFree(text->str); gl2psFree(text->fontname); gl2psFree(text); } /* Helpers for blending modes */ static GLboolean gl2psSupportedBlendMode(GLenum sfactor, GLenum dfactor) { /* returns TRUE if gl2ps supports the argument combination: only two blending modes have been implemented so far */ if( (sfactor == GL_SRC_ALPHA && dfactor == GL_ONE_MINUS_SRC_ALPHA) || (sfactor == GL_ONE && dfactor == GL_ZERO) ) return GL_TRUE; return GL_FALSE; } static void gl2psAdaptVertexForBlending(GL2PSvertex *v) { /* Transforms vertex depending on the actual blending function - currently the vertex v is considered as source vertex and his alpha value is changed to 1.0 if source blending GL_ONE is active. This might be extended in the future */ if(!v || !gl2ps) return; if(gl2ps->options & GL2PS_NO_BLENDING || !gl2ps->blending){ v->rgba[3] = 1.0F; return; } switch(gl2ps->blendfunc[0]){ case GL_ONE: v->rgba[3] = 1.0F; break; default: break; } } static void gl2psAssignTriangleProperties(GL2PStriangle *t) { /* int i; */ t->prop = T_VAR_COLOR; /* Uncommenting the following lines activates an even more fine grained distinction between triangle types - please don't delete, a remarkable amount of PDF handling code inside this file depends on it if activated */ /* t->prop = T_CONST_COLOR; for(i = 0; i < 3; ++i){ if(!GL2PS_ZERO(t->vertex[0].rgba[i] - t->vertex[1].rgba[i]) || !GL2PS_ZERO(t->vertex[1].rgba[i] - t->vertex[2].rgba[i])){ t->prop = T_VAR_COLOR; break; } } */ if(!GL2PS_ZERO(t->vertex[0].rgba[3] - t->vertex[1].rgba[3]) || !GL2PS_ZERO(t->vertex[1].rgba[3] - t->vertex[2].rgba[3])){ t->prop |= T_VAR_ALPHA; } else{ if(t->vertex[0].rgba[3] < 1) t->prop |= T_ALPHA_LESS_1; else t->prop |= T_ALPHA_1; } } static void gl2psFillTriangleFromPrimitive(GL2PStriangle *t, GL2PSprimitive *p, GLboolean assignprops) { t->vertex[0] = p->verts[0]; t->vertex[1] = p->verts[1]; t->vertex[2] = p->verts[2]; if(GL_TRUE == assignprops) gl2psAssignTriangleProperties(t); } static void gl2psInitTriangle(GL2PStriangle *t) { int i; GL2PSvertex vertex = { {-1.0F, -1.0F, -1.0F}, {-1.0F, -1.0F, -1.0F, -1.0F} }; for(i = 0; i < 3; i++) t->vertex[i] = vertex; t->prop = T_UNDEFINED; } /* Miscellaneous helper routines */ static void gl2psResetLineProperties(void) { gl2ps->lastlinewidth = 0.; gl2ps->lastlinecap = gl2ps->lastlinejoin = 0; } static GL2PSprimitive *gl2psCopyPrimitive(GL2PSprimitive *p) { GL2PSprimitive *prim; if(!p){ gl2psMsg(GL2PS_ERROR, "Trying to copy an empty primitive"); return NULL; } prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); prim->type = p->type; prim->numverts = p->numverts; prim->boundary = p->boundary; prim->offset = p->offset; prim->ofactor = p->ofactor; prim->ounits = p->ounits; prim->pattern = p->pattern; prim->factor = p->factor; prim->culled = p->culled; prim->width = p->width; prim->linecap = p->linecap; prim->linejoin = p->linejoin; prim->verts = (GL2PSvertex*)gl2psMalloc(p->numverts*sizeof(GL2PSvertex)); memcpy(prim->verts, p->verts, p->numverts * sizeof(GL2PSvertex)); switch(prim->type){ case GL2PS_PIXMAP : prim->data.image = gl2psCopyPixmap(p->data.image); break; case GL2PS_TEXT : case GL2PS_SPECIAL : prim->data.text = gl2psCopyText(p->data.text); break; default: break; } return prim; } static GLboolean gl2psSamePosition(GL2PSxyz p1, GL2PSxyz p2) { if(!GL2PS_ZERO(p1[0] - p2[0]) || !GL2PS_ZERO(p1[1] - p2[1]) || !GL2PS_ZERO(p1[2] - p2[2])) return GL_FALSE; return GL_TRUE; } /********************************************************************* * * 3D sorting routines * *********************************************************************/ static GLfloat gl2psComparePointPlane(GL2PSxyz point, GL2PSplane plane) { return (plane[0] * point[0] + plane[1] * point[1] + plane[2] * point[2] + plane[3]); } static GLfloat gl2psPsca(GLfloat *a, GLfloat *b) { return (a[0]*b[0] + a[1]*b[1] + a[2]*b[2]); } static void gl2psPvec(GLfloat *a, GLfloat *b, GLfloat *c) { c[0] = a[1]*b[2] - a[2]*b[1]; c[1] = a[2]*b[0] - a[0]*b[2]; c[2] = a[0]*b[1] - a[1]*b[0]; } static GLfloat gl2psNorm(GLfloat *a) { return (GLfloat)sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]); } static void gl2psGetNormal(GLfloat *a, GLfloat *b, GLfloat *c) { GLfloat norm; gl2psPvec(a, b, c); if(!GL2PS_ZERO(norm = gl2psNorm(c))){ c[0] = c[0] / norm; c[1] = c[1] / norm; c[2] = c[2] / norm; } else{ /* The plane is still wrong despite our tests in gl2psGetPlane. Let's return a dummy value for now (this is a hack: we should do more intelligent tests in GetPlane) */ c[0] = c[1] = 0.0F; c[2] = 1.0F; } } static void gl2psGetPlane(GL2PSprimitive *prim, GL2PSplane plane) { GL2PSxyz v = {0.0F, 0.0F, 0.0F}, w = {0.0F, 0.0F, 0.0F}; switch(prim->type){ case GL2PS_TRIANGLE : case GL2PS_QUADRANGLE : v[0] = prim->verts[1].xyz[0] - prim->verts[0].xyz[0]; v[1] = prim->verts[1].xyz[1] - prim->verts[0].xyz[1]; v[2] = prim->verts[1].xyz[2] - prim->verts[0].xyz[2]; w[0] = prim->verts[2].xyz[0] - prim->verts[0].xyz[0]; w[1] = prim->verts[2].xyz[1] - prim->verts[0].xyz[1]; w[2] = prim->verts[2].xyz[2] - prim->verts[0].xyz[2]; if((GL2PS_ZERO(v[0]) && GL2PS_ZERO(v[1]) && GL2PS_ZERO(v[2])) || (GL2PS_ZERO(w[0]) && GL2PS_ZERO(w[1]) && GL2PS_ZERO(w[2]))){ plane[0] = plane[1] = 0.0F; plane[2] = 1.0F; plane[3] = -prim->verts[0].xyz[2]; } else{ gl2psGetNormal(v, w, plane); plane[3] = - plane[0] * prim->verts[0].xyz[0] - plane[1] * prim->verts[0].xyz[1] - plane[2] * prim->verts[0].xyz[2]; } break; case GL2PS_LINE : v[0] = prim->verts[1].xyz[0] - prim->verts[0].xyz[0]; v[1] = prim->verts[1].xyz[1] - prim->verts[0].xyz[1]; v[2] = prim->verts[1].xyz[2] - prim->verts[0].xyz[2]; if(GL2PS_ZERO(v[0]) && GL2PS_ZERO(v[1]) && GL2PS_ZERO(v[2])){ plane[0] = plane[1] = 0.0F; plane[2] = 1.0F; plane[3] = -prim->verts[0].xyz[2]; } else{ if(GL2PS_ZERO(v[0])) w[0] = 1.0F; else if(GL2PS_ZERO(v[1])) w[1] = 1.0F; else w[2] = 1.0F; gl2psGetNormal(v, w, plane); plane[3] = - plane[0] * prim->verts[0].xyz[0] - plane[1] * prim->verts[0].xyz[1] - plane[2] * prim->verts[0].xyz[2]; } break; case GL2PS_POINT : case GL2PS_PIXMAP : case GL2PS_TEXT : case GL2PS_SPECIAL : case GL2PS_IMAGEMAP: plane[0] = plane[1] = 0.0F; plane[2] = 1.0F; plane[3] = -prim->verts[0].xyz[2]; break; default : gl2psMsg(GL2PS_ERROR, "Unknown primitive type in BSP tree"); plane[0] = plane[1] = plane[3] = 0.0F; plane[2] = 1.0F; break; } } static void gl2psCutEdge(GL2PSvertex *a, GL2PSvertex *b, GL2PSplane plane, GL2PSvertex *c) { GL2PSxyz v; GLfloat sect, psca; v[0] = b->xyz[0] - a->xyz[0]; v[1] = b->xyz[1] - a->xyz[1]; v[2] = b->xyz[2] - a->xyz[2]; if(!GL2PS_ZERO(psca = gl2psPsca(plane, v))) sect = -gl2psComparePointPlane(a->xyz, plane) / psca; else sect = 0.0F; c->xyz[0] = a->xyz[0] + v[0] * sect; c->xyz[1] = a->xyz[1] + v[1] * sect; c->xyz[2] = a->xyz[2] + v[2] * sect; c->rgba[0] = (1 - sect) * a->rgba[0] + sect * b->rgba[0]; c->rgba[1] = (1 - sect) * a->rgba[1] + sect * b->rgba[1]; c->rgba[2] = (1 - sect) * a->rgba[2] + sect * b->rgba[2]; c->rgba[3] = (1 - sect) * a->rgba[3] + sect * b->rgba[3]; } static void gl2psCreateSplitPrimitive(GL2PSprimitive *parent, GL2PSplane plane, GL2PSprimitive *child, GLshort numverts, GLshort *index0, GLshort *index1) { GLshort i; if(parent->type == GL2PS_IMAGEMAP){ child->type = GL2PS_IMAGEMAP; child->data.image = parent->data.image; } else{ if(numverts > 4){ gl2psMsg(GL2PS_WARNING, "%d vertices in polygon", numverts); numverts = 4; } switch(numverts){ case 1 : child->type = GL2PS_POINT; break; case 2 : child->type = GL2PS_LINE; break; case 3 : child->type = GL2PS_TRIANGLE; break; case 4 : child->type = GL2PS_QUADRANGLE; break; default: child->type = GL2PS_NO_TYPE; break; } } child->boundary = 0; /* FIXME: not done! */ child->culled = parent->culled; child->offset = parent->offset; child->ofactor = parent->ofactor; child->ounits = parent->ounits; child->pattern = parent->pattern; child->factor = parent->factor; child->width = parent->width; child->linecap = parent->linecap; child->linejoin = parent->linejoin; child->numverts = numverts; child->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex)); for(i = 0; i < numverts; i++){ if(index1[i] < 0){ child->verts[i] = parent->verts[index0[i]]; } else{ gl2psCutEdge(&parent->verts[index0[i]], &parent->verts[index1[i]], plane, &child->verts[i]); } } } static void gl2psAddIndex(GLshort *index0, GLshort *index1, GLshort *nb, GLshort i, GLshort j) { GLint k; for(k = 0; k < *nb; k++){ if((index0[k] == i && index1[k] == j) || (index1[k] == i && index0[k] == j)) return; } index0[*nb] = i; index1[*nb] = j; (*nb)++; } static GLshort gl2psGetIndex(GLshort i, GLshort num) { return (i < num - 1) ? i + 1 : 0; } static GLint gl2psTestSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane) { GLint type = GL2PS_COINCIDENT; GLshort i, j; GLfloat d[5]; for(i = 0; i < prim->numverts; i++){ d[i] = gl2psComparePointPlane(prim->verts[i].xyz, plane); } if(prim->numverts < 2){ return 0; } else{ for(i = 0; i < prim->numverts; i++){ j = gl2psGetIndex(i, prim->numverts); if(d[j] > GL2PS_EPSILON){ if(type == GL2PS_COINCIDENT) type = GL2PS_IN_BACK_OF; else if(type != GL2PS_IN_BACK_OF) return 1; if(d[i] < -GL2PS_EPSILON) return 1; } else if(d[j] < -GL2PS_EPSILON){ if(type == GL2PS_COINCIDENT) type = GL2PS_IN_FRONT_OF; else if(type != GL2PS_IN_FRONT_OF) return 1; if(d[i] > GL2PS_EPSILON) return 1; } } } return 0; } static GLint gl2psSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane, GL2PSprimitive **front, GL2PSprimitive **back) { GLshort i, j, in = 0, out = 0, in0[5], in1[5], out0[5], out1[5]; GLint type; GLfloat d[5]; type = GL2PS_COINCIDENT; for(i = 0; i < prim->numverts; i++){ d[i] = gl2psComparePointPlane(prim->verts[i].xyz, plane); } switch(prim->type){ case GL2PS_POINT : if(d[0] > GL2PS_EPSILON) type = GL2PS_IN_BACK_OF; else if(d[0] < -GL2PS_EPSILON) type = GL2PS_IN_FRONT_OF; else type = GL2PS_COINCIDENT; break; default : for(i = 0; i < prim->numverts; i++){ j = gl2psGetIndex(i, prim->numverts); if(d[j] > GL2PS_EPSILON){ if(type == GL2PS_COINCIDENT) type = GL2PS_IN_BACK_OF; else if(type != GL2PS_IN_BACK_OF) type = GL2PS_SPANNING; if(d[i] < -GL2PS_EPSILON){ gl2psAddIndex(in0, in1, &in, i, j); gl2psAddIndex(out0, out1, &out, i, j); type = GL2PS_SPANNING; } gl2psAddIndex(out0, out1, &out, j, -1); } else if(d[j] < -GL2PS_EPSILON){ if(type == GL2PS_COINCIDENT) type = GL2PS_IN_FRONT_OF; else if(type != GL2PS_IN_FRONT_OF) type = GL2PS_SPANNING; if(d[i] > GL2PS_EPSILON){ gl2psAddIndex(in0, in1, &in, i, j); gl2psAddIndex(out0, out1, &out, i, j); type = GL2PS_SPANNING; } gl2psAddIndex(in0, in1, &in, j, -1); } else{ gl2psAddIndex(in0, in1, &in, j, -1); gl2psAddIndex(out0, out1, &out, j, -1); } } break; } if(type == GL2PS_SPANNING){ *back = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); *front = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); gl2psCreateSplitPrimitive(prim, plane, *back, out, out0, out1); gl2psCreateSplitPrimitive(prim, plane, *front, in, in0, in1); } return type; } static void gl2psDivideQuad(GL2PSprimitive *quad, GL2PSprimitive **t1, GL2PSprimitive **t2) { *t1 = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); *t2 = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); (*t1)->type = (*t2)->type = GL2PS_TRIANGLE; (*t1)->numverts = (*t2)->numverts = 3; (*t1)->culled = (*t2)->culled = quad->culled; (*t1)->offset = (*t2)->offset = quad->offset; (*t1)->ofactor = (*t2)->ofactor = quad->ofactor; (*t1)->ounits = (*t2)->ounits = quad->ounits; (*t1)->pattern = (*t2)->pattern = quad->pattern; (*t1)->factor = (*t2)->factor = quad->factor; (*t1)->width = (*t2)->width = quad->width; (*t1)->linecap = (*t2)->linecap = quad->linecap; (*t1)->linejoin = (*t2)->linejoin = quad->linejoin; (*t1)->verts = (GL2PSvertex*)gl2psMalloc(3 * sizeof(GL2PSvertex)); (*t2)->verts = (GL2PSvertex*)gl2psMalloc(3 * sizeof(GL2PSvertex)); (*t1)->verts[0] = quad->verts[0]; (*t1)->verts[1] = quad->verts[1]; (*t1)->verts[2] = quad->verts[2]; (*t1)->boundary = ((quad->boundary & 1) ? 1 : 0) | ((quad->boundary & 2) ? 2 : 0); (*t2)->verts[0] = quad->verts[0]; (*t2)->verts[1] = quad->verts[2]; (*t2)->verts[2] = quad->verts[3]; (*t2)->boundary = ((quad->boundary & 4) ? 2 : 0) | ((quad->boundary & 8) ? 4 : 0); } static int gl2psCompareDepth(const void *a, const void *b) { const GL2PSprimitive *q, *w; GLfloat dq = 0.0F, dw = 0.0F, diff; int i; q = *(const GL2PSprimitive* const*)a; w = *(const GL2PSprimitive* const*)b; for(i = 0; i < q->numverts; i++){ dq += q->verts[i].xyz[2]; } dq /= (GLfloat)q->numverts; for(i = 0; i < w->numverts; i++){ dw += w->verts[i].xyz[2]; } dw /= (GLfloat)w->numverts; diff = dq - dw; if(diff > 0.){ return -1; } else if(diff < 0.){ return 1; } else{ /* Ensure that initial ordering is preserved when depths match. */ return q->sortid < w->sortid ? -1 : 1; } } static int gl2psTrianglesFirst(const void *a, const void *b) { const GL2PSprimitive *q, *w; q = *(const GL2PSprimitive* const*)a; w = *(const GL2PSprimitive* const*)b; return (q->type < w->type ? 1 : -1); } static GLint gl2psFindRoot(GL2PSlist *primitives, GL2PSprimitive **root) { GLint i, j, count, best = 1000000, idx = 0; GL2PSprimitive *prim1, *prim2; GL2PSplane plane; GLint maxp; if(!gl2psListNbr(primitives)){ gl2psMsg(GL2PS_ERROR, "Cannot fint root in empty primitive list"); return 0; } *root = *(GL2PSprimitive**)gl2psListPointer(primitives, 0); if(gl2ps->options & GL2PS_BEST_ROOT){ maxp = gl2psListNbr(primitives); if(maxp > gl2ps->maxbestroot){ maxp = gl2ps->maxbestroot; } for(i = 0; i < maxp; i++){ prim1 = *(GL2PSprimitive**)gl2psListPointer(primitives, i); gl2psGetPlane(prim1, plane); count = 0; for(j = 0; j < gl2psListNbr(primitives); j++){ if(j != i){ prim2 = *(GL2PSprimitive**)gl2psListPointer(primitives, j); count += gl2psTestSplitPrimitive(prim2, plane); } if(count > best) break; } if(count < best){ best = count; idx = i; *root = prim1; if(!count) return idx; } } /* if(index) gl2psMsg(GL2PS_INFO, "GL2PS_BEST_ROOT was worth it: %d", index); */ return idx; } else{ return 0; } } static void gl2psFreeImagemap(GL2PSimagemap *list) { GL2PSimagemap *next; while(list != NULL){ next = list->next; gl2psFree(list->image->pixels); gl2psFree(list->image); gl2psFree(list); list = next; } } static void gl2psFreePrimitive(void *data) { GL2PSprimitive *q; q = *(GL2PSprimitive**)data; gl2psFree(q->verts); if(q->type == GL2PS_TEXT || q->type == GL2PS_SPECIAL){ gl2psFreeText(q->data.text); } else if(q->type == GL2PS_PIXMAP){ gl2psFreePixmap(q->data.image); } gl2psFree(q); } static void gl2psAddPrimitiveInList(GL2PSprimitive *prim, GL2PSlist *list) { GL2PSprimitive *t1, *t2; if(prim->type != GL2PS_QUADRANGLE){ gl2psListAdd(list, &prim); } else{ gl2psDivideQuad(prim, &t1, &t2); gl2psListAdd(list, &t1); gl2psListAdd(list, &t2); gl2psFreePrimitive(&prim); } } static void gl2psFreeBspTree(GL2PSbsptree **tree) { if(*tree){ if((*tree)->back) gl2psFreeBspTree(&(*tree)->back); if((*tree)->primitives){ gl2psListAction((*tree)->primitives, gl2psFreePrimitive); gl2psListDelete((*tree)->primitives); } if((*tree)->front) gl2psFreeBspTree(&(*tree)->front); gl2psFree(*tree); *tree = NULL; } } static GLboolean gl2psGreater(GLfloat f1, GLfloat f2) { if(f1 > f2) return GL_TRUE; else return GL_FALSE; } static GLboolean gl2psLess(GLfloat f1, GLfloat f2) { if(f1 < f2) return GL_TRUE; else return GL_FALSE; } static void gl2psBuildBspTree(GL2PSbsptree *tree, GL2PSlist *primitives) { GL2PSprimitive *prim = 0, *frontprim = NULL, *backprim = NULL; GL2PSlist *frontlist, *backlist; GLint i, idx; tree->front = NULL; tree->back = NULL; tree->primitives = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); idx = gl2psFindRoot(primitives, &prim); gl2psGetPlane(prim, tree->plane); gl2psAddPrimitiveInList(prim, tree->primitives); frontlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); backlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); for(i = 0; i < gl2psListNbr(primitives); i++){ if(i != idx){ prim = *(GL2PSprimitive**)gl2psListPointer(primitives,i); switch(gl2psSplitPrimitive(prim, tree->plane, &frontprim, &backprim)){ case GL2PS_COINCIDENT: gl2psAddPrimitiveInList(prim, tree->primitives); break; case GL2PS_IN_BACK_OF: gl2psAddPrimitiveInList(prim, backlist); break; case GL2PS_IN_FRONT_OF: gl2psAddPrimitiveInList(prim, frontlist); break; case GL2PS_SPANNING: gl2psAddPrimitiveInList(backprim, backlist); gl2psAddPrimitiveInList(frontprim, frontlist); gl2psFreePrimitive(&prim); break; } } } if(gl2psListNbr(tree->primitives)){ gl2psListSort(tree->primitives, gl2psTrianglesFirst); } if(gl2psListNbr(frontlist)){ gl2psListSort(frontlist, gl2psTrianglesFirst); tree->front = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree)); gl2psBuildBspTree(tree->front, frontlist); } else{ gl2psListDelete(frontlist); } if(gl2psListNbr(backlist)){ gl2psListSort(backlist, gl2psTrianglesFirst); tree->back = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree)); gl2psBuildBspTree(tree->back, backlist); } else{ gl2psListDelete(backlist); } gl2psListDelete(primitives); } static void gl2psTraverseBspTree(GL2PSbsptree *tree, GL2PSxyz eye, GLfloat epsilon, GLboolean (*compare)(GLfloat f1, GLfloat f2), void (*action)(void *data), int inverse) { GLfloat result; if(!tree) return; result = gl2psComparePointPlane(eye, tree->plane); if(GL_TRUE == compare(result, epsilon)){ gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse); if(inverse){ gl2psListActionInverse(tree->primitives, action); } else{ gl2psListAction(tree->primitives, action); } gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse); } else if(GL_TRUE == compare(-epsilon, result)){ gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse); if(inverse){ gl2psListActionInverse(tree->primitives, action); } else{ gl2psListAction(tree->primitives, action); } gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse); } else{ gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse); gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse); } } static void gl2psRescaleAndOffset(void) { GL2PSprimitive *prim; GLfloat minZ, maxZ, rangeZ, scaleZ; GLfloat factor, units, area, dZ, dZdX, dZdY, maxdZ; int i, j; if(!gl2psListNbr(gl2ps->primitives)) return; /* get z-buffer range */ prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, 0); minZ = maxZ = prim->verts[0].xyz[2]; for(i = 1; i < prim->numverts; i++){ if(prim->verts[i].xyz[2] < minZ) minZ = prim->verts[i].xyz[2]; if(prim->verts[i].xyz[2] > maxZ) maxZ = prim->verts[i].xyz[2]; } for(i = 1; i < gl2psListNbr(gl2ps->primitives); i++){ prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, i); for(j = 0; j < prim->numverts; j++){ if(prim->verts[j].xyz[2] < minZ) minZ = prim->verts[j].xyz[2]; if(prim->verts[j].xyz[2] > maxZ) maxZ = prim->verts[j].xyz[2]; } } rangeZ = (maxZ - minZ); /* rescale z-buffer coordinate in [0,GL2PS_ZSCALE], to make it of the same order of magnitude as the x and y coordinates */ scaleZ = GL2PS_ZERO(rangeZ) ? GL2PS_ZSCALE : (GL2PS_ZSCALE / rangeZ); /* avoid precision loss (we use floats!) */ if(scaleZ > 100000.F) scaleZ = 100000.F; /* apply offsets */ for(i = 0; i < gl2psListNbr(gl2ps->primitives); i++){ prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, i); for(j = 0; j < prim->numverts; j++){ prim->verts[j].xyz[2] = (prim->verts[j].xyz[2] - minZ) * scaleZ; } if((gl2ps->options & GL2PS_SIMPLE_LINE_OFFSET) && (prim->type == GL2PS_LINE)){ if(gl2ps->sort == GL2PS_SIMPLE_SORT){ prim->verts[0].xyz[2] -= GL2PS_ZOFFSET_LARGE; prim->verts[1].xyz[2] -= GL2PS_ZOFFSET_LARGE; } else{ prim->verts[0].xyz[2] -= GL2PS_ZOFFSET; prim->verts[1].xyz[2] -= GL2PS_ZOFFSET; } } else if(prim->offset && (prim->type == GL2PS_TRIANGLE)){ factor = prim->ofactor; units = prim->ounits; area = (prim->verts[1].xyz[0] - prim->verts[0].xyz[0]) * (prim->verts[2].xyz[1] - prim->verts[1].xyz[1]) - (prim->verts[2].xyz[0] - prim->verts[1].xyz[0]) * (prim->verts[1].xyz[1] - prim->verts[0].xyz[1]); if(!GL2PS_ZERO(area)){ dZdX = ((prim->verts[2].xyz[1] - prim->verts[1].xyz[1]) * (prim->verts[1].xyz[2] - prim->verts[0].xyz[2]) - (prim->verts[1].xyz[1] - prim->verts[0].xyz[1]) * (prim->verts[2].xyz[2] - prim->verts[1].xyz[2])) / area; dZdY = ((prim->verts[1].xyz[0] - prim->verts[0].xyz[0]) * (prim->verts[2].xyz[2] - prim->verts[1].xyz[2]) - (prim->verts[2].xyz[0] - prim->verts[1].xyz[0]) * (prim->verts[1].xyz[2] - prim->verts[0].xyz[2])) / area; maxdZ = (GLfloat)sqrt(dZdX * dZdX + dZdY * dZdY); } else{ maxdZ = 0.0F; } dZ = factor * maxdZ + units; prim->verts[0].xyz[2] += dZ; prim->verts[1].xyz[2] += dZ; prim->verts[2].xyz[2] += dZ; } } } /********************************************************************* * * 2D sorting routines (for occlusion culling) * *********************************************************************/ static GLint gl2psGetPlaneFromPoints(GL2PSxyz a, GL2PSxyz b, GL2PSplane plane) { GLfloat n; plane[0] = b[1] - a[1]; plane[1] = a[0] - b[0]; n = (GLfloat)sqrt(plane[0]*plane[0] + plane[1]*plane[1]); plane[2] = 0.0F; if(!GL2PS_ZERO(n)){ plane[0] /= n; plane[1] /= n; plane[3] = -plane[0]*a[0]-plane[1]*a[1]; return 1; } else{ plane[0] = -1.0F; plane[1] = 0.0F; plane[3] = a[0]; return 0; } } static void gl2psFreeBspImageTree(GL2PSbsptree2d **tree) { if(*tree){ if((*tree)->back) gl2psFreeBspImageTree(&(*tree)->back); if((*tree)->front) gl2psFreeBspImageTree(&(*tree)->front); gl2psFree(*tree); *tree = NULL; } } static GLint gl2psCheckPoint(GL2PSxyz point, GL2PSplane plane) { GLfloat pt_dis; pt_dis = gl2psComparePointPlane(point, plane); if(pt_dis > GL2PS_EPSILON) return GL2PS_POINT_INFRONT; else if(pt_dis < -GL2PS_EPSILON) return GL2PS_POINT_BACK; else return GL2PS_POINT_COINCIDENT; } static void gl2psAddPlanesInBspTreeImage(GL2PSprimitive *prim, GL2PSbsptree2d **tree) { GLint ret = 0; GLint i; GLint offset = 0; GL2PSbsptree2d *head = NULL, *cur = NULL; if((*tree == NULL) && (prim->numverts > 2)){ /* don't cull if transparent for(i = 0; i < prim->numverts - 1; i++) if(prim->verts[i].rgba[3] < 1.0F) return; */ head = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d)); for(i = 0; i < prim->numverts-1; i++){ if(!gl2psGetPlaneFromPoints(prim->verts[i].xyz, prim->verts[i+1].xyz, head->plane)){ if(prim->numverts-i > 3){ offset++; } else{ gl2psFree(head); return; } } else{ break; } } head->back = NULL; head->front = NULL; for(i = 2+offset; i < prim->numverts; i++){ ret = gl2psCheckPoint(prim->verts[i].xyz, head->plane); if(ret != GL2PS_POINT_COINCIDENT) break; } switch(ret){ case GL2PS_POINT_INFRONT : cur = head; for(i = 1+offset; i < prim->numverts-1; i++){ if(cur->front == NULL){ cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d)); } if(gl2psGetPlaneFromPoints(prim->verts[i].xyz, prim->verts[i+1].xyz, cur->front->plane)){ cur = cur->front; cur->front = NULL; cur->back = NULL; } } if(cur->front == NULL){ cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d)); } if(gl2psGetPlaneFromPoints(prim->verts[i].xyz, prim->verts[offset].xyz, cur->front->plane)){ cur->front->front = NULL; cur->front->back = NULL; } else{ gl2psFree(cur->front); cur->front = NULL; } break; case GL2PS_POINT_BACK : for(i = 0; i < 4; i++){ head->plane[i] = -head->plane[i]; } cur = head; for(i = 1+offset; i < prim->numverts-1; i++){ if(cur->front == NULL){ cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d)); } if(gl2psGetPlaneFromPoints(prim->verts[i+1].xyz, prim->verts[i].xyz, cur->front->plane)){ cur = cur->front; cur->front = NULL; cur->back = NULL; } } if(cur->front == NULL){ cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d)); } if(gl2psGetPlaneFromPoints(prim->verts[offset].xyz, prim->verts[i].xyz, cur->front->plane)){ cur->front->front = NULL; cur->front->back = NULL; } else{ gl2psFree(cur->front); cur->front = NULL; } break; default: gl2psFree(head); return; } (*tree) = head; } } static GLint gl2psCheckPrimitive(GL2PSprimitive *prim, GL2PSplane plane) { GLint i; GLint pos; pos = gl2psCheckPoint(prim->verts[0].xyz, plane); for(i = 1; i < prim->numverts; i++){ pos |= gl2psCheckPoint(prim->verts[i].xyz, plane); if(pos == (GL2PS_POINT_INFRONT | GL2PS_POINT_BACK)) return GL2PS_SPANNING; } if(pos & GL2PS_POINT_INFRONT) return GL2PS_IN_FRONT_OF; else if(pos & GL2PS_POINT_BACK) return GL2PS_IN_BACK_OF; else return GL2PS_COINCIDENT; } static GL2PSprimitive *gl2psCreateSplitPrimitive2D(GL2PSprimitive *parent, GLshort numverts, GL2PSvertex *vertx) { GLint i; GL2PSprimitive *child = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); if(parent->type == GL2PS_IMAGEMAP){ child->type = GL2PS_IMAGEMAP; child->data.image = parent->data.image; } else { switch(numverts){ case 1 : child->type = GL2PS_POINT; break; case 2 : child->type = GL2PS_LINE; break; case 3 : child->type = GL2PS_TRIANGLE; break; case 4 : child->type = GL2PS_QUADRANGLE; break; default: child->type = GL2PS_NO_TYPE; break; /* FIXME */ } } child->boundary = 0; /* FIXME: not done! */ child->culled = parent->culled; child->offset = parent->offset; child->ofactor = parent->ofactor; child->ounits = parent->ounits; child->pattern = parent->pattern; child->factor = parent->factor; child->width = parent->width; child->linecap = parent->linecap; child->linejoin = parent->linejoin; child->numverts = numverts; child->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex)); for(i = 0; i < numverts; i++){ child->verts[i] = vertx[i]; } return child; } static void gl2psSplitPrimitive2D(GL2PSprimitive *prim, GL2PSplane plane, GL2PSprimitive **front, GL2PSprimitive **back) { /* cur will hold the position of the current vertex prev will hold the position of the previous vertex prev0 will hold the position of the vertex number 0 v1 and v2 represent the current and previous vertices, respectively flag is set if the current vertex should be checked against the plane */ GLint cur = -1, prev = -1, i, v1 = 0, v2 = 0, flag = 1, prev0 = -1; /* list of vertices that will go in front and back primitive */ GL2PSvertex *front_list = NULL, *back_list = NULL; /* number of vertices in front and back list */ GLshort front_count = 0, back_count = 0; for(i = 0; i <= prim->numverts; i++){ v1 = i; if(v1 == prim->numverts){ if(prim->numverts < 3) break; v1 = 0; v2 = prim->numverts - 1; cur = prev0; } else if(flag){ cur = gl2psCheckPoint(prim->verts[v1].xyz, plane); if(i == 0){ prev0 = cur; } } if(((prev == -1) || (prev == cur) || (prev == 0) || (cur == 0)) && (i < prim->numverts)){ if(cur == GL2PS_POINT_INFRONT){ front_count++; front_list = (GL2PSvertex*)gl2psRealloc(front_list, sizeof(GL2PSvertex)*front_count); front_list[front_count-1] = prim->verts[v1]; } else if(cur == GL2PS_POINT_BACK){ back_count++; back_list = (GL2PSvertex*)gl2psRealloc(back_list, sizeof(GL2PSvertex)*back_count); back_list[back_count-1] = prim->verts[v1]; } else{ front_count++; front_list = (GL2PSvertex*)gl2psRealloc(front_list, sizeof(GL2PSvertex)*front_count); front_list[front_count-1] = prim->verts[v1]; back_count++; back_list = (GL2PSvertex*)gl2psRealloc(back_list, sizeof(GL2PSvertex)*back_count); back_list[back_count-1] = prim->verts[v1]; } flag = 1; } else if((prev != cur) && (cur != 0) && (prev != 0)){ if(v1 != 0){ v2 = v1-1; i--; } front_count++; front_list = (GL2PSvertex*)gl2psRealloc(front_list, sizeof(GL2PSvertex)*front_count); gl2psCutEdge(&prim->verts[v2], &prim->verts[v1], plane, &front_list[front_count-1]); back_count++; back_list = (GL2PSvertex*)gl2psRealloc(back_list, sizeof(GL2PSvertex)*back_count); back_list[back_count-1] = front_list[front_count-1]; flag = 0; } prev = cur; } *front = gl2psCreateSplitPrimitive2D(prim, front_count, front_list); *back = gl2psCreateSplitPrimitive2D(prim, back_count, back_list); gl2psFree(front_list); gl2psFree(back_list); } static GLint gl2psAddInBspImageTree(GL2PSprimitive *prim, GL2PSbsptree2d **tree) { GLint ret = 0; GL2PSprimitive *frontprim = NULL, *backprim = NULL; /* FIXME: until we consider the actual extent of text strings and pixmaps, never cull them. Otherwise the whole string/pixmap gets culled as soon as the reference point is hidden */ if(prim->type == GL2PS_PIXMAP || prim->type == GL2PS_TEXT || prim->type == GL2PS_SPECIAL){ return 1; } if(*tree == NULL){ if((prim->type != GL2PS_IMAGEMAP) && (GL_FALSE == gl2ps->zerosurfacearea)){ gl2psAddPlanesInBspTreeImage(gl2ps->primitivetoadd, tree); } return 1; } else{ switch(gl2psCheckPrimitive(prim, (*tree)->plane)){ case GL2PS_IN_BACK_OF: return gl2psAddInBspImageTree(prim, &(*tree)->back); case GL2PS_IN_FRONT_OF: if((*tree)->front != NULL) return gl2psAddInBspImageTree(prim, &(*tree)->front); else return 0; case GL2PS_SPANNING: gl2psSplitPrimitive2D(prim, (*tree)->plane, &frontprim, &backprim); ret = gl2psAddInBspImageTree(backprim, &(*tree)->back); if((*tree)->front != NULL){ if(gl2psAddInBspImageTree(frontprim, &(*tree)->front)){ ret = 1; } } gl2psFree(frontprim->verts); gl2psFree(frontprim); gl2psFree(backprim->verts); gl2psFree(backprim); return ret; case GL2PS_COINCIDENT: if((*tree)->back != NULL){ gl2ps->zerosurfacearea = GL_TRUE; ret = gl2psAddInBspImageTree(prim, &(*tree)->back); gl2ps->zerosurfacearea = GL_FALSE; if(ret) return ret; } if((*tree)->front != NULL){ gl2ps->zerosurfacearea = GL_TRUE; ret = gl2psAddInBspImageTree(prim, &(*tree)->front); gl2ps->zerosurfacearea = GL_FALSE; if(ret) return ret; } if(prim->type == GL2PS_LINE) return 1; else return 0; } } return 0; } static void gl2psAddInImageTree(void *data) { GL2PSprimitive *prim = *(GL2PSprimitive **)data; gl2ps->primitivetoadd = prim; if(prim->type == GL2PS_IMAGEMAP && prim->data.image->format == GL2PS_IMAGEMAP_VISIBLE){ prim->culled = 1; } else if(!gl2psAddInBspImageTree(prim, &gl2ps->imagetree)){ prim->culled = 1; } else if(prim->type == GL2PS_IMAGEMAP){ prim->data.image->format = GL2PS_IMAGEMAP_VISIBLE; } } /* Boundary construction */ static void gl2psAddBoundaryInList(GL2PSprimitive *prim, GL2PSlist *list) { GL2PSprimitive *b; GLshort i; GL2PSxyz c; c[0] = c[1] = c[2] = 0.0F; for(i = 0; i < prim->numverts; i++){ c[0] += prim->verts[i].xyz[0]; c[1] += prim->verts[i].xyz[1]; } c[0] /= prim->numverts; c[1] /= prim->numverts; for(i = 0; i < prim->numverts; i++){ if(prim->boundary & (GLint)pow(2., i)){ b = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); b->type = GL2PS_LINE; b->offset = prim->offset; b->ofactor = prim->ofactor; b->ounits = prim->ounits; b->pattern = prim->pattern; b->factor = prim->factor; b->culled = prim->culled; b->width = prim->width; b->linecap = prim->linecap; b->linejoin = prim->linejoin; b->boundary = 0; b->numverts = 2; b->verts = (GL2PSvertex*)gl2psMalloc(2 * sizeof(GL2PSvertex)); #if 0 /* FIXME: need to work on boundary offset... */ v[0] = c[0] - prim->verts[i].xyz[0]; v[1] = c[1] - prim->verts[i].xyz[1]; v[2] = 0.0F; norm = gl2psNorm(v); v[0] /= norm; v[1] /= norm; b->verts[0].xyz[0] = prim->verts[i].xyz[0] +0.1*v[0]; b->verts[0].xyz[1] = prim->verts[i].xyz[1] +0.1*v[1]; b->verts[0].xyz[2] = prim->verts[i].xyz[2]; v[0] = c[0] - prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0]; v[1] = c[1] - prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1]; norm = gl2psNorm(v); v[0] /= norm; v[1] /= norm; b->verts[1].xyz[0] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0] +0.1*v[0]; b->verts[1].xyz[1] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1] +0.1*v[1]; b->verts[1].xyz[2] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[2]; #else b->verts[0].xyz[0] = prim->verts[i].xyz[0]; b->verts[0].xyz[1] = prim->verts[i].xyz[1]; b->verts[0].xyz[2] = prim->verts[i].xyz[2]; b->verts[1].xyz[0] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0]; b->verts[1].xyz[1] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1]; b->verts[1].xyz[2] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[2]; #endif b->verts[0].rgba[0] = 0.0F; b->verts[0].rgba[1] = 0.0F; b->verts[0].rgba[2] = 0.0F; b->verts[0].rgba[3] = 0.0F; b->verts[1].rgba[0] = 0.0F; b->verts[1].rgba[1] = 0.0F; b->verts[1].rgba[2] = 0.0F; b->verts[1].rgba[3] = 0.0F; gl2psListAdd(list, &b); } } } static void gl2psBuildPolygonBoundary(GL2PSbsptree *tree) { GLint i; GL2PSprimitive *prim; if(!tree) return; gl2psBuildPolygonBoundary(tree->back); for(i = 0; i < gl2psListNbr(tree->primitives); i++){ prim = *(GL2PSprimitive**)gl2psListPointer(tree->primitives, i); if(prim->boundary) gl2psAddBoundaryInList(prim, tree->primitives); } gl2psBuildPolygonBoundary(tree->front); } /********************************************************************* * * Feedback buffer parser * *********************************************************************/ GL2PSDLL_API void gl2psAddPolyPrimitive(GLshort type, GLshort numverts, GL2PSvertex *verts, GLint offset, GLfloat ofactor, GLfloat ounits, GLushort pattern, GLint factor, GLfloat width, GLint linecap, GLint linejoin,char boundary) { GL2PSprimitive *prim; prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); prim->type = type; prim->numverts = numverts; prim->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex)); memcpy(prim->verts, verts, numverts * sizeof(GL2PSvertex)); prim->boundary = boundary; prim->offset = (char)offset; prim->ofactor = ofactor; prim->ounits = ounits; prim->pattern = pattern; prim->factor = factor; prim->width = width; prim->linecap = linecap; prim->linejoin = linejoin; prim->culled = 0; /* FIXME: here we should have an option to split stretched tris/quads to enhance SIMPLE_SORT */ gl2psListAdd(gl2ps->primitives, &prim); } static GLint gl2psGetVertex(GL2PSvertex *v, GLfloat *p) { GLint i; v->xyz[0] = p[0]; v->xyz[1] = p[1]; v->xyz[2] = p[2]; if(gl2ps->colormode == GL_COLOR_INDEX && gl2ps->colorsize > 0){ i = (GLint)(p[3] + 0.5); v->rgba[0] = gl2ps->colormap[i][0]; v->rgba[1] = gl2ps->colormap[i][1]; v->rgba[2] = gl2ps->colormap[i][2]; v->rgba[3] = gl2ps->colormap[i][3]; return 4; } else{ v->rgba[0] = p[3]; v->rgba[1] = p[4]; v->rgba[2] = p[5]; v->rgba[3] = p[6]; return 7; } } static void gl2psParseFeedbackBuffer(GLint used) { char flag; GLushort pattern = 0; GLboolean boundary; GLint i, sizeoffloat, count, v, vtot, offset = 0, factor = 0, auxindex = 0; GLint lcap = 0, ljoin = 0; GLfloat lwidth = 1.0F, psize = 1.0F, ofactor = 0.0F, ounits = 0.0F; GLfloat *current; GL2PSvertex vertices[3]; GL2PSprimitive *prim; GL2PSimagemap *node; current = gl2ps->feedback; boundary = gl2ps->boundary = GL_FALSE; while(used > 0){ if(GL_TRUE == boundary) gl2ps->boundary = GL_TRUE; switch((GLint)*current){ case GL_POINT_TOKEN : current ++; used --; i = gl2psGetVertex(&vertices[0], current); current += i; used -= i; gl2psAddPolyPrimitive(GL2PS_POINT, 1, vertices, 0, 0.0, 0.0, pattern, factor, psize, lcap, ljoin, 0); break; case GL_LINE_TOKEN : case GL_LINE_RESET_TOKEN : current ++; used --; i = gl2psGetVertex(&vertices[0], current); current += i; used -= i; i = gl2psGetVertex(&vertices[1], current); current += i; used -= i; gl2psAddPolyPrimitive(GL2PS_LINE, 2, vertices, 0, 0.0, 0.0, pattern, factor, lwidth, lcap, ljoin, 0); break; case GL_POLYGON_TOKEN : count = (GLint)current[1]; current += 2; used -= 2; v = vtot = 0; while(count > 0 && used > 0){ i = gl2psGetVertex(&vertices[v], current); gl2psAdaptVertexForBlending(&vertices[v]); current += i; used -= i; count --; vtot++; if(v == 2){ if(GL_TRUE == boundary){ if(!count && vtot == 2) flag = 1|2|4; else if(!count) flag = 2|4; else if(vtot == 2) flag = 1|2; else flag = 2; } else flag = 0; gl2psAddPolyPrimitive(GL2PS_TRIANGLE, 3, vertices, offset, ofactor, ounits, pattern, factor, 1, lcap, ljoin, flag); vertices[1] = vertices[2]; } else v ++; } break; case GL_BITMAP_TOKEN : case GL_DRAW_PIXEL_TOKEN : case GL_COPY_PIXEL_TOKEN : current ++; used --; i = gl2psGetVertex(&vertices[0], current); current += i; used -= i; break; case GL_PASS_THROUGH_TOKEN : switch((GLint)current[1]){ case GL2PS_BEGIN_OFFSET_TOKEN : offset = 1; current += 2; used -= 2; ofactor = current[1]; current += 2; used -= 2; ounits = current[1]; break; case GL2PS_END_OFFSET_TOKEN : offset = 0; ofactor = 0.0; ounits = 0.0; break; case GL2PS_BEGIN_BOUNDARY_TOKEN : boundary = GL_TRUE; break; case GL2PS_END_BOUNDARY_TOKEN : boundary = GL_FALSE; break; case GL2PS_END_STIPPLE_TOKEN : pattern = 0; factor = 0; break; case GL2PS_BEGIN_BLEND_TOKEN : gl2ps->blending = GL_TRUE; break; case GL2PS_END_BLEND_TOKEN : gl2ps->blending = GL_FALSE; break; case GL2PS_BEGIN_STIPPLE_TOKEN : current += 2; used -= 2; pattern = (GLushort)current[1]; current += 2; used -= 2; factor = (GLint)current[1]; break; case GL2PS_SRC_BLEND_TOKEN : current += 2; used -= 2; gl2ps->blendfunc[0] = (GLint)current[1]; break; case GL2PS_DST_BLEND_TOKEN : current += 2; used -= 2; gl2ps->blendfunc[1] = (GLint)current[1]; break; case GL2PS_POINT_SIZE_TOKEN : current += 2; used -= 2; psize = current[1]; break; case GL2PS_LINE_CAP_TOKEN : current += 2; used -= 2; lcap = (GLint)current[1]; break; case GL2PS_LINE_JOIN_TOKEN : current += 2; used -= 2; ljoin = (GLint)current[1]; break; case GL2PS_LINE_WIDTH_TOKEN : current += 2; used -= 2; lwidth = current[1]; break; case GL2PS_IMAGEMAP_TOKEN : prim = (GL2PSprimitive *)gl2psMalloc(sizeof(GL2PSprimitive)); prim->type = GL2PS_IMAGEMAP; prim->boundary = 0; prim->numverts = 4; prim->verts = (GL2PSvertex *)gl2psMalloc(4 * sizeof(GL2PSvertex)); prim->culled = 0; prim->offset = 0; prim->ofactor = 0.0; prim->ounits = 0.0; prim->pattern = 0; prim->factor = 0; prim->width = 1; node = (GL2PSimagemap*)gl2psMalloc(sizeof(GL2PSimagemap)); node->image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage)); node->image->type = 0; node->image->format = 0; node->image->zoom_x = 1.0F; node->image->zoom_y = 1.0F; node->next = NULL; if(gl2ps->imagemap_head == NULL) gl2ps->imagemap_head = node; else gl2ps->imagemap_tail->next = node; gl2ps->imagemap_tail = node; prim->data.image = node->image; current += 2; used -= 2; i = gl2psGetVertex(&prim->verts[0], ¤t[1]); current += i; used -= i; node->image->width = (GLint)current[2]; current += 2; used -= 2; node->image->height = (GLint)current[2]; prim->verts[0].xyz[0] = prim->verts[0].xyz[0] - (int)(node->image->width / 2) + 0.5F; prim->verts[0].xyz[1] = prim->verts[0].xyz[1] - (int)(node->image->height / 2) + 0.5F; for(i = 1; i < 4; i++){ for(v = 0; v < 3; v++){ prim->verts[i].xyz[v] = prim->verts[0].xyz[v]; prim->verts[i].rgba[v] = prim->verts[0].rgba[v]; } prim->verts[i].rgba[v] = prim->verts[0].rgba[v]; } prim->verts[1].xyz[0] = prim->verts[1].xyz[0] + node->image->width; prim->verts[2].xyz[0] = prim->verts[1].xyz[0]; prim->verts[2].xyz[1] = prim->verts[2].xyz[1] + node->image->height; prim->verts[3].xyz[1] = prim->verts[2].xyz[1]; sizeoffloat = sizeof(GLfloat); v = 2 * sizeoffloat; vtot = node->image->height + node->image->height * ((node->image->width - 1) / 8); node->image->pixels = (GLfloat*)gl2psMalloc(v + vtot); node->image->pixels[0] = prim->verts[0].xyz[0]; node->image->pixels[1] = prim->verts[0].xyz[1]; for(i = 0; i < vtot; i += sizeoffloat){ current += 2; used -= 2; if((vtot - i) >= 4) memcpy(&(((char*)(node->image->pixels))[i + v]), &(current[2]), sizeoffloat); else memcpy(&(((char*)(node->image->pixels))[i + v]), &(current[2]), vtot - i); } current++; used--; gl2psListAdd(gl2ps->primitives, &prim); break; case GL2PS_DRAW_PIXELS_TOKEN : case GL2PS_TEXT_TOKEN : if(auxindex < gl2psListNbr(gl2ps->auxprimitives)) gl2psListAdd(gl2ps->primitives, gl2psListPointer(gl2ps->auxprimitives, auxindex++)); else gl2psMsg(GL2PS_ERROR, "Wrong number of auxiliary tokens in buffer"); break; } current += 2; used -= 2; break; default : gl2psMsg(GL2PS_WARNING, "Unknown token in buffer"); current ++; used --; break; } } gl2psListReset(gl2ps->auxprimitives); } /********************************************************************* * * PostScript routines * *********************************************************************/ static void gl2psWriteByte(unsigned char byte) { unsigned char h = byte / 16; unsigned char l = byte % 16; gl2psPrintf("%x%x", h, l); } static void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GL2PSimage *im) { GLuint nbhex, nbyte, nrgb, nbits; GLuint row, col, ibyte, icase; GLfloat dr = 0., dg = 0., db = 0., fgrey; unsigned char red = 0, green = 0, blue = 0, b, grey; GLuint width = (GLuint)im->width; GLuint height = (GLuint)im->height; /* FIXME: should we define an option for these? Or just keep the 8-bit per component case? */ int greyscale = 0; /* set to 1 to output greyscale image */ int nbit = 8; /* number of bits per color compoment (2, 4 or 8) */ if((width <= 0) || (height <= 0)) return; gl2psPrintf("gsave\n"); gl2psPrintf("%.2f %.2f translate\n", x, y); gl2psPrintf("%.2f %.2f scale\n", width * im->zoom_x, height * im->zoom_y); if(greyscale){ /* greyscale */ gl2psPrintf("/picstr %d string def\n", width); gl2psPrintf("%d %d %d\n", width, height, 8); gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height); gl2psPrintf("{ currentfile picstr readhexstring pop }\n"); gl2psPrintf("image\n"); for(row = 0; row < height; row++){ for(col = 0; col < width; col++){ gl2psGetRGB(im, col, row, &dr, &dg, &db); fgrey = (0.30F * dr + 0.59F * dg + 0.11F * db); grey = (unsigned char)(255. * fgrey); gl2psWriteByte(grey); } gl2psPrintf("\n"); } nbhex = width * height * 2; gl2psPrintf("%%%% nbhex digit :%d\n", nbhex); } else if(nbit == 2){ /* color, 2 bits for r and g and b; rgbs following each other */ nrgb = width * 3; nbits = nrgb * nbit; nbyte = nbits / 8; if((nbyte * 8) != nbits) nbyte++; gl2psPrintf("/rgbstr %d string def\n", nbyte); gl2psPrintf("%d %d %d\n", width, height, nbit); gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height); gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n"); gl2psPrintf("false 3\n"); gl2psPrintf("colorimage\n"); for(row = 0; row < height; row++){ icase = 1; col = 0; b = 0; for(ibyte = 0; ibyte < nbyte; ibyte++){ if(icase == 1) { if(col < width) { gl2psGetRGB(im, col, row, &dr, &dg, &db); } else { dr = dg = db = 0; } col++; red = (unsigned char)(3. * dr); green = (unsigned char)(3. * dg); blue = (unsigned char)(3. * db); b = red; b = (unsigned char)(b<<2) + green; b = (unsigned char)(b<<2) + blue; if(col < width) { gl2psGetRGB(im, col, row, &dr, &dg, &db); } else { dr = dg = db = 0; } col++; red = (unsigned char)(3. * dr); green = (unsigned char)(3. * dg); blue = (unsigned char)(3. * db); b = (unsigned char)(b<<2) + red; gl2psWriteByte(b); b = 0; icase++; } else if(icase == 2) { b = green; b = (unsigned char)(b<<2) + blue; if(col < width) { gl2psGetRGB(im, col, row, &dr, &dg, &db); } else { dr = dg = db = 0; } col++; red = (unsigned char)(3. * dr); green = (unsigned char)(3. * dg); blue = (unsigned char)(3. * db); b = (unsigned char)(b<<2) + red; b = (unsigned char)(b<<2) + green; gl2psWriteByte(b); b = 0; icase++; } else if(icase == 3) { b = blue; if(col < width) { gl2psGetRGB(im, col, row, &dr, &dg, &db); } else { dr = dg = db = 0; } col++; red = (unsigned char)(3. * dr); green = (unsigned char)(3. * dg); blue = (unsigned char)(3. * db); b = (unsigned char)(b<<2) + red; b = (unsigned char)(b<<2) + green; b = (unsigned char)(b<<2) + blue; gl2psWriteByte(b); b = 0; icase = 1; } } gl2psPrintf("\n"); } } else if(nbit == 4){ /* color, 4 bits for r and g and b; rgbs following each other */ nrgb = width * 3; nbits = nrgb * nbit; nbyte = nbits / 8; if((nbyte * 8) != nbits) nbyte++; gl2psPrintf("/rgbstr %d string def\n", nbyte); gl2psPrintf("%d %d %d\n", width, height, nbit); gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height); gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n"); gl2psPrintf("false 3\n"); gl2psPrintf("colorimage\n"); for(row = 0; row < height; row++){ col = 0; icase = 1; for(ibyte = 0; ibyte < nbyte; ibyte++){ if(icase == 1) { if(col < width) { gl2psGetRGB(im, col, row, &dr, &dg, &db); } else { dr = dg = db = 0; } col++; red = (unsigned char)(15. * dr); green = (unsigned char)(15. * dg); gl2psPrintf("%x%x", red, green); icase++; } else if(icase == 2) { blue = (unsigned char)(15. * db); if(col < width) { gl2psGetRGB(im, col, row, &dr, &dg, &db); } else { dr = dg = db = 0; } col++; red = (unsigned char)(15. * dr); gl2psPrintf("%x%x", blue, red); icase++; } else if(icase == 3) { green = (unsigned char)(15. * dg); blue = (unsigned char)(15. * db); gl2psPrintf("%x%x", green, blue); icase = 1; } } gl2psPrintf("\n"); } } else{ /* 8 bit for r and g and b */ nbyte = width * 3; gl2psPrintf("/rgbstr %d string def\n", nbyte); gl2psPrintf("%d %d %d\n", width, height, 8); gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height); gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n"); gl2psPrintf("false 3\n"); gl2psPrintf("colorimage\n"); for(row = 0; row < height; row++){ for(col = 0; col < width; col++){ gl2psGetRGB(im, col, row, &dr, &dg, &db); red = (unsigned char)(255. * dr); gl2psWriteByte(red); green = (unsigned char)(255. * dg); gl2psWriteByte(green); blue = (unsigned char)(255. * db); gl2psWriteByte(blue); } gl2psPrintf("\n"); } } gl2psPrintf("grestore\n"); } static void gl2psPrintPostScriptImagemap(GLfloat x, GLfloat y, GLsizei width, GLsizei height, const unsigned char *imagemap){ int i, size; if((width <= 0) || (height <= 0)) return; size = height + height * (width - 1) / 8; gl2psPrintf("gsave\n"); gl2psPrintf("%.2f %.2f translate\n", x, y); gl2psPrintf("%d %d scale\n%d %d\ntrue\n", width, height,width, height); gl2psPrintf("[ %d 0 0 -%d 0 %d ] {<", width, height); for(i = 0; i < size; i++){ gl2psWriteByte(*imagemap); imagemap++; } gl2psPrintf(">} imagemask\ngrestore\n"); } static void gl2psPrintPostScriptHeader(void) { time_t now; /* Since compression is not part of the PostScript standard, compressed PostScript files are just gzipped PostScript files ("ps.gz" or "eps.gz") */ gl2psPrintGzipHeader(); time(&now); if(gl2ps->format == GL2PS_PS){ gl2psPrintf("%%!PS-Adobe-3.0\n"); } else{ gl2psPrintf("%%!PS-Adobe-3.0 EPSF-3.0\n"); } gl2psPrintf("%%%%Title: %s\n" "%%%%Creator: GL2PS %d.%d.%d%s, %s\n" "%%%%For: %s\n" "%%%%CreationDate: %s" "%%%%LanguageLevel: 3\n" "%%%%DocumentData: Clean7Bit\n" "%%%%Pages: 1\n", gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, gl2ps->producer, ctime(&now)); if(gl2ps->format == GL2PS_PS){ gl2psPrintf("%%%%Orientation: %s\n" "%%%%DocumentMedia: Default %d %d 0 () ()\n", (gl2ps->options & GL2PS_LANDSCAPE) ? "Landscape" : "Portrait", (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[3] : (int)gl2ps->viewport[2], (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] : (int)gl2ps->viewport[3]); } gl2psPrintf("%%%%BoundingBox: %d %d %d %d\n" "%%%%EndComments\n", (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[1] : (int)gl2ps->viewport[0], (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[0] : (int)gl2ps->viewport[1], (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[3] : (int)gl2ps->viewport[2], (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] : (int)gl2ps->viewport[3]); /* RGB color: r g b C (replace C by G in output to change from rgb to gray) Grayscale: r g b G Font choose: size fontname FC Text string: (string) x y size fontname S?? Rotated text string: (string) angle x y size fontname S??R Point primitive: x y size P Line width: width W Line start: x y LS Line joining last point: x y L Line end: x y LE Flat-shaded triangle: x3 y3 x2 y2 x1 y1 T Smooth-shaded triangle: x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 ST */ gl2psPrintf("%%%%BeginProlog\n" "/gl2psdict 64 dict def gl2psdict begin\n" "/tryPS3shading %s def %% set to false to force subdivision\n" "/rThreshold %g def %% red component subdivision threshold\n" "/gThreshold %g def %% green component subdivision threshold\n" "/bThreshold %g def %% blue component subdivision threshold\n", (gl2ps->options & GL2PS_NO_PS3_SHADING) ? "false" : "true", gl2ps->threshold[0], gl2ps->threshold[1], gl2ps->threshold[2]); gl2psPrintf("/BD { bind def } bind def\n" "/C { setrgbcolor } BD\n" "/G { 0.082 mul exch 0.6094 mul add exch 0.3086 mul add neg 1.0 add setgray } BD\n" "/W { setlinewidth } BD\n" "/LC { setlinecap } BD\n" "/LJ { setlinejoin } BD\n"); gl2psPrintf("/FC { findfont exch /SH exch def SH scalefont setfont } BD\n" "/SW { dup stringwidth pop } BD\n" "/S { FC moveto show } BD\n" "/SBC{ FC moveto SW -2 div 0 rmoveto show } BD\n" "/SBR{ FC moveto SW neg 0 rmoveto show } BD\n" "/SCL{ FC moveto 0 SH -2 div rmoveto show } BD\n" "/SCC{ FC moveto SW -2 div SH -2 div rmoveto show } BD\n" "/SCR{ FC moveto SW neg SH -2 div rmoveto show } BD\n" "/STL{ FC moveto 0 SH neg rmoveto show } BD\n" "/STC{ FC moveto SW -2 div SH neg rmoveto show } BD\n" "/STR{ FC moveto SW neg SH neg rmoveto show } BD\n"); /* rotated text routines: same nameanem with R appended */ gl2psPrintf("/FCT { FC translate 0 0 } BD\n" "/SR { gsave FCT moveto rotate show grestore } BD\n" "/SBCR{ gsave FCT moveto rotate SW -2 div 0 rmoveto show grestore } BD\n" "/SBRR{ gsave FCT moveto rotate SW neg 0 rmoveto show grestore } BD\n" "/SCLR{ gsave FCT moveto rotate 0 SH -2 div rmoveto show grestore} BD\n"); gl2psPrintf("/SCCR{ gsave FCT moveto rotate SW -2 div SH -2 div rmoveto show grestore} BD\n" "/SCRR{ gsave FCT moveto rotate SW neg SH -2 div rmoveto show grestore} BD\n" "/STLR{ gsave FCT moveto rotate 0 SH neg rmoveto show grestore } BD\n" "/STCR{ gsave FCT moveto rotate SW -2 div SH neg rmoveto show grestore } BD\n" "/STRR{ gsave FCT moveto rotate SW neg SH neg rmoveto show grestore } BD\n"); gl2psPrintf("/P { newpath 0.0 360.0 arc closepath fill } BD\n" "/LS { newpath moveto } BD\n" "/L { lineto } BD\n" "/LE { lineto stroke } BD\n" "/T { newpath moveto lineto lineto closepath fill } BD\n"); /* Smooth-shaded triangle with PostScript level 3 shfill operator: x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STshfill */ gl2psPrintf("/STshfill {\n" " /b1 exch def /g1 exch def /r1 exch def /y1 exch def /x1 exch def\n" " /b2 exch def /g2 exch def /r2 exch def /y2 exch def /x2 exch def\n" " /b3 exch def /g3 exch def /r3 exch def /y3 exch def /x3 exch def\n" " gsave << /ShadingType 4 /ColorSpace [/DeviceRGB]\n" " /DataSource [ 0 x1 y1 r1 g1 b1 0 x2 y2 r2 g2 b2 0 x3 y3 r3 g3 b3 ] >>\n" " shfill grestore } BD\n"); /* Flat-shaded triangle with middle color: x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 Tm */ gl2psPrintf(/* stack : x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 */ "/Tm { 3 -1 roll 8 -1 roll 13 -1 roll add add 3 div\n" /* r = (r1+r2+r3)/3 */ /* stack : x3 y3 g3 b3 x2 y2 g2 b2 x1 y1 g1 b1 r */ " 3 -1 roll 7 -1 roll 11 -1 roll add add 3 div\n" /* g = (g1+g2+g3)/3 */ /* stack : x3 y3 b3 x2 y2 b2 x1 y1 b1 r g b */ " 3 -1 roll 6 -1 roll 9 -1 roll add add 3 div" /* b = (b1+b2+b3)/3 */ /* stack : x3 y3 x2 y2 x1 y1 r g b */ " C T } BD\n"); /* Split triangle in four sub-triangles (at sides middle points) and call the STnoshfill procedure on each, interpolating the colors in RGB space: x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STsplit (in procedure comments key: (Vi) = xi yi ri gi bi) */ gl2psPrintf("/STsplit {\n" " 4 index 15 index add 0.5 mul\n" /* x13 = (x1+x3)/2 */ " 4 index 15 index add 0.5 mul\n" /* y13 = (y1+y3)/2 */ " 4 index 15 index add 0.5 mul\n" /* r13 = (r1+r3)/2 */ " 4 index 15 index add 0.5 mul\n" /* g13 = (g1+g3)/2 */ " 4 index 15 index add 0.5 mul\n" /* b13 = (b1+b3)/2 */ " 5 copy 5 copy 25 15 roll\n"); /* at his point, stack = (V3) (V13) (V13) (V13) (V2) (V1) */ gl2psPrintf(" 9 index 30 index add 0.5 mul\n" /* x23 = (x2+x3)/2 */ " 9 index 30 index add 0.5 mul\n" /* y23 = (y2+y3)/2 */ " 9 index 30 index add 0.5 mul\n" /* r23 = (r2+r3)/2 */ " 9 index 30 index add 0.5 mul\n" /* g23 = (g2+g3)/2 */ " 9 index 30 index add 0.5 mul\n" /* b23 = (b2+b3)/2 */ " 5 copy 5 copy 35 5 roll 25 5 roll 15 5 roll\n"); /* stack = (V3) (V13) (V23) (V13) (V23) (V13) (V23) (V2) (V1) */ gl2psPrintf(" 4 index 10 index add 0.5 mul\n" /* x12 = (x1+x2)/2 */ " 4 index 10 index add 0.5 mul\n" /* y12 = (y1+y2)/2 */ " 4 index 10 index add 0.5 mul\n" /* r12 = (r1+r2)/2 */ " 4 index 10 index add 0.5 mul\n" /* g12 = (g1+g2)/2 */ " 4 index 10 index add 0.5 mul\n" /* b12 = (b1+b2)/2 */ " 5 copy 5 copy 40 5 roll 25 5 roll 15 5 roll 25 5 roll\n"); /* stack = (V3) (V13) (V23) (V13) (V12) (V23) (V13) (V1) (V12) (V23) (V12) (V2) */ gl2psPrintf(" STnoshfill STnoshfill STnoshfill STnoshfill } BD\n"); /* Gouraud shaded triangle using recursive subdivision until the difference between corner colors does not exceed the thresholds: x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STnoshfill */ gl2psPrintf("/STnoshfill {\n" " 2 index 8 index sub abs rThreshold gt\n" /* |r1-r2|>rth */ " { STsplit }\n" " { 1 index 7 index sub abs gThreshold gt\n" /* |g1-g2|>gth */ " { STsplit }\n" " { dup 6 index sub abs bThreshold gt\n" /* |b1-b2|>bth */ " { STsplit }\n" " { 2 index 13 index sub abs rThreshold gt\n" /* |r1-r3|>rht */ " { STsplit }\n" " { 1 index 12 index sub abs gThreshold gt\n" /* |g1-g3|>gth */ " { STsplit }\n" " { dup 11 index sub abs bThreshold gt\n" /* |b1-b3|>bth */ " { STsplit }\n" " { 7 index 13 index sub abs rThreshold gt\n"); /* |r2-r3|>rht */ gl2psPrintf(" { STsplit }\n" " { 6 index 12 index sub abs gThreshold gt\n" /* |g2-g3|>gth */ " { STsplit }\n" " { 5 index 11 index sub abs bThreshold gt\n" /* |b2-b3|>bth */ " { STsplit }\n" " { Tm }\n" /* all colors sufficiently similar */ " ifelse }\n" " ifelse }\n" " ifelse }\n" " ifelse }\n" " ifelse }\n" " ifelse }\n" " ifelse }\n" " ifelse }\n" " ifelse } BD\n"); gl2psPrintf("tryPS3shading\n" "{ /shfill where\n" " { /ST { STshfill } BD }\n" " { /ST { STnoshfill } BD }\n" " ifelse }\n" "{ /ST { STnoshfill } BD }\n" "ifelse\n"); gl2psPrintf("end\n" "%%%%EndProlog\n" "%%%%BeginSetup\n" "/DeviceRGB setcolorspace\n" "gl2psdict begin\n" "%%%%EndSetup\n" "%%%%Page: 1 1\n" "%%%%BeginPageSetup\n"); if(gl2ps->options & GL2PS_LANDSCAPE){ gl2psPrintf("%d 0 translate 90 rotate\n", (int)gl2ps->viewport[3]); } gl2psPrintf("%%%%EndPageSetup\n" "mark\n" "gsave\n" "1.0 1.0 scale\n"); if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ gl2psPrintf("%g %g %g C\n" "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n" "closepath fill\n", gl2ps->bgcolor[0], gl2ps->bgcolor[1], gl2ps->bgcolor[2], (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[3], (int)gl2ps->viewport[0], (int)gl2ps->viewport[3]); } } static void gl2psPrintPostScriptColor(GL2PSrgba rgba) { if(!gl2psSameColor(gl2ps->lastrgba, rgba)){ gl2psSetLastColor(rgba); gl2psPrintf("%g %g %g C\n", rgba[0], rgba[1], rgba[2]); } } static void gl2psResetPostScriptColor(void) { gl2ps->lastrgba[0] = gl2ps->lastrgba[1] = gl2ps->lastrgba[2] = -1.; } static void gl2psEndPostScriptLine(void) { int i; if(gl2ps->lastvertex.rgba[0] >= 0.){ gl2psPrintf("%g %g LE\n", gl2ps->lastvertex.xyz[0], gl2ps->lastvertex.xyz[1]); for(i = 0; i < 3; i++) gl2ps->lastvertex.xyz[i] = -1.; for(i = 0; i < 4; i++) gl2ps->lastvertex.rgba[i] = -1.; } } static void gl2psParseStipplePattern(GLushort pattern, GLint factor, int *nb, int array[10]) { int i, n; int on[8] = {0, 0, 0, 0, 0, 0, 0, 0}; int off[8] = {0, 0, 0, 0, 0, 0, 0, 0}; char tmp[16]; /* extract the 16 bits from the OpenGL stipple pattern */ for(n = 15; n >= 0; n--){ tmp[n] = (char)(pattern & 0x01); pattern >>= 1; } /* compute the on/off pixel sequence */ n = 0; for(i = 0; i < 8; i++){ while(n < 16 && !tmp[n]){ off[i]++; n++; } while(n < 16 && tmp[n]){ on[i]++; n++; } if(n >= 15){ i++; break; } } /* store the on/off array from right to left, starting with off pixels. The PostScript specification allows for at most 11 elements in the on/off array, so we limit ourselves to 5 on/off couples (our longest possible array is thus [on4 off4 on3 off3 on2 off2 on1 off1 on0 off0]) */ *nb = 0; for(n = i - 1; n >= 0; n--){ array[(*nb)++] = factor * on[n]; array[(*nb)++] = factor * off[n]; if(*nb == 10) break; } } static int gl2psPrintPostScriptDash(GLushort pattern, GLint factor, const char *str) { int len = 0, i, n, array[10]; if(pattern == gl2ps->lastpattern && factor == gl2ps->lastfactor) return 0; gl2ps->lastpattern = pattern; gl2ps->lastfactor = factor; if(!pattern || !factor){ /* solid line */ len += gl2psPrintf("[] 0 %s\n", str); } else{ gl2psParseStipplePattern(pattern, factor, &n, array); len += gl2psPrintf("["); for(i = 0; i < n; i++){ if(i) len += gl2psPrintf(" "); len += gl2psPrintf("%d", array[i]); } len += gl2psPrintf("] 0 %s\n", str); } return len; } static void gl2psPrintPostScriptPrimitive(void *data) { int newline; GL2PSprimitive *prim; prim = *(GL2PSprimitive**)data; if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return; /* Every effort is made to draw lines as connected segments (i.e., using a single PostScript path): this is the only way to get nice line joins and to not restart the stippling for every line segment. So if the primitive to print is not a line we must first finish the current line (if any): */ if(prim->type != GL2PS_LINE) gl2psEndPostScriptLine(); switch(prim->type){ case GL2PS_POINT : gl2psPrintPostScriptColor(prim->verts[0].rgba); gl2psPrintf("%g %g %g P\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1], 0.5 * prim->width); break; case GL2PS_LINE : if(!gl2psSamePosition(gl2ps->lastvertex.xyz, prim->verts[0].xyz) || !gl2psSameColor(gl2ps->lastrgba, prim->verts[0].rgba) || gl2ps->lastlinewidth != prim->width || gl2ps->lastlinecap != prim->linecap || gl2ps->lastlinejoin != prim->linejoin || gl2ps->lastpattern != prim->pattern || gl2ps->lastfactor != prim->factor){ /* End the current line if the new segment does not start where the last one ended, or if the color, the width or the stippling have changed (multi-stroking lines with changing colors is necessary until we use /shfill for lines; unfortunately this means that at the moment we can screw up line stippling for smooth-shaded lines) */ gl2psEndPostScriptLine(); newline = 1; } else{ newline = 0; } if(gl2ps->lastlinewidth != prim->width){ gl2ps->lastlinewidth = prim->width; gl2psPrintf("%g W\n", gl2ps->lastlinewidth); } if(gl2ps->lastlinecap != prim->linecap){ gl2ps->lastlinecap = prim->linecap; gl2psPrintf("%d LC\n", gl2ps->lastlinecap); } if(gl2ps->lastlinejoin != prim->linejoin){ gl2ps->lastlinejoin = prim->linejoin; gl2psPrintf("%d LJ\n", gl2ps->lastlinejoin); } gl2psPrintPostScriptDash(prim->pattern, prim->factor, "setdash"); gl2psPrintPostScriptColor(prim->verts[0].rgba); gl2psPrintf("%g %g %s\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1], newline ? "LS" : "L"); gl2ps->lastvertex = prim->verts[1]; break; case GL2PS_TRIANGLE : if(!gl2psVertsSameColor(prim)){ gl2psResetPostScriptColor(); gl2psPrintf("%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g ST\n", prim->verts[2].xyz[0], prim->verts[2].xyz[1], prim->verts[2].rgba[0], prim->verts[2].rgba[1], prim->verts[2].rgba[2], prim->verts[1].xyz[0], prim->verts[1].xyz[1], prim->verts[1].rgba[0], prim->verts[1].rgba[1], prim->verts[1].rgba[2], prim->verts[0].xyz[0], prim->verts[0].xyz[1], prim->verts[0].rgba[0], prim->verts[0].rgba[1], prim->verts[0].rgba[2]); } else{ gl2psPrintPostScriptColor(prim->verts[0].rgba); gl2psPrintf("%g %g %g %g %g %g T\n", prim->verts[2].xyz[0], prim->verts[2].xyz[1], prim->verts[1].xyz[0], prim->verts[1].xyz[1], prim->verts[0].xyz[0], prim->verts[0].xyz[1]); } break; case GL2PS_QUADRANGLE : gl2psMsg(GL2PS_WARNING, "There should not be any quad left to print"); break; case GL2PS_PIXMAP : gl2psPrintPostScriptPixmap(prim->verts[0].xyz[0], prim->verts[0].xyz[1], prim->data.image); break; case GL2PS_IMAGEMAP : if(prim->data.image->type != GL2PS_IMAGEMAP_WRITTEN){ gl2psPrintPostScriptColor(prim->verts[0].rgba); gl2psPrintPostScriptImagemap(prim->data.image->pixels[0], prim->data.image->pixels[1], prim->data.image->width, prim->data.image->height, (const unsigned char*)(&(prim->data.image->pixels[2]))); prim->data.image->type = GL2PS_IMAGEMAP_WRITTEN; } break; case GL2PS_TEXT : gl2psPrintPostScriptColor(prim->verts[0].rgba); gl2psPrintf("(%s) ", prim->data.text->str); if(prim->data.text->angle != 0.0) gl2psPrintf("%g ", prim->data.text->angle); gl2psPrintf("%g %g %d /%s ", prim->verts[0].xyz[0], prim->verts[0].xyz[1], prim->data.text->fontsize, prim->data.text->fontname); switch(prim->data.text->alignment){ case GL2PS_TEXT_C: gl2psPrintf(prim->data.text->angle != 0.0 ? "SCCR\n" : "SCC\n"); break; case GL2PS_TEXT_CL: gl2psPrintf(prim->data.text->angle != 0.0 ? "SCLR\n" : "SCL\n"); break; case GL2PS_TEXT_CR: gl2psPrintf(prim->data.text->angle != 0.0 ? "SCRR\n" : "SCR\n"); break; case GL2PS_TEXT_B: gl2psPrintf(prim->data.text->angle != 0.0 ? "SBCR\n" : "SBC\n"); break; case GL2PS_TEXT_BR: gl2psPrintf(prim->data.text->angle != 0.0 ? "SBRR\n" : "SBR\n"); break; case GL2PS_TEXT_T: gl2psPrintf(prim->data.text->angle != 0.0 ? "STCR\n" : "STC\n"); break; case GL2PS_TEXT_TL: gl2psPrintf(prim->data.text->angle != 0.0 ? "STLR\n" : "STL\n"); break; case GL2PS_TEXT_TR: gl2psPrintf(prim->data.text->angle != 0.0 ? "STRR\n" : "STR\n"); break; case GL2PS_TEXT_BL: default: gl2psPrintf(prim->data.text->angle != 0.0 ? "SR\n" : "S\n"); break; } break; case GL2PS_SPECIAL : /* alignment contains the format for which the special output text is intended */ if(prim->data.text->alignment == GL2PS_PS || prim->data.text->alignment == GL2PS_EPS) gl2psPrintf("%s\n", prim->data.text->str); break; default : break; } } static void gl2psPrintPostScriptFooter(void) { gl2psPrintf("grestore\n" "showpage\n" "cleartomark\n" "%%%%PageTrailer\n" "%%%%Trailer\n" "end\n" "%%%%EOF\n"); gl2psPrintGzipFooter(); } static void gl2psPrintPostScriptBeginViewport(GLint viewport[4]) { GLint idx; GLfloat rgba[4]; int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; glRenderMode(GL_FEEDBACK); if(gl2ps->header){ gl2psPrintPostScriptHeader(); gl2ps->header = GL_FALSE; } gl2psResetPostScriptColor(); gl2psResetLineProperties(); gl2psPrintf("gsave\n" "1.0 1.0 scale\n"); if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){ glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba); } else{ glGetIntegerv(GL_INDEX_CLEAR_VALUE, &idx); rgba[0] = gl2ps->colormap[idx][0]; rgba[1] = gl2ps->colormap[idx][1]; rgba[2] = gl2ps->colormap[idx][2]; rgba[3] = 1.0F; } gl2psPrintf("%g %g %g C\n" "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n" "closepath fill\n", rgba[0], rgba[1], rgba[2], x, y, x+w, y, x+w, y+h, x, y+h); } gl2psPrintf("newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n" "closepath clip\n", x, y, x+w, y, x+w, y+h, x, y+h); } static GLint gl2psPrintPostScriptEndViewport(void) { GLint res; res = gl2psPrintPrimitives(); gl2psPrintf("grestore\n"); return res; } static void gl2psPrintPostScriptFinalPrimitive(void) { /* End any remaining line, if any */ gl2psEndPostScriptLine(); } /* definition of the PostScript and Encapsulated PostScript backends */ static GL2PSbackend gl2psPS = { gl2psPrintPostScriptHeader, gl2psPrintPostScriptFooter, gl2psPrintPostScriptBeginViewport, gl2psPrintPostScriptEndViewport, gl2psPrintPostScriptPrimitive, gl2psPrintPostScriptFinalPrimitive, "ps", "Postscript" }; static GL2PSbackend gl2psEPS = { gl2psPrintPostScriptHeader, gl2psPrintPostScriptFooter, gl2psPrintPostScriptBeginViewport, gl2psPrintPostScriptEndViewport, gl2psPrintPostScriptPrimitive, gl2psPrintPostScriptFinalPrimitive, "eps", "Encapsulated Postscript" }; /********************************************************************* * * LaTeX routines * *********************************************************************/ static void gl2psPrintTeXHeader(void) { char name[256]; time_t now; int i; GLfloat s; if(gl2ps->filename && strlen(gl2ps->filename) < 256){ for(i = (int)strlen(gl2ps->filename) - 1; i >= 0; i--){ if(gl2ps->filename[i] == '.'){ strncpy(name, gl2ps->filename, i); name[i] = '\0'; break; } } if(i <= 0) strcpy(name, gl2ps->filename); } else{ strcpy(name, "untitled"); } time(&now); fprintf(gl2ps->stream, "%% Title: %s\n" "%% Creator: GL2PS %d.%d.%d%s, %s\n" "%% For: %s\n" "%% CreationDate: %s", gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, gl2ps->producer, ctime(&now)); s = gl2ps->tex_scaling; if(s <= 0.) s = 1.; fprintf(gl2ps->stream, "\\setlength{\\unitlength}{%gpt}\n" "\\begin{picture}(0,0)\n" "\\includegraphics[scale=%g]{%s}\n" "\\end{picture}%%\n" "%s\\begin{picture}(%d,%d)(0,0)\n", s, s, name, (gl2ps->options & GL2PS_LANDSCAPE) ? "\\rotatebox{90}{" : "", (int)(gl2ps->viewport[2]), (int)(gl2ps->viewport[3])); } static void gl2psPrintTeXPrimitive(void *data) { GL2PSprimitive *prim; prim = *(GL2PSprimitive**)data; switch(prim->type){ case GL2PS_TEXT : if(!(gl2ps->options & GL2PS_NO_TEX_FONTSIZE)) fprintf(gl2ps->stream, "\\fontsize{%d}{0}\\selectfont", prim->data.text->fontsize); fprintf(gl2ps->stream, "\\put(%g,%g)", prim->verts[0].xyz[0], prim->verts[0].xyz[1]); if(prim->data.text->angle != 0.0) fprintf(gl2ps->stream, "{\\rotatebox{%g}", prim->data.text->angle); fprintf(gl2ps->stream, "{\\makebox(0,0)"); switch(prim->data.text->alignment){ case GL2PS_TEXT_C: fprintf(gl2ps->stream, "{"); break; case GL2PS_TEXT_CL: fprintf(gl2ps->stream, "[l]{"); break; case GL2PS_TEXT_CR: fprintf(gl2ps->stream, "[r]{"); break; case GL2PS_TEXT_B: fprintf(gl2ps->stream, "[b]{"); break; case GL2PS_TEXT_BR: fprintf(gl2ps->stream, "[br]{"); break; case GL2PS_TEXT_T: fprintf(gl2ps->stream, "[t]{"); break; case GL2PS_TEXT_TL: fprintf(gl2ps->stream, "[tl]{"); break; case GL2PS_TEXT_TR: fprintf(gl2ps->stream, "[tr]{"); break; case GL2PS_TEXT_BL: default: fprintf(gl2ps->stream, "[bl]{"); break; } fprintf(gl2ps->stream, "\\textcolor[rgb]{%g,%g,%g}{{%s}}", prim->verts[0].rgba[0], prim->verts[0].rgba[1], prim->verts[0].rgba[2], prim->data.text->str); if(prim->data.text->angle != 0.0) fprintf(gl2ps->stream, "}"); fprintf(gl2ps->stream, "}}\n"); break; case GL2PS_SPECIAL : /* alignment contains the format for which the special output text is intended */ if (prim->data.text->alignment == GL2PS_TEX) fprintf(gl2ps->stream, "%s\n", prim->data.text->str); break; default : break; } } static void gl2psPrintTeXFooter(void) { fprintf(gl2ps->stream, "\\end{picture}%s\n", (gl2ps->options & GL2PS_LANDSCAPE) ? "}" : ""); } static void gl2psPrintTeXBeginViewport(GLint viewport[4]) { (void) viewport; /* not used */ glRenderMode(GL_FEEDBACK); gl2psResetLineProperties(); if(gl2ps->header){ gl2psPrintTeXHeader(); gl2ps->header = GL_FALSE; } } static GLint gl2psPrintTeXEndViewport(void) { return gl2psPrintPrimitives(); } static void gl2psPrintTeXFinalPrimitive(void) { } /* definition of the LaTeX backend */ static GL2PSbackend gl2psTEX = { gl2psPrintTeXHeader, gl2psPrintTeXFooter, gl2psPrintTeXBeginViewport, gl2psPrintTeXEndViewport, gl2psPrintTeXPrimitive, gl2psPrintTeXFinalPrimitive, "tex", "LaTeX text" }; /********************************************************************* * * PDF routines * *********************************************************************/ static int gl2psPrintPDFCompressorType(void) { #if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ return fprintf(gl2ps->stream, "/Filter [/FlateDecode]\n"); } #endif return 0; } static int gl2psPrintPDFStrokeColor(GL2PSrgba rgba) { int i, offs = 0; gl2psSetLastColor(rgba); for(i = 0; i < 3; ++i){ if(GL2PS_ZERO(rgba[i])) offs += gl2psPrintf("%.0f ", 0.); else if(rgba[i] < 1e-4 || rgba[i] > 1e6) /* avoid %e formatting */ offs += gl2psPrintf("%f ", rgba[i]); else offs += gl2psPrintf("%g ", rgba[i]); } offs += gl2psPrintf("RG\n"); return offs; } static int gl2psPrintPDFFillColor(GL2PSrgba rgba) { int i, offs = 0; for(i = 0; i < 3; ++i){ if(GL2PS_ZERO(rgba[i])) offs += gl2psPrintf("%.0f ", 0.); else if(rgba[i] < 1e-4 || rgba[i] > 1e6) /* avoid %e formatting */ offs += gl2psPrintf("%f ", rgba[i]); else offs += gl2psPrintf("%g ", rgba[i]); } offs += gl2psPrintf("rg\n"); return offs; } static int gl2psPrintPDFLineWidth(GLfloat lw) { if(GL2PS_ZERO(lw)) return gl2psPrintf("%.0f w\n", 0.); else if(lw < 1e-4 || lw > 1e6) /* avoid %e formatting */ return gl2psPrintf("%f w\n", lw); else return gl2psPrintf("%g w\n", lw); } static int gl2psPrintPDFLineCap(GLint lc) { if(gl2ps->lastlinecap == lc) return 0; else return gl2psPrintf("%d J\n", lc); } static int gl2psPrintPDFLineJoin(GLint lj) { if(gl2ps->lastlinejoin == lj) return 0; else return gl2psPrintf("%d j\n", lj); } static void gl2psPutPDFText(GL2PSstring *text, int cnt, GLfloat x, GLfloat y) { GLfloat rad, crad, srad; if(text->angle == 0.0F){ gl2ps->streamlength += gl2psPrintf ("BT\n" "/F%d %d Tf\n" "%f %f Td\n" "(%s) Tj\n" "ET\n", cnt, text->fontsize, x, y, text->str); } else{ rad = (GLfloat)(3.141593F * text->angle / 180.0F); srad = (GLfloat)sin(rad); crad = (GLfloat)cos(rad); gl2ps->streamlength += gl2psPrintf ("BT\n" "/F%d %d Tf\n" "%f %f %f %f %f %f Tm\n" "(%s) Tj\n" "ET\n", cnt, text->fontsize, crad, srad, -srad, crad, x, y, text->str); } } /* This is used for producing aligned text in PDF. (x, y) is the anchor for the aligned text, (xbl, ybl) is the bottom left corner. Rotation happens around (x, y).*/ static void gl2psPutPDFTextBL(GL2PSstring *text, int cnt, GLfloat x, GLfloat y, GLfloat xbl, GLfloat ybl) { if(text->angle == 0.0F){ gl2ps->streamlength += gl2psPrintf ("BT\n" "/F%d %d Tf\n" "%f %f Td\n" "(%s) Tj\n" "ET\n", cnt, text->fontsize, xbl, ybl, text->str); } else{ GLfloat a, ca, sa; GLfloat pi = 3.141593F; GLfloat i = atan2f(y - ybl, x - xbl); GLfloat r = sqrtf((y - ybl) * (y - ybl) + (x - xbl) * (x - xbl)); a = (GLfloat)(pi * text->angle / 180.0F); sa = (GLfloat)sin(a); ca = (GLfloat)cos(a); gl2ps->streamlength += gl2psPrintf ("BT\n" "/F%d %d Tf\n" "%f %f %f %f %f %f Tm\n" "(%s) Tj\n" "ET\n", cnt, text->fontsize, ca, sa, -sa, ca, xbl + r * (cos(i) - cos(i + a)), ybl + r * (sin(i) - sin(i+a)), text->str); } } static void gl2psPutPDFSpecial(int prim, int sec, GL2PSstring *text) { gl2ps->streamlength += gl2psPrintf("/GS%d%d gs\n", prim, sec); gl2ps->streamlength += gl2psPrintf("%s\n", text->str); } static void gl2psPutPDFImage(GL2PSimage *image, int cnt, GLfloat x, GLfloat y) { gl2ps->streamlength += gl2psPrintf ("q\n" "%d 0 0 %d %f %f cm\n" "/Im%d Do\n" "Q\n", (int)(image->zoom_x * image->width), (int)(image->zoom_y * image->height), x, y, cnt); } static void gl2psPDFstacksInit(void) { gl2ps->objects_stack = 7 /* FIXED_XREF_ENTRIES */ + 1; gl2ps->extgs_stack = 0; gl2ps->font_stack = 0; gl2ps->im_stack = 0; gl2ps->trgroupobjects_stack = 0; gl2ps->shader_stack = 0; gl2ps->mshader_stack = 0; } static void gl2psPDFgroupObjectInit(GL2PSpdfgroup *gro) { if(!gro) return; gro->ptrlist = NULL; gro->fontno = gro->gsno = gro->imno = gro->maskshno = gro->shno = gro->trgroupno = gro->fontobjno = gro->imobjno = gro->shobjno = gro->maskshobjno = gro->gsobjno = gro->trgroupobjno = -1; } /* Build up group objects and assign name and object numbers */ static void gl2psPDFgroupListInit(void) { int i; GL2PSprimitive *p = NULL; GL2PSpdfgroup gro; int lasttype = GL2PS_NO_TYPE; GL2PSrgba lastrgba = {-1.0F, -1.0F, -1.0F, -1.0F}; GLushort lastpattern = 0; GLint lastfactor = 0; GLfloat lastwidth = 1; GLint lastlinecap = 0; GLint lastlinejoin = 0; GL2PStriangle lastt, tmpt; int lastTriangleWasNotSimpleWithSameColor = 0; if(!gl2ps->pdfprimlist) return; gl2ps->pdfgrouplist = gl2psListCreate(500, 500, sizeof(GL2PSpdfgroup)); gl2psInitTriangle(&lastt); for(i = 0; i < gl2psListNbr(gl2ps->pdfprimlist); ++i){ p = *(GL2PSprimitive**)gl2psListPointer(gl2ps->pdfprimlist, i); switch(p->type){ case GL2PS_PIXMAP: gl2psPDFgroupObjectInit(&gro); gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); gro.imno = gl2ps->im_stack++; gl2psListAdd(gro.ptrlist, &p); gl2psListAdd(gl2ps->pdfgrouplist, &gro); break; case GL2PS_TEXT: gl2psPDFgroupObjectInit(&gro); gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); gro.fontno = gl2ps->font_stack++; gl2psListAdd(gro.ptrlist, &p); gl2psListAdd(gl2ps->pdfgrouplist, &gro); break; case GL2PS_LINE: if(lasttype != p->type || lastwidth != p->width || lastlinecap != p->linecap || lastlinejoin != p->linejoin || lastpattern != p->pattern || lastfactor != p->factor || !gl2psSameColor(p->verts[0].rgba, lastrgba)){ gl2psPDFgroupObjectInit(&gro); gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); gl2psListAdd(gro.ptrlist, &p); gl2psListAdd(gl2ps->pdfgrouplist, &gro); } else{ gl2psListAdd(gro.ptrlist, &p); } lastpattern = p->pattern; lastfactor = p->factor; lastwidth = p->width; lastlinecap = p->linecap; lastlinejoin = p->linejoin; lastrgba[0] = p->verts[0].rgba[0]; lastrgba[1] = p->verts[0].rgba[1]; lastrgba[2] = p->verts[0].rgba[2]; break; case GL2PS_POINT: if(lasttype != p->type || lastwidth != p->width || !gl2psSameColor(p->verts[0].rgba, lastrgba)){ gl2psPDFgroupObjectInit(&gro); gro.ptrlist = gl2psListCreate(1,2,sizeof(GL2PSprimitive*)); gl2psListAdd(gro.ptrlist, &p); gl2psListAdd(gl2ps->pdfgrouplist, &gro); } else{ gl2psListAdd(gro.ptrlist, &p); } lastwidth = p->width; lastrgba[0] = p->verts[0].rgba[0]; lastrgba[1] = p->verts[0].rgba[1]; lastrgba[2] = p->verts[0].rgba[2]; break; case GL2PS_TRIANGLE: gl2psFillTriangleFromPrimitive(&tmpt, p, GL_TRUE); lastTriangleWasNotSimpleWithSameColor = !(tmpt.prop & T_CONST_COLOR && tmpt.prop & T_ALPHA_1) || !gl2psSameColor(tmpt.vertex[0].rgba, lastt.vertex[0].rgba); if(lasttype == p->type && tmpt.prop == lastt.prop && lastTriangleWasNotSimpleWithSameColor){ /* TODO Check here for last alpha */ gl2psListAdd(gro.ptrlist, &p); } else{ gl2psPDFgroupObjectInit(&gro); gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); gl2psListAdd(gro.ptrlist, &p); gl2psListAdd(gl2ps->pdfgrouplist, &gro); } lastt = tmpt; break; case GL2PS_SPECIAL: gl2psPDFgroupObjectInit(&gro); gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); gl2psListAdd(gro.ptrlist, &p); gl2psListAdd(gl2ps->pdfgrouplist, &gro); break; default: break; } lasttype = p->type; } } static void gl2psSortOutTrianglePDFgroup(GL2PSpdfgroup *gro) { GL2PStriangle t; GL2PSprimitive *prim = NULL; if(!gro) return; if(!gl2psListNbr(gro->ptrlist)) return; prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0); if(prim->type != GL2PS_TRIANGLE) return; gl2psFillTriangleFromPrimitive(&t, prim, GL_TRUE); if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){ gro->gsno = gl2ps->extgs_stack++; gro->gsobjno = gl2ps->objects_stack ++; } else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){ gro->gsno = gl2ps->extgs_stack++; gro->gsobjno = gl2ps->objects_stack++; gro->trgroupno = gl2ps->trgroupobjects_stack++; gro->trgroupobjno = gl2ps->objects_stack++; gro->maskshno = gl2ps->mshader_stack++; gro->maskshobjno = gl2ps->objects_stack++; } else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){ gro->shno = gl2ps->shader_stack++; gro->shobjno = gl2ps->objects_stack++; } else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){ gro->gsno = gl2ps->extgs_stack++; gro->gsobjno = gl2ps->objects_stack++; gro->shno = gl2ps->shader_stack++; gro->shobjno = gl2ps->objects_stack++; } else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){ gro->gsno = gl2ps->extgs_stack++; gro->gsobjno = gl2ps->objects_stack++; gro->shno = gl2ps->shader_stack++; gro->shobjno = gl2ps->objects_stack++; gro->trgroupno = gl2ps->trgroupobjects_stack++; gro->trgroupobjno = gl2ps->objects_stack++; gro->maskshno = gl2ps->mshader_stack++; gro->maskshobjno = gl2ps->objects_stack++; } } /* Main stream data */ static void gl2psPDFgroupListWriteMainStream(void) { int i, j, lastel, count; GL2PSprimitive *prim = NULL, *prev = NULL; GL2PSpdfgroup *gro; GL2PStriangle t; if(!gl2ps->pdfgrouplist) return; count = gl2psListNbr(gl2ps->pdfgrouplist); for(i = 0; i < count; ++i){ gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); lastel = gl2psListNbr(gro->ptrlist) - 1; if(lastel < 0) continue; prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0); switch(prim->type){ case GL2PS_POINT: gl2ps->streamlength += gl2psPrintf("1 J\n"); gl2ps->streamlength += gl2psPrintPDFLineWidth(prim->width); gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba); for(j = 0; j <= lastel; ++j){ prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); gl2ps->streamlength += gl2psPrintf("%f %f m %f %f l\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1], prim->verts[0].xyz[0], prim->verts[0].xyz[1]); } gl2ps->streamlength += gl2psPrintf("S\n"); gl2ps->streamlength += gl2psPrintf("0 J\n"); break; case GL2PS_LINE: /* We try to use as few paths as possible to draw lines, in order to get nice stippling even when the individual segments are smaller than the stipple */ gl2ps->streamlength += gl2psPrintPDFLineWidth(prim->width); gl2ps->streamlength += gl2psPrintPDFLineCap(prim->linecap); gl2ps->streamlength += gl2psPrintPDFLineJoin(prim->linejoin); gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba); gl2ps->streamlength += gl2psPrintPostScriptDash(prim->pattern, prim->factor, "d"); /* start new path */ gl2ps->streamlength += gl2psPrintf("%f %f m\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1]); for(j = 1; j <= lastel; ++j){ prev = prim; prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); if(!gl2psSamePosition(prim->verts[0].xyz, prev->verts[1].xyz)){ /* the starting point of the new segment does not match the end point of the previous line, so we end the current path and start a new one */ gl2ps->streamlength += gl2psPrintf("%f %f l\n", prev->verts[1].xyz[0], prev->verts[1].xyz[1]); gl2ps->streamlength += gl2psPrintf("%f %f m\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1]); } else{ /* the two segements are connected, so we just append to the current path */ gl2ps->streamlength += gl2psPrintf("%f %f l\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1]); } } /* end last path */ gl2ps->streamlength += gl2psPrintf("%f %f l\n", prim->verts[1].xyz[0], prim->verts[1].xyz[1]); gl2ps->streamlength += gl2psPrintf("S\n"); break; case GL2PS_TRIANGLE: gl2psFillTriangleFromPrimitive(&t, prim, GL_TRUE); gl2psSortOutTrianglePDFgroup(gro); /* No alpha and const color: Simple PDF draw orders */ if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_1){ gl2ps->streamlength += gl2psPrintPDFFillColor(t.vertex[0].rgba); for(j = 0; j <= lastel; ++j){ prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); gl2ps->streamlength += gl2psPrintf("%f %f m\n" "%f %f l\n" "%f %f l\n" "h f\n", t.vertex[0].xyz[0], t.vertex[0].xyz[1], t.vertex[1].xyz[0], t.vertex[1].xyz[1], t.vertex[2].xyz[0], t.vertex[2].xyz[1]); } } /* Const alpha < 1 and const color: Simple PDF draw orders and an extra extended Graphics State for the alpha const */ else if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){ gl2ps->streamlength += gl2psPrintf("q\n" "/GS%d gs\n", gro->gsno); gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba); for(j = 0; j <= lastel; ++j){ prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); gl2ps->streamlength += gl2psPrintf("%f %f m\n" "%f %f l\n" "%f %f l\n" "h f\n", t.vertex[0].xyz[0], t.vertex[0].xyz[1], t.vertex[1].xyz[0], t.vertex[1].xyz[1], t.vertex[2].xyz[0], t.vertex[2].xyz[1]); } gl2ps->streamlength += gl2psPrintf("Q\n"); } /* Variable alpha and const color: Simple PDF draw orders and an extra extended Graphics State + Xobject + Shader object for the alpha mask */ else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){ gl2ps->streamlength += gl2psPrintf("q\n" "/GS%d gs\n" "/TrG%d Do\n", gro->gsno, gro->trgroupno); gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba); for(j = 0; j <= lastel; ++j){ prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); gl2ps->streamlength += gl2psPrintf("%f %f m\n" "%f %f l\n" "%f %f l\n" "h f\n", t.vertex[0].xyz[0], t.vertex[0].xyz[1], t.vertex[1].xyz[0], t.vertex[1].xyz[1], t.vertex[2].xyz[0], t.vertex[2].xyz[1]); } gl2ps->streamlength += gl2psPrintf("Q\n"); } /* Variable color and no alpha: Shader Object for the colored triangle(s) */ else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){ gl2ps->streamlength += gl2psPrintf("/Sh%d sh\n", gro->shno); } /* Variable color and const alpha < 1: Shader Object for the colored triangle(s) and an extra extended Graphics State for the alpha const */ else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){ gl2ps->streamlength += gl2psPrintf("q\n" "/GS%d gs\n" "/Sh%d sh\n" "Q\n", gro->gsno, gro->shno); } /* Variable alpha and color: Shader Object for the colored triangle(s) and an extra extended Graphics State + Xobject + Shader object for the alpha mask */ else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){ gl2ps->streamlength += gl2psPrintf("q\n" "/GS%d gs\n" "/TrG%d Do\n" "/Sh%d sh\n" "Q\n", gro->gsno, gro->trgroupno, gro->shno); } break; case GL2PS_PIXMAP: for(j = 0; j <= lastel; ++j){ prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); gl2psPutPDFImage(prim->data.image, gro->imno, prim->verts[0].xyz[0], prim->verts[0].xyz[1]); } break; case GL2PS_TEXT: for(j = 0; j <= lastel; ++j){ prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba); if (prim->numverts == 2) { gl2psPutPDFTextBL(prim->data.text, gro->fontno, prim->verts[0].xyz[0], prim->verts[0].xyz[1], prim->verts[1].xyz[0], prim->verts[1].xyz[1]); } else { gl2psPutPDFText(prim->data.text, gro->fontno, prim->verts[0].xyz[0], prim->verts[0].xyz[1]); } } break; case GL2PS_SPECIAL: lastel = gl2psListNbr(gro->ptrlist) - 1; if(lastel < 0) continue; for(j = 0; j <= lastel; ++j){ prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); gl2psPutPDFSpecial(i, j, prim->data.text); } default: break; } } } /* Graphics State names */ static int gl2psPDFgroupListWriteGStateResources(void) { GL2PSpdfgroup *gro; int offs = 0; int i; offs += fprintf(gl2ps->stream, "/ExtGState\n" "<<\n" "/GSa 7 0 R\n"); for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); if(gro->gsno >= 0) offs += fprintf(gl2ps->stream, "/GS%d %d 0 R\n", gro->gsno, gro->gsobjno); } offs += fprintf(gl2ps->stream, ">>\n"); return offs; } /* Main Shader names */ static int gl2psPDFgroupListWriteShaderResources(void) { GL2PSpdfgroup *gro; int offs = 0; int i; offs += fprintf(gl2ps->stream, "/Shading\n" "<<\n"); for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); if(gro->shno >= 0) offs += fprintf(gl2ps->stream, "/Sh%d %d 0 R\n", gro->shno, gro->shobjno); if(gro->maskshno >= 0) offs += fprintf(gl2ps->stream, "/TrSh%d %d 0 R\n", gro->maskshno, gro->maskshobjno); } offs += fprintf(gl2ps->stream,">>\n"); return offs; } /* Images & Mask Shader XObject names */ static int gl2psPDFgroupListWriteXObjectResources(void) { int i; GL2PSprimitive *p = NULL; GL2PSpdfgroup *gro; int offs = 0; offs += fprintf(gl2ps->stream, "/XObject\n" "<<\n"); for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); if(!gl2psListNbr(gro->ptrlist)) continue; p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0); switch(p->type){ case GL2PS_PIXMAP: gro->imobjno = gl2ps->objects_stack++; if(GL_RGBA == p->data.image->format) /* reserve one object for image mask */ gl2ps->objects_stack++; offs += fprintf(gl2ps->stream, "/Im%d %d 0 R\n", gro->imno, gro->imobjno); case GL2PS_TRIANGLE: if(gro->trgroupno >=0) offs += fprintf(gl2ps->stream, "/TrG%d %d 0 R\n", gro->trgroupno, gro->trgroupobjno); break; default: break; } } offs += fprintf(gl2ps->stream,">>\n"); return offs; } /* Font names */ static int gl2psPDFgroupListWriteFontResources(void) { int i; GL2PSpdfgroup *gro; int offs = 0; offs += fprintf(gl2ps->stream, "/Font\n<<\n"); for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); if(gro->fontno < 0) continue; gro->fontobjno = gl2ps->objects_stack++; offs += fprintf(gl2ps->stream, "/F%d %d 0 R\n", gro->fontno, gro->fontobjno); } offs += fprintf(gl2ps->stream, ">>\n"); return offs; } static void gl2psPDFgroupListDelete(void) { int i; GL2PSpdfgroup *gro = NULL; if(!gl2ps->pdfgrouplist) return; for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist,i); gl2psListDelete(gro->ptrlist); } gl2psListDelete(gl2ps->pdfgrouplist); gl2ps->pdfgrouplist = NULL; } /* Print 1st PDF object - file info */ static int gl2psPrintPDFInfo(void) { int offs; time_t now; struct tm *newtime; time(&now); newtime = gmtime(&now); offs = fprintf(gl2ps->stream, "1 0 obj\n" "<<\n" "/Title (%s)\n" "/Creator (GL2PS %d.%d.%d%s, %s)\n" "/Producer (%s)\n", gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, gl2ps->producer); if(!newtime){ offs += fprintf(gl2ps->stream, ">>\n" "endobj\n"); return offs; } offs += fprintf(gl2ps->stream, "/CreationDate (D:%d%02d%02d%02d%02d%02d)\n" ">>\n" "endobj\n", newtime->tm_year+1900, newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, newtime->tm_sec); return offs; } /* Create catalog and page structure - 2nd and 3th PDF object */ static int gl2psPrintPDFCatalog(void) { return fprintf(gl2ps->stream, "2 0 obj\n" "<<\n" "/Type /Catalog\n" "/Pages 3 0 R\n" ">>\n" "endobj\n"); } static int gl2psPrintPDFPages(void) { return fprintf(gl2ps->stream, "3 0 obj\n" "<<\n" "/Type /Pages\n" "/Kids [6 0 R]\n" "/Count 1\n" ">>\n" "endobj\n"); } /* Open stream for data - graphical objects, fonts etc. PDF object 4 */ static int gl2psOpenPDFDataStream(void) { int offs = 0; offs += fprintf(gl2ps->stream, "4 0 obj\n" "<<\n" "/Length 5 0 R\n" ); offs += gl2psPrintPDFCompressorType(); offs += fprintf(gl2ps->stream, ">>\n" "stream\n"); return offs; } /* Stream setup - Graphics state, fill background if allowed */ static int gl2psOpenPDFDataStreamWritePreface(void) { int offs; offs = gl2psPrintf("/GSa gs\n"); if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ offs += gl2psPrintPDFFillColor(gl2ps->bgcolor); offs += gl2psPrintf("%d %d %d %d re\n", (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); offs += gl2psPrintf("f\n"); } return offs; } /* Use the functions above to create the first part of the PDF*/ static void gl2psPrintPDFHeader(void) { int offs = 0; gl2ps->pdfprimlist = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*)); gl2psPDFstacksInit(); gl2ps->xreflist = (int*)gl2psMalloc(sizeof(int) * gl2ps->objects_stack); #if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ gl2psSetupCompress(); } #endif gl2ps->xreflist[0] = 0; offs += fprintf(gl2ps->stream, "%%PDF-1.4\n"); gl2ps->xreflist[1] = offs; offs += gl2psPrintPDFInfo(); gl2ps->xreflist[2] = offs; offs += gl2psPrintPDFCatalog(); gl2ps->xreflist[3] = offs; offs += gl2psPrintPDFPages(); gl2ps->xreflist[4] = offs; offs += gl2psOpenPDFDataStream(); gl2ps->xreflist[5] = offs; /* finished in gl2psPrintPDFFooter */ gl2ps->streamlength = gl2psOpenPDFDataStreamWritePreface(); } /* The central primitive drawing */ static void gl2psPrintPDFPrimitive(void *data) { GL2PSprimitive *prim = *(GL2PSprimitive**)data; if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return; prim = gl2psCopyPrimitive(prim); /* deep copy */ gl2psListAdd(gl2ps->pdfprimlist, &prim); } /* close stream and ... */ static int gl2psClosePDFDataStream(void) { int offs = 0; #if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ if(Z_OK != gl2psDeflate()) gl2psMsg(GL2PS_ERROR, "Zlib deflate error"); else fwrite(gl2ps->compress->dest, gl2ps->compress->destLen, 1, gl2ps->stream); gl2ps->streamlength += gl2ps->compress->destLen; offs += gl2ps->streamlength; gl2psFreeCompress(); } #endif offs += fprintf(gl2ps->stream, "endstream\n" "endobj\n"); return offs; } /* ... write the now known length object */ static int gl2psPrintPDFDataStreamLength(int val) { return fprintf(gl2ps->stream, "5 0 obj\n" "%d\n" "endobj\n", val); } /* Put the info created before in PDF objects */ static int gl2psPrintPDFOpenPage(void) { int offs; /* Write fixed part */ offs = fprintf(gl2ps->stream, "6 0 obj\n" "<<\n" "/Type /Page\n" "/Parent 3 0 R\n" "/MediaBox [%d %d %d %d]\n", (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); if(gl2ps->options & GL2PS_LANDSCAPE) offs += fprintf(gl2ps->stream, "/Rotate -90\n"); offs += fprintf(gl2ps->stream, "/Contents 4 0 R\n" "/Resources\n" "<<\n" "/ProcSet [/PDF /Text /ImageB /ImageC] %%/ImageI\n"); return offs; /* End fixed part, proceeds in gl2psPDFgroupListWriteVariableResources() */ } static int gl2psPDFgroupListWriteVariableResources(void) { int offs = 0; /* a) Graphics States for shader alpha masks*/ offs += gl2psPDFgroupListWriteGStateResources(); /* b) Shader and shader masks */ offs += gl2psPDFgroupListWriteShaderResources(); /* c) XObjects (Images & Shader Masks) */ offs += gl2psPDFgroupListWriteXObjectResources(); /* d) Fonts */ offs += gl2psPDFgroupListWriteFontResources(); /* End resources and page */ offs += fprintf(gl2ps->stream, ">>\n" ">>\n" "endobj\n"); return offs; } /* Standard Graphics State */ static int gl2psPrintPDFGSObject(void) { return fprintf(gl2ps->stream, "7 0 obj\n" "<<\n" "/Type /ExtGState\n" "/SA false\n" "/SM 0.02\n" "/OP false\n" "/op false\n" "/OPM 0\n" "/BG2 /Default\n" "/UCR2 /Default\n" "/TR2 /Default\n" ">>\n" "endobj\n"); } /* Put vertex' edge flag (8bit) and coordinates (32bit) in shader stream */ static int gl2psPrintPDFShaderStreamDataCoord(GL2PSvertex *vertex, int (*action)(unsigned long data, int size), GLfloat dx, GLfloat dy, GLfloat xmin, GLfloat ymin) { int offs = 0; unsigned long imap; GLfloat diff; double dmax = ~1UL; char edgeflag = 0; /* FIXME: temp bux fix for 64 bit archs: */ if(sizeof(unsigned long) == 8) dmax = dmax - 2048.; offs += (*action)(edgeflag, 1); /* The Shader stream in PDF requires to be in a 'big-endian' order */ if(GL2PS_ZERO(dx * dy)){ offs += (*action)(0, 4); offs += (*action)(0, 4); } else{ diff = (vertex->xyz[0] - xmin) / dx; if(diff > 1) diff = 1.0F; else if(diff < 0) diff = 0.0F; imap = (unsigned long)(diff * dmax); offs += (*action)(imap, 4); diff = (vertex->xyz[1] - ymin) / dy; if(diff > 1) diff = 1.0F; else if(diff < 0) diff = 0.0F; imap = (unsigned long)(diff * dmax); offs += (*action)(imap, 4); } return offs; } /* Put vertex' rgb value (8bit for every component) in shader stream */ static int gl2psPrintPDFShaderStreamDataRGB(GL2PSvertex *vertex, int (*action)(unsigned long data, int size)) { int offs = 0; unsigned long imap; double dmax = ~1UL; /* FIXME: temp bux fix for 64 bit archs: */ if(sizeof(unsigned long) == 8) dmax = dmax - 2048.; imap = (unsigned long)((vertex->rgba[0]) * dmax); offs += (*action)(imap, 1); imap = (unsigned long)((vertex->rgba[1]) * dmax); offs += (*action)(imap, 1); imap = (unsigned long)((vertex->rgba[2]) * dmax); offs += (*action)(imap, 1); return offs; } /* Put vertex' alpha (8/16bit) in shader stream */ static int gl2psPrintPDFShaderStreamDataAlpha(GL2PSvertex *vertex, int (*action)(unsigned long data, int size), int sigbyte) { int offs = 0; unsigned long imap; double dmax = ~1UL; /* FIXME: temp bux fix for 64 bit archs: */ if(sizeof(unsigned long) == 8) dmax = dmax - 2048.; if(sigbyte != 8 && sigbyte != 16) sigbyte = 8; sigbyte /= 8; imap = (unsigned long)((vertex->rgba[3]) * dmax); offs += (*action)(imap, sigbyte); return offs; } /* Put a triangles raw data in shader stream */ static int gl2psPrintPDFShaderStreamData(GL2PStriangle *triangle, GLfloat dx, GLfloat dy, GLfloat xmin, GLfloat ymin, int (*action)(unsigned long data, int size), int gray) { int i, offs = 0; GL2PSvertex v; if(gray && gray != 8 && gray != 16) gray = 8; for(i = 0; i < 3; ++i){ offs += gl2psPrintPDFShaderStreamDataCoord(&triangle->vertex[i], action, dx, dy, xmin, ymin); if(gray){ v = triangle->vertex[i]; offs += gl2psPrintPDFShaderStreamDataAlpha(&v, action, gray); } else{ offs += gl2psPrintPDFShaderStreamDataRGB(&triangle->vertex[i], action); } } return offs; } static void gl2psPDFRectHull(GLfloat *xmin, GLfloat *xmax, GLfloat *ymin, GLfloat *ymax, GL2PStriangle *triangles, int cnt) { int i, j; *xmin = triangles[0].vertex[0].xyz[0]; *xmax = triangles[0].vertex[0].xyz[0]; *ymin = triangles[0].vertex[0].xyz[1]; *ymax = triangles[0].vertex[0].xyz[1]; for(i = 0; i < cnt; ++i){ for(j = 0; j < 3; ++j){ if(*xmin > triangles[i].vertex[j].xyz[0]) *xmin = triangles[i].vertex[j].xyz[0]; if(*xmax < triangles[i].vertex[j].xyz[0]) *xmax = triangles[i].vertex[j].xyz[0]; if(*ymin > triangles[i].vertex[j].xyz[1]) *ymin = triangles[i].vertex[j].xyz[1]; if(*ymax < triangles[i].vertex[j].xyz[1]) *ymax = triangles[i].vertex[j].xyz[1]; } } } /* Writes shaded triangle gray == 0 means write RGB triangles gray == 8 8bit-grayscale (for alpha masks) gray == 16 16bit-grayscale (for alpha masks) */ static int gl2psPrintPDFShader(int obj, GL2PStriangle *triangles, int size, int gray) { int i, offs = 0, vertexbytes, done = 0; GLfloat xmin, xmax, ymin, ymax; switch(gray){ case 0: vertexbytes = 1+4+4+1+1+1; break; case 8: vertexbytes = 1+4+4+1; break; case 16: vertexbytes = 1+4+4+2; break; default: gray = 8; vertexbytes = 1+4+4+1; break; } gl2psPDFRectHull(&xmin, &xmax, &ymin, &ymax, triangles, size); offs += fprintf(gl2ps->stream, "%d 0 obj\n" "<< " "/ShadingType 4 " "/ColorSpace %s " "/BitsPerCoordinate 32 " "/BitsPerComponent %d " "/BitsPerFlag 8 " "/Decode [%f %f %f %f 0 1 %s] ", obj, (gray) ? "/DeviceGray" : "/DeviceRGB", (gray) ? gray : 8, xmin, xmax, ymin, ymax, (gray) ? "" : "0 1 0 1"); #if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ gl2psAllocCompress(vertexbytes * size * 3); for(i = 0; i < size; ++i) gl2psPrintPDFShaderStreamData(&triangles[i], xmax-xmin, ymax-ymin, xmin, ymin, gl2psWriteBigEndianCompress, gray); if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){ offs += gl2psPrintPDFCompressorType(); offs += fprintf(gl2ps->stream, "/Length %d " ">>\n" "stream\n", (int)gl2ps->compress->destLen); offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest, gl2ps->compress->destLen, 1, gl2ps->stream); done = 1; } gl2psFreeCompress(); } #endif if(!done){ /* no compression, or too long after compression, or compress error -> write non-compressed entry */ offs += fprintf(gl2ps->stream, "/Length %d " ">>\n" "stream\n", vertexbytes * 3 * size); for(i = 0; i < size; ++i) offs += gl2psPrintPDFShaderStreamData(&triangles[i], xmax-xmin, ymax-ymin, xmin, ymin, gl2psWriteBigEndian, gray); } offs += fprintf(gl2ps->stream, "\nendstream\n" "endobj\n"); return offs; } /* Writes a XObject for a shaded triangle mask */ static int gl2psPrintPDFShaderMask(int obj, int childobj) { int offs = 0, len; offs += fprintf(gl2ps->stream, "%d 0 obj\n" "<<\n" "/Type /XObject\n" "/Subtype /Form\n" "/BBox [ %d %d %d %d ]\n" "/Group \n<<\n/S /Transparency /CS /DeviceRGB\n" ">>\n", obj, (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); len = (childobj>0) ? (int)strlen("/TrSh sh\n") + (int)log10((double)childobj)+1 : (int)strlen("/TrSh0 sh\n"); offs += fprintf(gl2ps->stream, "/Length %d\n" ">>\n" "stream\n", len); offs += fprintf(gl2ps->stream, "/TrSh%d sh\n", childobj); offs += fprintf(gl2ps->stream, "endstream\n" "endobj\n"); return offs; } /* Writes a Extended graphics state for a shaded triangle mask if simplealpha ist true the childobj argument is ignored and a /ca statement will be written instead */ static int gl2psPrintPDFShaderExtGS(int obj, int childobj) { int offs = 0; offs += fprintf(gl2ps->stream, "%d 0 obj\n" "<<\n", obj); offs += fprintf(gl2ps->stream, "/SMask << /S /Alpha /G %d 0 R >> ", childobj); offs += fprintf(gl2ps->stream, ">>\n" "endobj\n"); return offs; } /* a simple graphics state */ static int gl2psPrintPDFShaderSimpleExtGS(int obj, GLfloat alpha) { int offs = 0; offs += fprintf(gl2ps->stream, "%d 0 obj\n" "<<\n" "/ca %g" ">>\n" "endobj\n", obj, alpha); return offs; } /* Similar groups of functions for pixmaps and text */ static int gl2psPrintPDFPixmapStreamData(GL2PSimage *im, int (*action)(unsigned long data, int size), int gray) { int x, y, shift; GLfloat r, g, b, a; if(im->format != GL_RGBA && gray) return 0; if(gray && gray != 8 && gray != 16) gray = 8; gray /= 8; shift = (sizeof(unsigned long) - 1) * 8; for(y = 0; y < im->height; ++y){ for(x = 0; x < im->width; ++x){ a = gl2psGetRGB(im, x, y, &r, &g, &b); if(im->format == GL_RGBA && gray){ (*action)((unsigned long)(a * 255) << shift, gray); } else{ (*action)((unsigned long)(r * 255) << shift, 1); (*action)((unsigned long)(g * 255) << shift, 1); (*action)((unsigned long)(b * 255) << shift, 1); } } } switch(gray){ case 0: return 3 * im->width * im->height; case 1: return im->width * im->height; case 2: return 2 * im->width * im->height; default: return 3 * im->width * im->height; } } static int gl2psPrintPDFPixmap(int obj, int childobj, GL2PSimage *im, int gray) { int offs = 0, done = 0, sigbytes = 3; if(gray && gray !=8 && gray != 16) gray = 8; if(gray) sigbytes = gray / 8; offs += fprintf(gl2ps->stream, "%d 0 obj\n" "<<\n" "/Type /XObject\n" "/Subtype /Image\n" "/Width %d\n" "/Height %d\n" "/ColorSpace %s \n" "/BitsPerComponent 8\n", obj, (int)im->width, (int)im->height, (gray) ? "/DeviceGray" : "/DeviceRGB" ); if(GL_RGBA == im->format && gray == 0){ offs += fprintf(gl2ps->stream, "/SMask %d 0 R\n", childobj); } #if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ gl2psAllocCompress((int)(im->width * im->height * sigbytes)); gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndianCompress, gray); if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){ offs += gl2psPrintPDFCompressorType(); offs += fprintf(gl2ps->stream, "/Length %d " ">>\n" "stream\n", (int)gl2ps->compress->destLen); offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest, gl2ps->compress->destLen, 1, gl2ps->stream); done = 1; } gl2psFreeCompress(); } #endif if(!done){ /* no compression, or too long after compression, or compress error -> write non-compressed entry */ offs += fprintf(gl2ps->stream, "/Length %d " ">>\n" "stream\n", (int)(im->width * im->height * sigbytes)); offs += gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndian, gray); } offs += fprintf(gl2ps->stream, "\nendstream\n" "endobj\n"); return offs; } static int gl2psPrintPDFText(int obj, GL2PSstring *s, int fontnumber) { int offs = 0; offs += fprintf(gl2ps->stream, "%d 0 obj\n" "<<\n" "/Type /Font\n" "/Subtype /Type1\n" "/Name /F%d\n" "/BaseFont /%s\n" "/Encoding /MacRomanEncoding\n" ">>\n" "endobj\n", obj, fontnumber, s->fontname); return offs; } /* Write the physical objects */ static int gl2psPDFgroupListWriteObjects(int entryoffs) { int i,j; GL2PSprimitive *p = NULL; GL2PSpdfgroup *gro; int offs = entryoffs; GL2PStriangle *triangles; int size = 0; if(!gl2ps->pdfgrouplist) return offs; for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); if(!gl2psListNbr(gro->ptrlist)) continue; p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0); switch(p->type){ case GL2PS_POINT: break; case GL2PS_LINE: break; case GL2PS_TRIANGLE: size = gl2psListNbr(gro->ptrlist); triangles = (GL2PStriangle*)gl2psMalloc(sizeof(GL2PStriangle) * size); for(j = 0; j < size; ++j){ p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); gl2psFillTriangleFromPrimitive(&triangles[j], p, GL_TRUE); } if(triangles[0].prop & T_VAR_COLOR){ gl2ps->xreflist[gro->shobjno] = offs; offs += gl2psPrintPDFShader(gro->shobjno, triangles, size, 0); } if(triangles[0].prop & T_ALPHA_LESS_1){ gl2ps->xreflist[gro->gsobjno] = offs; offs += gl2psPrintPDFShaderSimpleExtGS(gro->gsobjno, triangles[0].vertex[0].rgba[3]); } if(triangles[0].prop & T_VAR_ALPHA){ gl2ps->xreflist[gro->gsobjno] = offs; offs += gl2psPrintPDFShaderExtGS(gro->gsobjno, gro->trgroupobjno); gl2ps->xreflist[gro->trgroupobjno] = offs; offs += gl2psPrintPDFShaderMask(gro->trgroupobjno, gro->maskshno); gl2ps->xreflist[gro->maskshobjno] = offs; offs += gl2psPrintPDFShader(gro->maskshobjno, triangles, size, 8); } gl2psFree(triangles); break; case GL2PS_PIXMAP: gl2ps->xreflist[gro->imobjno] = offs; offs += gl2psPrintPDFPixmap(gro->imobjno, gro->imobjno+1, p->data.image, 0); if(p->data.image->format == GL_RGBA){ gl2ps->xreflist[gro->imobjno+1] = offs; offs += gl2psPrintPDFPixmap(gro->imobjno+1, -1, p->data.image, 8); } break; case GL2PS_TEXT: gl2ps->xreflist[gro->fontobjno] = offs; offs += gl2psPrintPDFText(gro->fontobjno,p->data.text,gro->fontno); break; case GL2PS_SPECIAL : /* alignment contains the format for which the special output text is intended */ if(p->data.text->alignment == GL2PS_PDF) offs += fprintf(gl2ps->stream, "%s\n", p->data.text->str); break; default: break; } } return offs; } /* All variable data has been written at this point and all required functioninality has been gathered, so we can write now file footer with cross reference table and trailer */ static void gl2psPrintPDFFooter(void) { int i, offs; gl2psPDFgroupListInit(); gl2psPDFgroupListWriteMainStream(); offs = gl2ps->xreflist[5] + gl2ps->streamlength; offs += gl2psClosePDFDataStream(); gl2ps->xreflist[5] = offs; offs += gl2psPrintPDFDataStreamLength(gl2ps->streamlength); gl2ps->xreflist[6] = offs; gl2ps->streamlength = 0; offs += gl2psPrintPDFOpenPage(); offs += gl2psPDFgroupListWriteVariableResources(); gl2ps->xreflist = (int*)gl2psRealloc(gl2ps->xreflist, sizeof(int) * (gl2ps->objects_stack + 1)); gl2ps->xreflist[7] = offs; offs += gl2psPrintPDFGSObject(); gl2ps->xreflist[8] = offs; gl2ps->xreflist[gl2ps->objects_stack] = gl2psPDFgroupListWriteObjects(gl2ps->xreflist[8]); /* Start cross reference table. The file has to been opened in binary mode to preserve the 20 digit string length! */ fprintf(gl2ps->stream, "xref\n" "0 %d\n" "%010d 65535 f \n", gl2ps->objects_stack, 0); for(i = 1; i < gl2ps->objects_stack; ++i) fprintf(gl2ps->stream, "%010d 00000 n \n", gl2ps->xreflist[i]); fprintf(gl2ps->stream, "trailer\n" "<<\n" "/Size %d\n" "/Info 1 0 R\n" "/Root 2 0 R\n" ">>\n" "startxref\n%d\n" "%%%%EOF\n", gl2ps->objects_stack, gl2ps->xreflist[gl2ps->objects_stack]); /* Free auxiliary lists and arrays */ gl2psFree(gl2ps->xreflist); gl2psListAction(gl2ps->pdfprimlist, gl2psFreePrimitive); gl2psListDelete(gl2ps->pdfprimlist); gl2psPDFgroupListDelete(); #if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ gl2psFreeCompress(); gl2psFree(gl2ps->compress); gl2ps->compress = NULL; } #endif } /* PDF begin viewport */ static void gl2psPrintPDFBeginViewport(GLint viewport[4]) { int offs = 0; GLint idx; GLfloat rgba[4]; int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; glRenderMode(GL_FEEDBACK); gl2psResetLineProperties(); if(gl2ps->header){ gl2psPrintPDFHeader(); gl2ps->header = GL_FALSE; } offs += gl2psPrintf("q\n"); if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){ glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba); } else{ glGetIntegerv(GL_INDEX_CLEAR_VALUE, &idx); rgba[0] = gl2ps->colormap[idx][0]; rgba[1] = gl2ps->colormap[idx][1]; rgba[2] = gl2ps->colormap[idx][2]; rgba[3] = 1.0F; } offs += gl2psPrintPDFFillColor(rgba); offs += gl2psPrintf("%d %d %d %d re\n" "W\n" "f\n", x, y, w, h); } else{ offs += gl2psPrintf("%d %d %d %d re\n" "W\n" "n\n", x, y, w, h); } gl2ps->streamlength += offs; } static GLint gl2psPrintPDFEndViewport(void) { GLint res; res = gl2psPrintPrimitives(); gl2ps->streamlength += gl2psPrintf("Q\n"); return res; } static void gl2psPrintPDFFinalPrimitive(void) { } /* definition of the PDF backend */ static GL2PSbackend gl2psPDF = { gl2psPrintPDFHeader, gl2psPrintPDFFooter, gl2psPrintPDFBeginViewport, gl2psPrintPDFEndViewport, gl2psPrintPDFPrimitive, gl2psPrintPDFFinalPrimitive, "pdf", "Portable Document Format" }; /********************************************************************* * * SVG routines * *********************************************************************/ static void gl2psSVGGetCoordsAndColors(int n, GL2PSvertex *verts, GL2PSxyz *xyz, GL2PSrgba *rgba) { int i, j; for(i = 0; i < n; i++){ xyz[i][0] = verts[i].xyz[0]; xyz[i][1] = gl2ps->viewport[3] - verts[i].xyz[1]; xyz[i][2] = 0.0F; for(j = 0; j < 4; j++) rgba[i][j] = verts[i].rgba[j]; } } static void gl2psSVGGetColorString(GL2PSrgba rgba, char str[32]) { int r = (int)(255. * rgba[0]); int g = (int)(255. * rgba[1]); int b = (int)(255. * rgba[2]); int rc = (r < 0) ? 0 : (r > 255) ? 255 : r; int gc = (g < 0) ? 0 : (g > 255) ? 255 : g; int bc = (b < 0) ? 0 : (b > 255) ? 255 : b; snprintf(str, 32, "#%2.2x%2.2x%2.2x", rc, gc, bc); } static void gl2psPrintSVGHeader(void) { int x, y, width, height; char col[32]; time_t now; time(&now); if (gl2ps->options & GL2PS_LANDSCAPE){ x = (int)gl2ps->viewport[1]; y = (int)gl2ps->viewport[0]; width = (int)gl2ps->viewport[3]; height = (int)gl2ps->viewport[2]; } else{ x = (int)gl2ps->viewport[0]; y = (int)gl2ps->viewport[1]; width = (int)gl2ps->viewport[2]; height = (int)gl2ps->viewport[3]; } /* Compressed SVG files (.svgz) are simply gzipped SVG files */ gl2psPrintGzipHeader(); gl2psPrintf("\n"); gl2psPrintf("\n", width, height, x, y, width, height); gl2psPrintf("%s\n", gl2ps->title); gl2psPrintf("\n"); gl2psPrintf("Creator: GL2PS %d.%d.%d%s, %s\n" "For: %s\n" "CreationDate: %s", GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, gl2ps->producer, ctime(&now)); gl2psPrintf("\n"); gl2psPrintf("\n"); gl2psPrintf("\n"); if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ gl2psSVGGetColorString(gl2ps->bgcolor, col); gl2psPrintf("\n", col, (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[3], (int)gl2ps->viewport[0], (int)gl2ps->viewport[3]); } /* group all the primitives and disable antialiasing */ gl2psPrintf("\n"); } static void gl2psPrintSVGSmoothTriangle(GL2PSxyz xyz[3], GL2PSrgba rgba[3]) { int i; GL2PSxyz xyz2[3]; GL2PSrgba rgba2[3]; char col[32]; /* Apparently there is no easy way to do Gouraud shading in SVG without explicitly pre-defining gradients, so for now we just do recursive subdivision */ if(gl2psSameColorThreshold(3, rgba, gl2ps->threshold)){ gl2psSVGGetColorString(rgba[0], col); gl2psPrintf("\n", xyz[0][0], xyz[0][1], xyz[1][0], xyz[1][1], xyz[2][0], xyz[2][1]); } else{ /* subdivide into 4 subtriangles */ for(i = 0; i < 3; i++){ xyz2[0][i] = xyz[0][i]; xyz2[1][i] = 0.5F * (xyz[0][i] + xyz[1][i]); xyz2[2][i] = 0.5F * (xyz[0][i] + xyz[2][i]); } for(i = 0; i < 4; i++){ rgba2[0][i] = rgba[0][i]; rgba2[1][i] = 0.5F * (rgba[0][i] + rgba[1][i]); rgba2[2][i] = 0.5F * (rgba[0][i] + rgba[2][i]); } gl2psPrintSVGSmoothTriangle(xyz2, rgba2); for(i = 0; i < 3; i++){ xyz2[0][i] = 0.5F * (xyz[0][i] + xyz[1][i]); xyz2[1][i] = xyz[1][i]; xyz2[2][i] = 0.5F * (xyz[1][i] + xyz[2][i]); } for(i = 0; i < 4; i++){ rgba2[0][i] = 0.5F * (rgba[0][i] + rgba[1][i]); rgba2[1][i] = rgba[1][i]; rgba2[2][i] = 0.5F * (rgba[1][i] + rgba[2][i]); } gl2psPrintSVGSmoothTriangle(xyz2, rgba2); for(i = 0; i < 3; i++){ xyz2[0][i] = 0.5F * (xyz[0][i] + xyz[2][i]); xyz2[1][i] = xyz[2][i]; xyz2[2][i] = 0.5F * (xyz[1][i] + xyz[2][i]); } for(i = 0; i < 4; i++){ rgba2[0][i] = 0.5F * (rgba[0][i] + rgba[2][i]); rgba2[1][i] = rgba[2][i]; rgba2[2][i] = 0.5F * (rgba[1][i] + rgba[2][i]); } gl2psPrintSVGSmoothTriangle(xyz2, rgba2); for(i = 0; i < 3; i++){ xyz2[0][i] = 0.5F * (xyz[0][i] + xyz[1][i]); xyz2[1][i] = 0.5F * (xyz[1][i] + xyz[2][i]); xyz2[2][i] = 0.5F * (xyz[0][i] + xyz[2][i]); } for(i = 0; i < 4; i++){ rgba2[0][i] = 0.5F * (rgba[0][i] + rgba[1][i]); rgba2[1][i] = 0.5F * (rgba[1][i] + rgba[2][i]); rgba2[2][i] = 0.5F * (rgba[0][i] + rgba[2][i]); } gl2psPrintSVGSmoothTriangle(xyz2, rgba2); } } static void gl2psPrintSVGDash(GLushort pattern, GLint factor) { int i, n, array[10]; if(!pattern || !factor) return; /* solid line */ gl2psParseStipplePattern(pattern, factor, &n, array); gl2psPrintf("stroke-dasharray=\""); for(i = 0; i < n; i++){ if(i) gl2psPrintf(","); gl2psPrintf("%d", array[i]); } gl2psPrintf("\" "); } static void gl2psEndSVGLine(void) { int i; if(gl2ps->lastvertex.rgba[0] >= 0.){ gl2psPrintf("%g,%g\"/>\n", gl2ps->lastvertex.xyz[0], gl2ps->viewport[3] - gl2ps->lastvertex.xyz[1]); for(i = 0; i < 3; i++) gl2ps->lastvertex.xyz[i] = -1.; for(i = 0; i < 4; i++) gl2ps->lastvertex.rgba[i] = -1.; } } static void gl2psPrintSVGPixmap(GLfloat x, GLfloat y, GL2PSimage *pixmap) { #if defined(GL2PS_HAVE_LIBPNG) GL2PSlist *png; unsigned char c; int i; /* The only image types supported by the SVG standard are JPEG, PNG and SVG. Here we choose PNG, and since we want to embed the image directly in the SVG stream (and not link to an external image file), we need to encode the pixmap into PNG in memory, then encode it into base64. */ png = gl2psListCreate(pixmap->width * pixmap->height * 3, 1000, sizeof(unsigned char)); gl2psConvertPixmapToPNG(pixmap, png); gl2psListEncodeBase64(png); /* Use "transform" attribute to scale and translate the image from the coordinates origin (0,0) */ y -= pixmap->zoom_y * (GLfloat)pixmap->height; gl2psPrintf("width, pixmap->height); gl2psPrintf("transform=\"matrix(%g,0,0,%g,%g,%g)\"\n", pixmap->zoom_x, pixmap->zoom_y, x, y); gl2psPrintf("xlink:href=\"data:image/png;base64,"); for(i = 0; i < gl2psListNbr(png); i++){ gl2psListRead(png, i, &c); gl2psPrintf("%c", c); } gl2psPrintf("\"/>\n"); gl2psListDelete(png); #else (void) x; (void) y; (void) pixmap; /* not used */ gl2psMsg(GL2PS_WARNING, "GL2PS must be compiled with PNG support in " "order to embed images in SVG streams"); #endif } static void gl2psPrintSVGPrimitive(void *data) { GL2PSprimitive *prim; GL2PSxyz xyz[4]; GL2PSrgba rgba[4]; char col[32]; char lcap[7], ljoin[7]; int newline; prim = *(GL2PSprimitive**)data; if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return; /* We try to draw connected lines as a single path to get nice line joins and correct stippling. So if the primitive to print is not a line we must first finish the current line (if any): */ if(prim->type != GL2PS_LINE) gl2psEndSVGLine(); gl2psSVGGetCoordsAndColors(prim->numverts, prim->verts, xyz, rgba); switch(prim->type){ case GL2PS_POINT : gl2psSVGGetColorString(rgba[0], col); gl2psPrintf("\n", xyz[0][0], xyz[0][1], 0.5 * prim->width); break; case GL2PS_LINE : if(!gl2psSamePosition(gl2ps->lastvertex.xyz, prim->verts[0].xyz) || !gl2psSameColor(gl2ps->lastrgba, prim->verts[0].rgba) || gl2ps->lastlinewidth != prim->width || gl2ps->lastlinecap != prim->linecap || gl2ps->lastlinejoin != prim->linejoin || gl2ps->lastpattern != prim->pattern || gl2ps->lastfactor != prim->factor){ /* End the current line if the new segment does not start where the last one ended, or if the color, the width or the stippling have changed (we will need to use multi-point gradients for smooth-shaded lines) */ gl2psEndSVGLine(); newline = 1; } else{ newline = 0; } gl2ps->lastvertex = prim->verts[1]; gl2psSetLastColor(prim->verts[0].rgba); gl2ps->lastlinewidth = prim->width; gl2ps->lastlinecap = prim->linecap; gl2ps->lastlinejoin = prim->linejoin; gl2ps->lastpattern = prim->pattern; gl2ps->lastfactor = prim->factor; if(newline){ gl2psSVGGetColorString(rgba[0], col); gl2psPrintf("width); switch (prim->linecap){ case GL2PS_LINE_CAP_BUTT: snprintf (lcap, sizeof(lcap), "%s", "butt"); break; case GL2PS_LINE_CAP_ROUND: snprintf (lcap, sizeof(lcap), "%s", "round"); break; case GL2PS_LINE_CAP_SQUARE: snprintf (lcap, sizeof(lcap), "%s", "square"); break; } switch (prim->linejoin){ case GL2PS_LINE_JOIN_MITER: snprintf (ljoin, sizeof(ljoin), "%s", "miter"); break; case GL2PS_LINE_JOIN_ROUND: snprintf (ljoin, sizeof(ljoin), "%s", "round"); break; case GL2PS_LINE_JOIN_BEVEL: snprintf (ljoin, sizeof(ljoin), "%s", "bevel"); break; } gl2psPrintf("stroke-linecap=\"%s\" stroke-linejoin=\"%s\" ", lcap, ljoin); if(rgba[0][3] < 1.0F) gl2psPrintf("stroke-opacity=\"%g\" ", rgba[0][3]); gl2psPrintSVGDash(prim->pattern, prim->factor); gl2psPrintf("points=\"%g,%g ", xyz[0][0], xyz[0][1]); } else{ gl2psPrintf("%g,%g ", xyz[0][0], xyz[0][1]); } break; case GL2PS_TRIANGLE : gl2psPrintSVGSmoothTriangle(xyz, rgba); break; case GL2PS_QUADRANGLE : gl2psMsg(GL2PS_WARNING, "There should not be any quad left to print"); break; case GL2PS_PIXMAP : gl2psPrintSVGPixmap(xyz[0][0], xyz[0][1], prim->data.image); break; case GL2PS_TEXT : gl2psSVGGetColorString(prim->verts[0].rgba, col); gl2psPrintf("data.text->fontsize); if(prim->data.text->angle != 0.0) gl2psPrintf("transform=\"rotate(%g, %g, %g)\" ", -prim->data.text->angle, xyz[0][0], xyz[0][1]); switch(prim->data.text->alignment){ case GL2PS_TEXT_C: gl2psPrintf("text-anchor=\"middle\" dy=\"%d\" ", prim->data.text->fontsize / 2); break; case GL2PS_TEXT_CL: gl2psPrintf("text-anchor=\"start\" dy=\"%d\" ", prim->data.text->fontsize / 2); break; case GL2PS_TEXT_CR: gl2psPrintf("text-anchor=\"end\" dy=\"%d\" ", prim->data.text->fontsize / 2); break; case GL2PS_TEXT_B: gl2psPrintf("text-anchor=\"middle\" dy=\"0\" "); break; case GL2PS_TEXT_BR: gl2psPrintf("text-anchor=\"end\" dy=\"0\" "); break; case GL2PS_TEXT_T: gl2psPrintf("text-anchor=\"middle\" dy=\"%d\" ", prim->data.text->fontsize); break; case GL2PS_TEXT_TL: gl2psPrintf("text-anchor=\"start\" dy=\"%d\" ", prim->data.text->fontsize); break; case GL2PS_TEXT_TR: gl2psPrintf("text-anchor=\"end\" dy=\"%d\" ", prim->data.text->fontsize); break; case GL2PS_TEXT_BL: default: /* same as GL2PS_TEXT_BL */ gl2psPrintf("text-anchor=\"start\" dy=\"0\" "); break; } if(!strcmp(prim->data.text->fontname, "Times-Roman")) gl2psPrintf("font-family=\"Times\">"); else if(!strcmp(prim->data.text->fontname, "Times-Bold")) gl2psPrintf("font-family=\"Times\" font-weight=\"bold\">"); else if(!strcmp(prim->data.text->fontname, "Times-Italic")) gl2psPrintf("font-family=\"Times\" font-style=\"italic\">"); else if(!strcmp(prim->data.text->fontname, "Times-BoldItalic")) gl2psPrintf("font-family=\"Times\" font-style=\"italic\" font-weight=\"bold\">"); else if(!strcmp(prim->data.text->fontname, "Helvetica-Bold")) gl2psPrintf("font-family=\"Helvetica\" font-weight=\"bold\">"); else if(!strcmp(prim->data.text->fontname, "Helvetica-Oblique")) gl2psPrintf("font-family=\"Helvetica\" font-style=\"oblique\">"); else if(!strcmp(prim->data.text->fontname, "Helvetica-BoldOblique")) gl2psPrintf("font-family=\"Helvetica\" font-style=\"oblique\" font-weight=\"bold\">"); else if(!strcmp(prim->data.text->fontname, "Courier-Bold")) gl2psPrintf("font-family=\"Courier\" font-weight=\"bold\">"); else if(!strcmp(prim->data.text->fontname, "Courier-Oblique")) gl2psPrintf("font-family=\"Courier\" font-style=\"oblique\">"); else if(!strcmp(prim->data.text->fontname, "Courier-BoldOblique")) gl2psPrintf("font-family=\"Courier\" font-style=\"oblique\" font-weight=\"bold\">"); else gl2psPrintf("font-family=\"%s\">", prim->data.text->fontname); gl2psPrintf("%s\n", prim->data.text->str); break; case GL2PS_SPECIAL : /* alignment contains the format for which the special output text is intended */ if(prim->data.text->alignment == GL2PS_SVG) gl2psPrintf("%s\n", prim->data.text->str); break; default : break; } } static void gl2psPrintSVGFooter(void) { gl2psPrintf("\n"); gl2psPrintf("\n"); gl2psPrintGzipFooter(); } static void gl2psPrintSVGBeginViewport(GLint viewport[4]) { GLint idx; char col[32]; GLfloat rgba[4]; int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; glRenderMode(GL_FEEDBACK); gl2psResetLineProperties(); if(gl2ps->header){ gl2psPrintSVGHeader(); gl2ps->header = GL_FALSE; } if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){ glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba); } else{ glGetIntegerv(GL_INDEX_CLEAR_VALUE, &idx); rgba[0] = gl2ps->colormap[idx][0]; rgba[1] = gl2ps->colormap[idx][1]; rgba[2] = gl2ps->colormap[idx][2]; rgba[3] = 1.0F; } gl2psSVGGetColorString(rgba, col); gl2psPrintf("viewport[3] - y, x + w, gl2ps->viewport[3] - y, x + w, gl2ps->viewport[3] - (y + h), x, gl2ps->viewport[3] - (y + h)); gl2psPrintf("shape-rendering=\"crispEdges\"/>\n"); } gl2psPrintf("\n", x, y, w, h); gl2psPrintf(" \n", x, gl2ps->viewport[3] - y, x + w, gl2ps->viewport[3] - y, x + w, gl2ps->viewport[3] - (y + h), x, gl2ps->viewport[3] - (y + h)); gl2psPrintf("\n"); gl2psPrintf("\n", x, y, w, h); } static GLint gl2psPrintSVGEndViewport(void) { GLint res; res = gl2psPrintPrimitives(); gl2psPrintf("\n"); return res; } static void gl2psPrintSVGFinalPrimitive(void) { /* End any remaining line, if any */ gl2psEndSVGLine(); } /* definition of the SVG backend */ static GL2PSbackend gl2psSVG = { gl2psPrintSVGHeader, gl2psPrintSVGFooter, gl2psPrintSVGBeginViewport, gl2psPrintSVGEndViewport, gl2psPrintSVGPrimitive, gl2psPrintSVGFinalPrimitive, "svg", "Scalable Vector Graphics" }; /********************************************************************* * * PGF routines * *********************************************************************/ static void gl2psPrintPGFColor(GL2PSrgba rgba) { if(!gl2psSameColor(gl2ps->lastrgba, rgba)){ gl2psSetLastColor(rgba); fprintf(gl2ps->stream, "\\color[rgb]{%f,%f,%f}\n", rgba[0], rgba[1], rgba[2]); } } static void gl2psPrintPGFHeader(void) { time_t now; time(&now); fprintf(gl2ps->stream, "%% Title: %s\n" "%% Creator: GL2PS %d.%d.%d%s, %s\n" "%% For: %s\n" "%% CreationDate: %s", gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, gl2ps->producer, ctime(&now)); fprintf(gl2ps->stream, "\\begin{pgfpicture}\n"); if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ gl2psPrintPGFColor(gl2ps->bgcolor); fprintf(gl2ps->stream, "\\pgfpathrectanglecorners{" "\\pgfpoint{%dpt}{%dpt}}{\\pgfpoint{%dpt}{%dpt}}\n" "\\pgfusepath{fill}\n", (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); } } static void gl2psPrintPGFDash(GLushort pattern, GLint factor) { int i, n, array[10]; if(pattern == gl2ps->lastpattern && factor == gl2ps->lastfactor) return; gl2ps->lastpattern = pattern; gl2ps->lastfactor = factor; if(!pattern || !factor){ /* solid line */ fprintf(gl2ps->stream, "\\pgfsetdash{}{0pt}\n"); } else{ gl2psParseStipplePattern(pattern, factor, &n, array); fprintf(gl2ps->stream, "\\pgfsetdash{"); for(i = 0; i < n; i++) fprintf(gl2ps->stream, "{%dpt}", array[i]); fprintf(gl2ps->stream, "}{0pt}\n"); } } static const char *gl2psPGFTextAlignment(int align) { switch(align){ case GL2PS_TEXT_C : return "center"; case GL2PS_TEXT_CL : return "west"; case GL2PS_TEXT_CR : return "east"; case GL2PS_TEXT_B : return "south"; case GL2PS_TEXT_BR : return "south east"; case GL2PS_TEXT_T : return "north"; case GL2PS_TEXT_TL : return "north west"; case GL2PS_TEXT_TR : return "north east"; case GL2PS_TEXT_BL : default : return "south west"; } } static void gl2psPrintPGFPrimitive(void *data) { GL2PSprimitive *prim; prim = *(GL2PSprimitive**)data; switch(prim->type){ case GL2PS_POINT : /* Points in openGL are rectangular */ gl2psPrintPGFColor(prim->verts[0].rgba); fprintf(gl2ps->stream, "\\pgfpathrectangle{\\pgfpoint{%fpt}{%fpt}}" "{\\pgfpoint{%fpt}{%fpt}}\n\\pgfusepath{fill}\n", prim->verts[0].xyz[0]-0.5*prim->width, prim->verts[0].xyz[1]-0.5*prim->width, prim->width,prim->width); break; case GL2PS_LINE : gl2psPrintPGFColor(prim->verts[0].rgba); if(gl2ps->lastlinewidth != prim->width){ gl2ps->lastlinewidth = prim->width; fprintf(gl2ps->stream, "\\pgfsetlinewidth{%fpt}\n", gl2ps->lastlinewidth); } if(gl2ps->lastlinecap != prim->linecap){ gl2ps->lastlinecap = prim->linecap; switch (prim->linecap){ case GL2PS_LINE_CAP_BUTT: fprintf(gl2ps->stream, "\\pgfset%s\n", "buttcap"); break; case GL2PS_LINE_CAP_ROUND: fprintf(gl2ps->stream, "\\pgfset%s\n", "roundcap"); break; case GL2PS_LINE_CAP_SQUARE: fprintf(gl2ps->stream, "\\pgfset%s\n", "rectcap"); break; } } if(gl2ps->lastlinejoin != prim->linejoin){ gl2ps->lastlinejoin = prim->linejoin; switch (prim->linejoin){ case GL2PS_LINE_JOIN_MITER: fprintf(gl2ps->stream, "\\pgfset%s\n", "miterjoin"); break; case GL2PS_LINE_JOIN_ROUND: fprintf(gl2ps->stream, "\\pgfset%s\n", "roundjoin"); break; case GL2PS_LINE_JOIN_BEVEL: fprintf(gl2ps->stream, "\\pgfset%s\n", "beveljoin"); break; } } gl2psPrintPGFDash(prim->pattern, prim->factor); fprintf(gl2ps->stream, "\\pgfpathmoveto{\\pgfpoint{%fpt}{%fpt}}\n" "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n" "\\pgfusepath{stroke}\n", prim->verts[1].xyz[0], prim->verts[1].xyz[1], prim->verts[0].xyz[0], prim->verts[0].xyz[1]); break; case GL2PS_TRIANGLE : if(gl2ps->lastlinewidth != 0){ gl2ps->lastlinewidth = 0; fprintf(gl2ps->stream, "\\pgfsetlinewidth{0.01pt}\n"); } if(gl2ps->lastlinecap != prim->linecap){ gl2ps->lastlinecap = prim->linecap; switch (prim->linecap){ case GL2PS_LINE_CAP_BUTT: fprintf(gl2ps->stream, "\\pgfset%s\n", "buttcap"); break; case GL2PS_LINE_CAP_ROUND: fprintf(gl2ps->stream, "\\pgfset%s\n", "roundcap"); break; case GL2PS_LINE_CAP_SQUARE: fprintf(gl2ps->stream, "\\pgfset%s\n", "rectcap"); break; } } if(gl2ps->lastlinejoin != prim->linejoin){ gl2ps->lastlinejoin = prim->linejoin; switch (prim->linejoin){ case GL2PS_LINE_JOIN_MITER: fprintf(gl2ps->stream, "\\pgfset%s\n", "miterjoin"); break; case GL2PS_LINE_JOIN_ROUND: fprintf(gl2ps->stream, "\\pgfset%s\n", "roundjoin"); break; case GL2PS_LINE_JOIN_BEVEL: fprintf(gl2ps->stream, "\\pgfset%s\n", "beveljoin"); break; } } gl2psPrintPGFColor(prim->verts[0].rgba); fprintf(gl2ps->stream, "\\pgfpathmoveto{\\pgfpoint{%fpt}{%fpt}}\n" "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n" "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n" "\\pgfpathclose\n" "\\pgfusepath{fill,stroke}\n", prim->verts[2].xyz[0], prim->verts[2].xyz[1], prim->verts[1].xyz[0], prim->verts[1].xyz[1], prim->verts[0].xyz[0], prim->verts[0].xyz[1]); break; case GL2PS_TEXT : fprintf(gl2ps->stream, "{\n\\pgftransformshift{\\pgfpoint{%fpt}{%fpt}}\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1]); if(prim->data.text->angle != 0.0) fprintf(gl2ps->stream, "\\pgftransformrotate{%f}{", prim->data.text->angle); fprintf(gl2ps->stream, "\\pgfnode{rectangle}{%s}{\\fontsize{%d}{0}\\selectfont", gl2psPGFTextAlignment(prim->data.text->alignment), prim->data.text->fontsize); fprintf(gl2ps->stream, "\\textcolor[rgb]{%g,%g,%g}{{%s}}", prim->verts[0].rgba[0], prim->verts[0].rgba[1], prim->verts[0].rgba[2], prim->data.text->str); fprintf(gl2ps->stream, "}{}{\\pgfusepath{discard}}"); if(prim->data.text->angle != 0.0) fprintf(gl2ps->stream, "}"); fprintf(gl2ps->stream, "\n}\n"); break; case GL2PS_SPECIAL : /* alignment contains the format for which the special output text is intended */ if (prim->data.text->alignment == GL2PS_PGF) fprintf(gl2ps->stream, "%s\n", prim->data.text->str); break; default : break; } } static void gl2psPrintPGFFooter(void) { fprintf(gl2ps->stream, "\\end{pgfpicture}\n"); } static void gl2psPrintPGFBeginViewport(GLint viewport[4]) { GLint idx; GLfloat rgba[4]; int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; glRenderMode(GL_FEEDBACK); gl2psResetLineProperties(); if(gl2ps->header){ gl2psPrintPGFHeader(); gl2ps->header = GL_FALSE; } fprintf(gl2ps->stream, "\\begin{pgfscope}\n"); if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){ glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba); } else{ glGetIntegerv(GL_INDEX_CLEAR_VALUE, &idx); rgba[0] = gl2ps->colormap[idx][0]; rgba[1] = gl2ps->colormap[idx][1]; rgba[2] = gl2ps->colormap[idx][2]; rgba[3] = 1.0F; } gl2psPrintPGFColor(rgba); fprintf(gl2ps->stream, "\\pgfpathrectangle{\\pgfpoint{%dpt}{%dpt}}" "{\\pgfpoint{%dpt}{%dpt}}\n" "\\pgfusepath{fill}\n", x, y, w, h); } fprintf(gl2ps->stream, "\\pgfpathrectangle{\\pgfpoint{%dpt}{%dpt}}" "{\\pgfpoint{%dpt}{%dpt}}\n" "\\pgfusepath{clip}\n", x, y, w, h); } static GLint gl2psPrintPGFEndViewport(void) { GLint res; res = gl2psPrintPrimitives(); fprintf(gl2ps->stream, "\\end{pgfscope}\n"); return res; } static void gl2psPrintPGFFinalPrimitive(void) { } /* definition of the PGF backend */ static GL2PSbackend gl2psPGF = { gl2psPrintPGFHeader, gl2psPrintPGFFooter, gl2psPrintPGFBeginViewport, gl2psPrintPGFEndViewport, gl2psPrintPGFPrimitive, gl2psPrintPGFFinalPrimitive, "tex", "PGF Latex Graphics" }; /********************************************************************* * * General primitive printing routine * *********************************************************************/ /* Warning: the ordering of the backends must match the format #defines in gl2ps.h */ static GL2PSbackend *gl2psbackends[] = { &gl2psPS, /* 0 */ &gl2psEPS, /* 1 */ &gl2psTEX, /* 2 */ &gl2psPDF, /* 3 */ &gl2psSVG, /* 4 */ &gl2psPGF /* 5 */ }; static void gl2psComputeTightBoundingBox(void *data) { GL2PSprimitive *prim; int i; prim = *(GL2PSprimitive**)data; for(i = 0; i < prim->numverts; i++){ if(prim->verts[i].xyz[0] < gl2ps->viewport[0]) gl2ps->viewport[0] = (GLint)prim->verts[i].xyz[0]; if(prim->verts[i].xyz[0] > gl2ps->viewport[2]) gl2ps->viewport[2] = (GLint)(prim->verts[i].xyz[0] + 0.5F); if(prim->verts[i].xyz[1] < gl2ps->viewport[1]) gl2ps->viewport[1] = (GLint)prim->verts[i].xyz[1]; if(prim->verts[i].xyz[1] > gl2ps->viewport[3]) gl2ps->viewport[3] = (GLint)(prim->verts[i].xyz[1] + 0.5F); } } static GLint gl2psPrintPrimitives(void) { GL2PSbsptree *root; GL2PSxyz eye = {0.0F, 0.0F, 100.0F * GL2PS_ZSCALE}; GLint used = 0; if ((gl2ps->options & GL2PS_NO_OPENGL_CONTEXT) == GL2PS_NONE) { used = glRenderMode(GL_RENDER); } if(used < 0){ gl2psMsg(GL2PS_INFO, "OpenGL feedback buffer overflow"); return GL2PS_OVERFLOW; } if(used > 0) gl2psParseFeedbackBuffer(used); gl2psRescaleAndOffset(); if(gl2ps->header){ if(gl2psListNbr(gl2ps->primitives) && (gl2ps->options & GL2PS_TIGHT_BOUNDING_BOX)){ gl2ps->viewport[0] = gl2ps->viewport[1] = 100000; gl2ps->viewport[2] = gl2ps->viewport[3] = -100000; gl2psListAction(gl2ps->primitives, gl2psComputeTightBoundingBox); } (gl2psbackends[gl2ps->format]->printHeader)(); gl2ps->header = GL_FALSE; } if(!gl2psListNbr(gl2ps->primitives)){ /* empty feedback buffer and/or nothing else to print */ return GL2PS_NO_FEEDBACK; } switch(gl2ps->sort){ case GL2PS_NO_SORT : gl2psListAction(gl2ps->primitives, gl2psbackends[gl2ps->format]->printPrimitive); gl2psListAction(gl2ps->primitives, gl2psFreePrimitive); /* reset the primitive list, waiting for the next viewport */ gl2psListReset(gl2ps->primitives); break; case GL2PS_SIMPLE_SORT : gl2psListAssignSortIds(gl2ps->primitives); gl2psListSort(gl2ps->primitives, gl2psCompareDepth); if(gl2ps->options & GL2PS_OCCLUSION_CULL){ gl2psListActionInverse(gl2ps->primitives, gl2psAddInImageTree); gl2psFreeBspImageTree(&gl2ps->imagetree); } gl2psListAction(gl2ps->primitives, gl2psbackends[gl2ps->format]->printPrimitive); gl2psListAction(gl2ps->primitives, gl2psFreePrimitive); /* reset the primitive list, waiting for the next viewport */ gl2psListReset(gl2ps->primitives); break; case GL2PS_BSP_SORT : root = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree)); gl2psBuildBspTree(root, gl2ps->primitives); if(GL_TRUE == gl2ps->boundary) gl2psBuildPolygonBoundary(root); if(gl2ps->options & GL2PS_OCCLUSION_CULL){ gl2psTraverseBspTree(root, eye, -GL2PS_EPSILON, gl2psLess, gl2psAddInImageTree, 1); gl2psFreeBspImageTree(&gl2ps->imagetree); } gl2psTraverseBspTree(root, eye, GL2PS_EPSILON, gl2psGreater, gl2psbackends[gl2ps->format]->printPrimitive, 0); gl2psFreeBspTree(&root); /* reallocate the primitive list (it's been deleted by gl2psBuildBspTree) in case there is another viewport */ gl2ps->primitives = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*)); break; } gl2psbackends[gl2ps->format]->printFinalPrimitive(); return GL2PS_SUCCESS; } static GLboolean gl2psCheckOptions(GLint options, GLint colormode) { if (options & GL2PS_NO_OPENGL_CONTEXT) { if (options & GL2PS_DRAW_BACKGROUND) { gl2psMsg(GL2PS_ERROR, "Options GL2PS_NO_OPENGL_CONTEXT and " "GL2PS_DRAW_BACKGROUND are incompatible."); return GL_FALSE; } if (options & GL2PS_USE_CURRENT_VIEWPORT) { gl2psMsg(GL2PS_ERROR, "Options GL2PS_NO_OPENGL_CONTEXT and " "GL2PS_USE_CURRENT_VIEWPORT are incompatible."); return GL_FALSE; } if ((options & GL2PS_NO_BLENDING) == GL2PS_NONE) { gl2psMsg(GL2PS_ERROR, "Option GL2PS_NO_OPENGL_CONTEXT requires " "option GL2PS_NO_BLENDING."); return GL_FALSE; } if (colormode != GL_RGBA) { gl2psMsg(GL2PS_ERROR, "Option GL2PS_NO_OPENGL_CONTEXT requires colormode " "to be GL_RGBA."); return GL_FALSE; } } return GL_TRUE; } /********************************************************************* * * Public routines * *********************************************************************/ GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, GLint viewport[4], GLint format, GLint sort, GLint options, GLint colormode, GLint colorsize, GL2PSrgba *colormap, GLint nr, GLint ng, GLint nb, GLint buffersize, FILE *stream, const char *filename) { GLint idx; int i; if(gl2ps){ gl2psMsg(GL2PS_ERROR, "gl2psBeginPage called in wrong program state"); return GL2PS_ERROR; } gl2ps = (GL2PScontext*)gl2psMalloc(sizeof(GL2PScontext)); /* Validate options */ if (gl2psCheckOptions(options, colormode) == GL_FALSE) { gl2psFree(gl2ps); gl2ps = NULL; return GL2PS_ERROR; } if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0]))){ gl2ps->format = format; } else { gl2psMsg(GL2PS_ERROR, "Unknown output format: %d", format); gl2psFree(gl2ps); gl2ps = NULL; return GL2PS_ERROR; } switch(sort){ case GL2PS_NO_SORT : case GL2PS_SIMPLE_SORT : case GL2PS_BSP_SORT : gl2ps->sort = sort; break; default : gl2psMsg(GL2PS_ERROR, "Unknown sorting algorithm: %d", sort); gl2psFree(gl2ps); gl2ps = NULL; return GL2PS_ERROR; } if(stream){ gl2ps->stream = stream; } else{ gl2psMsg(GL2PS_ERROR, "Bad file pointer"); gl2psFree(gl2ps); gl2ps = NULL; return GL2PS_ERROR; } gl2ps->header = GL_TRUE; gl2ps->forcerasterpos = GL_FALSE; gl2ps->maxbestroot = 10; gl2ps->options = options; gl2ps->compress = NULL; gl2ps->imagemap_head = NULL; gl2ps->imagemap_tail = NULL; if(gl2ps->options & GL2PS_USE_CURRENT_VIEWPORT){ glGetIntegerv(GL_VIEWPORT, gl2ps->viewport); } else{ for(i = 0; i < 4; i++){ gl2ps->viewport[i] = viewport[i]; } } if(!gl2ps->viewport[2] || !gl2ps->viewport[3]){ gl2psMsg(GL2PS_ERROR, "Incorrect viewport (x=%d, y=%d, width=%d, height=%d)", gl2ps->viewport[0], gl2ps->viewport[1], gl2ps->viewport[2], gl2ps->viewport[3]); gl2psFree(gl2ps); gl2ps = NULL; return GL2PS_ERROR; } gl2ps->threshold[0] = nr ? 1.0F / (GLfloat)nr : 0.064F; gl2ps->threshold[1] = ng ? 1.0F / (GLfloat)ng : 0.034F; gl2ps->threshold[2] = nb ? 1.0F / (GLfloat)nb : 0.100F; gl2ps->colormode = colormode; gl2ps->buffersize = buffersize > 0 ? buffersize : 2048 * 2048; for(i = 0; i < 3; i++){ gl2ps->lastvertex.xyz[i] = -1.0F; } for(i = 0; i < 4; i++){ gl2ps->lastvertex.rgba[i] = -1.0F; gl2ps->lastrgba[i] = -1.0F; } gl2ps->lastlinewidth = -1.0F; gl2ps->lastlinecap = 0; gl2ps->lastlinejoin = 0; gl2ps->lastpattern = 0; gl2ps->lastfactor = 0; gl2ps->imagetree = NULL; gl2ps->primitivetoadd = NULL; gl2ps->zerosurfacearea = GL_FALSE; gl2ps->pdfprimlist = NULL; gl2ps->pdfgrouplist = NULL; gl2ps->xreflist = NULL; /* get default blending mode from current OpenGL state (enabled by default for SVG) */ if ((gl2ps->options & GL2PS_NO_BLENDING) == GL2PS_NONE) { gl2ps->blending = (gl2ps->format == GL2PS_SVG) ? GL_TRUE : glIsEnabled(GL_BLEND); glGetIntegerv(GL_BLEND_SRC, &gl2ps->blendfunc[0]); glGetIntegerv(GL_BLEND_DST, &gl2ps->blendfunc[1]); } else { gl2ps->blending = GL_FALSE; } if(gl2ps->colormode == GL_RGBA){ gl2ps->colorsize = 0; gl2ps->colormap = NULL; if ((gl2ps->options & GL2PS_NO_OPENGL_CONTEXT) == GL2PS_NONE) { glGetFloatv(GL_COLOR_CLEAR_VALUE, gl2ps->bgcolor); } } else if(gl2ps->colormode == GL_COLOR_INDEX){ if(!colorsize || !colormap){ gl2psMsg(GL2PS_ERROR, "Missing colormap for GL_COLOR_INDEX rendering"); gl2psFree(gl2ps); gl2ps = NULL; return GL2PS_ERROR; } gl2ps->colorsize = colorsize; gl2ps->colormap = (GL2PSrgba*)gl2psMalloc(gl2ps->colorsize * sizeof(GL2PSrgba)); memcpy(gl2ps->colormap, colormap, gl2ps->colorsize * sizeof(GL2PSrgba)); glGetIntegerv(GL_INDEX_CLEAR_VALUE, &idx); gl2ps->bgcolor[0] = gl2ps->colormap[idx][0]; gl2ps->bgcolor[1] = gl2ps->colormap[idx][1]; gl2ps->bgcolor[2] = gl2ps->colormap[idx][2]; gl2ps->bgcolor[3] = 1.0F; } else{ gl2psMsg(GL2PS_ERROR, "Unknown color mode in gl2psBeginPage"); gl2psFree(gl2ps); gl2ps = NULL; return GL2PS_ERROR; } if(!title){ gl2ps->title = (char*)gl2psMalloc(sizeof(char)); gl2ps->title[0] = '\0'; } else{ gl2ps->title = (char*)gl2psMalloc((strlen(title)+1)*sizeof(char)); strcpy(gl2ps->title, title); } if(!producer){ gl2ps->producer = (char*)gl2psMalloc(sizeof(char)); gl2ps->producer[0] = '\0'; } else{ gl2ps->producer = (char*)gl2psMalloc((strlen(producer)+1)*sizeof(char)); strcpy(gl2ps->producer, producer); } if(!filename){ gl2ps->filename = (char*)gl2psMalloc(sizeof(char)); gl2ps->filename[0] = '\0'; } else{ gl2ps->filename = (char*)gl2psMalloc((strlen(filename)+1)*sizeof(char)); strcpy(gl2ps->filename, filename); } gl2ps->primitives = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*)); gl2ps->auxprimitives = gl2psListCreate(100, 100, sizeof(GL2PSprimitive*)); if ((gl2ps->options & GL2PS_NO_OPENGL_CONTEXT) == GL2PS_NONE) { gl2ps->feedback = (GLfloat*)gl2psMalloc(gl2ps->buffersize * sizeof(GLfloat)); glFeedbackBuffer(gl2ps->buffersize, GL_3D_COLOR, gl2ps->feedback); glRenderMode(GL_FEEDBACK); } else { gl2ps->feedback = NULL; gl2ps->buffersize = 0; } gl2ps->tex_scaling = 1.; return GL2PS_SUCCESS; } GL2PSDLL_API GLint gl2psEndPage(void) { GLint res; if(!gl2ps) return GL2PS_UNINITIALIZED; res = gl2psPrintPrimitives(); if(res != GL2PS_OVERFLOW) (gl2psbackends[gl2ps->format]->printFooter)(); fflush(gl2ps->stream); gl2psListDelete(gl2ps->primitives); gl2psListDelete(gl2ps->auxprimitives); gl2psFreeImagemap(gl2ps->imagemap_head); gl2psFree(gl2ps->colormap); gl2psFree(gl2ps->title); gl2psFree(gl2ps->producer); gl2psFree(gl2ps->filename); gl2psFree(gl2ps->feedback); gl2psFree(gl2ps); gl2ps = NULL; return res; } GL2PSDLL_API GLint gl2psBeginViewport(GLint viewport[4]) { if(!gl2ps) return GL2PS_UNINITIALIZED; (gl2psbackends[gl2ps->format]->beginViewport)(viewport); return GL2PS_SUCCESS; } GL2PSDLL_API GLint gl2psEndViewport(void) { GLint res; if(!gl2ps) return GL2PS_UNINITIALIZED; res = (gl2psbackends[gl2ps->format]->endViewport)(); /* reset last used colors, line widths */ gl2psResetLineProperties(); return res; } GL2PSDLL_API GLint gl2psSorting(GLint mode) { GLint res; if(!gl2ps) return GL2PS_UNINITIALIZED; switch(mode){ case GL2PS_NO_SORT : case GL2PS_SIMPLE_SORT : case GL2PS_BSP_SORT : gl2ps->sort = mode; res = GL2PS_SUCCESS; break; default : gl2psMsg(GL2PS_ERROR, "Unknown sorting algorithm: %d", mode); gl2psFree(gl2ps); gl2ps = NULL; res = GL2PS_ERROR; } return res; } GL2PSDLL_API GLint gl2psTextOptColor(const char *str, const char *fontname, GLshort fontsize, GLint alignment, GLfloat angle, GL2PSrgba color) { return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, alignment, angle, color, GL_FALSE, 0, 0); } /** * This version of gl2psTextOptColor is used to go around the * fact that PDF does not support text alignment. The extra parameters * (blx, bly) represent the bottom left corner of the text bounding box. */ GL2PSDLL_API GLint gl2psTextOptColorBL(const char *str, const char *fontname, GLshort fontsize, GLint alignment, GLfloat angle, GL2PSrgba color, GLfloat blx, GLfloat bly) { return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, alignment, angle, color, GL_TRUE, blx, bly); } GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, GLshort fontsize, GLint alignment, GLfloat angle) { return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, alignment, angle, NULL, GL_FALSE, 0, 0); } GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, GLshort fontsize) { return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, GL2PS_TEXT_BL, 0.0F, NULL, GL_FALSE, 0, 0); } GL2PSDLL_API GLint gl2psSpecial(GLint format, const char *str) { return gl2psAddText(GL2PS_SPECIAL, str, "", 0, format, 0.0F, NULL, GL_FALSE, 0, 0); } GL2PSDLL_API GLint gl2psSpecialColor(GLint format, const char *str, GL2PSrgba rgba) { return gl2psAddText(GL2PS_SPECIAL, str, "", 0, format, 0.0F, rgba, GL_FALSE, 0, 0); } GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height, GLint xorig, GLint yorig, GLenum format, GLenum type, const void *pixels) { int size, i; const GLfloat *piv; GLfloat pos[4], zoom_x, zoom_y; GL2PSprimitive *prim; GLboolean valid; if(!gl2ps || !pixels) return GL2PS_UNINITIALIZED; if((width <= 0) || (height <= 0)) return GL2PS_ERROR; if(gl2ps->options & GL2PS_NO_PIXMAP) return GL2PS_SUCCESS; if((format != GL_RGB && format != GL_RGBA) || type != GL_FLOAT){ gl2psMsg(GL2PS_ERROR, "gl2psDrawPixels only implemented for " "GL_RGB/GL_RGBA, GL_FLOAT pixels"); return GL2PS_ERROR; } if (gl2ps->forcerasterpos) { pos[0] = gl2ps->rasterpos.xyz[0]; pos[1] = gl2ps->rasterpos.xyz[1]; pos[2] = gl2ps->rasterpos.xyz[2]; pos[3] = 1.f; /* Hardcode zoom factors (for now?) */ zoom_x = 1.f; zoom_y = 1.f; } else { glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid); if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */ glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); glGetFloatv(GL_ZOOM_X, &zoom_x); glGetFloatv(GL_ZOOM_Y, &zoom_y); } prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); prim->type = GL2PS_PIXMAP; prim->boundary = 0; prim->numverts = 1; prim->verts = (GL2PSvertex*)gl2psMalloc(sizeof(GL2PSvertex)); prim->verts[0].xyz[0] = pos[0] + xorig; prim->verts[0].xyz[1] = pos[1] + yorig; prim->verts[0].xyz[2] = pos[2]; prim->culled = 0; prim->offset = 0; prim->ofactor = 0.0; prim->ounits = 0.0; prim->pattern = 0; prim->factor = 0; prim->width = 1; if (gl2ps->forcerasterpos) { prim->verts[0].rgba[0] = gl2ps->rasterpos.rgba[0]; prim->verts[0].rgba[1] = gl2ps->rasterpos.rgba[1]; prim->verts[0].rgba[2] = gl2ps->rasterpos.rgba[2]; prim->verts[0].rgba[3] = gl2ps->rasterpos.rgba[3]; } else { glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba); } prim->data.image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage)); prim->data.image->width = width; prim->data.image->height = height; prim->data.image->zoom_x = zoom_x; prim->data.image->zoom_y = zoom_y; prim->data.image->format = format; prim->data.image->type = type; gl2ps->forcerasterpos = GL_FALSE; switch(format){ case GL_RGBA: if(gl2ps->options & GL2PS_NO_BLENDING || !gl2ps->blending){ /* special case: blending turned off */ prim->data.image->format = GL_RGB; size = height * width * 3; prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat)); piv = (const GLfloat*)pixels; for(i = 0; i < size; ++i, ++piv){ prim->data.image->pixels[i] = *piv; if(!((i + 1) % 3)) ++piv; } } else{ size = height * width * 4; prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat)); memcpy(prim->data.image->pixels, pixels, size * sizeof(GLfloat)); } break; case GL_RGB: default: size = height * width * 3; prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat)); memcpy(prim->data.image->pixels, pixels, size * sizeof(GLfloat)); break; } /* If no OpenGL context, just add directly to primitives */ if ((gl2ps->options & GL2PS_NO_OPENGL_CONTEXT) == GL2PS_NONE) { gl2psListAdd(gl2ps->auxprimitives, &prim); glPassThrough(GL2PS_DRAW_PIXELS_TOKEN); } else { gl2psListAdd(gl2ps->primitives, &prim); } return GL2PS_SUCCESS; } GL2PSDLL_API GLint gl2psDrawImageMap(GLsizei width, GLsizei height, const GLfloat position[3], const unsigned char *imagemap){ int size, i; int sizeoffloat = sizeof(GLfloat); if(!gl2ps || !imagemap) return GL2PS_UNINITIALIZED; if((width <= 0) || (height <= 0)) return GL2PS_ERROR; size = height + height * ((width - 1) / 8); glPassThrough(GL2PS_IMAGEMAP_TOKEN); glBegin(GL_POINTS); glVertex3f(position[0], position[1],position[2]); glEnd(); glPassThrough((GLfloat)width); glPassThrough((GLfloat)height); for(i = 0; i < size; i += sizeoffloat){ const float *value = (const float*)imagemap; glPassThrough(*value); imagemap += sizeoffloat; } return GL2PS_SUCCESS; } GL2PSDLL_API GLint gl2psEnable(GLint mode) { GLint tmp; GLfloat tmp2; if(!gl2ps) return GL2PS_UNINITIALIZED; switch(mode){ case GL2PS_POLYGON_OFFSET_FILL : glPassThrough(GL2PS_BEGIN_OFFSET_TOKEN); glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &tmp2); glPassThrough(tmp2); glGetFloatv(GL_POLYGON_OFFSET_UNITS, &tmp2); glPassThrough(tmp2); break; case GL2PS_POLYGON_BOUNDARY : glPassThrough(GL2PS_BEGIN_BOUNDARY_TOKEN); break; case GL2PS_LINE_STIPPLE : glPassThrough(GL2PS_BEGIN_STIPPLE_TOKEN); glGetIntegerv(GL_LINE_STIPPLE_PATTERN, &tmp); glPassThrough((GLfloat)tmp); glGetIntegerv(GL_LINE_STIPPLE_REPEAT, &tmp); glPassThrough((GLfloat)tmp); break; case GL2PS_BLEND : glPassThrough(GL2PS_BEGIN_BLEND_TOKEN); break; default : gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psEnable: %d", mode); return GL2PS_WARNING; } return GL2PS_SUCCESS; } GL2PSDLL_API GLint gl2psDisable(GLint mode) { if(!gl2ps) return GL2PS_UNINITIALIZED; switch(mode){ case GL2PS_POLYGON_OFFSET_FILL : glPassThrough(GL2PS_END_OFFSET_TOKEN); break; case GL2PS_POLYGON_BOUNDARY : glPassThrough(GL2PS_END_BOUNDARY_TOKEN); break; case GL2PS_LINE_STIPPLE : glPassThrough(GL2PS_END_STIPPLE_TOKEN); break; case GL2PS_BLEND : glPassThrough(GL2PS_END_BLEND_TOKEN); break; default : gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psDisable: %d", mode); return GL2PS_WARNING; } return GL2PS_SUCCESS; } GL2PSDLL_API GLint gl2psPointSize(GLfloat value) { if(!gl2ps) return GL2PS_UNINITIALIZED; glPassThrough(GL2PS_POINT_SIZE_TOKEN); glPassThrough(value); return GL2PS_SUCCESS; } GL2PSDLL_API GLint gl2psLineCap(GLint value) { if(!gl2ps) return GL2PS_UNINITIALIZED; glPassThrough(GL2PS_LINE_CAP_TOKEN); glPassThrough(value); return GL2PS_SUCCESS; } GL2PSDLL_API GLint gl2psLineJoin(GLint value) { if(!gl2ps) return GL2PS_UNINITIALIZED; glPassThrough(GL2PS_LINE_JOIN_TOKEN); glPassThrough(value); return GL2PS_SUCCESS; } GL2PSDLL_API GLint gl2psLineWidth(GLfloat value) { if(!gl2ps) return GL2PS_UNINITIALIZED; glPassThrough(GL2PS_LINE_WIDTH_TOKEN); glPassThrough(value); return GL2PS_SUCCESS; } GL2PSDLL_API GLint gl2psBlendFunc(GLenum sfactor, GLenum dfactor) { if(!gl2ps) return GL2PS_UNINITIALIZED; if(GL_FALSE == gl2psSupportedBlendMode(sfactor, dfactor)) return GL2PS_WARNING; glPassThrough(GL2PS_SRC_BLEND_TOKEN); glPassThrough((GLfloat)sfactor); glPassThrough(GL2PS_DST_BLEND_TOKEN); glPassThrough((GLfloat)dfactor); return GL2PS_SUCCESS; } GL2PSDLL_API GLint gl2psSetOptions(GLint options) { if(!gl2ps) return GL2PS_UNINITIALIZED; if(gl2psCheckOptions(options, gl2ps->colormode) == GL_FALSE) { return GL2PS_ERROR; } gl2ps->options = options; return GL2PS_SUCCESS; } GL2PSDLL_API GLint gl2psGetOptions(GLint *options) { if(!gl2ps) { *options = 0; return GL2PS_UNINITIALIZED; } *options = gl2ps->options; return GL2PS_SUCCESS; } GL2PSDLL_API const char *gl2psGetFileExtension(GLint format) { if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0]))) return gl2psbackends[format]->file_extension; else return "Unknown format"; } GL2PSDLL_API const char *gl2psGetFormatDescription(GLint format) { if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0]))) return gl2psbackends[format]->description; else return "Unknown format"; } GL2PSDLL_API GLint gl2psGetFileFormat(void) { if(!gl2ps) { return GL2PS_UNINITIALIZED; } return gl2ps->format; } GL2PSDLL_API GLint gl2psForceRasterPos(GL2PSvertex *vert) { if(!gl2ps) { return GL2PS_UNINITIALIZED; } gl2ps->forcerasterpos = GL_TRUE; gl2ps->rasterpos.xyz[0] = vert->xyz[0]; gl2ps->rasterpos.xyz[1] = vert->xyz[1]; gl2ps->rasterpos.xyz[2] = vert->xyz[2]; gl2ps->rasterpos.rgba[0] = vert->rgba[0]; gl2ps->rasterpos.rgba[1] = vert->rgba[1]; gl2ps->rasterpos.rgba[2] = vert->rgba[2]; gl2ps->rasterpos.rgba[3] = vert->rgba[3]; return GL2PS_SUCCESS; } GL2PSDLL_API GLint gl2psSetTexScaling(GLfloat scaling) { if(!gl2ps) { return GL2PS_UNINITIALIZED; } gl2ps->tex_scaling = scaling; return GL2PS_SUCCESS; } #endif rgl/src/Viewpoint.h0000644000176200001440000000451114771520323013767 0ustar liggesusers#ifndef VIEWPOINT_H #define VIEWPOINT_H #include "SceneNode.h" #include "render.h" #include "geom.h" namespace rgl { class ModelViewpoint : public SceneNode { #define VIEWPOINT_MAX_ZOOM 10 public: ModelViewpoint(PolarCoord position=PolarCoord(0.0f,15.0f), Vec3 in_scale=Vec3(1.0f, 1.0f, 1.0f), bool interactive=true); ModelViewpoint(double* userMatrix, Vec3 in_scale=Vec3(1.0f, 1.0f, 1.0f), bool interactive=true); PolarCoord& getPosition(); void setPosition(const PolarCoord& position); void clearMouseMatrix(); void setupTransformation(RenderContext* rctx); void setupOrientation(RenderContext* rctx) const; bool isInteractive() const; void updateMouseMatrix(Vertex dragStart,Vertex dragCurrent); void updateMouseMatrix(PolarCoord newpos); void mouseOneAxis(Vertex dragStart,Vertex dragCurrent,Vertex axis); void mergeMouseMatrix(); void getUserMatrix(double* dest); void setUserMatrix(double* src); void getScale(double* dest); void setScale(double* src); void getPosition(double* dest); void setPosition(double* src); virtual std::string getTypeName() { return "modelviewpoint"; }; Vertex scale; bool scaleChanged; private: PolarCoord position; bool interactive; public: GLdouble userMatrix[16], mouseMatrix[16]; }; class UserViewpoint : public SceneNode { #define VIEWPOINT_MAX_ZOOM 10 public: UserViewpoint(float fov=90.0f, float zoom=1.0f); float getZoom(void) const; void setZoom(const float zoom); float getFOV(void) const; void setFOV(const float in_fov); void setupFrustum(RenderContext* rctx, const Sphere& viewvolumeSphere); void setupProjMatrix(RenderContext* rctx, const Sphere& viewvolumeSphere); Vertex getObserver(); void setObserver(bool automatic, Vertex in_eye); void setupViewer(RenderContext* rctx); virtual std::string getTypeName() { return "userviewpoint"; }; Frustum frustum; void getUserProjection(double* dest); void setUserProjection(double* src); void clearUserProjection(); private: float fov; float zoom; bool viewerInScene; Vertex eye; Matrix4x4 userProjection; }; } // namespace rgl #endif // VIEWPOINT_H rgl/src/R.h0000644000176200001440000000221115011677075012204 0ustar liggesusers#ifndef RGL_R_H #define RGL_R_H // This define avoids a warning about ERROR redefinition in Windows #define STRICT_R_HEADERS #include #include /* Default for antialiasing */ #define RGL_ANTIALIAS 8 /* Set this to 1 to turn on glGetError testing */ #define USE_GLGETERROR 0 #define NA_FLOAT static_cast(NA_REAL) namespace rgl { #if USE_GLGETERROR #define SAVEGLERROR saveGLerror(__FILE__, __LINE__); #define CHECKGLERROR checkGLerror(__FILE__, __LINE__); /* saveGLerror is safe to call from a message handler. It saves one error. */ /* checkGLerror is not safe within a message handler. It checks for saved errors or */ /* other errors, then reports them through R. */ /* Neither one can be called with glBegin() ... glEnd() pairs. */ /* They are defined in glErrors.cpp */ extern int SaveErrnum; void saveGLerror(const char *, int); void checkGLerror(const char *, int); #else #define SAVEGLERROR #define CHECKGLERROR #endif char* copyStringToR(std::string s); } // namespace rgl #endif /* RGL_R_H */ rgl/src/init.cpp0000644000176200001440000002343515011677075013314 0ustar liggesusers#include #include #include "lib.h" #include "DeviceManager.h" /* libfreetype 2.6 defines a conflicting TYPEOF macro */ #ifdef TYPEOF # undef TYPEOF #endif #include #include #include "R.h" #include "init.h" #include "api.h" using namespace rgl; // // FUNCTION // rgl_init // // // GLOBAL: deviceManager pointer // namespace rgl{ DeviceManager* deviceManager = NULL; int gInitValue; void* gHandle; SEXP rglNamespace; bool rglDebug; // // FUNCTION // rgl_init // // PARAMETERS // ioptions - platform-specific options. // Windows: // [0] multiple-document-interface console handle (MDI) // or 0 (SDI) // MacOSX: // [0] Formerly indicator of presence (1) or absence (0) of Carbon/Cocoa, now unused // #ifdef __cplusplus extern "C" { #endif SEXP rgl_init(SEXP initValue, SEXP useNULL, SEXP in_namespace, SEXP debug) { int success = 0; bool useNULLDevice = Rf_asLogical(useNULL); gInitValue = 0; gHandle = NULL; rglNamespace = in_namespace; rglDebug = Rf_asLogical(debug); if ( Rf_isNumeric(initValue) ) { gInitValue = Rf_asInteger(initValue); } else if ( TYPEOF(initValue) == EXTPTRSXP ) { gHandle = R_ExternalPtrAddr(initValue); } else if ( !Rf_isNull(initValue) ) { return Rf_ScalarInteger( 0 ); } /* Some systems write useless messages to stderr. We'll * hide those */ int stderr_copy = STDERR_FILENO, /* suppress "maybe undefined" warning */ devNull = -1; if (!rglDebug) { #if defined(_WIN32) || defined(windows) || defined(RGL_W32) devNull = open("nul", O_WRONLY); #endif if (devNull == -1) devNull = open("/dev/null", O_WRONLY); if (devNull != -1) { R_FlushConsole(); stderr_copy = dup(STDERR_FILENO); dup2(devNull, STDERR_FILENO); } } if ( init(useNULLDevice) ) { deviceManager = new DeviceManager(useNULLDevice); } if ( deviceManager && (useNULLDevice || deviceManager->createTestWindow())) success = 1; /* Restore STDERR */ if (devNull != -1) { dup2(stderr_copy, STDERR_FILENO); close(stderr_copy); } return(Rf_ScalarInteger(success)); } #define FUNDEF(name, n) {#name, (DL_FUNC) &name, n} #undef CHECK_ARGS #ifdef CHECK_ARGS R_NativePrimitiveArgType aI[1] = {INTSXP}; R_NativePrimitiveArgType aL[1] = {LGLSXP}; R_NativePrimitiveArgType aII[2] = {INTSXP, INTSXP}; R_NativePrimitiveArgType aLI[2] = {LGLSXP, INTSXP}; R_NativePrimitiveArgType aLL[2] = {LGLSXP, LGLSXP}; R_NativePrimitiveArgType aIII[3] = {INTSXP, INTSXP, INTSXP}; R_NativePrimitiveArgType aIIS[3] = {INTSXP, INTSXP, STRSXP}; R_NativePrimitiveArgType aIID[3] = {INTSXP, INTSXP, REALSXP}; R_NativePrimitiveArgType aLII[3] = {LGLSXP, INTSXP, INTSXP}; R_NativePrimitiveArgType aLIS[3] = {LGLSXP, INTSXP, STRSXP}; R_NativePrimitiveArgType aLID[3] = {LGLSXP, INTSXP, REALSXP}; R_NativePrimitiveArgType aLLI[3] = {LGLSXP, LGLSXP, INTSXP}; R_NativePrimitiveArgType aIIDD[4] = {INTSXP, INTSXP, REALSXP, REALSXP}; R_NativePrimitiveArgType aLISD[4] = {LGLSXP, INTSXP, STRSXP, REALSXP}; R_NativePrimitiveArgType aIISI[4] = {INTSXP, INTSXP, STRSXP, INTSXP}; R_NativePrimitiveArgType aLIDD[4] = {LGLSXP, INTSXP, REALSXP, REALSXP}; R_NativePrimitiveArgType aIIIID[5] = {INTSXP, INTSXP, INTSXP, INTSXP, REALSXP}; R_NativePrimitiveArgType aIIIIS[5] = {INTSXP, INTSXP, INTSXP, INTSXP, STRSXP}; R_NativePrimitiveArgType aLIIIS[5] = {LGLSXP, INTSXP, INTSXP, INTSXP, STRSXP}; R_NativePrimitiveArgType aLIIID[5] = {LGLSXP, INTSXP, INTSXP, INTSXP, REALSXP}; R_NativePrimitiveArgType aLIISD[5] = {LGLSXP, INTSXP, INTSXP, STRSXP, REALSXP}; R_NativePrimitiveArgType aLIIDS[5] = {LGLSXP, INTSXP, INTSXP, REALSXP, STRSXP}; R_NativePrimitiveArgType aLIIIF[5] = {LGLSXP, INTSXP, INTSXP, INTSXP, SINGLESXP}; R_NativePrimitiveArgType aLIDDD[5] = {LGLSXP, INTSXP, REALSXP, REALSXP, REALSXP}; R_NativePrimitiveArgType aIIDDD[5] = {INTSXP, INTSXP, REALSXP, REALSXP, REALSXP}; R_NativePrimitiveArgType aIIDDID[6] = {INTSXP, INTSXP, REALSXP, REALSXP, INTSXP, REALSXP}; R_NativePrimitiveArgType aLIDDDDI[7] = {LGLSXP, INTSXP, REALSXP, REALSXP, REALSXP, REALSXP, INTSXP}; R_NativePrimitiveArgType aLIDDSDSDS[9] = {LGLSXP, INTSXP, REALSXP, REALSXP, STRSXP, REALSXP, STRSXP, REALSXP, STRSXP}; R_NativePrimitiveArgType aIIDSDISIDI[10] = {INTSXP, INTSXP, REALSXP, STRSXP, REALSXP, INTSXP, STRSXP, INTSXP, REALSXP, INTSXP}; R_NativePrimitiveArgType aIIDDDDDDDDIII[13] = {INTSXP, INTSXP, REALSXP, REALSXP, REALSXP, REALSXP, REALSXP, REALSXP, REALSXP, REALSXP, INTSXP, INTSXP, INTSXP}; static const R_CMethodDef CEntries[] = { {"rgl_dev_open", (DL_FUNC) &rgl_dev_open, 3, aLLI}, {"rgl_dev_close", (DL_FUNC) &rgl_dev_close, 1, aL}, {"rgl_dev_setcurrent", (DL_FUNC) &rgl_dev_setcurrent, 2, aLI}, {"rgl_snapshot", (DL_FUNC) &rgl_snapshot, 3, aLIS}, {"rgl_postscript", (DL_FUNC) &rgl_postscript, 3, aLIS}, {"rgl_material", (DL_FUNC) &rgl_material, 4, aLISD}, {"rgl_getmaterial", (DL_FUNC) &rgl_getmaterial, 5, aLIISD}, {"rgl_getcolorcount", (DL_FUNC) &rgl_getcolorcount, 1, aI}, {"rgl_dev_bringtotop", (DL_FUNC) &rgl_dev_bringtotop, 2, aLL}, {"rgl_clear", (DL_FUNC) &rgl_clear, 2, aLI}, {"rgl_pop", (DL_FUNC) &rgl_pop, 2, aLI}, {"rgl_id_count", (DL_FUNC) &rgl_id_count, 3, aIII}, {"rgl_ids", (DL_FUNC) &rgl_ids, 4, aIISI}, {"rgl_viewpoint", (DL_FUNC) &rgl_viewpoint, 3, aLID}, {"rgl_getObserver", (DL_FUNC) &rgl_getObserver, 2, aID}, {"rgl_setObserver", (DL_FUNC) &rgl_setObserver, 2, aID}, {"rgl_attrib_count", (DL_FUNC) &rgl_attrib_count, 3, aIII}, {"rgl_attrib", (DL_FUNC) &rgl_attrib, 5, aIIIID}, {"rgl_text_attrib", (DL_FUNC) &rgl_text_attrib, 5, aIIIIS}, {"rgl_bg", (DL_FUNC) &rgl_bg, 3, aLID}, {"rgl_bbox", (DL_FUNC) &rgl_bbox, 9, aLIDDSDSDS}, {"rgl_light", (DL_FUNC) &rgl_light, 3, aIID}, {"rgl_pixels", (DL_FUNC) &rgl_pixels, 5, aLIIIF}, {"rgl_planes", (DL_FUNC) &rgl_planes, 4, aIIDD}, {"rgl_clipplanes", (DL_FUNC) &rgl_planes, 4, aIIDD}, {"rgl_abclines", (DL_FUNC) &rgl_abclines, 4, aIIDD}, {"rgl_surface", (DL_FUNC) &rgl_surface, 13, aIIDDDDDDDDIII}, {"rgl_spheres", (DL_FUNC) &rgl_spheres, 5, aIIDDI}, {"rgl_texts", (DL_FUNC) &rgl_texts, 12, aIIDSDISIDIII}, {"rgl_sprites", (DL_FUNC) &rgl_sprites, 9, aIIDDIDDID}, {"rgl_newsubscene", (DL_FUNC) &rgl_newsubscene, 4, aIIII}, {"rgl_setsubscene", (DL_FUNC) &rgl_setsubscene, 1, aI}, {"rgl_getsubsceneid", (DL_FUNC) &rgl_getsubsceneid, 2, aII}, {"rgl_getsubsceneparent", (DL_FUNC) &rgl_getsubsceneparent, 1, aI}, {"rgl_getsubscenechildcount",(DL_FUNC) &rgl_getsubscenechildcount, 2, aII}, {"rgl_getsubscenechildren", (DL_FUNC) &rgl_getsubscenechildren, 2, aII}, {"rgl_gc", (DL_FUNC) &rgl_gc, 2, aII}, {"rgl_setEmbeddings", (DL_FUNC) &rgl_setEmbeddings, 2, aII}, {"rgl_getEmbeddings", (DL_FUNC) &rgl_getEmbeddings, 2, aII}, {"rgl_addtosubscene", (DL_FUNC) &rgl_addtosubscene, 3, aIII}, {"rgl_delfromsubscene", (DL_FUNC) &rgl_delfromsubscene, 3, aIII}, {"rgl_selectstate", (DL_FUNC) &rgl_selectstate, 5, aIILID}, {"rgl_setselectstate", (DL_FUNC) &rgl_setselectstate, 4, aIILI}, {"rgl_quit", (DL_FUNC) &rgl_quit, 1, aL}, {"rgl_incrementID", (DL_FUNC) &rgl_incrementID, 1, aI}, {NULL, NULL, 0} }; #else // don't CHECK_ARGS static const R_CMethodDef CEntries[] = { FUNDEF(rgl_dev_open, 3), FUNDEF(rgl_dev_close, 1), FUNDEF(rgl_dev_setcurrent, 2), FUNDEF(rgl_snapshot, 3), FUNDEF(rgl_postscript, 3), FUNDEF(rgl_material, 4), FUNDEF(rgl_getmaterial, 5), FUNDEF(rgl_getcolorcount, 1), FUNDEF(rgl_dev_bringtotop, 2), FUNDEF(rgl_clear, 2), FUNDEF(rgl_pop, 2), FUNDEF(rgl_id_count, 3), FUNDEF(rgl_ids, 4), FUNDEF(rgl_viewpoint, 3), FUNDEF(rgl_getObserver, 2), FUNDEF(rgl_setObserver, 2), FUNDEF(rgl_attrib_count, 3), FUNDEF(rgl_attrib, 5), FUNDEF(rgl_text_attrib, 5), FUNDEF(rgl_bg, 3), FUNDEF(rgl_bbox, 9), FUNDEF(rgl_light, 3), FUNDEF(rgl_pixels, 5), FUNDEF(rgl_planes, 4), FUNDEF(rgl_clipplanes, 4), FUNDEF(rgl_abclines, 4), FUNDEF(rgl_surface, 13), FUNDEF(rgl_spheres, 5), FUNDEF(rgl_texts, 12), FUNDEF(rgl_sprites, 9), FUNDEF(rgl_newsubscene, 4), FUNDEF(rgl_setsubscene, 1), FUNDEF(rgl_getsubsceneid, 2), FUNDEF(rgl_getsubsceneparent, 1), FUNDEF(rgl_getsubscenechildcount, 2), FUNDEF(rgl_getsubscenechildren, 2), FUNDEF(rgl_gc, 2), FUNDEF(rgl_setEmbeddings, 2), FUNDEF(rgl_getEmbeddings, 2), FUNDEF(rgl_addtosubscene, 3), FUNDEF(rgl_delfromsubscene, 3), FUNDEF(rgl_selectstate, 5), FUNDEF(rgl_setselectstate, 4), FUNDEF(rgl_quit, 1), FUNDEF(rgl_incrementID, 1), {NULL, NULL, 0} }; #endif // CHECK_ARGS static const R_CallMethodDef CallEntries[] = { FUNDEF(rgl_init, 4), FUNDEF(rgl_dev_getcurrent, 0), FUNDEF(rgl_dev_list, 0), FUNDEF(rgl_earcut, 2), FUNDEF(rgl_par3d, 3), FUNDEF(rgl_setMouseCallbacks, 6), FUNDEF(rgl_setWheelCallback, 3), FUNDEF(rgl_setAxisCallback, 4), FUNDEF(rgl_getMouseCallbacks, 3), FUNDEF(rgl_getWheelCallback, 2), FUNDEF(rgl_getAxisCallback, 3), FUNDEF(rgl_primitive, 4), {NULL, NULL, 0} }; static const R_ExternalMethodDef ExtEntries[] = { {NULL, NULL, 0} }; void attribute_visible R_init_rgl(DllInfo *dll) { R_registerRoutines(dll, CEntries, CallEntries, NULL, ExtEntries); R_useDynamicSymbols(dll, FALSE); R_forceSymbols(dll, TRUE); } #ifdef __cplusplus } #endif // --------------------------------------------------------------------------- } // namespace rgl // --------------------------------------------------------------------------- rgl/src/NULLgui.cpp0000644000176200001440000000755315011677075013633 0ustar liggesusers #include #include "config.h" // C++ source // This file is part of RGL. // #include "NULLgui.h" #include "lib.h" #include "glgui.h" #include "assert.h" #include "R.h" #include // --------------------------------------------------------------------------- namespace rgl { class NULLWindowImpl : public WindowImpl { public: NULLWindowImpl(Window* in_window); ~NULLWindowImpl(); void setTitle(const char* title) {}; void setWindowRect(int left, int top, int right, int bottom); void getWindowRect(int *left, int *top, int *right, int *bottom); void show() {}; void hide() {}; void bringToTop(int stay) {}; void update() { if (window && !window->skipRedraw) window->paint(); }; void destroy() { delete this; } void captureMouse(View* pView) {}; void releaseMouse() {}; void watchMouse(bool withoutButton) {}; GLFont* getFont(const char* family, int style, double cex, bool useFreeType); int getAntialias() { return 8; } int getMaxClipPlanes() { return INT_MAX; } private: int rect[4]; friend class NULLGUIFactory; public: bool beginGL() { return false; }; void endGL() {}; void swap() {}; }; } // namespace rgl using namespace rgl; // ---------------------------------------------------------------------------- // constructor // ---------------------------------------------------------------------------- NULLWindowImpl::NULLWindowImpl(Window* in_window) : WindowImpl(in_window) { setWindowRect(0, 0, 256, 256); fonts[0] = new NULLFont("sans", 1, 1.0, true); } NULLWindowImpl::~NULLWindowImpl() { if (window) window->notifyDestroy(); } void NULLWindowImpl::setWindowRect(int left, int top, int right, int bottom) { rect[0] = left; rect[1] = top; rect[2] = right; rect[3] = bottom; window->resize(right-left, bottom-top); } void NULLWindowImpl::getWindowRect(int *left, int *top, int *right, int *bottom) { *left = rect[0]; *top = rect[1]; *right = rect[2]; *bottom = rect[3]; } GLFont* NULLWindowImpl::getFont(const char* family, int style, double cex, bool useFreeType) { for (unsigned int i=0; i < fonts.size(); i++) { if (fonts[i]->cex == cex && fonts[i]->style == style && !strcmp(fonts[i]->family, family) && fonts[i]->useFreeType == useFreeType) return fonts[i]; } GLFont* font = new NULLFont(family, style, cex, useFreeType); fonts.push_back(font); return font; } // --------------------------------------------------------------------------- // // NULLGUIFactory class // // --------------------------------------------------------------------------- NULLGUIFactory::NULLGUIFactory() { } // --------------------------------------------------------------------------- NULLGUIFactory::~NULLGUIFactory() { } // --------------------------------------------------------------------------- WindowImpl* NULLGUIFactory::createWindowImpl(Window* in_window, int antialias) { NULLWindowImpl* impl = new NULLWindowImpl(in_window); return impl; } // --------------------------------------------------------------------------- #ifdef RGL_NO_OPENGL #include namespace rgl { NULLGUIFactory* gpNULLGUIFactory = NULL; } void rgl::printMessage( const char* string ) { Rf_warning("RGL: %s\n", string); } GUIFactory* rgl::getGUIFactory(bool useNULLDevice) { if (useNULLDevice) return (GUIFactory*) gpNULLGUIFactory; else Rf_error("OpenGL is not available in this build"); } const char * rgl::GUIFactoryName(bool useNULLDevice) { return "null"; } bool rgl::init(bool useNULLDevice) { gpNULLGUIFactory = new NULLGUIFactory(); return true; } void rgl::quit() { assert(gpNULLGUIFactory != NULL); delete gpNULLGUIFactory; gpNULLGUIFactory = NULL; } double rgl::getTime() { struct ::timeval t; gettimeofday(&t,NULL); return ( (double) t.tv_sec ) * 1000.0 + ( ( (double) t.tv_usec ) / 1000.0 ); } #endif rgl/src/Device.h0000644000176200001440000000407715011677075013216 0ustar liggesusers#ifndef RGL_DEVICE_H #define RGL_DEVICE_H // C++ header file // This file is part of RGL // #include "Disposable.h" #include "types.h" #include "rglview.h" namespace rgl { // // class Device // // - display device title // - setup the view matrix container (rows and columns of views) // - setup the view/scene relation (scene per view -or- shared scene) // - manages current view // - dispatches scene services to current view's scene // class Device : public Disposable, protected IDisposeListener { public: // -- all methods are blocking until action completed Device(int id, bool useNULL, int antialias); virtual ~Device(); int getID(); void setName(const char* string); bool open(void); // -- if failed, instance is invalid and should be deleted void close(void); // -- when done, instance is invalid and should be deleted bool snapshot(int format, const char* filename); bool pixels(int* ll, int* size, int component, double* result); bool postscript(int format, const char* filename, bool drawText); bool clear(TypeID stackTypeID); int add(SceneNode* node); // -- return a unique id if successful, or zero if not bool pop(TypeID stackTypeID, int id); bool hasWindow() { return window != NULL; } // accessor method for Scene, modeled after getBoundingBox() // from scene.h Scene* getScene() const { return scene; } void bringToTop(int stay); RGLView* getRGLView(void); int getIgnoreExtent(void); void setIgnoreExtent(int in_ignoreExtent); int getSkipRedraw(void); void setSkipRedraw(int in_skipRedraw); void setWindowRect(int left, int top, int right, int bottom); void getWindowRect(int *left, int *top, int *right, int *bottom); void getFonts(FontArray& outfonts, int nfonts, char** family, int* style, double* cex, bool useFreeType); const char* getDevtype(void); // event handlers protected: void notifyDisposed(Disposable* disposable); private: void update(void); Window* window; RGLView* rglview; Scene* scene; const char* devtype; int id_; }; } // namespace rgl #endif // RGL_DEVICE_H rgl/src/subscene.cpp0000644000176200001440000012677015011677075014166 0ustar liggesusers#include "subscene.h" #include "rglview.h" #include "select.h" #include "gl2ps.h" #include "R.h" #include #include using namespace rgl; /* Code for debugging static void printMatrix(const char* msg, double* m) { Rprintf("%s:\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n", msg, m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[13], m[2], m[6], m[10], m[14], m[3], m[7], m[11], m[15]); } static void printMatrix(const char* msg, Matrix4x4 m) { double data[16]; m.getData(data); printMatrix(msg, data); } static void printMVMatrix(const char* msg) { double m[16] = {0}; #ifndef RGL_NO_OPENGL glGetDoublev(GL_MODELVIEW_MATRIX, m); #endif printMatrix(msg, m); } static void printPRMatrix(const char* msg) { double m[16] = {0}; #ifndef RGL_NO_OPENGL glGetDoublev(GL_PROJECTION_MATRIX, m); #endif printMatrix(msg, m); } */ ////////////////////////////////////////////////////////////////////////////// // // CLASS // Subscene // Subscene::Subscene(Embedding in_viewport, Embedding in_projection, Embedding in_model, Embedding in_mouseHandlers, bool in_ignoreExtent) : SceneNode(SUBSCENE), parent(NULL), do_viewport(in_viewport), do_projection(in_projection), do_model(in_model), do_mouseHandlers(in_mouseHandlers), viewport(0.,0.,1.,1.),Zrow(), Wrow(), pviewport(0,0,1024,1024), drag(0), ignoreExtent(in_ignoreExtent), selectState(msNONE), dragBase(0.0f,0.0f), dragCurrent(0.0f,0.0f) { userviewpoint = NULL; modelviewpoint = NULL; bboxdeco = NULL; background = NULL; bboxChanges = false; data_bbox.invalidate(); modelMatrix.setIdentity(); projMatrix.setIdentity(); mouseListeners.push_back(this); for (int i=0; i<5; i++) { mouseMode[i] = mmNONE; beginCallback[i] = NULL; updateCallback[i] = NULL; endCallback[i] = NULL; cleanupCallback[i] = NULL; for (int j=0; j<3; j++) userData[3*i + j] = NULL; } setDefaultMouseMode(); } Subscene::~Subscene() { // Don't destroy contained subscenes: they're // still in the scene list for (int i=0; i<5; i++) if (cleanupCallback[i]) (*cleanupCallback[i])(userData + 3*i); } bool Subscene::add(SceneNode* node) { bool success = false; switch( node->getTypeID() ) { case SHAPE: { Shape* shape = (Shape*) node; addShape(shape); success = true; } break; case LIGHT: { Light* light = (Light*) node; addLight(light); success = true; } break; case USERVIEWPOINT: { userviewpoint = (UserViewpoint*) node; success = true; } break; case MODELVIEWPOINT: { modelviewpoint = (ModelViewpoint*) node; success = true; } break; case SUBSCENE: { Subscene* subscene = static_cast(node); if (subscene->parent) Rf_error("Subscene %d is already a child of subscene %d.", subscene->getObjID(), subscene->parent->getObjID()); addSubscene(subscene); success = true; } break; case BACKGROUND: { Background* new_background = static_cast(node); addBackground(new_background); success = true; } break; case BBOXDECO: { BBoxDeco* new_bboxdeco = static_cast(node); addBBoxDeco(new_bboxdeco); success = true; } break; default: break; } return success; } void Subscene::addBackground(Background* newbackground) { background = newbackground; } void Subscene::addBBoxDeco(BBoxDeco* newbboxdeco) { bboxdeco = newbboxdeco; } void Subscene::addShape(Shape* shape) { if (!shape->getIgnoreExtent()) addBBox(shape->getBoundingBox(), shape->getBBoxChanges()); shapes.push_back(shape); if ( shape->isBlended() ) { zsortShapes.push_back(shape); } else if ( shape->isClipPlane() ) { clipPlanes.push_back(static_cast(shape)); newBBox(); } else unsortedShapes.push_back(shape); } void Subscene::addBBox(const AABox& bbox, bool changes) { bboxChanges |= changes; if (data_bbox.isValid()) { /* Update will make it test as valid but not * handle other shapes, so we don't * update unless it is already valid */ data_bbox += bbox; intersectClipplanes(); if (parent && !ignoreExtent) { parent->bboxChanges |= changes; parent->newBBox(); } } } void Subscene::addLight(Light* light) { lights.push_back(light); } void Subscene::addSubscene(Subscene* subscene) { subscenes.push_back(subscene); subscene->parent = this; subscene->newEmbedding(); if (!subscene->getIgnoreExtent()) newBBox(); } void Subscene::hideShape(int id) { std::vector::iterator ishape = std::find_if(shapes.begin(), shapes.end(), std::bind(&sameID, std::placeholders::_1, id)); if (ishape == shapes.end()) return; Shape* shape = *ishape; shapes.erase(ishape); if ( shape->isBlended() ) zsortShapes.erase(std::find_if(zsortShapes.begin(), zsortShapes.end(), std::bind(&sameID, std::placeholders::_1, id))); else if ( shape->isClipPlane() ) clipPlanes.erase(std::find_if(clipPlanes.begin(), clipPlanes.end(), std::bind(&sameID, std::placeholders::_1, id))); else unsortedShapes.erase(std::find_if(unsortedShapes.begin(), unsortedShapes.end(), std::bind(&sameID, std::placeholders::_1, id))); newBBox(); } void Subscene::hideLight(int id) { std::vector::iterator ilight = std::find_if(lights.begin(), lights.end(), std::bind(&sameID, std::placeholders::_1, id)); if (ilight != lights.end()) { lights.erase(ilight); } } void Subscene::hideBBoxDeco(int id) { if (bboxdeco && sameID(bboxdeco, id)) bboxdeco = NULL; } void Subscene::hideBackground(int id) { if (background && sameID(background, id) && parent) background = NULL; /* The root must always have a background */ } Subscene* Subscene::hideSubscene(int id, Subscene* current) { for (std::vector::iterator i = subscenes.begin(); i != subscenes.end(); ++ i) { if (sameID(*i, id)) { if ((*i)->getSubscene(current->getObjID())) current = (*i)->parent; (*i)->parent = NULL; subscenes.erase(i); newBBox(); return current; } } return current; } void Subscene::hideViewpoint(int id) { if (userviewpoint && sameID(userviewpoint, id)) { if (parent) /* the root needs a viewpoint */ userviewpoint = NULL; } else if (modelviewpoint && sameID(modelviewpoint, id)) { if (parent) /* the root needs a viewpoint */ modelviewpoint = NULL; } } Subscene* Subscene::getSubscene(int id) { if (id == getObjID()) return this; for (std::vector::iterator i = subscenes.begin(); i != subscenes.end() ; ++ i ) { Subscene* subscene = (*i)->getSubscene(id); if (subscene) return subscene; } return NULL; } Subscene* Subscene::whichSubscene(int id) { for (std::vector::iterator i = shapes.begin(); i != shapes.end() ; ++ i ) { if ((*i)->getObjID() == id) return this; } for (std::vector::iterator i = lights.begin(); i != lights.end() ; ++ i ) { if ((*i)->getObjID() == id) return this; } if (bboxdeco && bboxdeco->getObjID() == id) return this; for (std::vector::iterator i = subscenes.begin(); i != subscenes.end(); ++ i ) { if ((*i)->getObjID() == id) return this; } if (userviewpoint && userviewpoint->getObjID() == id) return this; if (modelviewpoint && modelviewpoint->getObjID() == id) return this; if (background && background->getObjID() == id) return this; for (std::vector::iterator i = subscenes.begin(); i != subscenes.end() ; ++ i ) { Subscene* result = (*i)->whichSubscene(id); if (result) return result; } return NULL; } Subscene* Subscene::whichSubscene(int mouseX, int mouseY) { Subscene* result = NULL; Subscene* sub; for (std::vector::iterator i = subscenes.begin(); i != subscenes.end() ; ++ i ) { result = (sub = (*i)->whichSubscene(mouseX, mouseY)) ? sub : result; } if (!result && pviewport.x <= mouseX && mouseX < pviewport.x + pviewport.width && pviewport.y <= mouseY && mouseY < pviewport.y + pviewport.height) result = this; return result; } int Subscene::getAttributeCount(SceneNode* subscene, AttribID attrib) { switch (attrib) { case IDS: case TYPES: return (int)shapes.size(); } return SceneNode::getAttributeCount(subscene, attrib); } void Subscene::getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result) { int n = getAttributeCount(subscene, attrib); int ind = 0; if (first + count < n) n = first + count; if (first < n) { switch(attrib) { case IDS: for (std::vector::iterator i = shapes.begin(); i != shapes.end() ; ++ i ) { if ( first <= ind && ind < n ) *result++ = (*i)->getObjID(); ind++; } return; } SceneNode::getAttribute(subscene, attrib, first, count, result); } } std::string Subscene::getTextAttribute(SceneNode* subscene, AttribID attrib, int index) { int n = getAttributeCount(subscene, attrib); if (index < n && attrib == TYPES) { return shapes[index]->getTypeName(); } else return SceneNode::getTextAttribute(subscene, attrib, index); } void Subscene::renderClipplanes(RenderContext* renderContext) { std::vector::iterator iter; ClipPlaneSet::num_planes = 0; for (iter = clipPlanes.begin() ; iter != clipPlanes.end() ; ++iter ) { ClipPlaneSet* plane = *iter; plane->render(renderContext); SAVEGLERROR; } } void Subscene::disableClipplanes(RenderContext* renderContext) { std::vector::iterator iter; for (iter = clipPlanes.begin() ; iter != clipPlanes.end() ; ++iter ) { ClipPlaneSet* plane = *iter; plane->enable(false); SAVEGLERROR; } } int Subscene::get_id_count(TypeID type, bool recursive) { int result = 0; if (recursive) for (std::vector::iterator i = subscenes.begin(); i != subscenes.end(); ++ i ) result += (*i)->get_id_count(type, recursive); switch (type) { case SHAPE: { result += shapes.size(); break; } case LIGHT: { result += lights.size(); break; } case BBOXDECO: { result += bboxdeco ? 1 : 0; break; } case SUBSCENE: { result += subscenes.size(); break; } case USERVIEWPOINT: { result += do_projection > EMBED_INHERIT ? 1 : 0; break; } case MODELVIEWPOINT: { result += do_model > EMBED_INHERIT ? 1 : 0; break; } case BACKGROUND: { result += background ? 1 : 0; break; } } return result; } int Subscene::get_ids(TypeID type, int* ids, char** types, bool recursive) { int count = 0; switch(type) { case SHAPE: for (std::vector::iterator i = shapes.begin(); i != shapes.end() ; ++ i ) { *ids++ = (*i)->getObjID(); *types = copyStringToR((*i)->getTypeName()); types++; count++; } break; case LIGHT: for (std::vector::iterator i = lights.begin(); i != lights.end() ; ++ i ) { *ids++ = (*i)->getObjID(); *types = R_alloc(strlen("light")+1, 1); strcpy(*types, "light"); types++; count++; } break; case BBOXDECO: if (bboxdeco) { *ids++ = bboxdeco->getObjID(); *types = R_alloc(strlen("bboxdeco")+1, 1); strcpy(*types, "bboxdeco"); types++; count++; } break; case SUBSCENE: for (std::vector::iterator i = subscenes.begin(); i != subscenes.end(); ++ i ) { *ids++ = (*i)->getObjID(); *types = R_alloc(strlen("subscene")+1, 1); strcpy(*types, "subscene"); types++; count++; } break; case USERVIEWPOINT: if (userviewpoint) { *ids++ = userviewpoint->getObjID(); *types = R_alloc(strlen("userviewpoint")+1, 1); strcpy(*types, "userviewpoint"); types++; count++; } break; case MODELVIEWPOINT: if (modelviewpoint) { *ids++ = modelviewpoint->getObjID(); *types = R_alloc(strlen("modelviewpoint")+1, 1); strcpy(*types, "modelviewpoint"); types++; count++; } break; case BACKGROUND: if (background) { *ids++ = background->getObjID(); *types = R_alloc(strlen("background")+1, 1); strcpy(*types, "background"); types++; count++; } break; } if (recursive) for (std::vector::iterator i = subscenes.begin(); i != subscenes.end(); ++ i ) { int newcount = (*i)->get_ids(type, ids, types, true); ids += newcount; types += newcount; count += newcount; } return count; } Background* Subscene::get_background() { if (background) return background; else if (parent) return parent->get_background(); else return NULL; } Background* Subscene::get_background(int id) { Background* this_background = get_background(); if (this_background && this_background->getObjID() == id) return this_background; std::vector::const_iterator iter; for(iter = subscenes.begin(); iter != subscenes.end(); ++iter) { this_background = (*iter)->get_background(id); if (this_background) return this_background; } return NULL; } BBoxDeco* Subscene::get_bboxdeco() { if (bboxdeco) return bboxdeco; else if (parent) return parent->get_bboxdeco(); else return NULL; } BBoxDeco* Subscene::get_bboxdeco(int id) { BBoxDeco* this_bboxdeco = get_bboxdeco(); if (this_bboxdeco && this_bboxdeco->getObjID() == id) return this_bboxdeco; std::vector::const_iterator iter; for(iter = subscenes.begin(); iter != subscenes.end(); ++iter) { this_bboxdeco = (*iter)->get_bboxdeco(id); if (this_bboxdeco) return this_bboxdeco; } return NULL; } UserViewpoint* Subscene::getUserViewpoint() { if (userviewpoint && do_projection > EMBED_INHERIT) return userviewpoint; else if (parent) return parent->getUserViewpoint(); else Rf_error("must have a user viewpoint"); } ModelViewpoint* Subscene::getModelViewpoint() { if (modelviewpoint && do_model > EMBED_INHERIT) return modelviewpoint; else if (parent) return parent->getModelViewpoint(); else Rf_error("must have a model viewpoint"); } void Subscene::update(RenderContext* renderContext) { GLdouble saveprojection[16]; renderContext->subscene = this; setupViewport(renderContext); // Make sure bounding box is up to date. getBoundingBox(); // Now get the matrices. First we compute the projection matrix. If we're inheriting, // just use the parent. if (do_projection > EMBED_INHERIT) { projMatrix.getData(saveprojection); setupProjMatrix(renderContext); } else projMatrix = parent->projMatrix; // Now the model matrix. Since this depends on both the viewpoint and the model // transformations, we don't bother using the parent one, we reconstruct in // every subscene. if (do_projection > EMBED_INHERIT || do_model > EMBED_INHERIT) setupModelViewMatrix(renderContext); else modelMatrix = parent->modelMatrix; // update subscenes std::vector::const_iterator iter; for(iter = subscenes.begin(); iter != subscenes.end(); ++iter) (*iter)->update(renderContext); } void Subscene::loadMatrices() { #ifndef RGL_NO_OPENGL double mat[16]; projMatrix.getData(mat); glMatrixMode(GL_PROJECTION); glLoadMatrixd(mat); SAVEGLERROR; modelMatrix.getData(mat); glMatrixMode(GL_MODELVIEW); glLoadMatrixd(mat); SAVEGLERROR; #endif } void Subscene::render(RenderContext* renderContext, bool opaquePass) { #ifndef RGL_NO_OPENGL renderContext->subscene = this; glViewport(pviewport.x, pviewport.y, pviewport.width, pviewport.height); glScissor(pviewport.x, pviewport.y, pviewport.width, pviewport.height); SAVEGLERROR; if (background && opaquePass) { GLbitfield clearFlags = background->getClearFlags(renderContext); // clear glDepthMask(GL_TRUE); glClear(clearFlags); } SAVEGLERROR; // Make sure bounding boxes are up to date. getBoundingBox(); // Now render the current scene. First we load the projection matrix, then the modelview matrix. loadMatrices(); setupLights(renderContext); if (opaquePass) { if (renderContext->gl2psActive > GL2PS_NONE) gl2psSorting(GL2PS_SIMPLE_SORT); if (background) { // // RENDER BACKGROUND // // DISABLE Z-BUFFER TEST glDisable(GL_DEPTH_TEST); // DISABLE Z-BUFFER FOR WRITING glDepthMask(GL_FALSE); background->render(renderContext); SAVEGLERROR; } // // RENDER SOLID SHAPES // // ENABLE Z-BUFFER TEST glEnable(GL_DEPTH_TEST); // ENABLE Z-BUFFER FOR WRITING glDepthMask(GL_TRUE); // DISABLE BLENDING glDisable(GL_BLEND); // // RENDER BBOX DECO // if (bboxdeco) bboxdeco->render(renderContext); // This changes the modelview/projection/viewport SAVEGLERROR; } // CLIP PLANES renderClipplanes(renderContext); if (opaquePass) { if (renderContext->gl2psActive > GL2PS_NONE) gl2psSorting(GL2PS_SIMPLE_SORT); renderUnsorted(renderContext); // #define NO_BLEND } else { #ifndef NO_BLEND // // RENDER BLENDED SHAPES // // render shapes in bounding-box sorted order according to z value // if (renderContext->gl2psActive > GL2PS_NONE) gl2psSorting(GL2PS_NO_SORT); // DISABLE Z-BUFFER FOR WRITING glDepthMask(GL_FALSE); SAVEGLERROR; // ENABLE BLENDING glEnable(GL_BLEND); SAVEGLERROR; // // GET THE TRANSFORMATION // Matrix4x4 M(modelMatrix); Matrix4x4 P(projMatrix); P = P*M; Zrow = P.getRow(2); Wrow = P.getRow(3); renderZsort(renderContext); #endif } /* Reset flag(s) now that scene has been rendered */ getModelViewpoint()->scaleChanged = false; /* Reset clipplanes */ disableClipplanes(renderContext); SAVEGLERROR; // Render subscenes std::vector::const_iterator iter; for(iter = subscenes.begin(); iter != subscenes.end(); ++iter) (*iter)->render(renderContext, opaquePass); if (selectState == msCHANGING) { SELECT select; select.render(mousePosition); } #endif } // static void printbbox(AABox bbox) { // Rprintf("%.3g %.3g %.3g %.3g %.3g %.3g\n", // bbox.vmin.x, bbox.vmax.x, // bbox.vmin.y, bbox.vmax.y, // bbox.vmin.z, bbox.vmax.z); // } void Subscene::calcDataBBox() { data_bbox.invalidate(); std::vector::const_iterator subiter; bboxChanges = false; for(subiter = subscenes.begin(); subiter != subscenes.end(); ++subiter) { Subscene* subscene = *subiter; if (!subscene->getIgnoreExtent()) { AABox sub_bbox = subscene->getBoundingBox(); if (!sub_bbox.isEmpty()) { Matrix4x4 M; if (subscene->getEmbedding(EM_MODEL) > EMBED_INHERIT) { double matrix[16]; subscene->getUserMatrix(matrix); M.loadData(matrix); } else M.setIdentity(); if (subscene->getEmbedding(EM_PROJECTION) > EMBED_INHERIT) { double scale[3]; subscene->getScale(scale); M = Matrix4x4::scaleMatrix(scale[0], scale[1], scale[2])*M; } sub_bbox = sub_bbox.transform(M); data_bbox += sub_bbox; } bboxChanges |= subscene->bboxChanges; } } std::vector::const_iterator iter; for(iter = shapes.begin(); iter != shapes.end(); ++iter) { Shape* shape = *iter; if (!shape->getIgnoreExtent()) { data_bbox += shape->getBoundingBox(this); bboxChanges |= shape->getBBoxChanges(); } } intersectClipplanes(); if (!data_bbox.isValid()) data_bbox.setEmpty(); } void Subscene::intersectClipplanes(void) { std::vector::iterator iter; for (iter = clipPlanes.begin() ; iter != clipPlanes.end() ; ++iter ) { ClipPlaneSet* plane = *iter; plane->intersectBBox(data_bbox); SAVEGLERROR; } } /* Call this when the bbox changes */ void Subscene::newBBox(void) { data_bbox.invalidate(); if (parent && !ignoreExtent) parent->newBBox(); } // --------------------------------------------------------------------------- void Subscene::setIgnoreExtent(int in_ignoreExtent) { if (ignoreExtent != (bool)in_ignoreExtent) { ignoreExtent = (bool)in_ignoreExtent; if (parent) parent->newBBox(); } } void Subscene::setupViewport(RenderContext* rctx) { Rect2 rect(0,0,0,0); if (do_viewport == EMBED_REPLACE) { rect.x = static_cast(rctx->rect.x + viewport.x*rctx->rect.width); rect.y = static_cast(rctx->rect.y + viewport.y*rctx->rect.height); rect.width = static_cast(rctx->rect.width*viewport.width); rect.height = static_cast(rctx->rect.height*viewport.height); } else { rect.x = static_cast(parent->pviewport.x + viewport.x*parent->pviewport.width); rect.y = static_cast(parent->pviewport.y + viewport.y*parent->pviewport.height); rect.width = static_cast(parent->pviewport.width*viewport.width); rect.height = static_cast(parent->pviewport.height*viewport.height); } pviewport = rect; } void Subscene::setupProjMatrix(RenderContext* rctx) { if (do_projection == EMBED_REPLACE) projMatrix.setIdentity(); getUserViewpoint()->setupProjMatrix(rctx, getViewSphere()); } // The ModelView matrix has components of the user view (the translation at the start) // and also the model transformations. The former comes from the userViewpoint, // the latter from the modelViewpoint, possibly after applying the same from the parents. // We always reconstruct from scratch rather than trying to use the matrix in place. void Subscene::setupModelViewMatrix(RenderContext* rctx) { modelMatrix.setIdentity(); getUserViewpoint()->setupViewer(rctx); setupModelMatrix(rctx); } void Subscene::setupModelMatrix(RenderContext* rctx) { /* This sets the active subscene modelMatrix, not the local one (though often they're the same one). */ if (do_model < EMBED_REPLACE && parent) parent->setupModelMatrix(rctx); if (do_model > EMBED_INHERIT) getModelViewpoint()->setupTransformation(rctx); if (do_model == EMBED_REPLACE) { Vertex center = getViewSphere().center; rctx->subscene->modelMatrix = rctx->subscene->modelMatrix * Matrix4x4::translationMatrix(-center.x, -center.y, -center.z); } } // // GET DATA VOLUME SPHERE // Sphere Subscene::getViewSphere() { Sphere total_bsphere; if (data_bbox.isValid()) { total_bsphere = Sphere( (bboxdeco) ? bboxdeco->getBoundingBox(data_bbox) : data_bbox, getModelViewpoint()->scale ); if (total_bsphere.radius <= 0.0) total_bsphere.radius = 1.0; } else total_bsphere = Sphere( Vertex(0,0,0), 1 ); return total_bsphere; } void Subscene::disableLights(RenderContext* rctx) { // // disable lights; setup will enable them // #ifndef RGL_NO_OPENGL for (int i=0;i<8;i++) glDisable(GL_LIGHT0 + i); #endif } void Subscene::setupLights(RenderContext* rctx) { #ifndef RGL_NO_OPENGL int nlights = 0; bool anyviewpoint = false; std::vector::const_iterator iter; disableLights(rctx); for(iter = lights.begin(); iter != lights.end() ; ++iter ) { Light* light = *iter; light->id = GL_LIGHT0 + (nlights++); if (!light->viewpoint) light->setup(rctx); else anyviewpoint = true; } SAVEGLERROR; if (nlights == 0 && parent) parent->setupLights(rctx); if (anyviewpoint) { // // viewpoint lights // glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); for(iter = lights.begin(); iter != lights.end() ; ++iter ) { Light* light = *iter; if (light->viewpoint) light->setup(rctx); } glPopMatrix(); } SAVEGLERROR; #endif } void Subscene::renderUnsorted(RenderContext* renderContext) { std::vector::iterator iter; for (iter = unsortedShapes.begin() ; iter != unsortedShapes.end() ; ++iter ) { Shape* shape = *iter; shape->render(renderContext); SAVEGLERROR; } } void Subscene::renderZsort(RenderContext* renderContext) { std::vector::iterator iter; std::multimap distanceMap; for (iter = zsortShapes.begin() ; iter != zsortShapes.end() ; ++iter ) { Shape* shape = *iter; shape->renderBegin(renderContext); for (int j = 0; j < shape->getPrimitiveCount(); j++) { ShapeItem* item = new ShapeItem(shape, j); float distance = getDistance( shape->getPrimitiveCenter(j) ); distanceMap.insert( std::pair(-distance, item) ); } } { Shape* prev = NULL; std::multimap::iterator iter; for (iter = distanceMap.begin() ; iter != distanceMap.end() ; ++ iter ) { ShapeItem* item = iter->second; Shape* shape = item->shape; if (shape != prev) { if (prev) prev->drawEnd(renderContext); shape->drawBegin(renderContext); prev = shape; } shape->drawPrimitive(renderContext, item->itemnum); delete item; } if (prev) prev->drawEnd(renderContext); } } const AABox& Subscene::getBoundingBox() { if (bboxChanges || !data_bbox.isValid()) { // Rprintf("recalc bbox for %d\n", getObjID()); calcDataBBox(); // Rprintf("%d: ", getObjID()); // if (data_bbox.isEmpty()) // Rprintf("empty\n"); // else if (data_bbox.isValid()) // Rprintf("%.1f %.1f\n", data_bbox.vmin.x, data_bbox.vmax.x); // else // Rprintf("invalid\n", data_bbox.vmin.x, data_bbox.vmax.x); } return data_bbox; } void Subscene::newEmbedding() { if (parent) { if (do_projection == EMBED_REPLACE && !userviewpoint) add(new UserViewpoint(*(parent->getUserViewpoint()))); else if (do_projection == EMBED_MODIFY && !userviewpoint) add(new UserViewpoint(0.0, 1.0)); /* should be like an identity */ if (do_model == EMBED_REPLACE && !modelviewpoint) add(new ModelViewpoint(*(parent->getModelViewpoint()))); else if (do_model == EMBED_MODIFY && !modelviewpoint) add(new ModelViewpoint(PolarCoord(0.0, 0.0), Vec3(1.0, 1.0, 1.0), parent->getModelViewpoint()->isInteractive())); } } void Subscene::setEmbedding(int which, Embedding value) { switch(which) { case 0: do_viewport = value; break; case 1: do_projection = value; break; case 2: do_model = value; break; case 3: do_mouseHandlers = value; break; } newEmbedding(); } // #include Embedding Subscene::getEmbedding(Embedded which) { // Rprintf("getEmbedding %d, subscene %d\n", which, getObjID()); // usleep(1000000); switch(which) { case EM_VIEWPORT: return do_viewport; case EM_PROJECTION: return do_projection; case EM_MODEL: return do_model; case EM_MOUSEHANDLERS: return do_mouseHandlers; default: Rf_error("Bad embedding requested"); } } Subscene* Subscene::getMaster(Embedded which) { if (getEmbedding(which) == EMBED_INHERIT) return getParent()->getMaster(which); else return this; } void Subscene::getUserMatrix(double* dest) { ModelViewpoint* this_modelviewpoint = getModelViewpoint(); this_modelviewpoint->getUserMatrix(dest); } void Subscene::setUserMatrix(double* src) { ModelViewpoint* this_modelviewpoint = getModelViewpoint(); this_modelviewpoint->setUserMatrix(src); newBBox(); } void Subscene::getUserProjection(double* dest) { UserViewpoint* this_userviewpoint = getUserViewpoint(); this_userviewpoint->getUserProjection(dest); } void Subscene::setUserProjection(double* src) { UserViewpoint* this_userviewpoint = getUserViewpoint(); this_userviewpoint->setUserProjection(src); } void Subscene::getScale(double* dest) { ModelViewpoint* this_modelviewpoint = getModelViewpoint(); this_modelviewpoint->getScale(dest); } void Subscene::setScale(double* src) { ModelViewpoint* this_modelviewpoint = getModelViewpoint(); this_modelviewpoint->setScale(src); } void Subscene::getPosition(double* dest) { ModelViewpoint* this_modelviewpoint = getModelViewpoint(); this_modelviewpoint->getPosition(dest); } void Subscene::setPosition(double* src) { ModelViewpoint* this_modelviewpoint = getModelViewpoint(); this_modelviewpoint->setPosition(src); } void Subscene::setViewport(double x, double y, double width, double height) { viewport.x = x; viewport.y = y; viewport.width = width; viewport.height = height; } void Subscene::clearMouseListeners() { mouseListeners.clear(); } void Subscene::addMouseListener(Subscene* sub) { mouseListeners.push_back(sub); } void Subscene::deleteMouseListener(Subscene* sub) { for (unsigned int i=0; i < mouseListeners.size(); i++) { if (sub == mouseListeners[i]) { mouseListeners.erase(mouseListeners.begin() + i); return; } } } void Subscene::getMouseListeners(size_t max, int* ids) { max = max > mouseListeners.size() ? mouseListeners.size() : max; for (unsigned int i = 0; i < max; i++) ids[i] = mouseListeners[i]->getObjID(); } float Subscene::getDistance(const Vertex& v) const { Vertex4 vec = Vertex4(v, 1.0f); return (Zrow*vec) / (Wrow*vec); } viewControlPtr Subscene::getButtonBeginFunc(int button) { return getMaster(EM_MOUSEHANDLERS)->ButtonBeginFunc[button]; } void Subscene::buttonBegin(int button, int mouseX, int mouseY) { (this->*getButtonBeginFunc(button))(mouseX, mouseY); } viewControlPtr Subscene::getButtonUpdateFunc(int button) { return getMaster(EM_MOUSEHANDLERS)->ButtonUpdateFunc[button]; } void Subscene::buttonUpdate(int button, int mouseX, int mouseY) { if (button == bnNOBUTTON && needsBegin != mmNONE) { buttonBegin(button, mouseX, mouseY); needsBegin = mmNONE; } (this->*getButtonUpdateFunc(button))(mouseX, mouseY); } viewControlEndPtr Subscene::getButtonEndFunc(int button) { return getMaster(EM_MOUSEHANDLERS)->ButtonEndFunc[button]; } void Subscene::buttonEnd(int button) { (this->*getButtonEndFunc(button))(); } void Subscene::setDefaultMouseMode() { setMouseMode(bnNOBUTTON,mmNONE); setMouseMode(bnLEFT, mmTRACKBALL); setMouseMode(bnRIGHT, mmZOOM); setMouseMode(bnMIDDLE, mmFOV); setMouseMode(bnWHEEL, wmPULL); needsBegin = mmNONE; busy = false; } bool Subscene::mouseNeedsWatching() { if (mouseMode[bnNOBUTTON] != mmNONE) return true; for (std::vector::iterator i = subscenes.begin(); i != subscenes.end(); ++ i ) if ((*i)->mouseNeedsWatching()) return true; return false; } void Subscene::setMouseMode(int button, MouseModeID mode) { if (getEmbedding(EM_MOUSEHANDLERS) == EMBED_INHERIT) getParent()->setMouseMode(button, mode); else { mouseMode[button] = mode; if (button == bnNOBUTTON) needsBegin = mode; switch (mode) { case mmNONE: ButtonBeginFunc[button] = &Subscene::noneBegin; ButtonUpdateFunc[button] = &Subscene::noneUpdate; ButtonEndFunc[button] = &Subscene::noneEnd; break; case mmTRACKBALL: ButtonBeginFunc[button] = &Subscene::trackballBegin; ButtonUpdateFunc[button] = &Subscene::trackballUpdate; ButtonEndFunc[button] = &Subscene::trackballEnd; break; case mmXAXIS: case mmYAXIS: case mmZAXIS: ButtonBeginFunc[button] = &Subscene::oneAxisBegin; ButtonUpdateFunc[button] = &Subscene::oneAxisUpdate; ButtonEndFunc[button] = &Subscene::trackballEnd; // No need for separate function if (mode == mmXAXIS) axis[button] = Vertex(1,0,0); else if (mode == mmYAXIS) axis[button] = Vertex(0,1,0); else axis[button] = Vertex(0,0,1); break; case mmPOLAR: ButtonBeginFunc[button] = &Subscene::polarBegin; ButtonUpdateFunc[button] = &Subscene::polarUpdate; ButtonEndFunc[button] = &Subscene::polarEnd; break; case mmSELECTING: ButtonBeginFunc[button] = &Subscene::mouseSelectionBegin; ButtonUpdateFunc[button] = &Subscene::mouseSelectionUpdate; ButtonEndFunc[button] = &Subscene::mouseSelectionEnd; break; case mmZOOM: ButtonBeginFunc[button] = &Subscene::adjustZoomBegin; ButtonUpdateFunc[button] = &Subscene::adjustZoomUpdate; ButtonEndFunc[button] = &Subscene::adjustZoomEnd; break; case mmFOV: ButtonBeginFunc[button] = &Subscene::adjustFOVBegin; ButtonUpdateFunc[button] = &Subscene::adjustFOVUpdate; ButtonEndFunc[button] = &Subscene::adjustFOVEnd; break; case mmUSER: ButtonBeginFunc[button] = &Subscene::userBegin; ButtonUpdateFunc[button] = &Subscene::userUpdate; ButtonEndFunc[button] = &Subscene::userEnd; break; case wmPULL: if (button == bnWHEEL) WheelRotateFunc = &Subscene::wheelRotatePull; break; case wmPUSH: if (button == bnWHEEL) WheelRotateFunc = &Subscene::wheelRotatePush; break; case wmUSER2: if (button == bnWHEEL) WheelRotateFunc = &Subscene::userWheel; break; } } } void Subscene::setMouseCallbacks(int button, userControlPtr begin, userControlPtr update, userControlEndPtr end, userCleanupPtr cleanup, void** user) { if (getEmbedding(EM_MOUSEHANDLERS) == EMBED_INHERIT) getParent()->setMouseCallbacks(button, begin, update, end, cleanup, user); else { if (cleanupCallback[button]) (*cleanupCallback[button])(userData + 3*button); beginCallback[button] = begin; updateCallback[button] = update; endCallback[button] = end; cleanupCallback[button] = cleanup; userData[3*button + 0] = *(user++); userData[3*button + 1] = *(user++); userData[3*button + 2] = *user; setMouseMode(button, mmUSER); } } void Subscene::getMouseCallbacks(int button, userControlPtr *begin, userControlPtr *update, userControlEndPtr *end, userCleanupPtr *cleanup, void** user) { if (getEmbedding(EM_MOUSEHANDLERS) == EMBED_INHERIT) getParent()->getMouseCallbacks(button, begin, update, end, cleanup, user); else { *begin = beginCallback[button]; *update = updateCallback[button]; *end = endCallback[button]; *cleanup = cleanupCallback[button]; *(user++) = userData[3*button + 0]; *(user++) = userData[3*button + 1]; *(user++) = userData[3*button + 2]; } } MouseModeID Subscene::getMouseMode(int button) { return getMaster(EM_MOUSEHANDLERS)->mouseMode[button]; } void Subscene::setWheelCallback(userWheelPtr wheel, void* user) { if (getEmbedding(EM_MOUSEHANDLERS) == EMBED_INHERIT) getParent()->setWheelCallback(wheel, user); else { wheelCallback = wheel; wheelData = user; setMouseMode(bnWHEEL, wmUSER2); } } void Subscene::getWheelCallback(userWheelPtr *wheel, void** user) { if (getEmbedding(EM_MOUSEHANDLERS) == EMBED_INHERIT) getParent()->getWheelCallback(wheel, user); *wheel = wheelCallback; *user = wheelData; } // // FUNCTION // screenToPolar // // DESCRIPTION // screen space is the same as in OpenGL, starting 0,0 at left/bottom(!) of viewport // static PolarCoord screenToPolar(int width, int height, int mouseX, int mouseY) { float cubelen, cx,cy,dx,dy,r; cubelen = (float) getMin(width,height); r = cubelen * 0.5f; cx = ((float)width) * 0.5f; cy = ((float)height) * 0.5f; dx = ((float)mouseX) - cx; dy = ((float)mouseY) - cy; // // dx,dy = distance to center in pixels // dx = clamp(dx, -r,r); dy = clamp(dy, -r,r); // // sin theta = dx / r // sin phi = dy / r // // phi = arc sin ( sin theta ) // theta = arc sin ( sin phi ) // return PolarCoord( math::rad2deg( math::asin( dx/r ) ), math::rad2deg( math::asin( dy/r ) ) ); } static Vertex screenToVector(int width, int height, int mouseX, int mouseY) { float radius = (float) getMax(width, height) * 0.5f; float cx = ((float)width) * 0.5f; float cy = ((float)height) * 0.5f; float x = (((float)mouseX) - cx)/radius; float y = (((float)mouseY) - cy)/radius; // Make unit vector float len = sqrt(x*x + y*y); if (len > 1.0e-6) { x = x/len; y = y/len; } // Find length to first edge float maxlen = math::sqrt(2.0f); // zero length is vertical, max length is horizontal float angle = (maxlen - len)/maxlen*math::pi()/2.0f; float z = math::sin(angle); // renorm to unit length len = math::sqrt(1.0f - z*z); x = x*len; y = y*len; return Vertex(x, y, z); } void Subscene::trackballBegin(int mouseX, int mouseY) { rotBase = screenToVector(pviewport.width,pviewport.height,mouseX,mouseY); } void Subscene::trackballUpdate(int mouseX, int mouseY) { rotCurrent = screenToVector(pviewport.width,pviewport.height,mouseX,mouseY); for (unsigned int i = 0; i < mouseListeners.size(); i++) { Subscene* sub = mouseListeners[i]; if (sub) { ModelViewpoint* this_modelviewpoint = sub->getModelViewpoint(); this_modelviewpoint->updateMouseMatrix(rotBase,rotCurrent); } } } void Subscene::trackballEnd() { for (unsigned int i = 0; i < mouseListeners.size(); i++) { Subscene* sub = mouseListeners[i]; if (sub) { ModelViewpoint* this_modelviewpoint = sub->getModelViewpoint(); this_modelviewpoint->mergeMouseMatrix(); } } } void Subscene::oneAxisBegin(int mouseX, int mouseY) { rotBase = screenToVector(pviewport.width,pviewport.height,mouseX,pviewport.height/2); } void Subscene::oneAxisUpdate(int mouseX, int mouseY) { rotCurrent = screenToVector(pviewport.width,pviewport.height,mouseX,pviewport.height/2); for (unsigned int i = 0; i < mouseListeners.size(); i++) { Subscene* sub = mouseListeners[i]; if (sub) { ModelViewpoint* this_modelviewpoint = sub->getModelViewpoint(); this_modelviewpoint->mouseOneAxis(rotBase,rotCurrent,axis[drag-1]); } } } void Subscene::polarBegin(int mouseX, int mouseY) { ModelViewpoint* this_modelviewpoint = getModelViewpoint(); camBase = this_modelviewpoint->getPosition(); dragBase = screenToPolar(pviewport.width,pviewport.height,mouseX,mouseY); } void Subscene::polarUpdate(int mouseX, int mouseY) { dragCurrent = screenToPolar(pviewport.width,pviewport.height,mouseX,mouseY); PolarCoord newpos = camBase - ( dragCurrent - dragBase ); newpos.phi = clamp( newpos.phi, -90.0f, 90.0f ); for (unsigned int i = 0; i < mouseListeners.size(); i++) { Subscene* sub = mouseListeners[i]; if (sub) { ModelViewpoint* this_modelviewpoint = sub->getModelViewpoint(); this_modelviewpoint->setPosition( newpos ); } } } void Subscene::polarEnd() { // Viewpoint* viewpoint = scene->getViewpoint(); // viewpoint->mergeMouseMatrix(); } void Subscene::adjustFOVBegin(int mouseX, int mouseY) { fovBaseY = mouseY; } void Subscene::adjustFOVUpdate(int mouseX, int mouseY) { int dy = mouseY - fovBaseY; float py = -((float)dy/(float)pviewport.height) * 180.0f; for (unsigned int i = 0; i < mouseListeners.size(); i++) { Subscene* sub = mouseListeners[i]; if (sub) { UserViewpoint* this_userviewpoint = sub->getUserViewpoint(); this_userviewpoint->setFOV( this_userviewpoint->getFOV() + py ); } } fovBaseY = mouseY; } void Subscene::adjustFOVEnd() { } void Subscene::wheelRotatePull(int dir) { for (unsigned int i = 0; i < mouseListeners.size(); i++) { Subscene* sub = mouseListeners[i]; if (sub) { UserViewpoint* this_userviewpoint = sub->getUserViewpoint(); float zoom = this_userviewpoint->getZoom(); #define ZOOM_STEP 1.05f #define ZOOM_PIXELLOGSTEP 0.02f #define ZOOM_MIN 0.0001f #define ZOOM_MAX 10000.0f switch(dir) { case GUI_WheelForward: zoom *= ZOOM_STEP; break; case GUI_WheelBackward: zoom /= ZOOM_STEP; break; } zoom = clamp( zoom , ZOOM_MIN, ZOOM_MAX); this_userviewpoint->setZoom(zoom); } } } void Subscene::wheelRotatePush(int dir) { switch (dir) { case GUI_WheelForward: wheelRotatePull(GUI_WheelBackward); break; case GUI_WheelBackward: wheelRotatePull(GUI_WheelForward); break; } } void Subscene::wheelRotate(int dir) { int mode = getMouseMode(bnWHEEL); if (mode >= wmPULL) (this->*WheelRotateFunc)(dir); else { // Need to fake a click and release dir = 1 rotates away, dir = 2 rotates towards buttonBegin(bnWHEEL, pviewport.width / 2, pviewport.height / 2); buttonUpdate(bnWHEEL, pviewport.width / 2, pviewport.height / 2 + 10*(dir == 1 ? 1 : -1)); buttonEnd(bnWHEEL); } } void Subscene::userBegin(int mouseX, int mouseY) { Subscene* master = getMaster(EM_MOUSEHANDLERS); beginCallback[drag] = master->beginCallback[drag]; void* this_userData = master->userData[3*drag+0]; activeButton = drag; if (beginCallback[drag]) { busy = true; (*beginCallback[drag])(this_userData, mouseX, pviewport.height-mouseY); busy = false; } } void Subscene::userUpdate(int mouseX, int mouseY) { Subscene* master = getMaster(EM_MOUSEHANDLERS); updateCallback[activeButton] = master->updateCallback[activeButton]; void* this_userData = master->userData[3*activeButton+1]; if (!busy && updateCallback[activeButton]) { busy = true; (*updateCallback[activeButton])(this_userData, mouseX, pviewport.height-mouseY); busy = false; } } void Subscene::userEnd() { Subscene* master = getMaster(EM_MOUSEHANDLERS); endCallback[activeButton] = master->endCallback[activeButton]; void* this_userData = master->userData[3*activeButton+2]; if (endCallback[activeButton]) (*endCallback[activeButton])(this_userData); } void Subscene::userWheel(int dir) { wheelCallback = getMaster(EM_MOUSEHANDLERS)->wheelCallback; if (wheelCallback) (*wheelCallback)(wheelData, dir); } void Subscene::adjustZoomBegin(int mouseX, int mouseY) { zoomBaseY = mouseY; } void Subscene::adjustZoomUpdate(int mouseX, int mouseY) { int dy = mouseY - zoomBaseY; for (unsigned int i = 0; i < mouseListeners.size(); i++) { Subscene* sub = mouseListeners[i]; if (sub) { UserViewpoint* this_userviewpoint = sub->getUserViewpoint(); float zoom = clamp ( this_userviewpoint->getZoom() * exp(dy*ZOOM_PIXELLOGSTEP), ZOOM_MIN, ZOOM_MAX); // Rprintf("zoom = %f for subscene %d\n", zoom, sub->getObjID()); this_userviewpoint->setZoom(zoom); } } zoomBaseY = mouseY; } void Subscene::adjustZoomEnd() { } double* Subscene::getMousePosition() { return mousePosition; } MouseSelectionID Subscene::getSelectState() { return selectState; } void Subscene::setSelectState(MouseSelectionID state) { selectState = state; } void Subscene::mouseSelectionBegin(int mouseX,int mouseY) { if (selectState == msABORT) return; mousePosition[0] = (float)mouseX/(float)pviewport.width; mousePosition[1] = (float)mouseY/(float)pviewport.height; mousePosition[2] = mousePosition[0]; mousePosition[3] = mousePosition[1]; selectState = msCHANGING; } void Subscene::mouseSelectionUpdate(int mouseX,int mouseY) { mousePosition[2] = (float)mouseX/(float)pviewport.width; mousePosition[3] = (float)mouseY/(float)pviewport.height; } void Subscene::mouseSelectionEnd() { if (selectState == msABORT) return; selectState = msDONE; } Subscene* Subscene::getRootSubscene() { return parent ? parent->getRootSubscene() : this; } rgl/src/pretty.c0000644000176200001440000001462414572644263013344 0ustar liggesusers/* This file is taken from the R sources, r61744 of src/appl/pretty.c, with minimal changes */ #include "pretty.h" #include #include #include #include /* * R : A Computer Language for Statistical Data Analysis * Copyright (C) 1995-2012 The R Core Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, a copy is available at * http://www.r-project.org/Licenses/ */ /* Pretty Intervals * ---------------- * Constructs m "pretty" values which cover the given interval *lo <= *up * m ~= *ndiv + 1 (i.e., ndiv := approximate number of INTERVALS) * * It is not quite clear what should happen for *lo = *up; * S itself behaves quite funilly, then. * * In my opinion, a proper 'pretty' should always ensure * *lo < *up, and hence *ndiv >=1 in the result. * However, in S and here, we allow *lo == *up, and *ndiv = 0. * Note however, that we are NOT COMPATIBLE to S. [Martin M.] * * NEW (0.63.2): ns, nu are double (==> no danger of integer overflow) * * We determine * if the interval (up - lo) is ``small'' [<==> i_small == TRUE, below]. * For the ``i_small'' situation, there is a parameter shrink_sml, * the factor by which the "scale" is shrunk. ~~~~~~~~~~ * It is advisable to set it to some (smaller) integer power of 2, * since this enables exact floating point division. */ /* Leave out all the R includes that we can #ifdef HAVE_CONFIG_H #include #endif #ifdef ENABLE_NLS #include #define _(String) gettext (String) #else #define _(String) (String) #endif #include #include #include #include #include #ifdef DEBUGpr # include #endif #ifdef HAVE_VISIBILITY_ATTRIBUTE # define attribute_hidden __attribute__ ((visibility ("hidden"))) #else # define attribute_hidden #endif */ /* non-API, used by rgl */ double R_pretty0(double *lo, double *up, int *ndiv, int min_n, double shrink_sml, double high_u_fact[], int eps_correction, int return_bounds) { /* From version 0.65 on, we had rounding_eps := 1e-5, before, r..eps = 0 * 1e-7 is consistent with seq.default() */ #define rounding_eps 1e-7 #define h high_u_fact[0] #define h5 high_u_fact[1] double dx, cell, unit, base, U; double ns, nu; int k; Rboolean i_small; dx = *up - *lo; /* cell := "scale" here */ if(dx == 0 && *up == 0) { /* up == lo == 0 */ cell = 1; i_small = TRUE; } else { cell = fmax2(fabs(*lo),fabs(*up)); /* U = upper bound on cell/unit */ U = (1 + (h5 >= 1.5*h+.5)) ? 1/(1+h) : 1.5/(1+h5); /* added times 3, as several calculations here */ i_small = dx < cell * U * imax2(1,*ndiv) * DBL_EPSILON *3; } /*OLD: cell = FLT_EPSILON+ dx / *ndiv; FLT_EPSILON = 1.192e-07 */ if(i_small) { if(cell > 10) cell = 9 + cell/10; cell *= shrink_sml; if(min_n > 1) cell /= min_n; } else { cell = dx; if(*ndiv > 1) cell /= *ndiv; } if(cell < 20*DBL_MIN) { /* warning(_("Internal(pretty()): very small range.. corrected")); */ cell = 20*DBL_MIN; } else if(cell * 10 > DBL_MAX) { /* warning(_("Internal(pretty()): very large range.. corrected")); */ cell = .1*DBL_MAX; } base = pow(10., floor(log10(cell))); /* base <= cell < 10*base */ /* unit : from { 1,2,5,10 } * base * such that |u - cell| is small, * favoring larger (if h > 1, else smaller) u values; * favor '5' more than '2' if h5 > h (default h5 = .5 + 1.5 h) */ unit = base; if((U = 2*base)-cell < h*(cell-unit)) { unit = U; if((U = 5*base)-cell < h5*(cell-unit)) { unit = U; if((U =10*base)-cell < h*(cell-unit)) unit = U; }} /* Result: c := cell, u := unit, b := base * c in [ 1, (2+ h) /(1+h) ] b ==> u= b * c in ( (2+ h)/(1+h), (5+2h5)/(1+h5)] b ==> u= 2b * c in ( (5+2h)/(1+h), (10+5h) /(1+h) ] b ==> u= 5b * c in ((10+5h)/(1+h), 10 ) b ==> u=10b * * ===> 2/5 *(2+h)/(1+h) <= c/u <= (2+h)/(1+h) */ ns = floor(*lo/unit+rounding_eps); nu = ceil (*up/unit-rounding_eps); #ifdef DEBUGpr REprintf("pretty(lo=%g,up=%g,ndiv=%d,min_n=%d,shrink=%g,high_u=(%g,%g)," "eps=%d)\n\t dx=%g; is.small:%d. ==> cell=%g; unit=%g\n", *lo, *up, *ndiv, min_n, shrink_sml, h, h5, eps_correction, dx, (int)i_small, cell, unit); #endif if(eps_correction && (eps_correction > 1 || !i_small)) { if(*lo != 0.0) *lo *= (1- DBL_EPSILON); else *lo = -DBL_MIN; if(*up != 0.0) *up *= (1+ DBL_EPSILON); else *up = +DBL_MIN; } #ifdef DEBUGpr if(ns*unit > *lo) REprintf("\t ns= %.0f -- while(ns*unit > *lo) ns--;\n", ns); #endif while(ns*unit > *lo + rounding_eps*unit) ns--; #ifdef DEBUGpr if(nu*unit < *up) REprintf("\t nu= %.0f -- while(nu*unit < *up) nu++;\n", nu); #endif while(nu*unit < *up - rounding_eps*unit) nu++; k = (int)(0.5 + nu - ns); if(k < min_n) { /* ensure that nu - ns == min_n */ #ifdef DEBUGpr REprintf("\tnu-ns=%.0f-%.0f=%d SMALL -> ensure nu-ns= min_n=%d\n", nu,ns, k, min_n); #endif k = min_n - k; if(ns >= 0.) { nu += k/2; ns -= k/2 + k%2;/* ==> nu-ns = old(nu-ns) + min_n -k = min_n */ } else { ns -= k/2; nu += k/2 + k%2; } *ndiv = min_n; } else { *ndiv = k; } if(return_bounds) { /* if()'s to ensure that result covers original range */ if(ns * unit < *lo) *lo = ns * unit; if(nu * unit > *up) *up = nu * unit; } else { *lo = ns; *up = nu; } #ifdef DEBUGpr REprintf("\t ns=%.0f ==> lo=%g\n", ns, *lo); REprintf("\t nu=%.0f ==> up=%g ==> ndiv = %d\n", nu, *up, *ndiv); #endif return unit; #undef h #undef h5 } /* attribute_hidden void R_pretty(double *lo, double *up, int *ndiv, int *min_n, double *shrink_sml, double *high_u_fact, int *eps_correction) { R_pretty0(lo, up, ndiv, *min_n, *shrink_sml, high_u_fact, *eps_correction, 1); } */ rgl/src/api.h0000644000176200001440000001140715011677075012563 0ustar liggesusers#ifndef RGL_API_H #define RGL_API_H #include "ABCLineSet.h" #include "PlaneSet.h" #include "SphereSet.h" #include "SpriteSet.h" #include "Surface.h" #include "TextSet.h" #include "R.h" #include namespace rgl { #ifdef __cplusplus extern "C" { #endif /* // RGL API IMPLEMENTATION // // // C API FUNCTION DESIGN // rgl_ ( successptr , ... ) // // PARAMETERS // successptr // [0] function success status */ /* library service */ void rgl_quit (int* successptr); /* device management */ void rgl_dev_open (int* successptr, int* useNULL, int* antialias); void rgl_dev_close (int* successptr); SEXP rgl_dev_getcurrent(void); SEXP rgl_dev_list (void); void rgl_dev_setcurrent(int* successptr, int* idata); void rgl_dev_bringtotop(int* successptr, int* stay); /* device services */ void rgl_snapshot (int* successptr, int* idata, char** cdata); void rgl_pixels(int* successptr, int* ll, int* size, int* component, double* result); void rgl_postscript (int* successptr, int* idata, char** cdata); /* scene management */ void rgl_clear (int* successptr, int* idata); void rgl_pop (int* successptr, int* idata); void rgl_id_count (int* type, int* count, int* subsceneID); void rgl_ids (int* type, int* ids, char** types, int* subsceneID); void rgl_attrib_count (int* id, int* attrib, int* count); void rgl_attrib (int* id, int* attrib, int* first, int* count, double* result); void rgl_text_attrib (int* id, int* attrib, int* first, int* count, char** result); void rgl_material (int* successptr, int* idata, char** cdata, double* ddata); void rgl_getcolorcount(int* count); void rgl_getmaterial (int* successptr, int *id, int* idata, char** cdata, double* ddata); void rgl_light (int* successptr, int* idata, double* ddata ); void rgl_viewpoint(int* successptr, int* idata, double* ddata); void rgl_bg (int* successptr, int* idata, double* fogScale); void rgl_bbox (int* successptr, int* idata, double* ddata, double* xat, char** xtext, double* yat, char** ytext, double* zat, char** ztext); SEXP rgl_primitive(SEXP idata, SEXP vertex, SEXP normals, SEXP texcoords); void rgl_texts (int* successptr, int* idata, double* adj, char** text, double* vertex, int* nfonts, char** family, int* style, double* cex, int* useFreeType, int* npos, int* pos); void rgl_spheres (int* successptr, int* idata, double* vertex, double* radius, int* fastTransparency); void rgl_planes (int* successptr, int* idata, double* normals, double* offsets); void rgl_clipplanes(int* successptr, int* idata, double* normals, double* offsets); void rgl_abclines (int* successptr, int* idata, double* bases, double* directions); void rgl_surface (int* successptr, int* idata, double* x, double* z, double* y, double* normal_x, double* normal_z, double* normal_y, double* texture_s, double* texture_t, int* coords, int* orientation, int* flags); void rgl_sprites (int* successptr, int* idata, double* vertex, double* radius, int* shapes, double* userMatrix, double* adj, int* pos, double* offset); void rgl_newsubscene (int* successptr, int* parentid, int* embedding, int* ignoreExtent); void rgl_setsubscene (int* id); void rgl_getsubsceneid (int* id, int* dev); /* On input, 0 for root, 1 for current */ void rgl_getsubsceneparent(int* id); void rgl_getsubscenechildcount(int* id, int* n); void rgl_getsubscenechildren(int* id, int* children); void rgl_addtosubscene (int* successptr, int* count, int* ids); void rgl_delfromsubscene(int* successptr, int* count, int* ids); void rgl_gc(int* count, int* protect); void rgl_locator(int* successptr, double* locations); void rgl_selectstate(int* dev, int* sub, int* successptr, int* selectstate, double* locations); void rgl_setselectstate(int* dev, int* sub, int* successptr, int *idata); void rgl_setEmbeddings(int* successptr, int* embeddings); void rgl_getEmbeddings(int* successptr, int* embeddings); SEXP rgl_setMouseCallbacks(SEXP button, SEXP begin, SEXP update, SEXP end, SEXP dev, SEXP sub); SEXP rgl_setWheelCallback(SEXP rotate, SEXP dev, SEXP sub); SEXP rgl_getMouseCallbacks(SEXP button, SEXP dev, SEXP sub); SEXP rgl_getWheelCallback(SEXP dev, SEXP sub); SEXP rgl_getAxisCallback(SEXP dev, SEXP sub, SEXP axis); SEXP rgl_setAxisCallback(SEXP draw, SEXP dev, SEXP sub, SEXP axis); SEXP rgl_par3d(SEXP device, SEXP subscene, SEXP args); /* These may be removed if observer is set completely by par3d */ void rgl_getObserver(int* successptr, double* ddata); void rgl_setObserver(int* successptr, double* ddata); void rgl_incrementID(int* n); SEXP rgl_earcut(SEXP x, SEXP y); #ifdef __cplusplus } #endif } // namespace rgl #endif /* RGL_API_H */ rgl/src/Makevars.win.in0000644000176200001440000000227215011677075014536 0ustar liggesusers# These definitions are for some future R version # when this file is used instead of Makevars.ucrt: PKG_CPPFLAGS = \ -DHAVE_PNG_H -DHAVE_FREETYPE -DR_NO_REMAP -Iext -Iext/ftgl -Iext/glad/include \ -I$(LOCAL_SOFT)/include/freetype2 -Iext/earcut \ -DRGL_W32 PKG_LIBS = \ -lfreetype -lharfbuzz -lfreetype -lpng -lbz2 -lz -lgdi32 -lopengl32 -lglu32 # These definitions are for older R versions: @HIDE_IF_R42PLUS@ VERSION = 2.10.4 @HIDE_IF_R42PLUS@ RWINLIB = ../windows/freetype-$(VERSION) @HIDE_IF_R42PLUS@ CXX_STD = CXX11 @HIDE_IF_R42PLUS@ PKG_CPPFLAGS = \ @HIDE_IF_R42PLUS@ -DHAVE_PNG_H -DHAVE_FREETYPE -DR_NO_REMAP -Iext -Iext/ftgl \ @HIDE_IF_R42PLUS@ -I$(RWINLIB)/include -I$(RWINLIB)/include/freetype2 \ @HIDE_IF_R42PLUS@ -Iext/glad/include -Iext/earcut @HIDE_IF_R42PLUS@ PKG_LIBS = -L$(RWINLIB)/lib$(R_ARCH) \ @HIDE_IF_R42PLUS@ -lfreetype -lpng -lz -lgdi32 -lopengl32 -lglu32 @HIDE_IF_R42PLUS@all: winlibs $(SHLIB) @HIDE_IF_R42PLUS@$(SHLIB): winlibs @HIDE_IF_R42PLUS@winlibs: @HIDE_IF_R42PLUS@ "${R_HOME}/bin${R_ARCH_BIN}/Rscript.exe" "../tools/winlibs.R" $(VERSION) @HIDE_IF_R42PLUS@ sed -e "s^@RGL_NO_OPENGL@^FALSE^" ../R/noOpenGL.R.in > ../R/noOpenGL.R clean: rm -f $(OBJECTS) $(SHLIB) rgl/src/x11lib.cpp0000644000176200001440000000505114771520323013436 0ustar liggesusers#include "config.h" #ifdef RGL_X11 // C++ source // This file is part of RGL. // #include "R.h" #include "lib.h" #include "NULLgui.h" // // ===[ GUI IMPLEMENTATION ]================================================= // #include "x11gui.h" using namespace rgl; namespace rgl { X11GUIFactory* gpX11GUIFactory = NULL; NULLGUIFactory* gpNULLGUIFactory = NULL; } GUIFactory* rgl::getGUIFactory(bool useNULLDevice) { if (useNULLDevice) return (GUIFactory*) gpNULLGUIFactory; else if (gpX11GUIFactory) return (GUIFactory*) gpX11GUIFactory; else Rf_error("glX device not initialized"); } // --------------------------------------------------------------------------- const char * rgl::GUIFactoryName(bool useNULLDevice) { return useNULLDevice ? "null" : "glX"; } // // ===[ R INTEGRATION ]======================================================= // #include "R.h" #include static InputHandler* R_handler = NULL; static void R_rgl_eventHandler(void * userData) { gpX11GUIFactory->processEvents(); } static void set_R_handler() { // add R input handler (R_ext/eventloop.h) // approach taken from GtkDevice ... good work guys! R_handler = ::addInputHandler(R_InputHandlers, gpX11GUIFactory->getFD(), R_rgl_eventHandler, XActivity); // seek end of node while(R_handler->next) R_handler = R_handler->next; } static void unset_R_handler() { if (R_handler) { ::removeInputHandler(&R_InputHandlers, R_handler); R_handler = NULL; } } // // ===[ LIB INIT / QUIT ]===================================================== // bool rgl::init(bool useNULLDevice) { bool success = false; // construct GUI Factory gpNULLGUIFactory = new NULLGUIFactory(); if (useNULLDevice) { success = true; } else { gpX11GUIFactory = new X11GUIFactory(NULL); if ( gpX11GUIFactory->isConnected() ) { set_R_handler(); success = true; } } return success; } void rgl::quit() { unset_R_handler(); delete gpX11GUIFactory; delete gpNULLGUIFactory; gpX11GUIFactory = 0; gpNULLGUIFactory = 0; } // // ===[ LIB SERVICES ]======================================================= // // // printMessage // void rgl::printMessage( const char* string ) { Rf_warning("RGL: %s\n", string); } // // getTime // #include #include double rgl::getTime() { struct ::timeval t; gettimeofday(&t,NULL); return ( (double) t.tv_sec ) * 1000.0 + ( ( (double) t.tv_usec ) / 1000.0 ); } // --------------------------------------------------------------------------- #endif // RGL_X11 rgl/src/assert.cpp0000644000176200001440000000035414771520323013640 0ustar liggesusers#include "R.h" #include "assert.h" void rgl_assert (const char* assertion, const char* file, int line) { Rf_error("Assertion failure: %s\nFile: %s\nLine: %d\nPlease report to rgl maintainer.", assertion, file, line); } rgl/src/Material.cpp0000644000176200001440000001244614771520323014102 0ustar liggesusers#include "Material.h" #include "gl2ps.h" #include "opengl.h" #include "Texture.h" #include "R.h" using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // Material // Material::Material(Color bg, Color fg) : ambient(0.0f,0.0f,0.0f,1.0f), specular(1.0f,1.0f,1.0f,1.0f), emission(0.0f,0.0f,0.0f,0.0f), shininess(50.0f), size(3.0f), lwd(1.0f), polygon_offset_factor(0.0f), polygon_offset_units(0.0f), colors(bg,fg), texture(), front(FILL_FACE), back(FILL_FACE), smooth(true), lit(true), fog(true), useColorArray(false), point_antialias(false), line_antialias(false), depth_mask(true), depth_test(1), // "less" textype(Texture::RGB), texmode(Texture::MODULATE), mipmap(false), minfilter(1), magfilter(1), envmap(false), marginCoord(-1), floating(false), tag(), glVersion(-1.0) { alphablend = ( ( bg.getAlphaf() < 1.0f ) || ( fg.getAlphaf() < 1.0f ) ) ? true : false; edge[0] = -2; edge[1] = -2; edge[2] = -2; blend[0] = 6; // GL_SRC_ALPHA blend[1] = 7; // GL_ONE_MINUS_SRC_ALPHA } void Material::setup() { #ifndef RGL_NO_OPENGL const char* version = (const char*)glGetString(GL_VERSION); if (version) glVersion = atof(version); else #endif glVersion = 1.0; } void Material::beginUse(RenderContext* renderContext) { #ifndef RGL_NO_OPENGL int ncolor = colors.getLength(); GLenum depthfunc[] = { GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL, GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS }; GLenum blendfunc[] = { GL_ZERO, GL_ONE, GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR, GL_DST_COLOR, GL_ONE_MINUS_DST_COLOR, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_CONSTANT_COLOR, GL_ONE_MINUS_CONSTANT_COLOR, GL_CONSTANT_ALPHA, GL_ONE_MINUS_CONSTANT_ALPHA, GL_SRC_ALPHA_SATURATE}; SAVEGLERROR; glDepthFunc(depthfunc[depth_test]); glDepthMask(depth_mask ? GL_TRUE : GL_FALSE); SAVEGLERROR; glPushAttrib( GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT ); SAVEGLERROR; if (!alphablend) glDepthMask(GL_TRUE); else { if (renderContext->gl2psActive == GL2PS_NONE) glBlendFunc(blendfunc[blend[0]], blendfunc[blend[1]]); else gl2psBlendFunc(blendfunc[blend[0]], blendfunc[blend[1]]); } SAVEGLERROR; if (point_antialias) glEnable(GL_POINT_SMOOTH); if (line_antialias) glEnable(GL_LINE_SMOOTH); SAVEGLERROR; glDisable(GL_CULL_FACE); for (int i=0;i<2;i++) { PolygonMode mode = (i==0) ? front : back; GLenum face = (i==0) ? GL_FRONT : GL_BACK; SAVEGLERROR; switch (mode) { case FILL_FACE: glPolygonMode( face, GL_FILL); break; case LINE_FACE: glPolygonMode( face, GL_LINE); break; case POINT_FACE: glPolygonMode( face, GL_POINT); break; case CULL_FACE: glEnable(GL_CULL_FACE); glCullFace(face); break; } } SAVEGLERROR; glShadeModel( (smooth) ? GL_SMOOTH : GL_FLAT ); SAVEGLERROR; if (lit) { glEnable(GL_LIGHTING); SAVEGLERROR; #ifdef GL_VERSION_1_2 if (glVersion < 0.0) setup(); if (glVersion >= 1.2) glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, (texture) ? GL_SEPARATE_SPECULAR_COLOR : GL_SINGLE_COLOR ); #endif SAVEGLERROR; glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); glEnable(GL_COLOR_MATERIAL); glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT, ambient.data); glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR, specular.data); glMaterialf (GL_FRONT_AND_BACK,GL_SHININESS, shininess); glMaterialfv(GL_FRONT_AND_BACK,GL_EMISSION, emission.data); } SAVEGLERROR; if ( (useColorArray) && ( ncolor > 1 ) ) { glEnableClientState(GL_COLOR_ARRAY); colors.useArray(); } else colors.useColor(0); SAVEGLERROR; if (renderContext->gl2psActive == GL2PS_NONE) { glPointSize( size ); glLineWidth( lwd ); } else { gl2psPointSize( size ); gl2psLineWidth( lwd ); } if (polygon_offset) { glPolygonOffset(polygon_offset_factor, polygon_offset_units); glEnable(GL_POLYGON_OFFSET_FILL); } if (texture) texture->beginUse(renderContext); SAVEGLERROR; if (!fog) glDisable(GL_FOG); SAVEGLERROR; #endif } void Material::useColor(int index) { if (colors.getLength() > 0) colors.useColor( index % colors.getLength() ); } void Material::endUse(RenderContext* renderContext) { #ifndef RGL_NO_OPENGL int ncolor = colors.getLength(); if ( (useColorArray) && ( ncolor > 1 ) ) { glDisableClientState(GL_COLOR_ARRAY); SAVEGLERROR; } if (texture) { texture->endUse(renderContext); SAVEGLERROR; } #if USE_GLGETERROR saveGLerror(__FILE__, __LINE__); #endif glPopAttrib(); #if USE_GLGETERROR if (SaveErrnum == GL_NO_ERROR) glGetError(); /* work around bug in some glX implementations */ #endif SAVEGLERROR; glDepthFunc(GL_LESS); glDepthMask(GL_TRUE); if (polygon_offset) glDisable(GL_POLYGON_OFFSET_FILL); #endif } void Material::colorPerVertex(bool enable, int numVertices) { useColorArray = enable; if (enable) colors.recycle(numVertices); } rgl/src/rglmath.h0000644000176200001440000002210414771520323013437 0ustar liggesusers#ifndef RGL_MATH_H #define RGL_MATH_H // C++ header file // This file is part of RGL // #include #include #include "types.h" #ifndef M_PI #define M_PI 3.1415926535897932384626433832795 #endif namespace rgl { namespace math { // template-based math functions with default 'double' implementation using math.h template inline T acos(T x) { return static_cast( ::acos( static_cast(x) ) ); } template inline T asin(T x) { return static_cast( ::asin( static_cast(x) ) ); } template inline T atan(T x) { return static_cast( ::atan( static_cast(x) ) ); } template inline T atan2(T x, T y) { return static_cast( ::atan2( static_cast(x), static_cast(y) ) ); } template inline T cos(T x) { return static_cast( ::cos( static_cast(x) ) ); } template inline T sin(T x) { return static_cast( ::sin( static_cast(x) ) ); } #ifdef HAVE_SINF template<> inline float sin(float rad) { return ::sinf(rad); } #endif template inline T tan(T x) { return static_cast( ::tan( static_cast(x) ) ); } // template inline T acosh(T x) { return static_cast( ::acosh( static_cast(x) ) ); } // template inline T asinh(T x) { return static_cast( ::asinh( static_cast(x) ) ); } // template inline T atanh(T x) { return static_cast( ::atanh( static_cast(x) ) ); } // template inline T cosh(T x) { return static_cast( ::cosh( static_cast(x) ) ); } // template inline T sinh(T x) { return static_cast( ::sinh( static_cast(x) ) ); } // template inline T tanh(T x) { return static_cast( ::tanh( static_cast(x) ) ); } template inline T exp(T x) { return static_cast( ::exp( static_cast(x) ) ); } // template inline T exp2(T x) { return static_cast( ::exp2( static_cast(x) ) ); } // template inline T expm1(T x) { return static_cast( ::expm1( static_cast(x) ) ); } template inline T log(T x) { return static_cast( ::log( static_cast(x) ) ); } template inline T log10(T x) { return static_cast( ::log10( static_cast(x) ) ); } // template inline T log2(T x) { return static_cast( ::log2( static_cast(x) ) ); } template inline T log1p(T x) { return static_cast( ::log1p( static_cast(x) ) ); } template inline T logb(T x) { return static_cast( ::logb( static_cast(x) ) ); } template inline T modf(T x, T* y) { double i; double r = ::modf( static_cast(x), &i ); *y = static_cast(i); return static_cast(r); } template<> inline double modf(double x, double* y) { return ::modf(x,y); } //template<> inline float modf(float x, float* y) { return ::modff(x,y); } template inline T ldexp(T x, int y) { return static_cast( ::ldexp(static_cast(x),y) ); } // template inline T frexp(T x, int* y) { return static_cast( ::frexp( static_cast(x),n) ); } template inline int ilogb(T x) { return ::ilogb( static_cast(x) ); } template inline T scalbn(T x, int n) { return static_cast( ::scalbn( static_cast(x),n ) ); } template inline T fabs(T x) { return static_cast( ::fabs( static_cast(x) ) ); } template inline T cbrt(T x) { return static_cast( ::cbrt( static_cast(x) ) ); } // template inline T hypot(T x) { return static_cast( ::hypot( static_cast(x) ) ); } template inline T pow(T x, T y) { return static_cast( ::pow( static_cast(x), static_cast(y) ) ); } template inline T sqrt(T x) { return static_cast( ::sqrt( static_cast(x) ) ); } template inline T erf(T x) { return static_cast( ::erf( static_cast(x) ) ); } template inline T erfc(T x) { return static_cast( ::erfc( static_cast(x) ) ); } template inline T lgamma(T x) { return static_cast( ::lgamma( static_cast(x) ) ); } // template inline T tgamma(T x) { return static_cast( ::tgamma( static_cast(x) ) ); } template inline T ceil(T x) { return static_cast( ::ceil( static_cast(x) ) ); } template inline T floor(T x) { return static_cast( ::floor( static_cast(x) ) ); } // template inline T nearbyint(T x) { return static_cast( ::nearbyint( static_cast(x) ) ); } template inline T rint(T x) { return static_cast( ::rint( static_cast(x) ) ); } // template inline long int lrint(T x) { return ( ::lrint( static_cast(x) ) ); } // template inline long long int llrint(T x) { return ::llrint( static_cast(x) ); } // template inline T round(T x) { return static_cast( ::round( static_cast(x) ) ); } template inline T pi() { return static_cast( M_PI ); } template inline T deg2rad(T deg) { return ( pi() / T(180.0) ) * deg; } template inline T rad2deg(T rad) { return rad / ( pi() / T(180.0) ); } } // inline float deg2radf(float deg) { return ((float)(PI/180.0)) * deg; } // inline float rad2degf(float rad) { return rad / ((float)(PI/180.0)); } // inline float deg2radf(float deg) { return deg2rad(deg); } // inline float rad2degf(float rad) { return rad2deg(rad); } struct Vec3 { float x,y,z; Vec3() : x(0),y(0),z(0) { } Vec3(float in_x,float in_y, float in_z) : x(in_x), y(in_y), z(in_z) { } Vec3(const Vec3& that) : x(that.x), y(that.y), z(that.z) { } inline float getLength() const { return math::sqrt( x*x + y*y + z*z ); } void normalize(); Vec3 cross(Vec3 op2) const; float angle(const Vec3& op2) const; float operator * (Vec3 op2); Vec3 operator * (float value); Vec3 operator+(Vec3 op2) const; Vec3 operator-(Vec3 op2) const; Vec3 scale(const Vec3& op2) const; void operator+=(Vec3 op2); void rotateX(float degree); void rotateY(float degree); bool missing() const; /* Any components missing */ float& operator[](int i); static inline Vec3& asVec3(float* ptr) { return *( reinterpret_cast( ptr ) ); } }; template<> inline void copy(double* from, Vec3* to, int size) { copy(from, (float*) to, size*3); } typedef Vec3 Vertex; typedef Vertex Vertex3; typedef Vertex3 Normal; struct Vec4 { float x,y,z,w; Vec4(const Normal& n, float in_w=0.0f) : x(n.x), y(n.y), z(n.z), w(in_w) {}; Vec4() {}; Vec4(const float x, const float y, const float z, const float w=1.0f); float operator * (const Vec4& op2) const; Vec4 operator * (const float value) const; Vec4 operator + (const Vec4& op2) const; bool missing() const; /* Any components missing */ float& operator[](int i); static inline Vec4& asVec4(float* ptr) { return *( reinterpret_cast( ptr ) ); } }; class Matrix4x4 { public: Matrix4x4(); Matrix4x4(const Matrix4x4& src); Matrix4x4(const double*); Vec3 operator*(const Vec3 op2) const; Vec4 operator*(const Vec4& op2) const; Matrix4x4 operator*(const Matrix4x4& op2) const; Vec4 getRow(int row); void setIdentity(void); void setRotate(const int axis, const float degree); void getData(double* dest); void loadData(const double* from); void loadData(const float* from); void loadData(const Matrix4x4& from); void transpose(); void multRight(const Matrix4x4& M); void multLeft(const Matrix4x4& M); static Matrix4x4 scaleMatrix(double sx, double sy, double sz); static Matrix4x4 translationMatrix(double x, double y, double z); static Matrix4x4 permutationMatrix(int newx, int newy, int newz); private: inline float val(int row, int column) const { return data[4*column+row]; } inline float& ref(int row, int column) { return data[4*column+row]; } float data[16]; }; // // CLASS // RectSize // struct RectSize { RectSize() : width(0), height(0) {}; RectSize(int in_width, int in_height) : width(in_width), height(in_height) {}; int width; int height; }; struct Rect2 { Rect2(int in_x, int in_y, int in_w, int in_h) : x(in_x) , y(in_y) , width(in_w) , height(in_h) { } int x, y; int width, height; }; struct Rect2d { Rect2d(double in_x, double in_y, double in_w, double in_h) : x(in_x) , y(in_y) , width(in_w) , height(in_h) { } double x, y; double width, height; }; // // CLASS // PolarCoord // struct PolarCoord { PolarCoord(float in_theta=0.0f, float in_phi=0.0f) : theta(in_theta), phi(in_phi) {}; PolarCoord(const PolarCoord& src) : theta(src.theta), phi(src.phi) {}; PolarCoord operator + (const PolarCoord& op2) const { return PolarCoord(theta+op2.theta, phi+op2.phi); } PolarCoord operator - (const PolarCoord& op2) const { return PolarCoord(theta-op2.theta, phi-op2.phi); } Vec3 vector() const; float theta; float phi; }; typedef Vec4 Vertex4; } // namespace rgl #endif /* MATH_H */ rgl/src/glgui.h0000644000176200001440000001205214771520323013111 0ustar liggesusers#ifndef GL_GUI_H #define GL_GUI_H // C++ header // This file is part of rgl #include "opengl.h" #include #ifdef HAVE_FREETYPE #include "FTGL/ftgl.h" #endif #include "RenderContext.h" namespace rgl { // CLASS // GLFont // class GLFont { public: GLFont(const char* in_family, int in_style, double in_cex, const char* in_fontname, bool in_useFreeType): style(in_style), cex(in_cex), useFreeType(in_useFreeType) { family = new char[strlen(in_family) + 1]; memcpy(family, in_family, strlen(in_family) + 1); fontname = new char[strlen(in_fontname) + 1]; memcpy(fontname, in_fontname, strlen(in_fontname) + 1); }; virtual ~GLFont() { delete [] family; delete [] fontname; } virtual void draw(const char* text, int length, double adjx, double adjy, double adjz, int pos, const RenderContext& rc) = 0; virtual void draw(const wchar_t* text, int length, double adjx, double adjy, double adjz, int pos, const RenderContext& rc) = 0; virtual double width(const char* text) = 0; virtual double width(const wchar_t* text) = 0; virtual double height() = 0; virtual bool valid(const char* text) { return true; }; // justify returns false if justification puts the text outside the viewport GLboolean justify(double width, double height, double adjx, double adjy, double adjz, int pos, const RenderContext& rc); char* family; int style; double cex; char* fontname; bool useFreeType; int gl2ps_centering; private: GLFont(const GLFont &); GLFont &operator=(const GLFont &); }; #define GL_BITMAP_FONT_FIRST_GLYPH 32 #define GL_BITMAP_FONT_LAST_GLYPH 127 #define GL_BITMAP_FONT_COUNT (GL_BITMAP_FONT_LAST_GLYPH-GL_BITMAP_FONT_FIRST_GLYPH+1) #define GL2PS_FONT "Helvetica" #define GL2PS_FONTSIZE 12 #define GL2PS_SCALING 0.8 #define GL2PS_NONE 0 #define GL2PS_LEFT_ONLY 1 #define GL2PS_POSITIONAL 2 // // CLASS // GLBitmapFont // class GLBitmapFont : public GLFont { public: // Most initialization of this object is done by the system-specific driver GLBitmapFont(const char* in_family, int in_style, double in_cex, const char* in_fontname): GLFont(in_family, in_style, in_cex, in_fontname, false) {}; ~GLBitmapFont(); void draw(const char* text, int length, double adjx, double adjy, double adjz, int draw, const RenderContext& rc); void draw(const wchar_t* text, int length, double adjx, double adjy, double adjz, int draw, const RenderContext& rc); double width(const char* text); double width(const wchar_t* text); double height(); bool valid(const char* text); GLuint listBase; GLuint firstGlyph; GLuint nglyph; unsigned int* widths; unsigned int ascent; }; // // CLASS // GLFTFont // class GLFTFont : public GLFont { public: GLFTFont(const char* in_family, int in_style, double in_cex, const char* in_fontname); ~GLFTFont(); #ifdef HAVE_FREETYPE void draw(const char* text, int length, double adjx, double adjy, double adjz, int pos, const RenderContext& rc); void draw(const wchar_t* text, int length, double adjx, double adjy, double adjz, int pos, const RenderContext& rc); double width(const char* text); double width(const wchar_t* text); double height(); FTFont *font; const char *errmsg; #endif }; // // CLASS // NULLFont // class NULLFont : public GLFont { public: NULLFont(const char* in_family, int in_style, double in_cex, bool useFreeType): GLFont(in_family, in_style, in_cex, "NULL", useFreeType) {}; void draw(const char* text, int length, double adjx, double adjy, double adjz, int pos, const RenderContext& rc) {}; void draw(const wchar_t* text, int length, double adjx, double adjy, double adjz, int pos, const RenderContext& rc) {}; double width(const char* text) {return 0.0;}; double width(const wchar_t* text) {return 0.0;}; double height() {return 0.0;}; }; /** * FontArray **/ typedef std::vector FontArray; /* The macros below are taken from the R internationalization code, which is marked Copyright (C) 1995-1999, 2000-2007 Free Software Foundation, Inc. */ /* Pathname support. ISSLASH(C) tests whether C is a directory separator character. IS_ABSOLUTE_PATH(P) tests whether P is an absolute path. If it is not, it may be concatenated to a directory pathname. */ #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__ /* Win32, Cygwin, OS/2, DOS */ # define ISSLASH(C) ((C) == '/' || (C) == '\\') # define HAS_DEVICE(P) \ ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \ && (P)[1] == ':') # define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P)) #else /* Unix */ # define ISSLASH(C) ((C) == '/') # define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0]) #endif } // namespace rgl #endif /* GL_GUI_H */ rgl/src/OpenGL/0000755000176200001440000000000014555455305012764 5ustar liggesusersrgl/src/OpenGL/gl.h0000644000176200001440000000644614555455305013551 0ustar liggesusers#ifndef __gl_h_ #define __gl_h_ /* This is extracted from gl.h, part of OpenGL. The following is the * original license statement from that file. */ /* ** License Applicability. Except to the extent portions of this file are ** made subject to an alternative license as permitted in the SGI Free ** Software License B, Version 1.1 (the "License"), the contents of this ** file are subject only to the provisions of the License. You may not use ** this file except in compliance with the License. You may obtain a copy ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at: ** ** http://oss.sgi.com/projects/FreeB ** ** Note that, as provided in the License, the Software is distributed on an ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT. ** ** Original Code. The Original Code is: OpenGL Sample Implementation, ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics, ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc. ** Copyright in any portions created by third parties is as indicated ** elsewhere herein. All Rights Reserved. ** ** Additional Notice Provisions: This software was created using the ** OpenGL(R) version 1.2.1 Sample Implementation published by SGI, but has ** not been independently verified as being compliant with the OpenGL(R) ** version 1.2.1 Specification. */ #include typedef uint32_t GLbitfield; typedef uint8_t GLboolean; typedef uint32_t GLenum; typedef float GLfloat; typedef int32_t GLint; typedef int16_t GLshort; typedef int32_t GLsizei; typedef uint32_t GLuint; typedef uint16_t GLushort; typedef double GLdouble; #ifdef __cplusplus extern "C" { #endif /*************************************************************/ /* AttribMask */ #define GL_DEPTH_BUFFER_BIT 0x00000100 #define GL_COLOR_BUFFER_BIT 0x00004000 /* BeginMode */ #define GL_POINTS 0x0000 #define GL_LINES 0x0001 #define GL_LINE_STRIP 0x0003 #define GL_TRIANGLES 0x0004 #define GL_QUADS 0x0007 /* Boolean */ #define GL_TRUE 1 #define GL_FALSE 0 /* ClipPlaneName */ #define GL_CLIP_PLANE0 0x3000 /* ErrorCode */ #define GL_NO_ERROR 0 /* PixelFormat */ #define GL_ALPHA 0x1906 #define GL_RGB 0x1907 #define GL_RGBA 0x1908 #define GL_LUMINANCE 0x1909 #define GL_LUMINANCE_ALPHA 0x190A /* TextureMagFilter */ #define GL_NEAREST 0x2600 #define GL_LINEAR 0x2601 /* TextureMinFilter */ #define GL_NEAREST_MIPMAP_NEAREST 0x2700 #define GL_LINEAR_MIPMAP_NEAREST 0x2701 #define GL_NEAREST_MIPMAP_LINEAR 0x2702 #define GL_LINEAR_MIPMAP_LINEAR 0x2703 /*************************************************************/ #ifdef __cplusplus } #endif #endif /* __gl_h_ */ rgl/src/pixmap.cpp0000644000176200001440000000472314771520323013641 0ustar liggesusers// C++ source // This file is part of RGL. // #include #include "pixmap.h" #include "lib.h" // PNG FORMAT IMPLEMENTATION using namespace rgl; #ifdef HAVE_PNG_H #include "pngpixmap.h" namespace rgl { PNGPixmapFormat png; } #endif // PIXMAP FORMAT TABLE PixmapFormat* rgl::pixmapFormat[PIXMAP_FILEFORMAT_LAST] = { // PNG FORMAT #ifdef HAVE_PNG_H &png, #else NULL, #endif }; ////////////////////////////////////////////////////////////////////////////// // // CLASS // Pixmap // Pixmap::Pixmap() { typeID = INVALID; width = 0; height = 0; bits_per_channel = 0; data = NULL; bytesperrow = 0; } Pixmap::~Pixmap() { if (data) delete[] data; } bool Pixmap::init(PixmapTypeID in_typeID, int in_width, int in_height, int in_bits_per_channel) { if (data) delete data; typeID = in_typeID; width = in_width; height = in_height; bits_per_channel = in_bits_per_channel; int channels; if (typeID == RGB24) channels = 3; else if (typeID == RGBA32) channels = 4; else if (typeID == GRAY8) channels = 1; else return false; bytesperrow = ( (channels * bits_per_channel) >> 3 ) * width; data = new unsigned char [ bytesperrow * height ]; if (data) return true; else return false; } void Pixmap::clear() { if (data) memset(data, 0, bytesperrow * height); } bool Pixmap::load(const char* filename) { bool success = false; std::FILE* file = NULL; file = fopen(filename, "rb"); if (!file) { char buffer[256]; snprintf(buffer, 256, "Pixmap load: unable to open file '%s' for reading", filename); printMessage(buffer); return false; } bool support = false; for(int i=0;icheckSignature(file) ) ) { support = true; success = format->load(file, this); break; } } if (!support) { printMessage("Pixmap load: file format unsupported"); } if (!success) { printMessage("Pixmap load: failed"); } fclose(file); return success; } bool Pixmap::save(PixmapFormat* format, const char* filename) { std::FILE* file = NULL; file = fopen(filename, "wb"); if (!file) { char buffer[256]; snprintf(buffer, 256, "Pixmap save: unable to open file '%s' for writing", filename); printMessage(buffer); return false; } bool success = format->save(file, this); fclose(file); return success; } rgl/src/scene.cpp0000644000176200001440000002033414771520323013434 0ustar liggesusers// C++ source // This file is part of RGL. // #include "scene.h" #include "gl2ps.h" #include "SpriteSet.h" #include "rglmath.h" #include "render.h" #include "geom.h" #include #include #include #include "R.h" using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // Scene // ObjID SceneNode::nextID = 1; Scene::Scene() : rootSubscene(EMBED_REPLACE, EMBED_REPLACE, EMBED_REPLACE, EMBED_REPLACE, false), doIgnoreExtent(false) { nodes.reserve(6); nodes.push_back( currentSubscene = &rootSubscene ); add( new UserViewpoint ); add( new ModelViewpoint ); add( new Background ); add( new Light ); } Scene::~Scene() { clear(SHAPE); clear(LIGHT); clear(BBOXDECO); clear(BACKGROUND); clear(MODELVIEWPOINT); clear(USERVIEWPOINT); } UserViewpoint* Scene::getUserViewpoint() { return currentSubscene->getUserViewpoint(); } ModelViewpoint* Scene::getModelViewpoint() { return currentSubscene->getModelViewpoint(); } bool Scene::clear(TypeID type) { std::vector::iterator iter; for (iter = nodes.begin(); iter != nodes.end();) { if ((*iter)->getTypeID() == type) { SceneNode* node = (*iter); int id = node->getObjID(); if (id == rootSubscene.getObjID()) ++iter; else { hide(node->getObjID()); if (node->owner) { ++iter; } else { delete node; iter = nodes.erase(iter); } } } else ++iter; } SAVEGLERROR; return true; } bool Scene::add(SceneNode* node) { nodes.push_back( node ); return currentSubscene->add(node); } bool Scene::pop(TypeID type, int id) { std::vector::iterator iter; if (id == 0) { for (iter = nodes.end(); iter != nodes.begin();) { --iter; if ((*iter)->getTypeID() == type) { id = (*iter)->getObjID(); break; } } if (!id) return false; } iter = std::find_if(nodes.begin(), nodes.end(), // std::bind(std::ptr_fun(&sameID), placeholders::_1, id)); std::bind(&sameID, std::placeholders::_1, id)); if (iter != nodes.end()) { SceneNode* node = *iter; if (node == &rootSubscene) return true; hide((*iter)->getObjID()); // Rprintf("removing references to %d\n", id); removeReferences(*iter); /* Might be in mouseListeners */ nodes.erase(iter); delete node; return true; } return false; } void Scene::hide(int id) { std::vector::iterator inode; SceneNode* node = get_scenenode(id); if (node) { TypeID type = node->getTypeID(); for (inode = nodes.begin(); inode != nodes.end(); ++inode) { if ((*inode)->getTypeID() == SUBSCENE) { Subscene* subscene = static_cast((*inode)); switch (type) { case SUBSCENE: currentSubscene = subscene->hideSubscene(id, currentSubscene); break; case SHAPE: subscene->hideShape(id); break; case LIGHT: subscene->hideLight(id); break; case BBOXDECO: subscene->hideBBoxDeco(id); break; case BACKGROUND: subscene->hideBackground(id); break; case USERVIEWPOINT: case MODELVIEWPOINT: subscene->hideViewpoint(id); break; default: Rf_error("hiding type %d not implemented", type); } } } } } void Scene::removeReferences(SceneNode* node) { int id = node->getObjID(), type = node->getTypeID(); // Rprintf("node id = %d type = %u\n", id, node); for (std::vector::iterator iter = nodes.begin(); iter != nodes.end(); ++iter) { int itertype = (*iter)->getTypeID(); // Rprintf("itertype = %u\n", itertype); if (itertype == SUBSCENE) { Subscene* subscene = (Subscene*)*iter; switch (type) { case SUBSCENE: subscene->deleteMouseListener((Subscene*)node); setCurrentSubscene(subscene->hideSubscene(id, getCurrentSubscene() ) ); break; case SHAPE: subscene->hideShape(id); break; case LIGHT: subscene->hideLight(id); break; case BACKGROUND: subscene->hideBackground(id); break; case USERVIEWPOINT: case MODELVIEWPOINT: subscene->hideViewpoint(id); break; } } else if (itertype == SHAPE) { if ((*iter)->getTypeName() == "sprites") { // Rprintf("removing from sprites\n"); SpriteSet* sprite = (SpriteSet*)*iter; sprite->remove_shape(id); } } } } int Scene::get_id_count(TypeID type) { int count = 0; for (std::vector::iterator iter = nodes.begin(); iter != nodes.end(); ++iter) if (type == (*iter)->getTypeID()) count++; return count; } void Scene::get_ids(TypeID type, int* ids, char** types) { for (std::vector::iterator iter = nodes.begin(); iter != nodes.end(); ++ iter) { if (type == (*iter)->getTypeID()) { *ids++ = (*iter)->getObjID(); *types = copyStringToR((*iter)->getTypeName()); types++; } } } SceneNode* Scene::get_scenenode(int id) { for (std::vector::iterator iter = nodes.begin(); iter != nodes.end(); ++iter) if (id == (*iter)->getObjID()) return *iter; return NULL; } SceneNode* Scene::get_scenenode(TypeID type, int id) { SceneNode* node = get_scenenode(id); if (node && node->getTypeID() == type) return node; else return NULL; } Shape* Scene::get_shape(int id) { return (Shape*)get_scenenode(SHAPE, id); } Background* Scene::get_background(int id) { return (Background*)get_scenenode(BACKGROUND, id); } BBoxDeco* Scene::get_bboxdeco(int id) { return (BBoxDeco*)get_scenenode(BBOXDECO, id); } Subscene* Scene::getSubscene(int id) { return (Subscene*)get_scenenode(SUBSCENE, id); } Subscene* Scene::whichSubscene(int id) { Subscene* result = rootSubscene.whichSubscene(id); if (!result) result = &rootSubscene; return result; } Subscene* Scene::whichSubscene(int mouseX, int mouseY) { Subscene* result = rootSubscene.whichSubscene(mouseX, mouseY); if (!result) result = &rootSubscene; return result; } Subscene* Scene::setCurrentSubscene(Subscene* subscene) { Subscene* prev = currentSubscene; currentSubscene = subscene; return prev; } void Scene::setupLightModel() { #ifndef RGL_NO_OPENGL Color global_ambient(0.0f,0.0f,0.0f,1.0f); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient.data ); glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE ); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE ); SAVEGLERROR; #endif } void Scene::update(RenderContext* renderContext) { rootSubscene.update(renderContext); } void Scene::render(RenderContext* renderContext) { #ifndef RGL_NO_OPENGL // // CLEAR BUFFERS // GLbitfield clearFlags = GL_COLOR_BUFFER_BIT; rootSubscene.get_background()->material.colors.getColor(0).useClearColor(); SAVEGLERROR; // Depth Buffer glClearDepth(1.0); glDepthFunc(GL_LESS); glDepthMask(GL_TRUE); // mask and func will be reset by material // if ( unsortedShapes.size() ) clearFlags |= GL_DEPTH_BUFFER_BIT; // The subscenes use the scissor test to limit where they draw, but we want to clear everything here // clear glDisable(GL_SCISSOR_TEST); glClear(clearFlags); glEnable(GL_SCISSOR_TEST); // userMatrix and scale might change the length of normals. If this slows us // down, we should test for that instead of just enabling GL_NORMALIZE glEnable(GL_NORMALIZE); setupLightModel(); SAVEGLERROR; // // RENDER MODEL // rootSubscene.render(renderContext, true); // All opaque stuff rootSubscene.render(renderContext, false); // non-opaque stuff #endif } // --------------------------------------------------------------------------- void Scene::invalidateDisplaylists() { std::vector::iterator iter; for (iter = nodes.begin(); iter != nodes.end(); ++iter) { if ((*iter)->getTypeID() == SHAPE) ((Shape*)(*iter))->invalidateDisplaylist(); } } bool rgl::sameID(SceneNode* node, int id) { return node->getObjID() == id; } rgl/src/win32lib.cpp0000644000176200001440000000447014771520323013773 0ustar liggesusers#include "config.h" #ifdef RGL_W32 // --------------------------------------------------------------------------- // W32 Library Implementation // --------------------------------------------------------------------------- #include "lib.h" #include "win32gui.h" #include "NULLgui.h" #include #include "assert.h" #include "R.h" using namespace rgl; // --------------------------------------------------------------------------- // GUI Factory // --------------------------------------------------------------------------- Win32GUIFactory* gpWin32GUIFactory = NULL; NULLGUIFactory* gpNULLGUIFactory = NULL; // --------------------------------------------------------------------------- GUIFactory* rgl::getGUIFactory(bool useNULLDevice) { if (useNULLDevice) return (GUIFactory*) gpNULLGUIFactory; else if (gpWin32GUIFactory) return (GUIFactory*) gpWin32GUIFactory; else Rf_error("wgl device not initialized"); } // --------------------------------------------------------------------------- const char * rgl::GUIFactoryName(bool useNULLDevice) { return useNULLDevice ? "null" : "wgl"; } // --------------------------------------------------------------------------- // printMessage // --------------------------------------------------------------------------- void rgl::printMessage( const char* string ) { Rf_warning("RGL: %s\n", string); } // --------------------------------------------------------------------------- // getTime // --------------------------------------------------------------------------- double rgl::getTime() { return ( (double) ::GetTickCount() ) * ( 1.0 / 1000.0 ); } // --------------------------------------------------------------------------- // init // --------------------------------------------------------------------------- bool rgl::init(bool useNULLDevice) { if (!useNULLDevice) gpWin32GUIFactory = new Win32GUIFactory(); gpNULLGUIFactory = new NULLGUIFactory(); return true; } // --------------------------------------------------------------------------- // quit // --------------------------------------------------------------------------- void rgl::quit() { delete gpWin32GUIFactory; gpWin32GUIFactory = NULL; delete gpNULLGUIFactory; gpNULLGUIFactory = NULL; } // --------------------------------------------------------------------------- #endif // RGL_W32 rgl/src/rglview.cpp0000644000176200001440000003214115011677075014022 0ustar liggesusers// C++ source // This file is part of RGL. // #ifdef __sun #include #else #include #endif #include #include "rglview.h" #include "opengl.h" #include "lib.h" #include "rglmath.h" #include "pixmap.h" #include "fps.h" #include "gl2ps.h" #include "R.h" // for Rf_error() using namespace rgl; RGLView::RGLView(Scene* in_scene) : View(0,0,256,256,0), autoUpdate(false) { scene = in_scene; flags = 0; renderContext.rect.x = 0; renderContext.rect.y = 0; // size is set elsewhere activeSubscene = 0; } RGLView::~RGLView() { } void RGLView::show() { fps.init( getTime() ); } void RGLView::hide() { autoUpdate=false; } void RGLView::setWindowImpl(WindowImpl* impl) { View::setWindowImpl(impl); #if defined HAVE_FREETYPE renderContext.font = impl->getFont("sans", 1, 1, true); #else renderContext.font = impl->fonts[0]; #endif } Scene* RGLView::getScene() { return scene; } void RGLView::resize(int in_width, int in_height) { View::resize(in_width, in_height); renderContext.rect.width = in_width; renderContext.rect.height = in_height; update(); if (activeSubscene) { Subscene* subscene = scene->getSubscene(activeSubscene); if (subscene && subscene->drag) captureLost(); } } void RGLView::paint(void) { double last = renderContext.time; double t = getTime(); double dt = (last != 0.0f) ? last - t : 0.0f; renderContext.time = t; renderContext.deltaTime = dt; /* This doesn't do any actual plotting, but it calculates matrices etc., and may call user callbacks */ int saveRedraw = windowImpl->setSkipRedraw(1); scene->update(&renderContext); windowImpl->setSkipRedraw(saveRedraw); #ifndef RGL_NO_OPENGL /* This section does the OpenGL plotting */ if (windowImpl->beginGL()) { SAVEGLERROR; Subscene* subscene = scene->getCurrentSubscene(); scene->render(&renderContext); glViewport(0,0, width, height); if (subscene) { if (flags & FSHOWFPS && subscene->getSelectState() == msNONE) fps.render(renderContext.time, &renderContext ); } glFinish(); windowImpl->endGL(); SAVEGLERROR; } #endif } ////////////////////////////////////////////////////////////////////////////// // // user input // // NB: This code has to deal with three conflicting descriptions of pixel locations. // The calls to buttonPress, buttonRelease, etc. are given in OS window-relative // coordinates, which count mouseX from the left, mouseY down from the top. // These are translated into the OpenGL convention which counts Y up from the bottom, // or subscene-relative coordinates, up from the bottom of the viewport. // We use RGLView::translateCoords to go from OS window-relative to OpenGL window-relative, // and Subscene::translateCoords to go from OpenGL window-relative to viewport-relative. void RGLView::keyPress(int key) { switch(key) { case GUI_KeyF1: flags ^= FSHOWFPS; windowImpl->update(); break; case GUI_KeyESC: Subscene* subscene = scene->getCurrentSubscene(); if (subscene) subscene->setSelectState(msABORT); break; } } void RGLView::buttonPress(int button, int mouseX, int mouseY) { ModelViewpoint* modelviewpoint = scene->getCurrentSubscene()->getModelViewpoint(); if ( modelviewpoint->isInteractive() ) { translateCoords(&mouseX, &mouseY); Subscene* subscene = scene->whichSubscene(mouseX, mouseY); subscene->translateCoords(&mouseX, &mouseY); subscene->drag = button; activeSubscene = subscene->getObjID(); windowImpl->captureMouse(this); subscene->buttonBegin(button ,mouseX, mouseY); View::update(); } } void RGLView::buttonRelease(int button, int mouseX, int mouseY) { Subscene* subscene; if (activeSubscene && (subscene = scene->getSubscene(activeSubscene))) { windowImpl->releaseMouse(); subscene->drag = 0; subscene->buttonEnd(button); View::update(); } // Rprintf("release happened, activeSubscene=0\n"); activeSubscene = 0; } void RGLView::mouseMove(int mouseX, int mouseY) { if (activeSubscene) { translateCoords(&mouseX, &mouseY); Subscene* subscene = scene->getSubscene(activeSubscene); if (!subscene) { buttonRelease(0, mouseX, mouseY); return; } subscene->translateCoords(&mouseX, &mouseY); int vwidth = subscene->pviewport.width, vheight = subscene->pviewport.height; mouseX = clamp(mouseX, 0, vwidth-1); mouseY = clamp(mouseY, 0, vheight-1); if (windowImpl->beginGL()) { subscene->buttonUpdate(subscene->drag, mouseX, mouseY); windowImpl->endGL(); View::update(); } } else { ModelViewpoint* modelviewpoint = scene->getCurrentSubscene()->getModelViewpoint(); if ( modelviewpoint->isInteractive() ) { translateCoords(&mouseX, &mouseY); Subscene* subscene = scene->whichSubscene(mouseX, mouseY); if (subscene && subscene->getMouseMode(bnNOBUTTON) != mmNONE) { subscene->translateCoords(&mouseX, &mouseY); subscene->drag = bnNOBUTTON; subscene->buttonUpdate(bnNOBUTTON, mouseX, mouseY); View::update(); } } } } void RGLView::wheelRotate(int dir, int mouseX, int mouseY) { Subscene* subscene = NULL; ModelViewpoint* modelviewpoint = scene->getCurrentSubscene()->getModelViewpoint(); if ( modelviewpoint->isInteractive() ) { translateCoords(&mouseX, &mouseY); subscene = scene->whichSubscene(mouseX, mouseY); } if (!subscene) subscene = scene->getCurrentSubscene(); subscene->wheelRotate(dir); View::update(); } void RGLView::captureLost() { if (activeSubscene) { Subscene* subscene = scene->getSubscene(activeSubscene); if (subscene) { subscene->buttonEnd(subscene->drag); subscene->drag = 0; } } } // // snapshot // bool RGLView::snapshot(PixmapFileFormatID formatID, const char* filename) { bool success = false; if ( (formatID < PIXMAP_FILEFORMAT_LAST) && (pixmapFormat[formatID])) { // alloc pixmap memory Pixmap snapshot; if (snapshot.init(RGB24, width, height, 8)) { #ifndef RGL_NO_OPENGL paint(); if ( windowImpl->beginGL() ) { // read back buffer glPushAttrib(GL_PIXEL_MODE_BIT); glReadBuffer(GL_BACK); glPixelStorei(GL_PACK_ALIGNMENT, 1); glReadPixels(0,0,width,height,GL_RGB, GL_UNSIGNED_BYTE, (GLvoid*) snapshot.data); glPopAttrib(); windowImpl->endGL(); } else #else Rf_warning("this build of rgl does not support snapshots"); #endif snapshot.clear(); success = snapshot.save( pixmapFormat[formatID], filename ); } else Rf_error("unable to create pixmap"); } else Rf_error("pixmap save format not supported in this build"); return success; } bool RGLView::pixels( int* ll, int* size, int component, double* result ) { bool success = false; #ifndef RGL_NO_OPENGL GLenum format[] = {GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_DEPTH_COMPONENT, GL_LUMINANCE}; paint(); if ( windowImpl->beginGL() ) { /* * Some OSX systems appear to have a glReadPixels * bug causing segfaults when reading the depth component. * Read those column by column. */ bool bycolumn = format[component] == GL_DEPTH_COMPONENT; int n = bycolumn ? size[1] : size[0]*size[1]; GLfloat* buffer = (GLfloat*) R_alloc(n, sizeof(GLfloat)); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); // read front buffer glPushAttrib(GL_PIXEL_MODE_BIT); glReadBuffer(GL_BACK); glPixelStorei(GL_PACK_ALIGNMENT, 1); if (bycolumn) { for(int ix=0; ixendGL(); } #endif return success; } void RGLView::getUserMatrix(double* dest) { Subscene* subscene = NULL; if (activeSubscene) subscene = scene->getSubscene(activeSubscene); if (!subscene) subscene = scene->getCurrentSubscene(); ModelViewpoint* modelviewpoint = subscene->getModelViewpoint(); modelviewpoint->getUserMatrix(dest); } void RGLView::setUserMatrix(double* src) { Subscene* subscene = NULL; if (activeSubscene) subscene = scene->getSubscene(activeSubscene); if (!subscene) subscene = scene->getCurrentSubscene(); subscene->setUserMatrix(src); View::update(); } void RGLView::getScale(double* dest) { Subscene* subscene = NULL; if (activeSubscene) subscene = scene->getSubscene(activeSubscene); if (!subscene) subscene = scene->getCurrentSubscene(); ModelViewpoint* modelviewpoint = subscene->getModelViewpoint(); modelviewpoint->getScale(dest); } void RGLView::setScale(double* src) { Subscene* subscene = NULL; if (activeSubscene) subscene = scene->getSubscene(activeSubscene); if (!subscene) subscene = scene->getCurrentSubscene(); subscene->setScale(src); View::update(); } void RGLView::setDefaultFont(const char* family, int style, double cex, bool useFreeType) { GLFont* font = View::windowImpl->getFont(family, style, cex, useFreeType); if (!font) Rf_error("font not available"); renderContext.font = font; } const char* RGLView::getFontFamily() const { if (!renderContext.font) Rf_error("font not available"); return renderContext.font->family; } void RGLView::setFontFamily(const char *family) { setDefaultFont(family, getFontStyle(), getFontCex(), getFontUseFreeType()); } int RGLView::getFontStyle() const { if (!renderContext.font) Rf_error("font not available"); return renderContext.font->style; } void RGLView::setFontStyle(int style) { setDefaultFont(getFontFamily(), style, getFontCex(), getFontUseFreeType()); } double RGLView::getFontCex() const { if (!renderContext.font) Rf_error("font not available"); return renderContext.font->cex; } void RGLView::setFontCex(double cex) { setDefaultFont(getFontFamily(), getFontStyle(), cex, getFontUseFreeType()); } const char* RGLView::getFontname() const { if (!renderContext.font) Rf_error("font not available"); return renderContext.font->fontname; } bool RGLView::getFontUseFreeType() const { if (!renderContext.font) Rf_error("font not available"); return renderContext.font->useFreeType; } void RGLView::setFontUseFreeType(bool useFreeType) { setDefaultFont(getFontFamily(), getFontStyle(), getFontCex(), useFreeType); } void RGLView::getPosition(double* dest) { Subscene* subscene = NULL; if (activeSubscene) subscene = scene->getSubscene(activeSubscene); if (!subscene) subscene = scene->getCurrentSubscene(); ModelViewpoint* modelviewpoint = subscene->getModelViewpoint(); modelviewpoint->getPosition(dest); } void RGLView::setPosition(double* src) { Subscene* subscene = NULL; if (activeSubscene) subscene = scene->getSubscene(activeSubscene); if (!subscene) subscene = scene->getCurrentSubscene(); ModelViewpoint* modelviewpoint = subscene->getModelViewpoint(); modelviewpoint->setPosition(src); } bool RGLView::postscript(int formatID, const char* filename, bool drawText) { bool success = false; std::FILE *fp = fopen(filename, "wb"); #ifndef RGL_NO_OPENGL char *oldlocale = setlocale(LC_NUMERIC, "C"); GLint buffsize = 0, state = GL2PS_OVERFLOW; GLint vp[4]; GLint options = GL2PS_SILENT | GL2PS_SIMPLE_LINE_OFFSET | GL2PS_OCCLUSION_CULL | GL2PS_BEST_ROOT; if (!drawText) options |= GL2PS_NO_TEXT; if (windowImpl->beginGL()) { glGetIntegerv(GL_VIEWPORT, vp); while( state == GL2PS_OVERFLOW ){ buffsize += 1024*1024; gl2psBeginPage ( filename, "Generated by rgl", vp, formatID, GL2PS_BSP_SORT, options, GL_RGBA, 0, NULL, 0, 0, 0, buffsize, fp, filename ); if ( drawText ) { // signal gl2ps for text scene->invalidateDisplaylists(); if (formatID == GL2PS_PS || formatID == GL2PS_EPS || formatID == GL2PS_TEX || formatID == GL2PS_PGF) renderContext.gl2psActive = GL2PS_POSITIONAL; else renderContext.gl2psActive = GL2PS_LEFT_ONLY; } // redraw: scene->render(&renderContext); glFinish(); if ( drawText ) { scene->invalidateDisplaylists(); renderContext.gl2psActive = GL2PS_NONE; } success = true; state = gl2psEndPage(); } windowImpl->endGL(); } setlocale(LC_NUMERIC, oldlocale); #else Rf_warning("this build of rgl does not support postscript"); #endif fclose(fp); return success; } void RGLView::setMouseListeners(Subscene* sub, unsigned int n, int* ids) { sub->clearMouseListeners(); for (unsigned int i=0; igetSubscene(ids[i]); if (subscene) sub->addMouseListener(subscene); } } rgl/src/NULLgui.h0000644000176200001440000000102315011677075013262 0ustar liggesusers#ifndef RGL_NULL_GUI_H #define RGL_NULL_GUI_H // --------------------------------------------------------------------------- #include "gui.h" namespace rgl { // --------------------------------------------------------------------------- class NULLGUIFactory : public GUIFactory { public: NULLGUIFactory(); virtual ~NULLGUIFactory(); WindowImpl* createWindowImpl(Window* window, int antialias); }; // --------------------------------------------------------------------------- } // namespace rgl #endif // RGL_NULL_GUI_H rgl/src/geom.cpp0000644000176200001440000001153314771520323013267 0ustar liggesusers#include "geom.h" #include "R.h" using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // AABox // AABox::AABox() { invalidate(); } void AABox::invalidate(void) { vmax = Vertex( -FLT_MAX, -FLT_MAX, -FLT_MAX ); vmin = Vertex( FLT_MAX, FLT_MAX, FLT_MAX ); } void AABox::setEmpty(void) { vmax = Vertex( -123.0, -123.0, -123.0); vmin = Vertex( 123.0, 123.0, 123.0); } void AABox::operator += (const Vertex& v) { if (!ISNAN(v.x)) { if (vmin.x <= vmax.x) { vmin.x = getMin(vmin.x, v.x); vmax.x = getMax(vmax.x, v.x); } else vmin.x = vmax.x = v.x; } if (!ISNAN(v.y)) { if (vmin.y <= vmax.y) { vmin.y = getMin(vmin.y, v.y); vmax.y = getMax(vmax.y, v.y); } else vmin.y = vmax.y = v.y; } if (!ISNAN(v.z)) { if (vmin.z <= vmax.z) { vmin.z = getMin(vmin.z, v.z); vmax.z = getMax(vmax.z, v.z); } else vmin.z = vmax.z = v.z; } } void AABox::operator += (const AABox& aabox) { if (aabox.isValid()) { *this += aabox.vmin; *this += aabox.vmax; } } void AABox::operator += (const Sphere& sphere) { *this += sphere.center - Vertex(sphere.radius,sphere.radius,sphere.radius); *this += sphere.center + Vertex(sphere.radius,sphere.radius,sphere.radius); } bool AABox::operator < (const AABox& that) const { return true; } bool AABox::isValid(void) const { return (isEmpty() || ((vmax.x >= vmin.x) && (vmax.y >= vmin.y) && (vmax.z >= vmin.z))) ? true: false; } bool AABox::isEmpty(void) const { return (vmin.x > vmax.x && vmin.x == 123.0) ? true : false; } Vertex AABox::getCenter(void) const { return Vertex( (vmax + vmin) * 0.5f ); } AABox AABox::transform(Matrix4x4& M) { if (!isValid()) return AABox(); AABox result; if (isEmpty()) { result.setEmpty(); return result; } Vertex corner; for (int i = 0; i < 2; i++) { corner.x = i ? vmax.x : vmin.x; for (int j = 0; j < 2; j++) { corner.y = j ? vmax.y : vmin.y; for (int k = 0; k < 2; k++) { corner.z = k ? vmax.z : vmin.z; result += M*corner; } } } return result; } ////////////////////////////////////////////////////////////////////////////// // // CLASS // Sphere // Sphere::Sphere(const AABox& bbox) { Vertex hdiagonal( (bbox.vmax - bbox.vmin) * 0.5f ); center = bbox.getCenter(); radius = hdiagonal.getLength(); } Sphere::Sphere(const AABox& bbox, const Vertex& s) { Vertex hdiagonal( ((bbox.vmax - bbox.vmin) * 0.5f).scale(s) ); center = bbox.getCenter(); radius = hdiagonal.getLength(); } Sphere::Sphere(const float in_radius) : center(0.0f, 0.0f, 0.0f), radius(in_radius) { } Sphere::Sphere(const Vertex& in_center, const float in_radius) : center(in_center), radius(in_radius) { } ////////////////////////////////////////////////////////////////////////////// // // CLASS // Frustum // // // setup frustum to enclose the space given by a bounding sphere, // field-of-view angle and window size. // // window size is used to provide aspect ratio. // // void Frustum::enclose(float sphere_radius, float fovangle, int width, int height) { float s=0.5, t=1.0; if (fovangle != 0.0) { float fovradians = math::deg2rad(fovangle/2.0f); s = math::sin(fovradians); t = math::tan(fovradians); ortho = false; } else { ortho = true; } distance = sphere_radius / s; znear = distance - sphere_radius; zfar = znear + sphere_radius*2.0f; float hlen = t * znear; // hold aspect ratio 1:1 float hwidth, hheight; bool inside = false; if (inside) { // inside bounding sphere: fit to max(winsize) if (width >= height) { hwidth = hlen; hheight = hlen * ( (float)height ) / ( (float)width ); } else { hwidth = hlen * ( (float)width ) / ( (float)height ); hheight = hlen; } } else { // outside(in front of) bounding sphere: fit to min(winsize) if (width >= height) { hwidth = hlen * ( (float)width ) / ( (float)height ); hheight = hlen; } else { hwidth = hlen; hheight = hlen * ( (float)height ) / ( (float)width ); } } left = -hwidth; right = hwidth; bottom = -hheight; top = hheight; } Matrix4x4 Frustum::getMatrix() { double data[16]; memset(data, 0, sizeof(data)); if (ortho) { data[0] = 2/(right - left); data[5] = 2/(top - bottom); data[10] = -2/(zfar - znear); data[12] = -(right + left)/(right - left); data[13] = -(top + bottom)/(top - bottom); data[14] = -(zfar + znear)/(zfar - znear); data[15] = 1; } else { data[0] = 2*znear/(right - left); data[5] = 2*znear/(top - bottom); data[8] = (right + left)/(right - left); data[9] = (top + bottom)/(top - bottom); data[10] = -(zfar + znear)/(zfar - znear); data[11] = -1; data[14] = -2*zfar*znear/(zfar - znear); } return Matrix4x4(data); } rgl/src/Texture.h0000644000176200001440000000265714771520323013454 0ustar liggesusers#ifndef TEXTURE_H #define TEXTURE_H #include #include "pixmap.h" #include "types.h" namespace rgl { // // CLASS // Texture // class RenderContext; class Pixmap; #include "opengl.h" class Texture : public AutoDestroy { public: enum Type { ALPHA = 1 , LUMINANCE, LUMINANCE_ALPHA, RGB, RGBA }; enum Mode { REPLACE = 0, MODULATE = 1, DECAL = 2, BLEND = 3, ADD = 4}; Texture(const char* in_filename , Type type , Mode mode , bool mipmap , unsigned int minfilter , unsigned int magfilter , bool envmap , bool deleteFile); virtual ~Texture(); bool isValid() const; void beginUse(RenderContext* renderContext); void endUse(RenderContext* renderContext); bool is_envmap() const { return envmap; } bool hasAlpha() const { return (type == ALPHA || type == LUMINANCE_ALPHA || type == RGBA ); } void getParameters(Type *out_type, Mode *out_mode, bool *out_mipmap, unsigned int *out_minfilter, unsigned int *out_magfilter, std::string *out_filename); Pixmap* getPixmap() const { return pixmap; } private: void init(RenderContext* renderContext); Pixmap* pixmap; GLuint texName; Type type; Mode mode; bool mipmap; GLenum minfilter; GLenum magfilter; bool envmap; std::string filename; #ifndef RGL_NO_OPENGL GLint internalMode; #endif bool deleteFile; }; } // namespace rgl #endif // TEXTURE_H rgl/src/TextSet.h0000644000176200001440000000257615011677075013421 0ustar liggesusers#ifndef TEXTSET_H #define TEXTSET_H #include #include #include "Shape.h" #include "render.h" #include "glgui.h" #ifdef HAVE_FREETYPE #include "FTGL/ftgl.h" #endif namespace rgl { // // TEXTSET // class TextSet : public Shape { public: TextSet(Material& in_material, int in_ntexts, char** in_texts, double *in_center, double in_adjx, double in_adjy, double in_adjz, int in_ignoreExtent, FontArray& in_fonts, int in_npos, const int* in_pos); ~TextSet(); /* Can't use display lists */ void render(RenderContext* renderContext); virtual std::string getTypeName() { return "text"; }; int getElementCount(void){ return static_cast(textArray.size()); } int getAttributeCount(SceneNode* subscene, AttribID attrib); void getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result); std::string getTextAttribute(SceneNode* subscene, AttribID attrib, int index); Vertex getPrimitiveCenter(int index) { return vertexArray[index]; } void drawBegin(RenderContext* renderContext); void drawPrimitive(RenderContext* renderContext, int index); void drawEnd(RenderContext* renderContext); private: VertexArray vertexArray; std::vector textArray; FontArray fonts; double adjx; double adjy; double adjz; int npos; int* pos; }; } // namespace rgl #endif // TEXTSET_H rgl/src/Shape.cpp0000644000176200001440000000571214771520323013402 0ustar liggesusers #include #include #include "Shape.h" #include "SceneNode.h" #include "R.h" using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // Shape // Shape::Shape(Material& in_material, bool in_ignoreExtent, TypeID in_typeID, bool in_bboxChanges) : SceneNode(in_typeID), bboxChanges(in_bboxChanges), ignoreExtent(in_ignoreExtent), material(in_material), #ifndef RGL_NO_OPENGL displayList(0), #endif drawLevel(0), doUpdate(true), transparent(in_material.isTransparent()), blended(in_material.isTransparent()) { } Shape::~Shape() { #ifndef RGL_NO_OPENGL if (displayList) glDeleteLists(displayList, 1); #endif } void Shape::update(RenderContext* renderContext) { doUpdate = false; } void Shape::draw(RenderContext* renderContext) { drawBegin(renderContext); SAVEGLERROR; for(int i=0;i/dev/null)) LIBBROTLI = $(or $(and $(wildcard $(R_TOOLS_SOFT)/lib/libbrotlidec.a),-lbrotlidec -lbrotlicommon),) PKG_LIBS += \ -lfreetype -lharfbuzz -lfreetype $(LIBBROTLI) -lpng -lbz2 -lz PKG_CPPFLAGS += -I$(R_TOOLS_SOFT)/include/freetype2 else PKG_LIBS += $(shell pkg-config --libs freetype2) PKG_CPPFLAGS += $(shell pkg-config --cflags freetype2) # work-around for freetype2 pkg-config file in Rtools43 PKG_CPPFLAGS += -I$(R_TOOLS_SOFT)/include/freetype2 endif all: winlibs $(SHLIB) $(SHLIB): winlibs winlibs: sed -e "s^@RGL_NO_OPENGL@^FALSE^" ../R/noOpenGL.R.in > ../R/noOpenGL.R clean: rm -f $(OBJECTS) $(SHLIB) rgl/src/glErrors.cpp0000644000176200001440000000152714771520323014141 0ustar liggesusers// // This file is part of RGL. // #include "opengl.h" #include "R.h" #include "platform.h" namespace rgl { int SaveErrnum = GL_NO_ERROR; } using namespace rgl; #ifndef RGL_NO_OPENGL static const char * SaveFile; static int SaveLine; #endif void saveGLerror(const char * file, int line) { #ifndef RGL_NO_OPENGL GLenum errnum; if (SaveErrnum == GL_NO_ERROR && (errnum = glGetError()) != GL_NO_ERROR) { SaveErrnum = errnum; SaveFile = file; SaveLine = line; } #endif } void checkGLerror(const char * file, int line) { #ifndef RGL_NO_OPENGL saveGLerror(file, line); if (SaveErrnum != GL_NO_ERROR) { int err = SaveErrnum; SaveErrnum = GL_NO_ERROR; while (glGetError() != GL_NO_ERROR) {} /* clear other errors, if any */ Rf_error("OpenGL error at %s:%d: %s", SaveFile, SaveLine, gluErrorString(err)); } #endif } rgl/src/BBoxDeco.cpp0000644000176200001440000006440015011677075013773 0ustar liggesusers#include "BBoxDeco.h" #ifndef RGL_NO_OPENGL #include "gl2ps.h" #endif #include "glgui.h" #include "scene.h" #include #include #include "R.h" #include "pretty.h" #if 0 // This is debugging code to track down font problems. #include "R.h" static GLenum flags[] = { GL_ALPHA_TEST , GL_AUTO_NORMAL , GL_MAP2_VERTEX_4, GL_BLEND, GL_CLIP_PLANE0, GL_CLIP_PLANE1, GL_CLIP_PLANE2, GL_COLOR_LOGIC_OP, GL_COLOR_MATERIAL, GL_COLOR_TABLE, GL_CONVOLUTION_1D, GL_CONVOLUTION_2D, GL_CULL_FACE, GL_DEPTH_TEST, GL_DITHER, GL_FOG, GL_HISTOGRAM, GL_INDEX_LOGIC_OP, GL_LIGHT0, GL_LIGHT1, GL_LIGHT2, GL_LIGHTING, GL_LINE_SMOOTH, GL_LINE_STIPPLE, GL_MAP1_COLOR_4, GL_MAP1_INDEX, GL_MAP1_NORMAL, GL_MAP1_TEXTURE_COORD_1, GL_MAP1_TEXTURE_COORD_2, GL_MAP1_TEXTURE_COORD_3, GL_MAP1_TEXTURE_COORD_4, GL_MAP1_VERTEX_3, GL_MAP1_VERTEX_4, GL_MAP2_COLOR_4, GL_MAP2_INDEX, GL_MAP2_NORMAL, GL_MAP2_TEXTURE_COORD_1, GL_MAP2_TEXTURE_COORD_2, GL_MAP2_TEXTURE_COORD_3, GL_MAP2_TEXTURE_COORD_4, GL_MAP2_VERTEX_3, GL_MAP2_VERTEX_4, GL_MINMAX, GL_NORMALIZE, GL_POINT_SMOOTH, GL_POLYGON_OFFSET_FILL, GL_POLYGON_OFFSET_LINE, GL_POLYGON_OFFSET_POINT, GL_POINT, GL_POLYGON_SMOOTH, GL_POLYGON_STIPPLE, GL_POST_COLOR_MATRIX_COLOR_TABLE, GL_POST_CONVOLUTION_COLOR_TABLE, GL_RESCALE_NORMAL, GL_SEPARABLE_2D, GL_SCISSOR_TEST, GL_STENCIL_TEST, GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_GEN_Q, GL_TEXTURE_GEN_R, GL_TEXTURE_GEN_S, GL_TEXTURE_GEN_T}; void Rpf(const char * msg) { int flag1=0, flag2 = 0; for (int i=0; i< 32; i++) { GLboolean f; glGetBooleanv( flags[i], &f); if (f) flag1 += (1 << i); glGetBooleanv( flags[i+32], &f); if (f) flag2 += (1 << i); } Rprintf("%s: Flags 0 to 31: %x 32 to 63: %x\n", msg, flag1, flag2); GLint modes[2]; glGetIntegerv( GL_POLYGON_MODE, modes); Rprintf(" Polygon modes: %X %X\n", modes[0], modes[1]); } #endif using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // BBoxDeco // AxisInfo::AxisInfo() : textArray() { mode = AXIS_LENGTH; nticks = 0; ticks = NULL; len = 2; unit = 0; } AxisInfo::AxisInfo(int in_nticks, double* in_ticks, char** in_texts, int in_len, float in_unit) { int i; nticks = in_nticks; for (i = 0; i < nticks; i++) textArray.push_back(in_texts[i]); len = in_len; unit = in_unit; ticks = NULL; if (nticks > 0) { mode = AXIS_CUSTOM; ticks = new float [nticks]; for(i=0;i 0) mode = AXIS_UNIT; else if (unit < 0 && len > 0) mode = AXIS_PRETTY; else if (len > 0) mode = AXIS_LENGTH; else mode = AXIS_NONE; } } AxisInfo::AxisInfo(AxisInfo& from) : textArray(from.textArray) { mode = from.mode; nticks = from.nticks; len = from.len; unit = from.unit; if (nticks > 0) { ticks = new float [nticks]; memcpy (ticks, from.ticks, sizeof(float)*nticks); } else ticks = NULL; } AxisInfo::~AxisInfo() { if (ticks) { delete [] ticks; } } void AxisInfo::draw(RenderContext* renderContext, Vertex4& v, Vertex4& dir, Matrix4x4& modelview, Vertex& marklen, std::string& string) { #ifndef RGL_NO_OPENGL Vertex4 p; GLboolean valid; // draw mark ( 1 time ml away ) p.x = v.x + dir.x * marklen.x; p.y = v.y + dir.y * marklen.y; p.z = v.z + dir.z * marklen.z; glBegin(GL_LINES); glVertex3f(v.x,v.y,v.z); glVertex3f(p.x,p.y,p.z); glEnd(); // draw text ( 2 times ml away ) p.x = v.x + 2 * dir.x * marklen.x; p.y = v.y + 2 * dir.y * marklen.y; p.z = v.z + 2 * dir.z * marklen.z; glRasterPos3f( p.x, p.y, p.z ); glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid); if (valid) { // Work out the text adjustment float adj = 0.5; Vertex4 eyedir = modelview * dir; bool xlarge = fabs(eyedir.x) > fabs(eyedir.y); if (xlarge) { adj = fabs(eyedir.y)/fabs(eyedir.x)/2.0f; if (eyedir.x < 0) adj = 1.0f - adj; } if (renderContext->font) renderContext->font->draw(string.c_str(), static_cast(string.size()), adj, 0.5, 0.5, 0, *renderContext); } #endif } int AxisInfo::getNticks(float low, float high) { switch (mode) { case AXIS_CUSTOM: return nticks; case AXIS_LENGTH: return len; case AXIS_UNIT: return static_cast((high - low)/unit); case AXIS_PRETTY: { double lo=low, up=high, shrink_sml=0.75, high_u_fact[2]; int ndiv=len, min_n=3, eps_correction=0; int count=0; high_u_fact[0] = 1.5; high_u_fact[1] = 2.75; unit = static_cast(R_pretty0(&lo, &up, &ndiv, min_n, shrink_sml, high_u_fact, eps_correction, 0)); for (int i=(int)lo; i<=up; i++) { float value = i*unit; if (value >= low && value <= high) count++; } return count; } } return 0; } double AxisInfo::getTick(float low, float high, int index) { switch (mode) { case AXIS_CUSTOM: return ticks[index]; case AXIS_LENGTH: { float delta = (len>1) ? (high-low)/(len-1) : 0; return low + delta*(float)index; } case AXIS_UNIT: { float value = ( (float) ( (int) ( ( low+(unit-1) ) / (unit) ) ) ) * (unit); return value + index*unit; } case AXIS_PRETTY: { double lo=low, up=high, shrink_sml=0.75, high_u_fact[2]; int ndiv=len, min_n=3, eps_correction=0; int count=0; high_u_fact[0] = 1.5; high_u_fact[1] = 2.75; unit = static_cast(R_pretty0(&lo, &up, &ndiv, min_n, shrink_sml, high_u_fact, eps_correction, 0)); for (int i=(int)lo; i<=up; i++) { float value = i*unit; if (value >= low && value <= high) { if (count == index) return value; count++; } } } } return NA_REAL; } struct Side { int vidx[4]; Vertex4 normal; Side( int i0, int i1, int i2, int i3, Vertex4 v ) : normal(v) { vidx[0] = i0; vidx[1] = i1; vidx[2] = i2; vidx[3] = i3; } }; static Side side[6] = { // BACK Side(0, 2, 3, 1, Vertex4( 0.0f, 0.0f,-1.0f, 0.0f) ), // FRONT Side(4, 5, 7, 6, Vertex4( 0.0f, 0.0f, 1.0f, 0.0f) ), // LEFT Side(4, 6, 2, 0, Vertex4(-1.0f, 0.0f, 0.0f, 0.0f) ), // RIGHT Side(5, 1, 3, 7, Vertex4( 1.0f, 0.0f, 0.0f, 0.0f) ), // BOTTOM Side(0, 1, 5, 4, Vertex4( 0.0f,-1.0f, 0.0f, 0.0f) ), // TOP Side(6, 7, 3, 2, Vertex4( 0.0f, 1.0f, 0.0f, 0.0f) ) }; struct Edge{ Edge(int in_from, int in_to, Vertex4 in_dir, Vertex3 in_code) : from(in_from), to(in_to), dir(in_dir), code(in_code) { } int from, to; Vertex4 dir; Vertex3 code; }; static Edge xaxisedge[4] = { Edge( 5,4, Vertex4( 0.0f, 0.0f, 1.0f, 0.0f), Vertex3( 0.0f, -1.0f, 1.0f) ), Edge( 0,1, Vertex4( 0.0f, 0.0f,-1.0f, 0.0f), Vertex3( 0.0f, -1.0f, -1.0f) ), Edge( 6,7, Vertex4( 0.0f, 0.0f, 1.0f, 0.0f), Vertex3( 0.0f, 1.0f, 1.0f) ), Edge( 3,2, Vertex4( 0.0f, 0.0f,-1.0f, 0.0f), Vertex3( 0.0f, 1.0f, -1.0f) ) }; static Edge yaxisedge[8] = { Edge( 5,7, Vertex4( 1.0f, 0.0f, 0.0f, 0.0f), Vertex3( 1.0f, 0.0f, 1.0f) ), Edge( 7,5, Vertex4( 0.0f, 0.0f, 1.0f, 0.0f), Vertex3( 1.0f, 0.0f, 1.0f) ), Edge( 6,4, Vertex4(-1.0f, 0.0f, 0.0f, 0.0f), Vertex3(-1.0f, 0.0f, 1.0f) ), Edge( 4,6, Vertex4( 0.0f, 0.0f, 1.0f, 0.0f), Vertex3(-1.0f, 0.0f, 1.0f) ), Edge( 2,0, Vertex4( 0.0f, 0.0f,-1.0f, 0.0f), Vertex3(-1.0f, 0.0f, -1.0f) ), Edge( 0,2, Vertex4(-1.0f, 0.0f, 0.0f, 0.0f), Vertex3(-1.0f, 0.0f, -1.0f) ), Edge( 3,1, Vertex4( 1.0f, 0.0f, 0.0f, 0.0f), Vertex3( 1.0f, 0.0f, -1.0f) ), Edge( 1,3, Vertex4( 0.0f, 0.0f,-1.0f, 0.0f), Vertex3( 1.0f, 0.0f, -1.0f) ) }; static Edge zaxisedge[4] = { Edge( 1,5, Vertex4( 1.0f, 0.0f, 0.0f, 0.0f), Vertex3( 1.0f,-1.0f, 0.0f) ), Edge( 4,0, Vertex4(-1.0f, 0.0f, 0.0f, 0.0f), Vertex3(-1.0f,-1.0f, 0.0f) ), Edge( 7,3, Vertex4( 1.0f, 0.0f, 0.0f, 0.0f), Vertex3( 1.0f, 1.0f, 0.0f) ), Edge( 2,6, Vertex4(-1.0f, 0.0f, 0.0f, 0.0f), Vertex3(-1.0f, 1.0f, 0.0f) ) }; AxisInfo BBoxDeco::defaultAxis(0,NULL,NULL,0,5); Material BBoxDeco::defaultMaterial( Color(0.6f,0.6f,0.6f,0.5f), Color(1.0f,1.0f,1.0f) ); BBoxDeco::BBoxDeco(Material& in_material, AxisInfo& in_xaxis, AxisInfo& in_yaxis, AxisInfo& in_zaxis, float in_marklen_value, bool in_marklen_fract, float in_expand, bool in_front) : SceneNode(BBOXDECO), material(in_material), xaxis(in_xaxis), yaxis(in_yaxis), zaxis(in_zaxis), marklen_value(in_marklen_value), marklen_fract(in_marklen_fract), expand(in_expand), draw_front(in_front) #ifndef RGL_NO_OPENGL , axisBusy(false) #endif { material.colors.recycle(2); } Vertex BBoxDeco::getMarkLength(const AABox& boundingBox) const { return (marklen_fract) ? (boundingBox.vmax - boundingBox.vmin) * (1 / marklen_value) : Vertex(1,1,1) * marklen_value; } AABox BBoxDeco::getBoundingBox(const AABox& in_bbox) const { AABox bbox2(in_bbox); Vertex marklen = getMarkLength(bbox2); Vertex v = marklen * 2; bbox2 += bbox2.vmin - v; bbox2 += bbox2.vmax + v; return bbox2; } struct BBoxDeco::BBoxDecoImpl { static Edge* chooseEdge(RenderContext* renderContext, BBoxDeco& bboxdeco, int coord) { AABox bbox = renderContext->subscene->getBoundingBox(); Vertex center = bbox.getCenter(); bbox += center + (bbox.vmin - center)*bboxdeco.expand; bbox += center + (bbox.vmax - center)*bboxdeco.expand; // edge adjacent matrix int adjacent[8][8] = { { 0 } }; int i,j; // vertex array: Vertex4 boxv[8] = { Vertex4( bbox.vmin.x, bbox.vmin.y, bbox.vmin.z ), Vertex4( bbox.vmax.x, bbox.vmin.y, bbox.vmin.z ), Vertex4( bbox.vmin.x, bbox.vmax.y, bbox.vmin.z ), Vertex4( bbox.vmax.x, bbox.vmax.y, bbox.vmin.z ), Vertex4( bbox.vmin.x, bbox.vmin.y, bbox.vmax.z ), Vertex4( bbox.vmax.x, bbox.vmin.y, bbox.vmax.z ), Vertex4( bbox.vmin.x, bbox.vmax.y, bbox.vmax.z ), Vertex4( bbox.vmax.x, bbox.vmax.y, bbox.vmax.z ) }; Vertex4 eyev[8]; // transform vertices: used for edge distance criterion and text justification Matrix4x4 modelview(renderContext->subscene->modelMatrix); for(i=0;i<8;i++) eyev[i] = modelview * boxv[i]; for(i=0;i<6;i++) { const Vertex4 q = modelview * side[i].normal; const Vertex4 view(0.0f,0.0f,1.0f,0.0f); float cos_a = view * q; /* break tie using x coordinate */ if (cos_a == 0.0f) { const Vertex4 view2(1.0f,0.0f,0.0f,0.0f); cos_a = view2 * q; } const bool front = (cos_a >= 0.0f) ? true : false; if (bboxdeco.draw_front || !front) { for(j=0;j<4;j++) { if (!front) { // modify adjacent matrix int from = side[i].vidx[j]; int to = side[i].vidx[(j+1)%4]; adjacent[from][to] = 1; } } } } Edge* axisedge; int nedges; switch(coord) { case 0: axisedge = xaxisedge; nedges = 4; break; case 1: axisedge = yaxisedge; nedges = 8; break; case 2: default: axisedge = zaxisedge; nedges = 4; break; } // search z-nearest contours float d = FLT_MAX; Edge* edge = NULL; for(j=0;jmarginCoord; bool match; switch(coord) { case 0: // Initialized to this case to suppress "may be unused" message // axisedge = xaxisedge; // lim = 4; break; case 1: axisedge = yaxisedge; lim = 8; break; case 2: axisedge = zaxisedge; lim = 4; break; } for (j = 0; j < lim; j++) { match = true; for (i = 0; i < 3; i++) if (coord != i && axisedge[j].code[i] != material->edge[i]) { match = false; break; } if (match) return &axisedge[j]; } Rf_error("fixedEdge: material->floating=%d marginCoord=%d edge=%d %d %d\n", material->floating, material->marginCoord, material->edge[0], material->edge[1], material->edge[2]); return axisedge; } static void setMarginParameters(RenderContext* renderContext, BBoxDeco& bboxdeco, Material* material, int *at, int* line, int* level, Vec3* trans, Vec3* scale) { Edge* edge; int j; *at = material->marginCoord; if (material->floating) edge = BBoxDecoImpl::chooseEdge(renderContext, bboxdeco, *at); else edge = BBoxDecoImpl::fixedEdge(material); if (!edge) { *at = NA_INTEGER; return; } for (j = 0; j < 3; j++) { if (edge->dir[j] != 0) { *line = j; break; } } *level = 2; for (j = 0; j < 2; j++) { if (*at != j && *line != j) { *level = j; break; } } /* Set up translation and scaling */ AABox bbox = renderContext->subscene->getBoundingBox(); Vertex marklen = bboxdeco.getMarkLength(bbox); for (j = 0; j < 3; j++) { if (j != *at) { int e = 1; if (material->floating && edge->code[j] < 0) e = -1; e = e*material->edge[j]; (*trans)[j] = e == 1 ? bbox.vmax[j] : bbox.vmin[j]; (*scale)[j] = marklen[j]*e; } else { (*trans)[j] = 0.0; (*scale)[j] = 1.0; } } }; }; void BBoxDeco::render(RenderContext* renderContext) { #ifndef RGL_NO_OPENGL AABox bbox = renderContext->subscene->getBoundingBox(); if (bbox.isValid()) { glPushAttrib(GL_ENABLE_BIT); int i,j; // vertex array: Vertex4 boxv[8] = { Vertex4( bbox.vmin.x, bbox.vmin.y, bbox.vmin.z ), Vertex4( bbox.vmax.x, bbox.vmin.y, bbox.vmin.z ), Vertex4( bbox.vmin.x, bbox.vmax.y, bbox.vmin.z ), Vertex4( bbox.vmax.x, bbox.vmax.y, bbox.vmin.z ), Vertex4( bbox.vmin.x, bbox.vmin.y, bbox.vmax.z ), Vertex4( bbox.vmax.x, bbox.vmin.y, bbox.vmax.z ), Vertex4( bbox.vmin.x, bbox.vmax.y, bbox.vmax.z ), Vertex4( bbox.vmax.x, bbox.vmax.y, bbox.vmax.z ) }; // // // transform vertices: used for edge distance criterion and text justification // Matrix4x4 modelview(renderContext->subscene->modelMatrix); // setup material material.beginUse(renderContext); if (material.line_antialias || material.isTransparent()) { // ENABLE BLENDING glEnable(GL_BLEND); } // draw back faces glBegin(GL_QUADS); for(i=0;i<6;i++) { const Vertex4 q = modelview * side[i].normal; const Vertex4 view(0.0f,0.0f,1.0f,0.0f); float cos_a = view * q; if (cos_a == 0.0f) { Vertex4 view2(1.0f,0.0f,0.0f,0.0f); cos_a = view2 * q; } const bool front = (cos_a >= 0.0f) ? true : false; if (draw_front || !front) { // draw face glNormal3f(side[i].normal.x, side[i].normal.y, side[i].normal.z); for(j=0;j<4;j++) { // feed vertex Vertex4& v = boxv[ side[i].vidx[j] ]; glVertex3f(v.x, v.y, v.z); } } } glEnd(); // setup mark length Vertex marklen = getMarkLength(bbox); // draw axis and tickmarks // find contours glDisable(GL_LIGHTING); material.useColor(1); for(i=0;i<3;i++) { Vertex4 v; AxisInfo* axis; float* valueptr; float low, high; switch(i) { case 0: axis = &xaxis; valueptr = &v.x; low = bbox.vmin.x; high = bbox.vmax.x; break; case 1: axis = &yaxis; valueptr = &v.y; low = bbox.vmin.y; high = bbox.vmax.y; break; case 2: default: axis = &zaxis; valueptr = &v.z; low = bbox.vmin.z; high = bbox.vmax.z; break; } if (axis->mode == AXIS_NONE) continue; Edge* edge = BBoxDecoImpl::chooseEdge(renderContext, *this, i); if (axis->mode == AXIS_USER) { if (!axisBusy) { axisBusy = true; if (axisCallback[i]) { int e[3]; if (edge) { e[0] = static_cast(edge->code[0]); e[1] = static_cast(edge->code[1]); e[2] = static_cast(edge->code[2]); } else{ e[0] = 0; e[1] = 0; e[2] = 0; } axisCallback[i](axisData[i], i, e); axisBusy = false; } } } else if (edge) { v = boxv[edge->from]; switch (axis->mode) { case AXIS_CUSTOM: { // draw axis and tickmarks std::vector::iterator iter; for (iter = axis->textArray.begin(), j=0; (jnticks) && (iter != axis->textArray.end());++iter, j++) { float value = axis->ticks[j]; // clip marks if ((value >= low) && (value <= high)) { *valueptr = value; axis->draw(renderContext, v, edge->dir, modelview, marklen, *iter); } } } break; case AXIS_LENGTH: { float delta = (axis->len>1) ? (high-low)/((axis->len)-1) : 0; for(int k=0;klen;k++) { float value = low + delta * (float)k; *valueptr = value; char text[32]; snprintf(text, 32, "%.4g", value); std::string string = text; axis->draw(renderContext, v, edge->dir, modelview, marklen, string); } } break; case AXIS_UNIT: { float value = ( (float) ( (int) ( ( low+(axis->unit-1) ) / (axis->unit) ) ) ) * (axis->unit); while(value < high) { *valueptr = value; char text[32]; snprintf(text, 32, "%.4g", value); std::string s = text; axis->draw(renderContext, v, edge->dir, modelview, marklen, s ); value += axis->unit; } } break; case AXIS_PRETTY: { /* These are the defaults from the R pretty() function, except min_n is 3 */ double lo=low, up=high, shrink_sml=0.75, high_u_fact[2]; int ndiv=axis->len, min_n=3, eps_correction=0; high_u_fact[0] = 1.5; high_u_fact[1] = 2.75; axis->unit = static_cast(R_pretty0(&lo, &up, &ndiv, min_n, shrink_sml, high_u_fact, eps_correction, 0)); for (int i=(int)lo; i<=up; i++) { float value = i*axis->unit; if (value >= low && value <= high) { *valueptr = value; char text[32]; snprintf(text, 32, "%.4g", value); std::string s = text; axis->draw(renderContext, v, edge->dir, modelview, marklen, s ); } } } break; } } } material.endUse(renderContext); glPopAttrib(); } #endif } Vec3 BBoxDeco::marginVecToDataVec(Vec3 marginvec, RenderContext* renderContext, Material* material) { /* Create permutation to map at, line, pos to x, y, z */ int at = 0, line = 0, level = 0; /* initialize to suppress warning */ Vec3 trans, scale; BBoxDecoImpl::setMarginParameters(renderContext, *this, material, &at, &line, &level, &trans, &scale); if (at == NA_INTEGER) return Vertex(NA_FLOAT, NA_FLOAT, NA_FLOAT); /* It might make more sense to do this by * modifying the MODELVIEW matrix, but * I couldn't get that right for some reason... */ Vertex result; AABox bbox = renderContext->subscene->getBoundingBox(); if (marginvec.missing()) result[at] = (bbox.vmin[at] + bbox.vmax[at])/2.0f; else if (marginvec.x == -INFINITY) result[at] = bbox.vmin[at]; else if (marginvec.x == INFINITY) result[at] = bbox.vmax[at]; else result[at] = marginvec.x*scale[at] + trans[at]; result[line] = marginvec.y*scale[line] + trans[line]; result[level] = marginvec.z*scale[level] + trans[level]; return result; } Vec3 BBoxDeco::marginNormalToDataNormal(Vec3 marginvec, RenderContext* renderContext, Material* material) { int at=0, line=0, level=0; /* initialize to suppress warning */ Vec3 trans, scale; BBoxDecoImpl::setMarginParameters(renderContext, *this, material, &at, &line, &level, &trans, &scale); if (at == NA_INTEGER) return Vertex(NA_FLOAT, NA_FLOAT, NA_FLOAT); Vertex result; result[at] = marginvec.x/scale[at]; result[line] = marginvec.y/scale[line]; result[level] = marginvec.z/scale[level]; return result; } void BBoxDeco::setAxisCallback(userAxisPtr fn, void* user, int axis) { axisCallback[axis] = fn; axisData[axis] = user; switch(axis) { case 0: xaxis.mode = AXIS_USER; break; case 1: yaxis.mode = AXIS_USER; break; case 2: zaxis.mode = AXIS_USER; break; } } void BBoxDeco::getAxisCallback(userAxisPtr *fn, void** user, int axis) { *fn = axisCallback[axis]; *user = axisData[axis]; } int BBoxDeco::getAttributeCount(SceneNode* subscene, AttribID attrib) { switch (attrib) { case TEXTS: { int count = ((xaxis.mode == AXIS_CUSTOM) ? xaxis.nticks : 0) + ((yaxis.mode == AXIS_CUSTOM) ? yaxis.nticks : 0) + ((zaxis.mode == AXIS_CUSTOM) ? zaxis.nticks : 0); if (count == 0) return 0; } /* if non-zero, we want labels for every vertex, so fall through. */ case VERTICES: { AABox bbox = ((Subscene*)subscene)->getBoundingBox(); return xaxis.getNticks(bbox.vmin.x, bbox.vmax.x) + yaxis.getNticks(bbox.vmin.y, bbox.vmax.y) + zaxis.getNticks(bbox.vmin.z, bbox.vmax.z); } case COLORS: return material.colors.getLength(); case FLAGS: return 2; case AXES: return 5; } return SceneNode::getAttributeCount(subscene, attrib); } void BBoxDeco::getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result) { int n = getAttributeCount(subscene, attrib); if (first + count < n) n = first + count; if (first < n) { switch(attrib) { case VERTICES: { float low, high; int i, thisn; AABox bbox = ((Subscene*)subscene)->getBoundingBox(); i = 0; low = bbox.vmin.x; high = bbox.vmax.x; thisn = xaxis.getNticks(low, high); for (int j=0; jgetBoundingBox(); count = xaxis.getNticks(bbox.vmin.x, bbox.vmax.x); if (index < count) { if (xaxis.mode == AXIS_CUSTOM) return xaxis.textArray[index]; else return ""; } index -= count; count = yaxis.getNticks(bbox.vmin.y, bbox.vmax.y); if (index < count) { if (yaxis.mode == AXIS_CUSTOM) return yaxis.textArray[index]; else return ""; } index -= count; count = zaxis.getNticks(bbox.vmin.z, bbox.vmax.z); if (index < count) { if (zaxis.mode == AXIS_CUSTOM) return zaxis.textArray[index]; else return ""; } break; } } } return ""; } rgl/src/SphereSet.h0000644000176200001440000000273514771520323013713 0ustar liggesusers#ifndef SPHERESET_H #define SPHERESET_H #include "scene.h" #include "Shape.h" #include "SphereMesh.h" namespace rgl { class SphereSet : public Shape { private: ARRAY center; ARRAY radius; SphereMesh sphereMesh; int facets, lastdrawn; bool lastendcap; bool fastTransparency; public: SphereSet(Material& in_material, int nsphere, double* center, int nradius, double* radius, int in_ignoreExtent, bool in_fastTransparency); ~SphereSet(); /** * overload **/ /* Check whether scale has changed before rendering */ void render(RenderContext* renderContext); int getElementCount(void){ return center.size(); } int getPrimitiveCount(void); int getAttributeCount(SceneNode* subscene, AttribID attrib); void getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result); /** * location of individual items **/ Vertex getPrimitiveCenter(int index); /** * Spheres appear as spheres, so their bbox depends on scaling **/ virtual AABox& getBoundingBox(Subscene* subscene); /** * begin sending items **/ void drawBegin(RenderContext* renderContext); /** * send one item **/ void drawPrimitive(RenderContext* renderContext, int index); /** * end sending items **/ void drawEnd(RenderContext* renderContext); virtual std::string getTypeName() { return "spheres"; }; }; } // namespace rgl #endif // SPHERESET_H rgl/src/gl2ps.h0000644000176200001440000002141715011677075013043 0ustar liggesusers/* * GL2PS, an OpenGL to PostScript Printing Library * Copyright (C) 1999-2020 C. Geuzaine * * This program is free software; you can redistribute it and/or * modify it under the terms of either: * * a) the GNU Library General Public License as published by the Free * Software Foundation, either version 2 of the License, or (at your * option) any later version; or * * b) the GL2PS License as published by Christophe Geuzaine, either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either * the GNU Library General Public License or the GL2PS License for * more details. * * You should have received a copy of the GNU Library General Public * License along with this library in the file named "COPYING.LGPL"; * if not, write to the Free Software Foundation, Inc., 51 Franklin * Street, Fifth Floor, Boston, MA 02110-1301, USA. * * You should have received a copy of the GL2PS License with this * library in the file named "COPYING.GL2PS"; if not, I will be glad * to provide one. * * For the latest info about gl2ps and a full list of contributors, * see http://www.geuz.org/gl2ps/. * * Please report all bugs and problems to . */ #ifndef GL2PS_H #define GL2PS_H #ifndef RGL_NO_OPENGL #include #include /* Define GL2PSDLL at compile time to build a Windows DLL */ #if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) # if defined(_MSC_VER) # pragma warning(disable:4115) # pragma warning(disable:4127) # pragma warning(disable:4996) # endif # if !defined(NOMINMAX) # define NOMINMAX # endif # include # undef NOMINMAX # if defined(GL2PSDLL) # if defined(GL2PSDLL_EXPORTS) # define GL2PSDLL_API __declspec(dllexport) # else # define GL2PSDLL_API __declspec(dllimport) # endif # else # define GL2PSDLL_API # endif #else # define GL2PSDLL_API #endif #if defined(__APPLE__) || defined(HAVE_OPENGL_GL_H) #define GL_SILENCE_DEPRECATION # include #else # include #endif /* Support for compressed PostScript/PDF/SVG and for embedded PNG images in SVG */ #if defined(HAVE_ZLIB) || defined(HAVE_LIBZ) # define GL2PS_HAVE_ZLIB # if defined(HAVE_LIBPNG) || defined(HAVE_PNG) # define GL2PS_HAVE_LIBPNG # endif #endif #if defined(HAVE_NO_VSNPRINTF) # define GL2PS_HAVE_NO_VSNPRINTF #endif /* Version number */ #define GL2PS_MAJOR_VERSION 1 #define GL2PS_MINOR_VERSION 4 #define GL2PS_PATCH_VERSION 2 #define GL2PS_EXTRA_VERSION "" #define GL2PS_VERSION (GL2PS_MAJOR_VERSION + \ 0.01 * GL2PS_MINOR_VERSION + \ 0.0001 * GL2PS_PATCH_VERSION) #define GL2PS_COPYRIGHT "(C) 1999-2020 C. Geuzaine" /* Output file formats (the values and the ordering are important!) */ #define GL2PS_PS 0 #define GL2PS_EPS 1 #define GL2PS_TEX 2 #define GL2PS_PDF 3 #define GL2PS_SVG 4 #define GL2PS_PGF 5 /* Sorting algorithms */ #define GL2PS_NO_SORT 1 #define GL2PS_SIMPLE_SORT 2 #define GL2PS_BSP_SORT 3 /* Message levels and error codes */ #define GL2PS_SUCCESS 0 #define GL2PS_INFO 1 #define GL2PS_WARNING 2 #define GL2PS_ERROR 3 #define GL2PS_NO_FEEDBACK 4 #define GL2PS_OVERFLOW 5 #define GL2PS_UNINITIALIZED 6 /* Options for gl2psBeginPage */ #define GL2PS_NONE 0 #define GL2PS_DRAW_BACKGROUND (1<<0) #define GL2PS_SIMPLE_LINE_OFFSET (1<<1) #define GL2PS_SILENT (1<<2) #define GL2PS_BEST_ROOT (1<<3) #define GL2PS_OCCLUSION_CULL (1<<4) #define GL2PS_NO_TEXT (1<<5) #define GL2PS_LANDSCAPE (1<<6) #define GL2PS_NO_PS3_SHADING (1<<7) #define GL2PS_NO_PIXMAP (1<<8) #define GL2PS_USE_CURRENT_VIEWPORT (1<<9) #define GL2PS_COMPRESS (1<<10) #define GL2PS_NO_BLENDING (1<<11) #define GL2PS_TIGHT_BOUNDING_BOX (1<<12) #define GL2PS_NO_OPENGL_CONTEXT (1<<13) #define GL2PS_NO_TEX_FONTSIZE (1<<14) /* Arguments for gl2psEnable/gl2psDisable */ #define GL2PS_POLYGON_OFFSET_FILL 1 #define GL2PS_POLYGON_BOUNDARY 2 #define GL2PS_LINE_STIPPLE 3 #define GL2PS_BLEND 4 /* Arguments for gl2psLineCap/Join */ #define GL2PS_LINE_CAP_BUTT 0 #define GL2PS_LINE_CAP_ROUND 1 #define GL2PS_LINE_CAP_SQUARE 2 #define GL2PS_LINE_JOIN_MITER 0 #define GL2PS_LINE_JOIN_ROUND 1 #define GL2PS_LINE_JOIN_BEVEL 2 /* Text alignment (o=raster position; default mode is BL): +---+ +---+ +---+ +---+ +---+ +---+ +-o-+ o---+ +---o | o | o | | o | | | | | | | | | | | | +---+ +---+ +---+ +-o-+ o---+ +---o +---+ +---+ +---+ C CL CR B BL BR T TL TR */ #define GL2PS_TEXT_C 1 #define GL2PS_TEXT_CL 2 #define GL2PS_TEXT_CR 3 #define GL2PS_TEXT_B 4 #define GL2PS_TEXT_BL 5 #define GL2PS_TEXT_BR 6 #define GL2PS_TEXT_T 7 #define GL2PS_TEXT_TL 8 #define GL2PS_TEXT_TR 9 typedef GLfloat GL2PSrgba[4]; typedef GLfloat GL2PSxyz[3]; typedef struct { GL2PSxyz xyz; GL2PSrgba rgba; } GL2PSvertex; /* Primitive types */ #define GL2PS_NO_TYPE -1 #define GL2PS_TEXT 1 #define GL2PS_POINT 2 #define GL2PS_LINE 3 #define GL2PS_QUADRANGLE 4 #define GL2PS_TRIANGLE 5 #define GL2PS_PIXMAP 6 #define GL2PS_IMAGEMAP 7 #define GL2PS_IMAGEMAP_WRITTEN 8 #define GL2PS_IMAGEMAP_VISIBLE 9 #define GL2PS_SPECIAL 10 #if defined(__cplusplus) extern "C" { #endif GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, GLint viewport[4], GLint format, GLint sort, GLint options, GLint colormode, GLint colorsize, GL2PSrgba *colormap, GLint nr, GLint ng, GLint nb, GLint buffersize, FILE *stream, const char *filename); GL2PSDLL_API GLint gl2psEndPage(void); GL2PSDLL_API GLint gl2psSetOptions(GLint options); GL2PSDLL_API GLint gl2psGetOptions(GLint *options); GL2PSDLL_API GLint gl2psBeginViewport(GLint viewport[4]); GL2PSDLL_API GLint gl2psEndViewport(void); GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, GLshort fontsize); GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, GLshort fontsize, GLint align, GLfloat angle); GL2PSDLL_API GLint gl2psTextOptColor(const char *str, const char *fontname, GLshort fontsize, GLint align, GLfloat angle, GL2PSrgba color); GL2PSDLL_API GLint gl2psTextOptColorBL(const char *str, const char *fontname, GLshort fontsize, GLint align, GLfloat angle, GL2PSrgba color, GLfloat blx, GLfloat bly); GL2PSDLL_API GLint gl2psSpecial(GLint format, const char *str); GL2PSDLL_API GLint gl2psSpecialColor(GLint format, const char *str, GL2PSrgba rgba); GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height, GLint xorig, GLint yorig, GLenum format, GLenum type, const void *pixels); GL2PSDLL_API GLint gl2psEnable(GLint mode); GL2PSDLL_API GLint gl2psDisable(GLint mode); GL2PSDLL_API GLint gl2psPointSize(GLfloat value); GL2PSDLL_API GLint gl2psLineCap(GLint value); GL2PSDLL_API GLint gl2psLineJoin(GLint value); GL2PSDLL_API GLint gl2psLineWidth(GLfloat value); GL2PSDLL_API GLint gl2psBlendFunc(GLenum sfactor, GLenum dfactor); GL2PSDLL_API GLint gl2psSorting(GLint mode); /* referenced in the documentation, but not fully documented */ GL2PSDLL_API GLint gl2psForceRasterPos(GL2PSvertex *vert); GL2PSDLL_API void gl2psAddPolyPrimitive(GLshort type, GLshort numverts, GL2PSvertex *verts, GLint offset, GLfloat ofactor, GLfloat ounits, GLushort pattern, GLint factor, GLfloat width, GLint linecap, GLint linejoin, char boundary); /* undocumented */ GL2PSDLL_API GLint gl2psDrawImageMap(GLsizei width, GLsizei height, const GLfloat position[3], const unsigned char *imagemap); GL2PSDLL_API const char *gl2psGetFileExtension(GLint format); GL2PSDLL_API const char *gl2psGetFormatDescription(GLint format); GL2PSDLL_API GLint gl2psGetFileFormat(void); GL2PSDLL_API GLint gl2psSetTexScaling(GLfloat scaling); #if defined(__cplusplus) } #endif #endif /* RGL_NO_OPENGL */ #endif /* GL2PS_H */ rgl/src/BBoxDeco.h0000644000176200001440000000476014771520323013436 0ustar liggesusers#ifndef BBOX_DECO_H #define BBOX_DECO_H #include #include #include "SceneNode.h" // // CLASS // BBoxDeco // #include "rglmath.h" #include "geom.h" #include "RenderContext.h" #include "Material.h" namespace rgl { enum { AXIS_CUSTOM, // "custom" AXIS_LENGTH, // "fixednum" AXIS_UNIT, // "fixedstep" AXIS_PRETTY, // "pretty" AXIS_USER, // "user" AXIS_NONE // "none" }; struct AxisInfo { AxisInfo(); AxisInfo(int in_nticks, double* in_values, char** in_texts, int xlen, float xunit); AxisInfo(AxisInfo& from); ~AxisInfo(); void draw(RenderContext* renderContext, Vertex4& v, Vertex4& dir, Matrix4x4& modelview, Vertex& marklen, std::string& string); int getNticks(float low, float high); double getTick(float low, float high, int index); /* double since it might be NA_REAL */ int mode; int nticks; float* ticks; int len; float unit; std::vector textArray; }; typedef void (*userAxisPtr)(void *userData, int axis, int edge[3]); class BBoxDeco : public SceneNode { public: BBoxDeco(Material& in_material=defaultMaterial, AxisInfo& xaxis=defaultAxis, AxisInfo& yaxis=defaultAxis, AxisInfo& zaxis=defaultAxis, float marklen=15.0, bool marklen_fract=true, float in_expand=1.0, bool in_front=false); void render(RenderContext* renderContext); AABox getBoundingBox(const AABox& boundingBox) const; Vertex getMarkLength(const AABox& boundingBox) const; int getAttributeCount(SceneNode* subscene, AttribID attrib); void getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result); std::string getTextAttribute(SceneNode* subscene, AttribID attrib, int index); Material* getMaterial() { return &material; } virtual std::string getTypeName() { return "bboxdeco"; }; Vec3 marginVecToDataVec(Vec3 marginvec, RenderContext* renderContext, Material* material); Vec3 marginNormalToDataNormal(Vec3 marginvec, RenderContext* renderContext, Material* material); void setAxisCallback(userAxisPtr fn, void * user, int axis); void getAxisCallback(userAxisPtr *fn, void ** user, int axis); private: struct BBoxDecoImpl; Material material; AxisInfo xaxis, yaxis, zaxis; float marklen_value; bool marklen_fract; float expand; bool draw_front; #ifndef RGL_NO_OPENGL bool axisBusy; #endif userAxisPtr axisCallback[3]; void* axisData[3]; static Material defaultMaterial; static AxisInfo defaultAxis; }; } // namespace rgl #endif // BBOX_DECO_H rgl/src/pixmap.h0000644000176200001440000000201414555455305013304 0ustar liggesusers#ifndef PIXMAP_H #define PIXMAP_H // C++ header file // This file is part of RGL #include #include "opengl.h" namespace rgl { class PixmapFormat; enum PixmapTypeID { INVALID=0, RGB24, RGB32, RGBA32, GRAY8 }; enum PixmapFileFormatID { PIXMAP_FILEFORMAT_PNG = 0, PIXMAP_FILEFORMAT_LAST }; class Pixmap { public: Pixmap(); ~Pixmap(); bool init(PixmapTypeID typeID, int width, int height, int bits_per_channel); bool load(const char* filename); bool save(PixmapFormat* format, const char* filename); void clear(); PixmapTypeID typeID; unsigned int width; unsigned int height; unsigned int bits_per_channel; unsigned int bytesperrow; unsigned char *data; }; class PixmapFormat { public: virtual ~PixmapFormat() { } virtual bool checkSignature(std::FILE* file) = 0; virtual bool load(std::FILE* file, Pixmap* pixmap) = 0; virtual bool save(std::FILE* file, Pixmap* pixmap) = 0; }; extern PixmapFormat* pixmapFormat[PIXMAP_FILEFORMAT_LAST]; } // namespace rgl #endif /* PIXMAP_H */ rgl/src/Surface.h0000644000176200001440000000304614771520323013375 0ustar liggesusers#ifndef SURFACE_H #define SURFACE_H #include "Shape.h" #include "render.h" #include namespace rgl { // // CLASS // Surface // class Surface : public Shape { public: Surface(Material& material, int nx, int nz, double* x, double* z, double* y, double* normal_x, double* normal_z, double* normal_y, double* texture_s, double* texture_t, int* coords, int orientation, int* flags, int ignoreExtent); /** * overload **/ virtual void draw(RenderContext* renderContext); /* Center of square with upper left at (ix, iz) */ Vertex getCenter(int ix, int iz); virtual std::string getTypeName() { return "surface"; }; int getAttributeCount(SceneNode* subscene, AttribID attrib); void getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result); virtual int getElementCount(void) { return (nx-1)*(nz-1); } /** * location of individual items **/ virtual Vertex getPrimitiveCenter(int item) ; /** * begin sending items **/ virtual void drawBegin(RenderContext* renderContext) ; /** * send one item **/ virtual void drawPrimitive(RenderContext* renderContext, int index) ; /** * end sending items **/ virtual void drawEnd(RenderContext* renderContext) ; private: Vertex getNormal(int ix, int iz); VertexArray vertexArray; NormalArray normalArray; TexCoordArray texCoordArray; int nx, nz, coords[3], orientation, user_normals, user_textures; bool use_normal, use_texcoord; }; } // namespace rgl #endif // SURFACE_H rgl/src/Surface.cpp0000644000176200001440000002021414771520323013724 0ustar liggesusers#include "Surface.h" #include "Material.h" using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // Surface // // in_coords permutes the coordinates to allow surfaces over arbitrary planes // orientation is 1 to swap front and back Surface::Surface(Material& in_material, int in_nx, int in_nz, double* in_x, double* in_z, double* in_y, double* in_normal_x, double* in_normal_z, double* in_normal_y, double* in_texture_s, double* in_texture_t, int* in_coords, int in_orientation, int* in_flags, int in_ignoreExtent) : Shape(in_material, in_ignoreExtent) { nx = in_nx; nz = in_nz; coords[0] = *(in_coords++); coords[1] = *(in_coords++); coords[2] = *(in_coords++); orientation = in_orientation; int nvertex = nx*nz; material.colorPerVertex(true, nvertex); vertexArray.alloc(nvertex); if (material.texture) texCoordArray.alloc(nvertex); Vertex v; float *x,*y,*z, *va[3]; va[0] = &(v.x); va[1] = &(v.y); va[2] = &(v.z); x = va[coords[0]-1]; y = va[coords[1]-1]; z = va[coords[2]-1]; int xmat = in_flags[0]; int zmat = in_flags[1]; user_normals = in_flags[2]; user_textures = in_flags[3]; if (user_normals) normalArray.alloc(nvertex); int iy = 0; for(int iz=0;izis_envmap() ) ) { if (!user_textures) { texCoordArray[iy].s = ((float)ix)/((float)(nx-1)); texCoordArray[iy].t = 1.0f - ((float)iz)/((float)(nz-1)); } else { texCoordArray[iy].s = static_cast(in_texture_s[iy]); texCoordArray[iy].t = static_cast(in_texture_t[iy]); } } } } use_normal = user_normals || material.lit || ( material.texture && material.texture->is_envmap() ); if ( use_normal && !user_normals ) { normalArray.alloc(nvertex); iy = 0; for(int iz=0;izis_envmap() ) ); if ((material.point_antialias && ( material.front == material.POINT_FACE || material.back == material.POINT_FACE)) || (material.line_antialias && ( material.front == material.LINE_FACE || material.back == material.LINE_FACE))) blended = true; } Vertex Surface::getNormal(int ix, int iz) { int i = iz*nx + ix; Vertex total(0.0f,0.0f,0.0f); if (!vertexArray[i].missing()) { // List the 8 surrounding vertices. Repat the 1st one to make looping simpler. int ind[9]; int xv[9] = { 1, 1, 0, -1, -1, -1, 0, 1, 1 }; int zv[9] = { 0, -1, -1, -1, 0, 1, 1, 1, 0 }; int okay[9]; /* checks of surrounding vertices from right counterclockwise */ for (int j=0; j<8; j++) { int xval = ix + xv[j], zval = iz + zv[j]; if (0 <= xval && xval < nx && 0 <= zval && zval < nz) { ind[j] = i + xv[j] + zv[j]*nx; okay[j] = !vertexArray[ind[j]].missing(); } else { okay[j] = 0; ind[j] = 0; } } okay[8] = okay[0]; ind[8] = ind[0]; /* Estimate normal by averaging cross-product in successive triangular sectors */ for (int j=0; j<8; j++) { if (okay[j] && okay[j+1] ) total += vertexArray.getNormal(i, ind[j], ind[j+1] ); } total.normalize(); } if (orientation) { total.x = -total.x; total.y = -total.y; total.z = -total.z; } return total; } void Surface::draw(RenderContext* renderContext) { #ifndef RGL_NO_OPENGL bool missing; drawBegin(renderContext); for(int iz=0;iz #include #include #include #include #include #include #include namespace mapbox { namespace util { template struct nth { inline static typename std::tuple_element::type get(const T& t) { return std::get(t); }; }; } namespace detail { template class Earcut { public: std::vector indices; std::size_t vertices = 0; template void operator()(const Polygon& points); private: struct Node { Node(N index, double x_, double y_) : i(index), x(x_), y(y_) {} Node(const Node&) = delete; Node& operator=(const Node&) = delete; Node(Node&&) = delete; Node& operator=(Node&&) = delete; const N i; const double x; const double y; // previous and next vertice nodes in a polygon ring Node* prev = nullptr; Node* next = nullptr; // z-order curve value int32_t z = 0; // previous and next nodes in z-order Node* prevZ = nullptr; Node* nextZ = nullptr; // indicates whether this is a steiner point bool steiner = false; }; template Node* linkedList(const Ring& points, const bool clockwise); Node* filterPoints(Node* start, Node* end = nullptr); void earcutLinked(Node* ear, int pass = 0); bool isEar(Node* ear); bool isEarHashed(Node* ear); Node* cureLocalIntersections(Node* start); void splitEarcut(Node* start); template Node* eliminateHoles(const Polygon& points, Node* outerNode); Node* eliminateHole(Node* hole, Node* outerNode); Node* findHoleBridge(Node* hole, Node* outerNode); bool sectorContainsSector(const Node* m, const Node* p); void indexCurve(Node* start); Node* sortLinked(Node* list); int32_t zOrder(const double x_, const double y_); Node* getLeftmost(Node* start); bool pointInTriangle(double ax, double ay, double bx, double by, double cx, double cy, double px, double py) const; bool isValidDiagonal(Node* a, Node* b); double area(const Node* p, const Node* q, const Node* r) const; bool equals(const Node* p1, const Node* p2); bool intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2); bool onSegment(const Node* p, const Node* q, const Node* r); int sign(double val); bool intersectsPolygon(const Node* a, const Node* b); bool locallyInside(const Node* a, const Node* b); bool middleInside(const Node* a, const Node* b); Node* splitPolygon(Node* a, Node* b); template Node* insertNode(std::size_t i, const Point& p, Node* last); void removeNode(Node* p); bool hashing; double minX, maxX; double minY, maxY; double inv_size = 0; template > class ObjectPool { public: ObjectPool() { } ObjectPool(std::size_t blockSize_) { reset(blockSize_); } ~ObjectPool() { clear(); } template T* construct(Args&&... args) { if (currentIndex >= blockSize) { currentBlock = alloc_traits::allocate(alloc, blockSize); allocations.emplace_back(currentBlock); currentIndex = 0; } T* object = ¤tBlock[currentIndex++]; alloc_traits::construct(alloc, object, std::forward(args)...); return object; } void reset(std::size_t newBlockSize) { for (auto allocation : allocations) { alloc_traits::deallocate(alloc, allocation, blockSize); } allocations.clear(); blockSize = std::max(1, newBlockSize); currentBlock = nullptr; currentIndex = blockSize; } void clear() { reset(blockSize); } private: T* currentBlock = nullptr; std::size_t currentIndex = 1; std::size_t blockSize = 1; std::vector allocations; Alloc alloc; typedef typename std::allocator_traits alloc_traits; }; ObjectPool nodes; }; template template void Earcut::operator()(const Polygon& points) { // reset indices.clear(); vertices = 0; if (points.empty()) return; double x; double y; int threshold = 80; std::size_t len = 0; for (size_t i = 0; threshold >= 0 && i < points.size(); i++) { threshold -= static_cast(points[i].size()); len += points[i].size(); } //estimate size of nodes and indices nodes.reset(len * 3 / 2); indices.reserve(len + points[0].size()); Node* outerNode = linkedList(points[0], true); if (!outerNode || outerNode->prev == outerNode->next) return; if (points.size() > 1) outerNode = eliminateHoles(points, outerNode); // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox hashing = threshold < 0; if (hashing) { Node* p = outerNode->next; minX = maxX = outerNode->x; minY = maxY = outerNode->y; do { x = p->x; y = p->y; minX = std::min(minX, x); minY = std::min(minY, y); maxX = std::max(maxX, x); maxY = std::max(maxY, y); p = p->next; } while (p != outerNode); // minX, minY and inv_size are later used to transform coords into integers for z-order calculation inv_size = std::max(maxX - minX, maxY - minY); inv_size = inv_size != .0 ? (32767. / inv_size) : .0; } earcutLinked(outerNode); nodes.clear(); } // create a circular doubly linked list from polygon points in the specified winding order template template typename Earcut::Node* Earcut::linkedList(const Ring& points, const bool clockwise) { using Point = typename Ring::value_type; double sum = 0; const std::size_t len = points.size(); std::size_t i, j; Node* last = nullptr; // calculate original winding order of a polygon ring for (i = 0, j = len > 0 ? len - 1 : 0; i < len; j = i++) { const auto& p1 = points[i]; const auto& p2 = points[j]; const double p20 = util::nth<0, Point>::get(p2); const double p10 = util::nth<0, Point>::get(p1); const double p11 = util::nth<1, Point>::get(p1); const double p21 = util::nth<1, Point>::get(p2); sum += (p20 - p10) * (p11 + p21); } // link points into circular doubly-linked list in the specified winding order if (clockwise == (sum > 0)) { for (i = 0; i < len; i++) last = insertNode(vertices + i, points[i], last); } else { for (i = len; i-- > 0;) last = insertNode(vertices + i, points[i], last); } if (last && equals(last, last->next)) { removeNode(last); last = last->next; } vertices += len; return last; } // eliminate colinear or duplicate points template typename Earcut::Node* Earcut::filterPoints(Node* start, Node* end) { if (!end) end = start; Node* p = start; bool again; do { again = false; if (!p->steiner && (equals(p, p->next) || area(p->prev, p, p->next) == 0)) { removeNode(p); p = end = p->prev; if (p == p->next) break; again = true; } else { p = p->next; } } while (again || p != end); return end; } // main ear slicing loop which triangulates a polygon (given as a linked list) template void Earcut::earcutLinked(Node* ear, int pass) { if (!ear) return; // interlink polygon nodes in z-order if (!pass && hashing) indexCurve(ear); Node* stop = ear; Node* prev; Node* next; // iterate through ears, slicing them one by one while (ear->prev != ear->next) { prev = ear->prev; next = ear->next; if (hashing ? isEarHashed(ear) : isEar(ear)) { // cut off the triangle indices.emplace_back(prev->i); indices.emplace_back(ear->i); indices.emplace_back(next->i); removeNode(ear); // skipping the next vertice leads to less sliver triangles ear = next->next; stop = next->next; continue; } ear = next; // if we looped through the whole remaining polygon and can't find any more ears if (ear == stop) { // try filtering points and slicing again if (!pass) earcutLinked(filterPoints(ear), 1); // if this didn't work, try curing all small self-intersections locally else if (pass == 1) { ear = cureLocalIntersections(filterPoints(ear)); earcutLinked(ear, 2); // as a last resort, try splitting the remaining polygon into two } else if (pass == 2) splitEarcut(ear); break; } } } // check whether a polygon node forms a valid ear with adjacent nodes template bool Earcut::isEar(Node* ear) { const Node* a = ear->prev; const Node* b = ear; const Node* c = ear->next; if (area(a, b, c) >= 0) return false; // reflex, can't be an ear // now make sure we don't have other points inside the potential ear Node* p = ear->next->next; while (p != ear->prev) { if (pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) && area(p->prev, p, p->next) >= 0) return false; p = p->next; } return true; } template bool Earcut::isEarHashed(Node* ear) { const Node* a = ear->prev; const Node* b = ear; const Node* c = ear->next; if (area(a, b, c) >= 0) return false; // reflex, can't be an ear // triangle bbox; min & max are calculated like this for speed const double minTX = std::min(a->x, std::min(b->x, c->x)); const double minTY = std::min(a->y, std::min(b->y, c->y)); const double maxTX = std::max(a->x, std::max(b->x, c->x)); const double maxTY = std::max(a->y, std::max(b->y, c->y)); // z-order range for the current triangle bbox; const int32_t minZ = zOrder(minTX, minTY); const int32_t maxZ = zOrder(maxTX, maxTY); // first look for points inside the triangle in increasing z-order Node* p = ear->nextZ; while (p && p->z <= maxZ) { if (p != ear->prev && p != ear->next && pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) && area(p->prev, p, p->next) >= 0) return false; p = p->nextZ; } // then look for points in decreasing z-order p = ear->prevZ; while (p && p->z >= minZ) { if (p != ear->prev && p != ear->next && pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) && area(p->prev, p, p->next) >= 0) return false; p = p->prevZ; } return true; } // go through all polygon nodes and cure small local self-intersections template typename Earcut::Node* Earcut::cureLocalIntersections(Node* start) { Node* p = start; do { Node* a = p->prev; Node* b = p->next->next; // a self-intersection where edge (v[i-1],v[i]) intersects (v[i+1],v[i+2]) if (!equals(a, b) && intersects(a, p, p->next, b) && locallyInside(a, b) && locallyInside(b, a)) { indices.emplace_back(a->i); indices.emplace_back(p->i); indices.emplace_back(b->i); // remove two nodes involved removeNode(p); removeNode(p->next); p = start = b; } p = p->next; } while (p != start); return filterPoints(p); } // try splitting polygon into two and triangulate them independently template void Earcut::splitEarcut(Node* start) { // look for a valid diagonal that divides the polygon into two Node* a = start; do { Node* b = a->next->next; while (b != a->prev) { if (a->i != b->i && isValidDiagonal(a, b)) { // split the polygon in two by the diagonal Node* c = splitPolygon(a, b); // filter colinear points around the cuts a = filterPoints(a, a->next); c = filterPoints(c, c->next); // run earcut on each half earcutLinked(a); earcutLinked(c); return; } b = b->next; } a = a->next; } while (a != start); } // link every hole into the outer loop, producing a single-ring polygon without holes template template typename Earcut::Node* Earcut::eliminateHoles(const Polygon& points, Node* outerNode) { const size_t len = points.size(); std::vector queue; for (size_t i = 1; i < len; i++) { Node* list = linkedList(points[i], false); if (list) { if (list == list->next) list->steiner = true; queue.push_back(getLeftmost(list)); } } std::sort(queue.begin(), queue.end(), [](const Node* a, const Node* b) { return a->x < b->x; }); // process holes from left to right for (size_t i = 0; i < queue.size(); i++) { outerNode = eliminateHole(queue[i], outerNode); } return outerNode; } // find a bridge between vertices that connects hole with an outer ring and and link it template typename Earcut::Node* Earcut::eliminateHole(Node* hole, Node* outerNode) { Node* bridge = findHoleBridge(hole, outerNode); if (!bridge) { return outerNode; } Node* bridgeReverse = splitPolygon(bridge, hole); // filter collinear points around the cuts filterPoints(bridgeReverse, bridgeReverse->next); // Check if input node was removed by the filtering return filterPoints(bridge, bridge->next); } // David Eberly's algorithm for finding a bridge between hole and outer polygon template typename Earcut::Node* Earcut::findHoleBridge(Node* hole, Node* outerNode) { Node* p = outerNode; double hx = hole->x; double hy = hole->y; double qx = -std::numeric_limits::infinity(); Node* m = nullptr; // find a segment intersected by a ray from the hole's leftmost Vertex to the left; // segment's endpoint with lesser x will be potential connection Vertex do { if (hy <= p->y && hy >= p->next->y && p->next->y != p->y) { double x = p->x + (hy - p->y) * (p->next->x - p->x) / (p->next->y - p->y); if (x <= hx && x > qx) { qx = x; m = p->x < p->next->x ? p : p->next; if (x == hx) return m; // hole touches outer segment; pick leftmost endpoint } } p = p->next; } while (p != outerNode); if (!m) return 0; // look for points inside the triangle of hole Vertex, segment intersection and endpoint; // if there are no points found, we have a valid connection; // otherwise choose the Vertex of the minimum angle with the ray as connection Vertex const Node* stop = m; double tanMin = std::numeric_limits::infinity(); double tanCur = 0; p = m; double mx = m->x; double my = m->y; do { if (hx >= p->x && p->x >= mx && hx != p->x && pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p->x, p->y)) { tanCur = std::abs(hy - p->y) / (hx - p->x); // tangential if (locallyInside(p, hole) && (tanCur < tanMin || (tanCur == tanMin && (p->x > m->x || sectorContainsSector(m, p))))) { m = p; tanMin = tanCur; } } p = p->next; } while (p != stop); return m; } // whether sector in vertex m contains sector in vertex p in the same coordinates template bool Earcut::sectorContainsSector(const Node* m, const Node* p) { return area(m->prev, m, p->prev) < 0 && area(p->next, m, m->next) < 0; } // interlink polygon nodes in z-order template void Earcut::indexCurve(Node* start) { assert(start); Node* p = start; do { p->z = p->z ? p->z : zOrder(p->x, p->y); p->prevZ = p->prev; p->nextZ = p->next; p = p->next; } while (p != start); p->prevZ->nextZ = nullptr; p->prevZ = nullptr; sortLinked(p); } // Simon Tatham's linked list merge sort algorithm // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html template typename Earcut::Node* Earcut::sortLinked(Node* list) { assert(list); Node* p; Node* q; Node* e; Node* tail; int i, numMerges, pSize, qSize; int inSize = 1; for (;;) { p = list; list = nullptr; tail = nullptr; numMerges = 0; while (p) { numMerges++; q = p; pSize = 0; for (i = 0; i < inSize; i++) { pSize++; q = q->nextZ; if (!q) break; } qSize = inSize; while (pSize > 0 || (qSize > 0 && q)) { if (pSize == 0) { e = q; q = q->nextZ; qSize--; } else if (qSize == 0 || !q) { e = p; p = p->nextZ; pSize--; } else if (p->z <= q->z) { e = p; p = p->nextZ; pSize--; } else { e = q; q = q->nextZ; qSize--; } if (tail) tail->nextZ = e; else list = e; e->prevZ = tail; tail = e; } p = q; } tail->nextZ = nullptr; if (numMerges <= 1) return list; inSize *= 2; } } // z-order of a Vertex given coords and size of the data bounding box template int32_t Earcut::zOrder(const double x_, const double y_) { // coords are transformed into non-negative 15-bit integer range int32_t x = static_cast((x_ - minX) * inv_size); int32_t y = static_cast((y_ - minY) * inv_size); x = (x | (x << 8)) & 0x00FF00FF; x = (x | (x << 4)) & 0x0F0F0F0F; x = (x | (x << 2)) & 0x33333333; x = (x | (x << 1)) & 0x55555555; y = (y | (y << 8)) & 0x00FF00FF; y = (y | (y << 4)) & 0x0F0F0F0F; y = (y | (y << 2)) & 0x33333333; y = (y | (y << 1)) & 0x55555555; return x | (y << 1); } // find the leftmost node of a polygon ring template typename Earcut::Node* Earcut::getLeftmost(Node* start) { Node* p = start; Node* leftmost = start; do { if (p->x < leftmost->x || (p->x == leftmost->x && p->y < leftmost->y)) leftmost = p; p = p->next; } while (p != start); return leftmost; } // check if a point lies within a convex triangle template bool Earcut::pointInTriangle(double ax, double ay, double bx, double by, double cx, double cy, double px, double py) const { return (cx - px) * (ay - py) >= (ax - px) * (cy - py) && (ax - px) * (by - py) >= (bx - px) * (ay - py) && (bx - px) * (cy - py) >= (cx - px) * (by - py); } // check if a diagonal between two polygon nodes is valid (lies in polygon interior) template bool Earcut::isValidDiagonal(Node* a, Node* b) { return a->next->i != b->i && a->prev->i != b->i && !intersectsPolygon(a, b) && // dones't intersect other edges ((locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible (area(a->prev, a, b->prev) != 0.0 || area(a, b->prev, b) != 0.0)) || // does not create opposite-facing sectors (equals(a, b) && area(a->prev, a, a->next) > 0 && area(b->prev, b, b->next) > 0)); // special zero-length case } // signed area of a triangle template double Earcut::area(const Node* p, const Node* q, const Node* r) const { return (q->y - p->y) * (r->x - q->x) - (q->x - p->x) * (r->y - q->y); } // check if two points are equal template bool Earcut::equals(const Node* p1, const Node* p2) { return p1->x == p2->x && p1->y == p2->y; } // check if two segments intersect template bool Earcut::intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2) { int o1 = sign(area(p1, q1, p2)); int o2 = sign(area(p1, q1, q2)); int o3 = sign(area(p2, q2, p1)); int o4 = sign(area(p2, q2, q1)); if (o1 != o2 && o3 != o4) return true; // general case if (o1 == 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1 if (o2 == 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1 if (o3 == 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2 if (o4 == 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2 return false; } // for collinear points p, q, r, check if point q lies on segment pr template bool Earcut::onSegment(const Node* p, const Node* q, const Node* r) { return q->x <= std::max(p->x, r->x) && q->x >= std::min(p->x, r->x) && q->y <= std::max(p->y, r->y) && q->y >= std::min(p->y, r->y); } template int Earcut::sign(double val) { return (0.0 < val) - (val < 0.0); } // check if a polygon diagonal intersects any polygon segments template bool Earcut::intersectsPolygon(const Node* a, const Node* b) { const Node* p = a; do { if (p->i != a->i && p->next->i != a->i && p->i != b->i && p->next->i != b->i && intersects(p, p->next, a, b)) return true; p = p->next; } while (p != a); return false; } // check if a polygon diagonal is locally inside the polygon template bool Earcut::locallyInside(const Node* a, const Node* b) { return area(a->prev, a, a->next) < 0 ? area(a, b, a->next) >= 0 && area(a, a->prev, b) >= 0 : area(a, b, a->prev) < 0 || area(a, a->next, b) < 0; } // check if the middle Vertex of a polygon diagonal is inside the polygon template bool Earcut::middleInside(const Node* a, const Node* b) { const Node* p = a; bool inside = false; double px = (a->x + b->x) / 2; double py = (a->y + b->y) / 2; do { if (((p->y > py) != (p->next->y > py)) && p->next->y != p->y && (px < (p->next->x - p->x) * (py - p->y) / (p->next->y - p->y) + p->x)) inside = !inside; p = p->next; } while (p != a); return inside; } // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits // polygon into two; if one belongs to the outer ring and another to a hole, it merges it into a // single ring template typename Earcut::Node* Earcut::splitPolygon(Node* a, Node* b) { Node* a2 = nodes.construct(a->i, a->x, a->y); Node* b2 = nodes.construct(b->i, b->x, b->y); Node* an = a->next; Node* bp = b->prev; a->next = b; b->prev = a; a2->next = an; an->prev = a2; b2->next = a2; a2->prev = b2; bp->next = b2; b2->prev = bp; return b2; } // create a node and util::optionally link it with previous one (in a circular doubly linked list) template template typename Earcut::Node* Earcut::insertNode(std::size_t i, const Point& pt, Node* last) { Node* p = nodes.construct(static_cast(i), util::nth<0, Point>::get(pt), util::nth<1, Point>::get(pt)); if (!last) { p->prev = p; p->next = p; } else { assert(last); p->next = last->next; p->prev = last; last->next->prev = p; last->next = p; } return p; } template void Earcut::removeNode(Node* p) { p->next->prev = p->prev; p->prev->next = p->next; if (p->prevZ) p->prevZ->nextZ = p->nextZ; if (p->nextZ) p->nextZ->prevZ = p->prevZ; } } template std::vector earcut(const Polygon& poly) { mapbox::detail::Earcut earcut; earcut(poly); return std::move(earcut.indices); } } rgl/src/useNULL/ext/earcut/earcut/0000755000176200001440000000000015026777212016473 5ustar liggesusersrgl/src/useNULL/ext/earcut/earcut/earcut.h0000644000176200001440000006062115011677075020134 0ustar liggesusers#pragma once #include #include #include #include #include #include #include #include namespace mapbox { namespace util { template struct nth { inline static typename std::tuple_element::type get(const T& t) { return std::get(t); }; }; } namespace detail { template class Earcut { public: std::vector indices; std::size_t vertices = 0; template void operator()(const Polygon& points); private: struct Node { Node(N index, double x_, double y_) : i(index), x(x_), y(y_) {} Node(const Node&) = delete; Node& operator=(const Node&) = delete; Node(Node&&) = delete; Node& operator=(Node&&) = delete; const N i; const double x; const double y; // previous and next vertice nodes in a polygon ring Node* prev = nullptr; Node* next = nullptr; // z-order curve value int32_t z = 0; // previous and next nodes in z-order Node* prevZ = nullptr; Node* nextZ = nullptr; // indicates whether this is a steiner point bool steiner = false; }; template Node* linkedList(const Ring& points, const bool clockwise); Node* filterPoints(Node* start, Node* end = nullptr); void earcutLinked(Node* ear, int pass = 0); bool isEar(Node* ear); bool isEarHashed(Node* ear); Node* cureLocalIntersections(Node* start); void splitEarcut(Node* start); template Node* eliminateHoles(const Polygon& points, Node* outerNode); Node* eliminateHole(Node* hole, Node* outerNode); Node* findHoleBridge(Node* hole, Node* outerNode); bool sectorContainsSector(const Node* m, const Node* p); void indexCurve(Node* start); Node* sortLinked(Node* list); int32_t zOrder(const double x_, const double y_); Node* getLeftmost(Node* start); bool pointInTriangle(double ax, double ay, double bx, double by, double cx, double cy, double px, double py) const; bool isValidDiagonal(Node* a, Node* b); double area(const Node* p, const Node* q, const Node* r) const; bool equals(const Node* p1, const Node* p2); bool intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2); bool onSegment(const Node* p, const Node* q, const Node* r); int sign(double val); bool intersectsPolygon(const Node* a, const Node* b); bool locallyInside(const Node* a, const Node* b); bool middleInside(const Node* a, const Node* b); Node* splitPolygon(Node* a, Node* b); template Node* insertNode(std::size_t i, const Point& p, Node* last); void removeNode(Node* p); bool hashing; double minX, maxX; double minY, maxY; double inv_size = 0; template > class ObjectPool { public: ObjectPool() { } ObjectPool(std::size_t blockSize_) { reset(blockSize_); } ~ObjectPool() { clear(); } template T* construct(Args&&... args) { if (currentIndex >= blockSize) { currentBlock = alloc_traits::allocate(alloc, blockSize); allocations.emplace_back(currentBlock); currentIndex = 0; } T* object = ¤tBlock[currentIndex++]; alloc_traits::construct(alloc, object, std::forward(args)...); return object; } void reset(std::size_t newBlockSize) { for (auto allocation : allocations) { alloc_traits::deallocate(alloc, allocation, blockSize); } allocations.clear(); blockSize = std::max(1, newBlockSize); currentBlock = nullptr; currentIndex = blockSize; } void clear() { reset(blockSize); } private: T* currentBlock = nullptr; std::size_t currentIndex = 1; std::size_t blockSize = 1; std::vector allocations; Alloc alloc; typedef typename std::allocator_traits alloc_traits; }; ObjectPool nodes; }; template template void Earcut::operator()(const Polygon& points) { // reset indices.clear(); vertices = 0; if (points.empty()) return; double x; double y; int threshold = 80; std::size_t len = 0; for (size_t i = 0; threshold >= 0 && i < points.size(); i++) { threshold -= static_cast(points[i].size()); len += points[i].size(); } //estimate size of nodes and indices nodes.reset(len * 3 / 2); indices.reserve(len + points[0].size()); Node* outerNode = linkedList(points[0], true); if (!outerNode || outerNode->prev == outerNode->next) return; if (points.size() > 1) outerNode = eliminateHoles(points, outerNode); // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox hashing = threshold < 0; if (hashing) { Node* p = outerNode->next; minX = maxX = outerNode->x; minY = maxY = outerNode->y; do { x = p->x; y = p->y; minX = std::min(minX, x); minY = std::min(minY, y); maxX = std::max(maxX, x); maxY = std::max(maxY, y); p = p->next; } while (p != outerNode); // minX, minY and inv_size are later used to transform coords into integers for z-order calculation inv_size = std::max(maxX - minX, maxY - minY); inv_size = inv_size != .0 ? (32767. / inv_size) : .0; } earcutLinked(outerNode); nodes.clear(); } // create a circular doubly linked list from polygon points in the specified winding order template template typename Earcut::Node* Earcut::linkedList(const Ring& points, const bool clockwise) { using Point = typename Ring::value_type; double sum = 0; const std::size_t len = points.size(); std::size_t i, j; Node* last = nullptr; // calculate original winding order of a polygon ring for (i = 0, j = len > 0 ? len - 1 : 0; i < len; j = i++) { const auto& p1 = points[i]; const auto& p2 = points[j]; const double p20 = util::nth<0, Point>::get(p2); const double p10 = util::nth<0, Point>::get(p1); const double p11 = util::nth<1, Point>::get(p1); const double p21 = util::nth<1, Point>::get(p2); sum += (p20 - p10) * (p11 + p21); } // link points into circular doubly-linked list in the specified winding order if (clockwise == (sum > 0)) { for (i = 0; i < len; i++) last = insertNode(vertices + i, points[i], last); } else { for (i = len; i-- > 0;) last = insertNode(vertices + i, points[i], last); } if (last && equals(last, last->next)) { removeNode(last); last = last->next; } vertices += len; return last; } // eliminate colinear or duplicate points template typename Earcut::Node* Earcut::filterPoints(Node* start, Node* end) { if (!end) end = start; Node* p = start; bool again; do { again = false; if (!p->steiner && (equals(p, p->next) || area(p->prev, p, p->next) == 0)) { removeNode(p); p = end = p->prev; if (p == p->next) break; again = true; } else { p = p->next; } } while (again || p != end); return end; } // main ear slicing loop which triangulates a polygon (given as a linked list) template void Earcut::earcutLinked(Node* ear, int pass) { if (!ear) return; // interlink polygon nodes in z-order if (!pass && hashing) indexCurve(ear); Node* stop = ear; Node* prev; Node* next; // iterate through ears, slicing them one by one while (ear->prev != ear->next) { prev = ear->prev; next = ear->next; if (hashing ? isEarHashed(ear) : isEar(ear)) { // cut off the triangle indices.emplace_back(prev->i); indices.emplace_back(ear->i); indices.emplace_back(next->i); removeNode(ear); // skipping the next vertice leads to less sliver triangles ear = next->next; stop = next->next; continue; } ear = next; // if we looped through the whole remaining polygon and can't find any more ears if (ear == stop) { // try filtering points and slicing again if (!pass) earcutLinked(filterPoints(ear), 1); // if this didn't work, try curing all small self-intersections locally else if (pass == 1) { ear = cureLocalIntersections(filterPoints(ear)); earcutLinked(ear, 2); // as a last resort, try splitting the remaining polygon into two } else if (pass == 2) splitEarcut(ear); break; } } } // check whether a polygon node forms a valid ear with adjacent nodes template bool Earcut::isEar(Node* ear) { const Node* a = ear->prev; const Node* b = ear; const Node* c = ear->next; if (area(a, b, c) >= 0) return false; // reflex, can't be an ear // now make sure we don't have other points inside the potential ear Node* p = ear->next->next; while (p != ear->prev) { if (pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) && area(p->prev, p, p->next) >= 0) return false; p = p->next; } return true; } template bool Earcut::isEarHashed(Node* ear) { const Node* a = ear->prev; const Node* b = ear; const Node* c = ear->next; if (area(a, b, c) >= 0) return false; // reflex, can't be an ear // triangle bbox; min & max are calculated like this for speed const double minTX = std::min(a->x, std::min(b->x, c->x)); const double minTY = std::min(a->y, std::min(b->y, c->y)); const double maxTX = std::max(a->x, std::max(b->x, c->x)); const double maxTY = std::max(a->y, std::max(b->y, c->y)); // z-order range for the current triangle bbox; const int32_t minZ = zOrder(minTX, minTY); const int32_t maxZ = zOrder(maxTX, maxTY); // first look for points inside the triangle in increasing z-order Node* p = ear->nextZ; while (p && p->z <= maxZ) { if (p != ear->prev && p != ear->next && pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) && area(p->prev, p, p->next) >= 0) return false; p = p->nextZ; } // then look for points in decreasing z-order p = ear->prevZ; while (p && p->z >= minZ) { if (p != ear->prev && p != ear->next && pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) && area(p->prev, p, p->next) >= 0) return false; p = p->prevZ; } return true; } // go through all polygon nodes and cure small local self-intersections template typename Earcut::Node* Earcut::cureLocalIntersections(Node* start) { Node* p = start; do { Node* a = p->prev; Node* b = p->next->next; // a self-intersection where edge (v[i-1],v[i]) intersects (v[i+1],v[i+2]) if (!equals(a, b) && intersects(a, p, p->next, b) && locallyInside(a, b) && locallyInside(b, a)) { indices.emplace_back(a->i); indices.emplace_back(p->i); indices.emplace_back(b->i); // remove two nodes involved removeNode(p); removeNode(p->next); p = start = b; } p = p->next; } while (p != start); return filterPoints(p); } // try splitting polygon into two and triangulate them independently template void Earcut::splitEarcut(Node* start) { // look for a valid diagonal that divides the polygon into two Node* a = start; do { Node* b = a->next->next; while (b != a->prev) { if (a->i != b->i && isValidDiagonal(a, b)) { // split the polygon in two by the diagonal Node* c = splitPolygon(a, b); // filter colinear points around the cuts a = filterPoints(a, a->next); c = filterPoints(c, c->next); // run earcut on each half earcutLinked(a); earcutLinked(c); return; } b = b->next; } a = a->next; } while (a != start); } // link every hole into the outer loop, producing a single-ring polygon without holes template template typename Earcut::Node* Earcut::eliminateHoles(const Polygon& points, Node* outerNode) { const size_t len = points.size(); std::vector queue; for (size_t i = 1; i < len; i++) { Node* list = linkedList(points[i], false); if (list) { if (list == list->next) list->steiner = true; queue.push_back(getLeftmost(list)); } } std::sort(queue.begin(), queue.end(), [](const Node* a, const Node* b) { return a->x < b->x; }); // process holes from left to right for (size_t i = 0; i < queue.size(); i++) { outerNode = eliminateHole(queue[i], outerNode); } return outerNode; } // find a bridge between vertices that connects hole with an outer ring and and link it template typename Earcut::Node* Earcut::eliminateHole(Node* hole, Node* outerNode) { Node* bridge = findHoleBridge(hole, outerNode); if (!bridge) { return outerNode; } Node* bridgeReverse = splitPolygon(bridge, hole); // filter collinear points around the cuts filterPoints(bridgeReverse, bridgeReverse->next); // Check if input node was removed by the filtering return filterPoints(bridge, bridge->next); } // David Eberly's algorithm for finding a bridge between hole and outer polygon template typename Earcut::Node* Earcut::findHoleBridge(Node* hole, Node* outerNode) { Node* p = outerNode; double hx = hole->x; double hy = hole->y; double qx = -std::numeric_limits::infinity(); Node* m = nullptr; // find a segment intersected by a ray from the hole's leftmost Vertex to the left; // segment's endpoint with lesser x will be potential connection Vertex do { if (hy <= p->y && hy >= p->next->y && p->next->y != p->y) { double x = p->x + (hy - p->y) * (p->next->x - p->x) / (p->next->y - p->y); if (x <= hx && x > qx) { qx = x; m = p->x < p->next->x ? p : p->next; if (x == hx) return m; // hole touches outer segment; pick leftmost endpoint } } p = p->next; } while (p != outerNode); if (!m) return 0; // look for points inside the triangle of hole Vertex, segment intersection and endpoint; // if there are no points found, we have a valid connection; // otherwise choose the Vertex of the minimum angle with the ray as connection Vertex const Node* stop = m; double tanMin = std::numeric_limits::infinity(); double tanCur = 0; p = m; double mx = m->x; double my = m->y; do { if (hx >= p->x && p->x >= mx && hx != p->x && pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p->x, p->y)) { tanCur = std::abs(hy - p->y) / (hx - p->x); // tangential if (locallyInside(p, hole) && (tanCur < tanMin || (tanCur == tanMin && (p->x > m->x || sectorContainsSector(m, p))))) { m = p; tanMin = tanCur; } } p = p->next; } while (p != stop); return m; } // whether sector in vertex m contains sector in vertex p in the same coordinates template bool Earcut::sectorContainsSector(const Node* m, const Node* p) { return area(m->prev, m, p->prev) < 0 && area(p->next, m, m->next) < 0; } // interlink polygon nodes in z-order template void Earcut::indexCurve(Node* start) { assert(start); Node* p = start; do { p->z = p->z ? p->z : zOrder(p->x, p->y); p->prevZ = p->prev; p->nextZ = p->next; p = p->next; } while (p != start); p->prevZ->nextZ = nullptr; p->prevZ = nullptr; sortLinked(p); } // Simon Tatham's linked list merge sort algorithm // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html template typename Earcut::Node* Earcut::sortLinked(Node* list) { assert(list); Node* p; Node* q; Node* e; Node* tail; int i, numMerges, pSize, qSize; int inSize = 1; for (;;) { p = list; list = nullptr; tail = nullptr; numMerges = 0; while (p) { numMerges++; q = p; pSize = 0; for (i = 0; i < inSize; i++) { pSize++; q = q->nextZ; if (!q) break; } qSize = inSize; while (pSize > 0 || (qSize > 0 && q)) { if (pSize == 0) { e = q; q = q->nextZ; qSize--; } else if (qSize == 0 || !q) { e = p; p = p->nextZ; pSize--; } else if (p->z <= q->z) { e = p; p = p->nextZ; pSize--; } else { e = q; q = q->nextZ; qSize--; } if (tail) tail->nextZ = e; else list = e; e->prevZ = tail; tail = e; } p = q; } tail->nextZ = nullptr; if (numMerges <= 1) return list; inSize *= 2; } } // z-order of a Vertex given coords and size of the data bounding box template int32_t Earcut::zOrder(const double x_, const double y_) { // coords are transformed into non-negative 15-bit integer range int32_t x = static_cast((x_ - minX) * inv_size); int32_t y = static_cast((y_ - minY) * inv_size); x = (x | (x << 8)) & 0x00FF00FF; x = (x | (x << 4)) & 0x0F0F0F0F; x = (x | (x << 2)) & 0x33333333; x = (x | (x << 1)) & 0x55555555; y = (y | (y << 8)) & 0x00FF00FF; y = (y | (y << 4)) & 0x0F0F0F0F; y = (y | (y << 2)) & 0x33333333; y = (y | (y << 1)) & 0x55555555; return x | (y << 1); } // find the leftmost node of a polygon ring template typename Earcut::Node* Earcut::getLeftmost(Node* start) { Node* p = start; Node* leftmost = start; do { if (p->x < leftmost->x || (p->x == leftmost->x && p->y < leftmost->y)) leftmost = p; p = p->next; } while (p != start); return leftmost; } // check if a point lies within a convex triangle template bool Earcut::pointInTriangle(double ax, double ay, double bx, double by, double cx, double cy, double px, double py) const { return (cx - px) * (ay - py) >= (ax - px) * (cy - py) && (ax - px) * (by - py) >= (bx - px) * (ay - py) && (bx - px) * (cy - py) >= (cx - px) * (by - py); } // check if a diagonal between two polygon nodes is valid (lies in polygon interior) template bool Earcut::isValidDiagonal(Node* a, Node* b) { return a->next->i != b->i && a->prev->i != b->i && !intersectsPolygon(a, b) && // dones't intersect other edges ((locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible (area(a->prev, a, b->prev) != 0.0 || area(a, b->prev, b) != 0.0)) || // does not create opposite-facing sectors (equals(a, b) && area(a->prev, a, a->next) > 0 && area(b->prev, b, b->next) > 0)); // special zero-length case } // signed area of a triangle template double Earcut::area(const Node* p, const Node* q, const Node* r) const { return (q->y - p->y) * (r->x - q->x) - (q->x - p->x) * (r->y - q->y); } // check if two points are equal template bool Earcut::equals(const Node* p1, const Node* p2) { return p1->x == p2->x && p1->y == p2->y; } // check if two segments intersect template bool Earcut::intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2) { int o1 = sign(area(p1, q1, p2)); int o2 = sign(area(p1, q1, q2)); int o3 = sign(area(p2, q2, p1)); int o4 = sign(area(p2, q2, q1)); if (o1 != o2 && o3 != o4) return true; // general case if (o1 == 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1 if (o2 == 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1 if (o3 == 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2 if (o4 == 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2 return false; } // for collinear points p, q, r, check if point q lies on segment pr template bool Earcut::onSegment(const Node* p, const Node* q, const Node* r) { return q->x <= std::max(p->x, r->x) && q->x >= std::min(p->x, r->x) && q->y <= std::max(p->y, r->y) && q->y >= std::min(p->y, r->y); } template int Earcut::sign(double val) { return (0.0 < val) - (val < 0.0); } // check if a polygon diagonal intersects any polygon segments template bool Earcut::intersectsPolygon(const Node* a, const Node* b) { const Node* p = a; do { if (p->i != a->i && p->next->i != a->i && p->i != b->i && p->next->i != b->i && intersects(p, p->next, a, b)) return true; p = p->next; } while (p != a); return false; } // check if a polygon diagonal is locally inside the polygon template bool Earcut::locallyInside(const Node* a, const Node* b) { return area(a->prev, a, a->next) < 0 ? area(a, b, a->next) >= 0 && area(a, a->prev, b) >= 0 : area(a, b, a->prev) < 0 || area(a, a->next, b) < 0; } // check if the middle Vertex of a polygon diagonal is inside the polygon template bool Earcut::middleInside(const Node* a, const Node* b) { const Node* p = a; bool inside = false; double px = (a->x + b->x) / 2; double py = (a->y + b->y) / 2; do { if (((p->y > py) != (p->next->y > py)) && p->next->y != p->y && (px < (p->next->x - p->x) * (py - p->y) / (p->next->y - p->y) + p->x)) inside = !inside; p = p->next; } while (p != a); return inside; } // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits // polygon into two; if one belongs to the outer ring and another to a hole, it merges it into a // single ring template typename Earcut::Node* Earcut::splitPolygon(Node* a, Node* b) { Node* a2 = nodes.construct(a->i, a->x, a->y); Node* b2 = nodes.construct(b->i, b->x, b->y); Node* an = a->next; Node* bp = b->prev; a->next = b; b->prev = a; a2->next = an; an->prev = a2; b2->next = a2; a2->prev = b2; bp->next = b2; b2->prev = bp; return b2; } // create a node and util::optionally link it with previous one (in a circular doubly linked list) template template typename Earcut::Node* Earcut::insertNode(std::size_t i, const Point& pt, Node* last) { Node* p = nodes.construct(static_cast(i), util::nth<0, Point>::get(pt), util::nth<1, Point>::get(pt)); if (!last) { p->prev = p; p->next = p; } else { assert(last); p->next = last->next; p->prev = last; last->next->prev = p; last->next = p; } return p; } template void Earcut::removeNode(Node* p) { p->next->prev = p->prev; p->prev->next = p->next; if (p->prevZ) p->prevZ->nextZ = p->nextZ; if (p->nextZ) p->nextZ->prevZ = p->prevZ; } } template std::vector earcut(const Polygon& poly) { mapbox::detail::Earcut earcut; earcut(poly); return std::move(earcut.indices); } } rgl/src/useNULL/ext/earcut/earcut/LICENSE0000644000176200001440000000134215011677075017500 0ustar liggesusersISC License Copyright (c) 2015, Mapbox Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. rgl/src/useNULL/ext/earcut/LICENSE0000644000176200001440000000134214716345667016227 0ustar liggesusersISC License Copyright (c) 2015, Mapbox Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. rgl/src/fps.cpp0000644000176200001440000000140014771520323013120 0ustar liggesusers// C++ source // This file is part of RGL. // #include "fps.h" #include "glgui.h" #include using namespace rgl; void FPS::init(double time) { lastTime = time; framecnt = 0; buffer[0] = '0'; buffer[1] = '\0'; } void FPS::render(double t, RenderContext* ctx) { #ifndef RGL_NO_OPENGL if (lastTime + 1.0f < t ) { lastTime = t; snprintf(buffer, sizeof(buffer), "FPS %d", framecnt); framecnt = 0; } glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.0f,1.0f,-1.0f,1.0f,-1.0f,1.0f); glColor3f(1.0f,1.0f,1.0f); glRasterPos2f( 1.0f, -0.9f); if (ctx->font) ctx->font->draw(buffer, static_cast(strlen(buffer)), -1, 0.0, 0.5, 0, *ctx); framecnt++; #endif } rgl/src/pragma.h0000644000176200001440000000150114265301465013250 0ustar liggesusers#ifndef RGL_PRAGMA_H #define RGL_PRAGMA_H /** * compiler- and platform-specific pragma's **/ // // ---[ Borland C++ ]--------------------------------------------------------- // #ifdef __BCPLUSPLUS__ #define _RWSTD_NO_EXCEPTIONS #define ARCH_X86 #endif // // ---[ Microsoft Visual C++ ]------------------------------------------------ // #ifdef _MSC_VER #pragma warning(disable:4530) /** * remove warnings on truncated 'debug information' to 255 characters **/ #pragma warning(disable:4786) /** * remove warnings " 'this' : used in base member initializer list " **/ #pragma warning(disable:4355) #ifdef _M_IX86 #define ARCH_X86 #endif #endif // // ---[ GCC ]----------------------------------------------------------------- // #ifdef __GNUC__ #ifdef _X86_ #define ARCH_X86 #endif #endif #endif // RGL_PRAGMA_H rgl/src/RenderContext.h0000644000176200001440000000112214771520323014562 0ustar liggesusers#ifndef RENDERCONTEXT_H #define RENDERCONTEXT_H namespace rgl { class Subscene; class GLFont; } // namespace rgl #include "rglmath.h" #include "opengl.h" namespace rgl { class RenderContext { public: RenderContext() : subscene(0) , rect(0,0,256,256) , font(0) , time(0.0) , lastTime(0.0) , deltaTime(0.0) , gl2psActive(0) { } Subscene* subscene; Rect2 rect; // This is the full window rectangle in pixels // RectSize size; GLFont* font; double time; double lastTime; double deltaTime; int gl2psActive; }; } // namespace rgl #endif // RENDERCONTEXT_H rgl/src/gui.h0000644000176200001440000001357715011677075012610 0ustar liggesusers#ifndef RGL_GUI_H #define RGL_GUI_H // --------------------------------------------------------------------------- // C++ header file // This file is part of RGL // // --------------------------------------------------------------------------- #include "R.h" #include "types.h" #include "glgui.h" #include "Disposable.h" namespace rgl { // --------------------------------------------------------------------------- enum { GUI_ButtonLeft = 1, GUI_ButtonRight, GUI_ButtonMiddle }; // --------------------------------------------------------------------------- enum { GUI_WheelForward = 1, GUI_WheelBackward }; // --------------------------------------------------------------------------- enum { GUI_KeyF1 = 128, GUI_KeyF2, GUI_KeyF3, GUI_KeyF4, GUI_KeyF5, GUI_KeyF6, GUI_KeyF7, GUI_KeyF8, GUI_KeyF9, GUI_KeyF10, GUI_KeyF11, GUI_KeyF12, GUI_KeyReturn, GUI_KeyUp, GUI_KeyDown, GUI_KeyLeft, GUI_KeyRight, GUI_KeyInsert, GUI_KeyESC }; // --------------------------------------------------------------------------- // // IMPLEMENTATION INTERFACE // // --------------------------------------------------------------------------- class View; class Window; // --------------------------------------------------------------------------- class WindowImpl { public: inline WindowImpl(Window* in_window) : window(in_window) { fonts.resize(1); } virtual ~WindowImpl() { } inline void unbind() { window = 0; } virtual void setTitle(const char* title) = 0; virtual void setWindowRect(int left, int top, int right, int bottom) = 0; virtual void getWindowRect(int *in_left, int *in_top, int *in_right, int *in_bottom) = 0; virtual int setSkipRedraw(int in_skipRedraw); virtual void show(void) = 0; virtual void hide(void) = 0; virtual void update(void) = 0; virtual void bringToTop(int stay) = 0; /// @doc notifyDestroy will be called on success virtual void destroy(void) = 0; virtual bool beginGL(void) = 0; virtual void endGL(void) = 0; virtual void swap(void) = 0; virtual void captureMouse(View* captureView) = 0; virtual void releaseMouse(void) = 0; virtual void watchMouse(bool withoutButton) = 0; virtual GLFont* getFont(const char* family, int style, double cex, bool useFreeType) = 0; void getFonts(FontArray& outfonts, int nfonts, char** family, int* style, double* cex, bool useFreeType); virtual int getAntialias(); virtual int getMaxClipPlanes(); // OpenGL support (FIXME: remove) FontArray fonts; protected: Window* window; }; // --------------------------------------------------------------------------- // // GUIFactory to be used in ABSTRACT GUI TOOLKIT // // --------------------------------------------------------------------------- class GUIFactory { public: virtual ~GUIFactory() { } virtual WindowImpl* createWindowImpl(Window*, int antialias) = 0; }; // --------------------------------------------------------------------------- // // implementation specific // rgl::GUIFactory* getGUIFactory(bool useNULLDevice); // --------------------------------------------------------------------------- // // ABSTRACT GUI TOOLKIT // // --------------------------------------------------------------------------- // // view flags // // --------------------------------------------------------------------------- #define WINDOW_IMPL_OWNER (1<<0) // --------------------------------------------------------------------------- class View { public: View(); View(int basex, int basey, int width, int height, int flags); virtual ~View(); // services: virtual void setSize(int width, int height); virtual void setLocation(int basex, int basey); virtual void update(void); // event handlers: virtual void show(void); virtual void hide(void); virtual void paint(void); virtual void relocate(int baseX, int baseY); virtual void resize(int inWidth, int inHeight); virtual void keyPress(int code); virtual void keyRelease(int code); virtual void buttonPress(int button, int mouseX, int mouseY); virtual void buttonRelease(int button, int mouseX, int mouseY); virtual void wheelRotate(int direction, int mouseX, int mouseY); virtual void mouseMove(int mouseX, int mouseY); virtual void captureLost(); // protected services: virtual void setWindowImpl(WindowImpl* impl); // data: int baseX, baseY; int width, height; int flags; WindowImpl* windowImpl; friend class Window; }; // --------------------------------------------------------------------------- class Window : public View, public Disposable { public: Window(View* child=NULL, GUIFactory* factory=rgl::getGUIFactory(0), int antialias = RGL_ANTIALIAS); ~Window(); // overloaded view methods: void setWindowImpl(WindowImpl* windowImpl); // services: void setTitle(const char* title); void setVisibility(bool state); void update(void); int getSkipRedraw(void); void setSkipRedraw(int in_skipRedraw, int doUpdate = 1); /** * Close the window. **/ public: void close() { if (windowImpl) windowImpl->destroy(); else dispose(); } // protected: // event handlers: void show(); void hide(); void resize(int width, int height); void paint(); void on_close(); void notifyDestroy(); void buttonPress(int button, int mouseX, int mouseY); void buttonRelease(int button, int mouseX, int mouseY); void mouseMove(int mouseX, int mouseY); void keyPress(int code); void wheelRotate(int dir, int mouseX, int mouseY); void bringToTop(int stay); void setWindowRect(int left, int top, int right, int bottom); void getWindowRect(int *left, int *top, int *right, int *bottom); void getFonts(FontArray& outfonts, int nfonts, char** family, int* style, double* cex, bool useFreeType); // data: View* child; const char* title; bool skipRedraw; }; // --------------------------------------------------------------------------- } // namespace rgl #endif // RGL_GUI_H rgl/src/Shape.h0000644000176200001440000000761714771520323013055 0ustar liggesusers#ifndef SHAPE_H #define SHAPE_H #include #include "SceneNode.h" #include "Material.h" #include "RenderContext.h" #include "opengl.h" #include "geom.h" namespace rgl { // // CLASS // Shape // class Shape : public SceneNode { public: Shape(Material& in_material,bool in_ignoreExtent, TypeID in_typeID=SHAPE, bool in_bboxChanges=false); ~Shape(); /** * render shape. * Default Implementation: uses z-buffer and a display list * that stores everything from a call to draw(). **/ virtual void render(RenderContext* renderContext); /** * request update of node due to content change. * This will result in a new 'recording' of the display list. **/ virtual void update(RenderContext* renderContext); /** * draw. **/ virtual void draw(RenderContext* renderContext); /** * obtain bounding box **/ const AABox& getBoundingBox() const { return boundingBox; } /** * does this shape change dimensions according to the way it is rendered? * if so, the above is just a guess... **/ const bool getBBoxChanges() const { return bboxChanges; } /** * this shows how the shape would be sized in the given context **/ virtual AABox& getBoundingBox(Subscene* subscene) { return boundingBox; } /** * obtain material **/ Material* getMaterial() { return &material; } const bool getIgnoreExtent() const { return ignoreExtent; } virtual std::string getTypeName() { return "shape"; }; /** * invalidate display list **/ void invalidateDisplaylist(); /** * access to individual items **/ virtual int getElementCount(void) = 0; /** * access to primitives (e.g. facets of sphere) **/ virtual int getPrimitiveCount(void) { return getElementCount(); } /* overrides */ int getAttributeCount(SceneNode* subscene, AttribID attrib); void getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result); /** * location of individual parts **/ virtual Vertex getPrimitiveCenter(int index) { return boundingBox.getCenter(); } /** * Starting to render the shape. After this, the renderContext won't change until * the next call. This will only be called once per rendering. **/ virtual void renderBegin(RenderContext* renderContext) { }; /** * begin sending items. This may be called multiple times, e.g. if the * items are being intermixed with items from other shapes **/ virtual void drawBegin(RenderContext* renderContext); /** * send one item **/ virtual void drawPrimitive(RenderContext* renderContext, int index) = 0; /** * end sending items **/ virtual void drawEnd(RenderContext* renderContext); /** * Some shapes (currently just sprites) contain others. Do a recursive search */ virtual Shape* get_shape(int id) { return NULL; } const bool isTransparent() const { return transparent; } const bool isBlended() const { return blended; } /** * Does this shape need to go at the head of the shape list, rather than the tail? * (e.g. clip planes need to come first **/ virtual bool isClipPlane() { return false; } protected: /** * bounding volume of overall geometry **/ AABox boundingBox; /** * bounding volume changes depending on the scene? **/ bool bboxChanges; /* * whether this object should be ignored in scene bounding box calculations */ bool ignoreExtent; /** * material **/ Material material; private: #ifndef RGL_NO_OPENGL /** * display list **/ GLuint displayList; #endif int drawLevel; /* for debugging */ protected: /** * update indicator **/ bool doUpdate; bool transparent, blended; }; class ShapeItem { public: ShapeItem(Shape* in_shape, int in_itemnum) : shape(in_shape), itemnum(in_itemnum) {}; Shape* shape; int itemnum; }; } // namespace rgl #endif // SHAPE_H rgl/src/select.h0000644000176200001440000000044314555455305013271 0ustar liggesusers#ifndef PLX_SELECT_H #define PLX_SELECT_H // C++ header file // This file is part of RGL #include "scene.h" namespace rgl { // // Mouse selection rectangle // class SELECT { public: inline SELECT() { }; void render(double* position); }; } // namespace rgl #endif // PLX_SELECT_H rgl/src/Background.h0000644000176200001440000000235014771520323014061 0ustar liggesusers#ifndef BACKGROUND_H #define BACKGROUND_H #include "Shape.h" #include "opengl.h" #include "PrimitiveSet.h" #include "SphereMesh.h" namespace rgl { // // CLASS // Background // class Background : public Shape { public: enum { FOG_NONE=1, FOG_LINEAR, FOG_EXP, FOG_EXP2 }; Background( Material& in_material = defaultMaterial, bool sphere=false, int fogtype=FOG_NONE, float in_fogScale = 1.0); ~Background(); void render(RenderContext* renderContext); int getElementCount(void) { return 1; } void drawPrimitive(RenderContext* renderContext, int index); GLbitfield getClearFlags(RenderContext* renderContext); int getAttributeCount(SceneNode* subscene, AttribID attrib); void getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result); std::string getTextAttribute(SceneNode* subscene, AttribID attrib, int index); virtual std::string getTypeName() { return "background"; }; SceneNode* getQuad() { return quad; }; protected: bool clearColorBuffer; bool sphere; int fogtype; float fogScale; SphereMesh sphereMesh; QuadSet* quad; // GLuint displayList; friend class Scene; private: static Material defaultMaterial; }; } // namespace rgl #endif // BACKGROUND_H rgl/src/Material.h0000644000176200001440000000316214771520323013542 0ustar liggesusers#ifndef MATERIAL_H #define MATERIAL_H #include "Color.h" #include "Texture.h" #include "RenderContext.h" #include namespace rgl { // // STRUCT // Material // class Material { public: enum PolygonMode { FILL_FACE=1, LINE_FACE, POINT_FACE, CULL_FACE }; Material( Color bg, Color fg ); void setup(); // called when complete void beginUse(RenderContext* renderContext); void endUse(RenderContext* renderContext); void useColor(int index); void colorPerVertex(bool enable, int numVertices=0); bool isTransparent() const { return alphablend; } Color ambient; Color specular; Color emission; float shininess; float size; // point size float lwd; // line width float polygon_offset_factor; float polygon_offset_units; ColorArray colors; // color or if lit, represents diffuse color Ref texture; PolygonMode front; PolygonMode back; bool alphablend; bool smooth; bool lit; bool fog; bool useColorArray; bool point_antialias; bool line_antialias; bool depth_mask; int depth_test; // 0=GL_NEVER, 1=GL_LESS, etc. Texture::Type textype; Texture::Mode texmode; bool mipmap; unsigned int minfilter; unsigned int magfilter; bool envmap; bool polygon_offset; int marginCoord; int edge[3]; bool floating; std::string tag; int blend[2]; double glVersion; }; } // namespace rgl #endif // MATERIAL_H rgl/src/SpriteSet.h0000644000176200001440000000413215011677075013731 0ustar liggesusers#ifndef SPRITE_SET_H #define SPRITE_SET_H #include #include "Shape.h" #include "scene.h" namespace rgl { // // SPRITESET // class SpriteSet : public Shape { private: ARRAY vertex; ARRAY size; ARRAY pos; float offset; public: SpriteSet(Material& material, int nvertex, double* vertex, int nsize, double* size, int ignoreExtent, int count = 0, Shape** shapelist = NULL, int nshapelens = 0, int* shapelens = NULL, double* userMatrix = NULL, bool fixedSize = false, bool rotating = false, Scene* scene = NULL, double* adj = NULL, int npos = 0, int* pos = NULL, double offset = 0.0); ~SpriteSet(); /** * overload **/ virtual void render(RenderContext* renderContext); virtual std::string getTypeName() { return "sprites"; }; virtual int getElementCount(void); int getAttributeCount(SceneNode* subscene, AttribID attrib); void getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result); std::string getTextAttribute(SceneNode* subscene, AttribID attrib, int index); /** * location of individual items **/ virtual Vertex getPrimitiveCenter(int index); /** * begin sending items **/ virtual void drawBegin(RenderContext* renderContext); /** * send one item **/ virtual void drawPrimitive(RenderContext* renderContext, int index); /** * end sending items **/ virtual void drawEnd(RenderContext* renderContext); /** * extract individual shape */ virtual Shape* get_shape(int id); /** * delete a shape */ void remove_shape(int id); private: GLdouble userMatrix[16]; /* Transformation for 3D sprites */ Matrix4x4 m; /* Modelview matrix cache */ Matrix4x4 p; /* Projection matrix cache */ #ifndef RGL_NO_OPENGL bool doTex; #endif std::vector shapes, shapefirst, shapelens; bool fixedSize; bool rotating; Scene* scene; Vec3 adj; void getAdj(int index); }; } // namespace rgl #endif // SPRITE_SET_H rgl/src/rglmath.cpp0000644000176200001440000001557014771520323014003 0ustar liggesusers// C++ source // This file is part of RGL. // #include "rglmath.h" #include "R.h" using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // Vertex // void Vec3::normalize() { float len = this->getLength(); if (len != 0.0f) { float f = 1.0f/len; x *= f; y *= f; z *= f; } } Vec3 Vec3::cross(Vec3 op2) const { Vec3 v; v.x = y * op2.z - z * op2.y; v.y = z * op2.x - x * op2.z; v.z = x * op2.y - y * op2.x; return v; } float Vec3::angle(const Vec3& that) const { float dot; dot = x*that.x + y*that.y + z*that.z; return math::rad2deg(math::acos( dot/(this->getLength() * that.getLength()))); } Vec3 Vec3::operator * (float s) { Vec3 v; v.x = x*s; v.y = y*s; v.z = z*s; return v; } float Vec3::operator * (Vec3 v) { return (x*v.x + y*v.y + z*v.z); } Vec3 Vec3::operator - (Vec3 op2) const { Vec3 v; v.x = x - op2.x; v.y = y - op2.y; v.z = z - op2.z; return v; } void Vec3::operator += (Vec3 op2) { x += op2.x; y += op2.y; z += op2.z; } float& Vec3::operator [] (int i) { switch (i) { case 0: return x; case 1: return y; case 2: return z; } Rf_error("out of bounds"); } Vec3 Vec3::scale(const Vec3& op2) const { Vec3 t(*this); t.x *= op2.x; t.y *= op2.y; t.z *= op2.z; return t; } Vec3 Vertex::operator + (Vec3 op2) const { Vec3 t(*this); t += op2; return t; } void Vec3::rotateX(float degree) { Vec3 t(*this); float rad = math::deg2rad(degree); float s = math::sin(rad); float c = math::cos(rad); y = c*t.y + -s*t.z; z = s*t.y + c*t.z; } void Vec3::rotateY(float degree) { Vec3 t(*this); float rad = math::deg2rad(degree); float s = math::sin(rad); float c = math::cos(rad); x = c*t.x + s*t.z; z = -s*t.x + c*t.z; } bool Vec3::missing() const { return ISNAN(x) || ISNAN(y) || ISNAN(z); } ////////////////////////////////////////////////////////////////////////////// // // CLASS // Vec4 // Vec4::Vec4(const float in_x, const float in_y, const float in_z, const float in_w) { x = in_x; y = in_y; z = in_z; w = in_w; } float Vec4::operator * (const Vec4& v) const { return (x*v.x + y*v.y + z*v.z + w*v.w); } Vec4 Vec4::operator * (const float s) const { Vec4 r; r.x = x*s; r.y = y*s; r.z = z*s; r.w = w*s; return r; } Vec4 Vec4::operator + (const Vec4& v) const { return Vec4(x+v.x, y+v.y, z+v.z, w+v.w); } float& Vec4::operator [] (int i) { switch (i) { case 0: return x; case 1: return y; case 2: return z; case 3: return w; } Rf_error("out of bounds"); } ////////////////////////////////////////////////////////////////////////////// // // CLASS // Matrix4x4 // Matrix4x4::Matrix4x4() { } Matrix4x4::Matrix4x4(const Matrix4x4& src) { for(int i=0;i<16;i++) data[i] = src.data[i]; } Matrix4x4::Matrix4x4(const double* from) { loadData(from); } void Matrix4x4::loadData(const double* from) { for(int i=0;i<16;i++) data[i] = (float) from[i]; } void Matrix4x4::loadData(const float* from) { for(int i=0;i<16;i++) data[i] = from[i]; } void Matrix4x4::loadData(const Matrix4x4& from) { loadData(from.data); } Vec3 Matrix4x4::operator * (const Vec3 v) const { Vec3 r; const float v_w = 1.0f; float rw; rw = val(3,0) * v.x + val(3,1) * v.y + val(3,2) * v.z + val(3,3) * v_w; r.x = (val(0,0) * v.x + val(0,1) * v.y + val(0,2) * v.z + val(0,3) * v_w)/rw; r.y = (val(1,0) * v.x + val(1,1) * v.y + val(1,2) * v.z + val(1,3) * v_w)/rw; r.z = (val(2,0) * v.x + val(2,1) * v.y + val(2,2) * v.z + val(2,3) * v_w)/rw; return r; } Vec4 Matrix4x4::operator*(const Vec4& v) const { Vec4 r; r.x = val(0,0) * v.x + val(0,1) * v.y + val(0,2) * v.z + val(0,3) * v.w; r.y = val(1,0) * v.x + val(1,1) * v.y + val(1,2) * v.z + val(1,3) * v.w; r.z = val(2,0) * v.x + val(2,1) * v.y + val(2,2) * v.z + val(2,3) * v.w; r.w = val(3,0) * v.x + val(3,1) * v.y + val(3,2) * v.z + val(3,3) * v.w; return r; } bool Vec4::missing() const { return ISNAN(x) || ISNAN(y) || ISNAN(z) || ISNAN(w); } Matrix4x4 Matrix4x4::operator * (const Matrix4x4& op2) const { Matrix4x4 r; for(int i=0;i<4;i++) for(int j=0;j<4;j++) { float tmp = 0; for(int k=0;k<4;k++) tmp += val(i, k) * op2.val(k, j); r.ref(i,j) = tmp; } return r; } Vec4 Matrix4x4::getRow(int row) { Vec4 r; r.x = val(row, 0); r.y = val(row, 1); r.z = val(row, 2); r.w = val(row, 3); return r; } void Matrix4x4::setIdentity(void) { for(int i=0;i<16;i++) data[i] = 0.0f; ref(0,0) = 1.0f; ref(1,1) = 1.0f; ref(2,2) = 1.0f; ref(3,3) = 1.0f; } void Matrix4x4::setRotate(const int axis, const float degree) { float rad = math::deg2rad(degree); float s = math::sin(rad); float c = math::cos(rad); setIdentity(); switch(axis) { case 0: ref(1,1) = c; ref(1,2) = -s; ref(2,1) = s; ref(2,2) = c; break; case 1: ref(0,0) = c; ref(0,2) = s; ref(2,0) = -s; ref(2,2) = c; break; case 2: ref(0,0) = c; ref(0,1) = -s; ref(1,0) = s; ref(1,1) = c; break; } } void Matrix4x4::transpose() { for (int i = 0; i < 3; i++) for (int j = i+1; j < 4; j++) { float temp = val(i,j); ref(i,j) = val(j,i); ref(j,i) = temp; } } void Matrix4x4::getData(double* dest) { for(int i=0;i<16;i++) dest[i] = data[i]; } Matrix4x4 Matrix4x4::scaleMatrix(double sx, double sy, double sz) { Matrix4x4 result; result.setIdentity(); result.ref(0,0) = static_cast(sx); result.ref(1,1) = static_cast(sy); result.ref(2,2) = static_cast(sz); return result; } Matrix4x4 Matrix4x4::translationMatrix(double x, double y, double z) { Matrix4x4 result; result.setIdentity(); result.ref(0,3) = static_cast(x); result.ref(1,3) = static_cast(y); result.ref(2,3) = static_cast(z); return result; } void Matrix4x4::multRight(const Matrix4x4& M) { Matrix4x4 result; for (int i = 0; i < 4; i++ ) for (int k = 0; k < 4; k++) { result.ref(i, k) = 0.0; for (int j = 0; j < 4; j++) result.ref(i, k) += val(i, j)*M.val(j, k); } loadData(result); } void Matrix4x4::multLeft(const Matrix4x4& M) { Matrix4x4 result; for (int i = 0; i < 4; i++ ) for (int k = 0; k < 4; k++) { result.ref(i, k) = 0.0; for (int j = 0; j < 4; j++) result.ref(i, k) += M.val(i, j)*val(j, k); } loadData(result); } Matrix4x4 Matrix4x4::permutationMatrix(int newx, int newy, int newz) { Matrix4x4 result; for(int i=0;i<16;i++) result.data[i] = 0.0f; result.ref(0, newx) = 1.0f; result.ref(1, newy) = 1.0f; result.ref(2, newz) = 1.0f; result.ref(3, 3) = 1.0f; return result; } Vertex PolarCoord::vector() const { float t = math::deg2rad(theta); float p = math::deg2rad(phi); return Vertex ( math::cos(p) * math::sin(t), math::sin(p), math::cos(p) * math::cos(t) ); } rgl/src/platform.h0000644000176200001440000000154614771520323013634 0ustar liggesusers#ifndef PLATFORM_H #define PLATFORM_H /* These are some platform-specific definitions, currently to support MacOSX */ #include "opengl.h" /* MacOSX */ #ifdef RGL_OSX #include #ifndef __MAC_10_9 #define __MAC_10_9 1090 #endif #if __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_9 // pre-Mavericks code #else // Mavericks and later #define gluUnProject rgl_gluUnProject #define gluErrorString rgl_gluErrorString GLint gluUnProject(GLdouble winX, GLdouble winY, GLdouble winZ, const GLdouble * model, const GLdouble * proj, const GLint * view, GLdouble* objX, GLdouble* objY, GLdouble* objZ); const GLubyte * gluErrorString(GLenum error); #endif /* Mavericks */ #endif /* RGL_OSX */ #endif /* PLATFORM_H */ rgl/src/par3d.cpp0000644000176200001440000005016714771520323013357 0ustar liggesusers/* Avoid conflict with Rinternals.h */ // #undef DEBUG #include "R.h" #include "Rversion.h" #include "DeviceManager.h" #include "rglview.h" #include "api.h" /* These defines are not in the installed version of R */ #define _ #define streql(s, t) (!strcmp((s), (t))) #include namespace rgl { void getObserver(double* ddata, Subscene* subscene); void setObserver(bool automatic, double* ddata, RGLView* rglview, Subscene* subscene); } using namespace rgl; /* These two are currently exposed, because observer3d uses them. */ void rgl::getObserver(double* ddata, Subscene* subscene) { UserViewpoint* userviewpoint = subscene->getUserViewpoint(); Vertex res = userviewpoint->getObserver(); ddata[0] = res.x; ddata[1] = res.y; ddata[2] = res.z; } void rgl::setObserver(bool automatic, double* ddata, RGLView* rglview, Subscene* subscene) { UserViewpoint* userviewpoint = subscene->getUserViewpoint(); userviewpoint->setObserver(automatic, Vertex(static_cast(ddata[0]), static_cast(ddata[1]), static_cast(ddata[2]))); rglview->update(); } /* These functions used to be in api.h and api.c, but are only accessed from par3d, so have been made static */ static void getZoom(double* zoom, Subscene* subscene) { UserViewpoint* userviewpoint = subscene->getUserViewpoint(); *zoom = userviewpoint->getZoom(); CHECKGLERROR; } static void setZoom(double* zoom, RGLView* rglview, Subscene* subscene) { UserViewpoint* userviewpoint = subscene->getUserViewpoint(); userviewpoint->setZoom(static_cast(*zoom) ); rglview->update(); CHECKGLERROR; } static void getFOV(double* fov, Subscene* subscene) { UserViewpoint* userviewpoint = subscene->getUserViewpoint(); *fov = userviewpoint->getFOV(); CHECKGLERROR; } static void setFOV(double* fov, RGLView* rglview, Subscene* sub) { UserViewpoint* userviewpoint = sub->getUserViewpoint(); userviewpoint->setFOV(static_cast(*fov)); rglview->update(); CHECKGLERROR; } static void getIgnoreExtent(int* ignoreExtent, Device* device) { *ignoreExtent = device->getIgnoreExtent(); CHECKGLERROR; } static void setIgnoreExtent(int* ignoreExtent, Device* device) { device->setIgnoreExtent(*ignoreExtent); CHECKGLERROR; } static void getSkipRedraw(int* skipRedraw, Device* device) { *skipRedraw = device->getSkipRedraw(); CHECKGLERROR; } static void setSkipRedraw(int* skipRedraw, Device* device) { device->setSkipRedraw(*skipRedraw); CHECKGLERROR; } static void getMouseMode(int *button, int* mode, Subscene* subscene) { *mode = static_cast( subscene->getMouseMode(*button) ); CHECKGLERROR; } static void setMouseMode(int* button, int* mode, RGLView* rglview, Subscene* subscene) { subscene->setMouseMode(*button, (MouseModeID)(*mode)); if (*button == bnNOBUTTON) rglview->windowImpl->watchMouse(subscene->getRootSubscene()->mouseNeedsWatching()); CHECKGLERROR; } static void getUserMatrix(double* userMatrix, Subscene* subscene) { subscene->getUserMatrix(userMatrix); CHECKGLERROR; } static void setUserMatrix(double* userMatrix, RGLView* rglview, Subscene* subscene) { subscene->setUserMatrix(userMatrix); rglview->update(); CHECKGLERROR; } static void getUserProjection(double* userProjection, Subscene* subscene) { subscene->getUserProjection(userProjection); CHECKGLERROR; } static void setUserProjection(double* userProjection, RGLView* rglview, Subscene* subscene) { subscene->setUserProjection(userProjection); rglview->update(); CHECKGLERROR; } static void getPosition(double* position, Subscene* subscene) { subscene->getPosition(position); CHECKGLERROR; } static void setPosition(double* position, RGLView* rglview, Subscene* subscene) { subscene->setPosition(position); rglview->update() CHECKGLERROR; } static void getScale(double* scale, Subscene* subscene) { subscene->getScale(scale); } static void setScale(double* scale, RGLView* rglview, Subscene* subscene) { subscene->setScale(scale); rglview->update(); CHECKGLERROR; } static void setViewport(double* viewport, Device* device, RGLView* rglview, Subscene* subscene) { subscene = subscene->getMaster(EM_VIEWPORT); int left, top, right, bottom; double x, y, width, height; if (subscene->getEmbedding(EM_VIEWPORT) == EMBED_REPLACE) { device->getWindowRect(&left, &top, &right, &bottom); width = right - left; height = bottom - top; bottom = 0; left = 0; } else { left = subscene->getParent()->pviewport.x; bottom = subscene->getParent()->pviewport.y; width = subscene->getParent()->pviewport.width; height = subscene->getParent()->pviewport.height; } x = (viewport[0]-left)/width; y = (viewport[1]-bottom)/height; width = viewport[2]/width; height = viewport[3]/height; subscene->setViewport(x, y, width, height); rglview->update(); } static void getViewport(int* viewport, Subscene* subscene) { viewport[0] = subscene->pviewport.x; viewport[1] = subscene->pviewport.y; viewport[2] = subscene->pviewport.width; viewport[3] = subscene->pviewport.height; CHECKGLERROR; } static void getWindowRect(int* rect, Device* device) { device->getWindowRect(rect, rect+1, rect+2, rect+3); CHECKGLERROR; } static void setWindowRect(int* rect, Device* dev) { dev->setWindowRect(rect[0], rect[1], rect[2], rect[3]); CHECKGLERROR; } static void getBoundingbox(double* bboxvec, Subscene* subscene) { const AABox& bbox = subscene->getBoundingBox(); bboxvec[0] = bbox.vmin.x; bboxvec[1] = bbox.vmax.x; bboxvec[2] = bbox.vmin.y; bboxvec[3] = bbox.vmax.y; bboxvec[4] = bbox.vmin.z; bboxvec[5] = bbox.vmax.z; CHECKGLERROR; } /* font access functions. These are only used from par3d */ static char* getFamily(RGLView* rglview) { const char* f = rglview->getFontFamily(); char* result; result = R_alloc(strlen(f)+1, 1); strcpy(result, f); CHECKGLERROR; return result; } static bool setFamily(const char *family, RGLView* rglview) { rglview->setFontFamily(family); CHECKGLERROR; return true; } static int getFont(RGLView* rglview) { int result = rglview->getFontStyle(); CHECKGLERROR; return result; } static bool setFont(int font, RGLView* rglview) { rglview->setFontStyle(font); CHECKGLERROR; return true; } static double getCex(RGLView* rglview) { double result = rglview->getFontCex(); CHECKGLERROR; return result; } static bool setCex(double cex, RGLView* rglview) { rglview->setFontCex(cex); CHECKGLERROR; return true; } static int getUseFreeType(RGLView* rglview) { int result = (int) rglview->getFontUseFreeType(); CHECKGLERROR; return result; } static bool setUseFreeType(bool useFreeType, RGLView* rglview) { rglview->setFontUseFreeType(useFreeType); CHECKGLERROR; return true; } static char* getFontname(RGLView* rglview) { char* result = NULL; const char* f = rglview->getFontname(); result = R_alloc(strlen(f)+1, 1); strcpy(result, f); CHECKGLERROR; return result; } static int getAntialias(RGLView* rglview) { return rglview->windowImpl->getAntialias(); } static int getMaxClipPlanes(RGLView* rglview) { return rglview->windowImpl->getMaxClipPlanes(); } static double getGlVersion() { #ifndef RGL_NO_OPENGL if (GLAD_GL_VERSION_1_0) { /* Might not be loaded yet... */ const char* version = (const char*)glGetString(GL_VERSION); if (version) return atof(version); } #endif return R_NaReal; } static int activeSubscene(RGLView* rglview) { return rglview->getActiveSubscene(); } /* par3d implementation based on R's par implementation * * Main functions: * par3d(.) * Specify(.) [ par(what = value) ] * Query(.) [ par(what) ] */ static void par_error(const char *what) { Rf_error(_("invalid value specified for rgl parameter \"%s\""), what); } static void lengthCheck(const char *what, SEXP v, int n) { if (Rf_length(v) != n) Rf_error(_("parameter \"%s\" has the wrong length"), what); } static void dimCheck(const char *what, SEXP v, int r, int c) { SEXP dim = Rf_coerceVector(Rf_getAttrib(v, R_DimSymbol), INTSXP); if (Rf_length(dim) != 2 || INTEGER(dim)[0] != r || INTEGER(dim)[1] != c) Rf_error(_("parameter \"%s\" has the wrong dimension"), what); } #ifdef UNUSED static void nonnegIntCheck(int x, const char *s) { if (x == NA_INTEGER || x < 0) par_error(s); } static void posIntCheck(int x, const char *s) { if (x == NA_INTEGER || x <= 0) par_error(s); } static void naIntCheck(int x, const char *s) { if (x == NA_INTEGER) par_error(s); } #endif static void posRealCheck(double x, const char *s) { if (!R_FINITE(x) || x <= 0) par_error(s); } #ifdef UNUSED static void nonnegRealCheck(double x, const char *s) { if (!R_FINITE(x) || x < 0) par_error(s); } static void naRealCheck(double x, const char *s) { if (!R_FINITE(x)) par_error(s); } #endif static void BoundsCheck(double x, double a, double b, const char *s) { /* Check if a <= x <= b */ if (!R_FINITE(x) || (R_FINITE(a) && x < a) || (R_FINITE(b) && x > b)) par_error(s); } /* These modes must match the definitions of mmTRACKBALL etc in rglview.h ! */ namespace rgl { const char* mouseModes[] = {"none", "trackball", "xAxis", "yAxis", "zAxis", "polar", "selecting", "zoom", "fov", "user", "push", "pull", "user2"}; const char* viewportlabels[] = {"x", "y", "width", "height"}; } #define mmLAST 10 #define wmLAST 13 /* At R 2.6.0, the type of the first arg to Rf_psmatch changed to const char *. Conditionally cast to char * if we're in an old version */ #if defined(R_VERSION) && R_VERSION < R_Version(2, 6, 0) #define OLDCAST (char *) #else #define OLDCAST #endif static void Specify(Device* dev, RGLView* rglview, Subscene* sub, const char *what, SEXP value) { /* Do NOT forget to update ../R/par3d.R */ /* if you ADD a NEW par !! */ SEXP x; double v; int iv; int success = 1; if (streql(what, "FOV")) { lengthCheck(what, value, 1); v = Rf_asReal(value); BoundsCheck(v, 0.0, 179.0, what); setFOV(&v, rglview, sub); } else if (streql(what, "ignoreExtent")) { lengthCheck(what, value, 1); iv = Rf_asLogical(value); setIgnoreExtent(&iv, dev); } else if (streql(what, "mouseMode")) { PROTECT(value = Rf_coerceVector(value, STRSXP)); if (Rf_length(value) > 5) par_error(what); for (int i=bnNOBUTTON; i<=bnWHEEL && i < Rf_length(value); i++) { if (STRING_ELT(value, i) != NA_STRING) { success = 0; /* check exact first, then partial */ for (int mode = 0; mode < (i != bnWHEEL ? mmLAST : wmLAST) ; mode++) { if (Rf_psmatch(OLDCAST mouseModes[mode], CHAR(STRING_ELT(value, i)), (Rboolean)TRUE)) { setMouseMode(&i, &mode, rglview, sub); success = 1; break; } } if (!success) { for (int mode = 0; mode < (i != 4 ? mmLAST : wmLAST) ; mode++) { if (Rf_psmatch(OLDCAST mouseModes[mode], CHAR(STRING_ELT(value, i)), (Rboolean)FALSE)) { setMouseMode(&i, &mode, rglview, sub); success = 1; break; } } } if (!success) par_error(what); } } UNPROTECT(1); } else if (streql(what, "listeners")) { x = Rf_coerceVector(value, INTSXP); rglview->setMouseListeners(sub, Rf_length(x), INTEGER(x)); } else if (streql(what, "skipRedraw")) { lengthCheck(what, value, 1); iv = Rf_asLogical(value); setSkipRedraw(&iv, dev); } else if (streql(what, "userMatrix")) { dimCheck(what, value, 4, 4); x = Rf_coerceVector(value, REALSXP); setUserMatrix(REAL(x), rglview, sub); } else if (streql(what, "userProjection")) { dimCheck(what, value, 4, 4); x = Rf_coerceVector(value, REALSXP); setUserProjection(REAL(x), rglview, sub); } else if (streql(what, "scale")) { lengthCheck(what, value, 3); x = Rf_coerceVector(value, REALSXP); setScale(REAL(x), rglview, sub); } else if (streql(what, "viewport")) { lengthCheck(what, value, 4); x = Rf_coerceVector(value, REALSXP); setViewport(REAL(x), dev, rglview, sub); } else if (streql(what, "zoom")) { lengthCheck(what, value, 1); v = Rf_asReal(value); posRealCheck(v, what); setZoom(&v, rglview, sub); } else if (streql(what, ".position")) { lengthCheck(what, value, 2); x = Rf_coerceVector(value, REALSXP); setPosition(REAL(x), rglview, sub); } else if (streql(what, "windowRect")) { lengthCheck(what, value, 4); x = Rf_coerceVector(value, INTSXP); setWindowRect(INTEGER(x), dev); } else if (streql(what, "family")) { lengthCheck(what, value, 1); x = Rf_coerceVector(value, STRSXP); if (!setFamily(CHAR(STRING_ELT(x, 0)), rglview)) success = 0; } else if (streql(what, "font")) { lengthCheck(what, value, 1); x=Rf_coerceVector(value, INTSXP); if (INTEGER(x)[0] < 1 || INTEGER(x)[0] > 5) { par_error(what); } if (!setFont(INTEGER(x)[0], rglview)) success = 0; } else if (streql(what, "cex")) { lengthCheck(what, value, 1); x=Rf_coerceVector(value, REALSXP); if (REAL(x)[0] <= 0) { par_error(what); } if (!setCex(REAL(x)[0],rglview)) success = 0; } else if (streql(what, "useFreeType")) { lengthCheck(what, value, 1); PROTECT(x=Rf_coerceVector(value, LGLSXP)); #ifndef HAVE_FREETYPE if (LOGICAL(x)[0] && strcmp( dev->getDevtype(), "null" )) Rf_warning("FreeType not supported in this build"); #endif if (!setUseFreeType(LOGICAL(x)[0], rglview)) success = 0; UNPROTECT(1); } else Rf_warning(_("parameter \"%s\" cannot be set"), what); if (!success) par_error(what); return; } /* Do NOT forget to update ../R/par3d.R */ /* if you ADD a NEW par !! */ static SEXP Query(Device* dev, RGLView* rglview, Subscene* sub, const char *what) { SEXP value, names; int i, mode, success = 1; char* buf; value = R_NilValue; if (streql(what, "FOV")) { PROTECT(value = Rf_allocVector(REALSXP, 1)); getFOV(REAL(value), sub); } else if (streql(what, "ignoreExtent")) { PROTECT(value = Rf_allocVector(LGLSXP, 1)); getIgnoreExtent(LOGICAL(value), dev); } else if (streql(what, "modelMatrix")) { PROTECT(value = Rf_allocMatrix(REALSXP, 4, 4)); sub->modelMatrix.getData(REAL(value)); } else if (streql(what, "mouseMode")) { PROTECT(value = Rf_allocVector(STRSXP, 5)); for (i=0; i<5; i++) { getMouseMode(&i, &mode, sub); if (mode < 0 || mode >= wmLAST) mode = 0; SET_STRING_ELT(value, i, Rf_mkChar(mouseModes[mode])); } PROTECT(names = Rf_allocVector(STRSXP, 5)); SET_STRING_ELT(names, 0, Rf_mkChar("none")); SET_STRING_ELT(names, 1, Rf_mkChar("left")); SET_STRING_ELT(names, 2, Rf_mkChar("right")); SET_STRING_ELT(names, 3, Rf_mkChar("middle")); SET_STRING_ELT(names, 4, Rf_mkChar("wheel")); value = Rf_namesgets(value, names); UNPROTECT(2); /* names and old values */ PROTECT(value); } else if (streql(what, "observer")) { PROTECT(value = Rf_allocVector(REALSXP, 3)); rgl::getObserver(REAL(value), sub); } else if (streql(what, "projMatrix")) { PROTECT(value = Rf_allocMatrix(REALSXP, 4, 4)); sub->projMatrix.getData(REAL(value)); } else if (streql(what, "listeners")) { PROTECT(value = Rf_allocVector(INTSXP, sub->mouseListeners.size())); sub->getMouseListeners(Rf_length(value), INTEGER(value)); } else if (streql(what, "skipRedraw")) { PROTECT(value = Rf_allocVector(LGLSXP, 1)); getSkipRedraw(LOGICAL(value), dev); } else if (streql(what, "userMatrix")) { PROTECT(value = Rf_allocMatrix(REALSXP, 4, 4)); getUserMatrix(REAL(value), sub); } else if (streql(what, "userProjection")) { PROTECT(value = Rf_allocMatrix(REALSXP, 4, 4)); getUserProjection(REAL(value), sub); } else if (streql(what, "scale")) { PROTECT(value = Rf_allocVector(REALSXP, 3)); getScale(REAL(value), sub); } else if (streql(what, "viewport")) { PROTECT(value = Rf_allocVector(INTSXP, 4)); getViewport(INTEGER(value), sub); PROTECT(names = Rf_allocVector(STRSXP, 4)); for (i=0; i<4; i++) SET_STRING_ELT(names, i, Rf_mkChar(viewportlabels[i])); value = Rf_namesgets(value, names); UNPROTECT(2); PROTECT(value); } else if (streql(what, "zoom")) { PROTECT(value = Rf_allocVector(REALSXP, 1)); getZoom(REAL(value), sub); } else if (streql(what, "bbox")) { PROTECT(value = Rf_allocVector(REALSXP, 6)); getBoundingbox(REAL(value), sub); } else if (streql(what, ".position")) { PROTECT(value = Rf_allocVector(REALSXP, 2)); getPosition(REAL(value), sub); } else if (streql(what, "windowRect")) { PROTECT(value = Rf_allocVector(INTSXP, 4)); getWindowRect(INTEGER(value), dev); } else if (streql(what, "family")) { buf = getFamily(rglview); if (buf) { value = Rf_mkString(buf); } PROTECT(value); } else if (streql(what, "font")) { PROTECT(value = Rf_allocVector(INTSXP, 1)); INTEGER(value)[0] = getFont(rglview); success = INTEGER(value)[0] >= 0; } else if (streql(what, "cex")) { PROTECT(value = Rf_allocVector(REALSXP, 1)); REAL(value)[0] = getCex(rglview); success = REAL(value)[0] >= 0; } else if (streql(what, "useFreeType")) { int useFreeType = getUseFreeType(rglview); PROTECT(value = Rf_allocVector(LGLSXP, 1)); if (useFreeType < 0) { LOGICAL(value)[0] = false; success = 0; } else { LOGICAL(value)[0] = (bool)useFreeType; } } else if (streql(what, "fontname")) { buf = getFontname(rglview); if (buf) { value = Rf_mkString(buf); } PROTECT(value); } else if (streql(what, "antialias")) { PROTECT(value = Rf_allocVector(INTSXP, 1)); INTEGER(value)[0] = getAntialias(rglview); } else if (streql(what, "maxClipPlanes")) { PROTECT(value = Rf_allocVector(INTSXP, 1)); INTEGER(value)[0] = getMaxClipPlanes(rglview); } else if (streql(what, "glVersion")) { PROTECT(value = Rf_allocVector(REALSXP, 1)); REAL(value)[0] = getGlVersion(); } else if (streql(what, "activeSubscene")) { PROTECT(value = Rf_allocVector(INTSXP, 1)); INTEGER(value)[0] = activeSubscene(rglview); } else PROTECT(value); UNPROTECT(1); if (! success) Rf_error(_("unknown error getting rgl parameter \"%s\""), what); return value; } namespace rgl { extern DeviceManager* deviceManager; } SEXP rgl::rgl_par3d(SEXP device, SEXP subscene, SEXP args) { Device* dev; if (!deviceManager || !(dev = deviceManager->getDevice(Rf_asInteger(device)))) Rf_error(_("rgl device %d cannot be found"), Rf_asInteger(device)); RGLView* rglview = dev->getRGLView(); Scene* scene = rglview->getScene(); Subscene* sub = scene->getSubscene(Rf_asInteger(subscene)); if (!sub) Rf_error(_("rgl subscene %d cannot be found"), Rf_asInteger(subscene)); SEXP value; int nargs; nargs = Rf_length(args); if (Rf_isNewList(args)) { SEXP oldnames, newnames, tag, val; int i; PROTECT(newnames = Rf_allocVector(STRSXP, nargs)); PROTECT(value = Rf_allocVector(VECSXP, nargs)); PROTECT(oldnames = Rf_getAttrib(args, R_NamesSymbol)); for (i = 0 ; i < nargs ; i++) { if (oldnames != R_NilValue) tag = STRING_ELT(oldnames, i); else tag = R_NilValue; val = VECTOR_ELT(args, i); if (tag != R_NilValue && CHAR(tag)[0]) { SET_VECTOR_ELT(value, i, Query(dev, rglview, sub, CHAR(tag))); SET_STRING_ELT(newnames, i, tag); Specify(dev, rglview, sub, CHAR(tag), val); CHECKGLERROR; } else if (Rf_isString(val) && Rf_length(val) > 0) { tag = STRING_ELT(val, 0); if (tag != R_NilValue && CHAR(tag)[0]) { SET_VECTOR_ELT(value, i, Query(dev, rglview, sub, CHAR(tag))); SET_STRING_ELT(newnames, i, tag); CHECKGLERROR; } } else { SET_VECTOR_ELT(value, i, R_NilValue); SET_STRING_ELT(newnames, i, R_BlankString); } } Rf_setAttrib(value, R_NamesSymbol, newnames); UNPROTECT(3); } else { Rf_error(_("invalid parameter passed to par3d()")); return R_NilValue/* -Wall */; } return value; } rgl/src/Makevars.in0000644000176200001440000000245415011677075013744 0ustar liggesusers# # R Makevars file auto-generated using template Makevars.in # AUTO-GENERATED from Makevars.in (using configure or configure.win) # This file is part of the RGL project. # # Makevars will be called in two different circumstances: # # When HIDE_IF_NO_OPENGL="": # # Trying to make $(SHLIB)=rgl.so with full OpenGL support, then # making it again by building it in useNULL, # using the Makevars file there. # # When HIDE_IF_NO_OPENGL="#": # # Trying to make $(SHLIB)=rgl.so with no OpenGL. @HIDE_IF_R42PLUS@ CXX_STD = CXX11 PKG_CFLAGS=$(C_VISIBILITY) PKG_CPPFLAGS=@NULL_CPPFLAGS@ -DR_NO_REMAP -Iext/earcut PKG_LIBS=@NULL_LIBS@ # These lines are only used if configure found OpenGL support @HIDE_IF_NO_OPENGL@ PKG_CPPFLAGS=@CPPFLAGS@ -DR_NO_REMAP -Iext -Iext/glad/include -Iext/earcut @HIDE_IF_NO_OPENGL@ PKG_LIBS=@LIBS@ all: $(SHLIB) @HIDE_IF_NO_OPENGL@ ../inst/useNULL$(R_ARCH)/$(SHLIB) ../inst/useNULL$(R_ARCH)/$(SHLIB): $(SHLIB) cp -Rp OpenGL useNULL && \ mkdir -p useNULL/ext && \ cp -Rp ext/earcut useNULL/ext/earcut && \ cp -p *.c *.h *.cpp useNULL/ && \ cd useNULL && \ $(R_HOME)/bin/R CMD SHLIB -o useNULL.so *.cpp *.c && \ cd .. && \ mkdir -p ../inst/useNULL$(R_ARCH) && \ mv useNULL/useNULL.so ../inst/useNULL$(R_ARCH)/$(SHLIB) && \ rm useNULL/*.cpp useNULL/*.c useNULL/*.h useNULL/OpenGL/* rgl/src/SphereSet.cpp0000644000176200001440000001240714771520323014243 0ustar liggesusers#include "SphereSet.h" #include "Viewpoint.h" #include "R.h" using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // SphereSet // SphereSet::SphereSet(Material& in_material, int in_ncenter, double* in_center, int in_nradius, double* in_radius, int in_ignoreExtent, bool in_fastTransparency) : Shape(in_material, in_ignoreExtent, SHAPE, true), center(in_ncenter, in_center), radius(in_nradius, in_radius), lastdrawn(-1), lastendcap(true), fastTransparency(in_fastTransparency) { material.colorPerVertex(false); if (material.lit) sphereMesh.setGenNormal(true); if ( (material.texture) && (!material.texture->is_envmap() ) ) sphereMesh.setGenTexCoord(true); sphereMesh.setGlobe(16,16); for (int i=0;igetModelViewpoint()->scale; scale.x = 1.0f/scale.x; scale.y = 1.0f/scale.y; scale.z = 1.0f/scale.z; boundingBox.invalidate(); for(int i=0;i= 0) { Subscene* subscene = renderContext->subscene; bboxdeco = subscene->get_bboxdeco(); } if (fastTransparency) { if (bboxdeco) { invalidateDisplaylist(); pt = bboxdeco->marginVecToDataVec(center.get(index), renderContext, &material); } else pt = center.get(index); if ( pt.missing() || ISNAN(radius.getRecycled(index)) ) return; material.useColor(index); sphereMesh.setCenter( pt ); sphereMesh.setRadius( radius.getRecycled(index) ); sphereMesh.update( renderContext->subscene->getModelViewpoint()->scale ); sphereMesh.draw(renderContext); } else { int i1 = index / facets, i2 = index % facets; bool endcap = i2 < sphereMesh.getSegments() || i2 >= facets - sphereMesh.getSegments(); if (i1 != lastdrawn) { if (bboxdeco) { invalidateDisplaylist(); pt = bboxdeco->marginVecToDataVec(center.get(i1), renderContext, &material); } else pt = center.get(index); if ( pt.missing() || ISNAN(radius.getRecycled(i1)) ) return; material.useColor(i1); if (lastdrawn >= 0) sphereMesh.drawEnd( renderContext ); sphereMesh.setCenter( pt ); sphereMesh.setRadius( radius.getRecycled(i1) ); sphereMesh.update( renderContext->subscene->getModelViewpoint()->scale ); sphereMesh.drawBegin( renderContext, endcap); lastdrawn = i1; lastendcap = endcap; } else if (endcap != lastendcap) { sphereMesh.drawEnd( renderContext ); sphereMesh.drawBegin( renderContext, endcap); lastendcap = endcap; } sphereMesh.drawPrimitive(renderContext, i2); } } void SphereSet::drawEnd(RenderContext* renderContext) { if (lastdrawn >= 0) sphereMesh.drawEnd( renderContext ); lastdrawn = -1; material.endUse(renderContext); Shape::drawEnd(renderContext); } void SphereSet::render(RenderContext* renderContext) { if (renderContext->subscene->getModelViewpoint()->scaleChanged) doUpdate = true; Shape::render(renderContext); } int SphereSet::getPrimitiveCount() { return (fastTransparency ? 1 : facets) * getElementCount(); } Vertex SphereSet::getPrimitiveCenter(int index) { if (fastTransparency) { return center.get(index); } else { int i1 = index / facets, i2 = index % facets; if (i1 != lastdrawn) { if ( center.get(i1).missing() || ISNAN(radius.getRecycled(i1)) ) return center.get(i1); sphereMesh.setCenter( center.get(i1) ); sphereMesh.setRadius( radius.getRecycled(i1) ); sphereMesh.update(); lastdrawn = i1; } return sphereMesh.getPrimitiveCenter(i2); } } int SphereSet::getAttributeCount(SceneNode* subscene, AttribID attrib) { switch (attrib) { case RADII: return radius.size(); case VERTICES: return center.size(); case FLAGS: return 2; } return Shape::getAttributeCount(subscene, attrib); } void SphereSet::getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result) { int n = getAttributeCount(subscene, attrib); if (first + count < n) n = first + count; if (first < n) { switch (attrib) { case VERTICES: while (first < n) { *result++ = center.get(first).x; *result++ = center.get(first).y; *result++ = center.get(first).z; first++; } return; case RADII: while (first < n) *result++ = radius.get(first++); return; case FLAGS: if (first == 0) *result++ = ignoreExtent; *result++ = (double) fastTransparency; return; } Shape::getAttribute(subscene, attrib, first, count, result); } } rgl/src/Color.cpp0000644000176200001440000001260614771520323013420 0ustar liggesusers#include "Color.h" #include "types.h" #include #include // for memcpy using namespace rgl; // // COLOR UTILS // // // FUNCTION // HexCharToNibble // static u8 HexCharToNibble(char c) { u8 nibble = 0; if ((c >= '0') && (c <= '9')) nibble = c - '0'; else if (( c >= 'A') && (c <= 'F')) nibble = (c - 'A') + 10; else if (( c >= 'a') && (c <= 'f')) nibble = (c - 'a') + 10; return nibble; } // // FUNCTION // StringToRGB8 // static void StringToRGB8(const char* string, u8* colorptr) { char* strptr = (char*) string; int cnt = 0; if (( *strptr++ == '#') && (cnt < 3)) { char c; while( (c = *strptr++) != '\0' ) { u8 component; component = static_cast(HexCharToNibble(c) << 4); if ( (c = *strptr++) == '\0') break; component |= HexCharToNibble(c); *colorptr++ = component; cnt++; } } for(int i=cnt;i<3;i++) *colorptr++ = 0x00; } ////////////////////////////////////////////////////////////////////////////// // // CLASS // Color // // Color::Color() { data[0] = 1.0f; data[1] = 1.0f; data[2] = 1.0f; data[3] = 1.0f; } Color::Color(float red, float green, float blue, float alpha) { data[0] = red; data[1] = green; data[2] = blue; data[3] = alpha; } Color::Color(u8 red, u8 green, u8 blue, u8 alpha) { data[0] = ((float)red)/255.0f; data[1] = ((float)green)/255.0f; data[2] = ((float)blue)/255.0f; data[3] = ((float)alpha)/255.0f; } Color::Color(const char* string) { u8 tmp[4]; tmp[3] = 255; StringToRGB8(string, tmp); for (int i=0;i<4;i++) data[i] = ((float)tmp[i])/255.0f; } void Color::set3iv(int* color) { data[0] = ((float)color[0])/255.0f; data[1] = ((float)color[1])/255.0f; data[2] = ((float)color[2])/255.0f; data[3] = 1.0f; } // TODO: move to rendergl.cpp #include "opengl.h" void Color::useClearColor() const { #ifndef RGL_NO_OPENGL glClearColor(data[0],data[1],data[2], data[3]); #endif } void Color::useColor() const { #ifndef RGL_NO_OPENGL glColor4fv(data); #endif } ////////////////////////////////////////////////////////////////////////////// // // CLASS // ColorArray // ColorArray::ColorArray() { arrayptr = NULL; ncolor = 0; nalpha = 0; } ColorArray::ColorArray( Color& bg, Color &fg ) { ncolor = 2; nalpha = 2; arrayptr = (u8*) realloc( NULL, sizeof(u8) * 4 * ncolor); arrayptr[0] = bg.getRedub(); arrayptr[1] = bg.getBlueub(); arrayptr[2] = bg.getGreenub(); arrayptr[3] = bg.getAlphaub(); arrayptr[4] = fg.getRedub(); arrayptr[5] = fg.getBlueub(); arrayptr[6] = fg.getGreenub(); arrayptr[7] = fg.getAlphaub(); hint_alphablend = ( (bg.getAlphaub() < 255) || (fg.getAlphaub() < 255) ) ? true : false; } ColorArray::ColorArray( ColorArray& src ) { ncolor = src.ncolor; nalpha = src.nalpha; hint_alphablend = src.hint_alphablend; if (ncolor > 0) { arrayptr = (u8*) realloc( NULL, sizeof(u8) * 4 * ncolor); memcpy( arrayptr, src.arrayptr, sizeof(u8) * 4 * ncolor); } else { arrayptr = NULL; } } ColorArray::~ColorArray() { if (arrayptr) free(arrayptr); } void ColorArray::set( int in_ncolor, char** in_color, int in_nalpha, double* in_alpha) { ncolor = getMax(in_ncolor, in_nalpha); nalpha = in_nalpha; u8* ptr = arrayptr = (u8*) realloc( arrayptr, sizeof(u8) * 4 * ncolor); hint_alphablend = false; for (unsigned int i=0;i 0) { u8 alpha = (u8) ( clamp( (float) in_alpha[i%in_nalpha], 0.0f, 1.0f) * 255.0f ); if (alpha < 255) hint_alphablend = true; ptr[3] = alpha; } else ptr[3] = 0xFF; ptr += 4; } } void ColorArray::set( int in_ncolor, int* in_color, int in_nalpha, double* in_alpha) { ncolor = getMax(in_ncolor, in_nalpha); nalpha = in_nalpha; u8* ptr = arrayptr = (u8*) realloc( arrayptr, sizeof(u8) * 4 * ncolor); hint_alphablend = false; for (unsigned int i=0;i 0) { u8 alpha = (u8) ( clamp( (float) in_alpha[i%in_nalpha], 0.0f, 1.0f) * 255.0f ); if (alpha < 255) hint_alphablend = true; ptr[3] = alpha; } else ptr[3] = 0xFF; ptr += 4; } } unsigned int ColorArray::getLength() const { return ncolor; } bool ColorArray::hasAlpha() const { return hint_alphablend; } void ColorArray::useArray() const { #ifndef RGL_NO_OPENGL glColorPointer(4, GL_UNSIGNED_BYTE, 0, (const GLvoid*) arrayptr ); #endif } void ColorArray::useColor(int index) const { #ifndef RGL_NO_OPENGL glColor4ubv( (const GLubyte*) &arrayptr[ index * 4] ); #endif } Color ColorArray::getColor(int index) const { return Color( arrayptr[index*4], arrayptr[index*4+1], arrayptr[index*4+2], arrayptr[index*4+3] ); } void ColorArray::recycle(unsigned int newsize) { if (ncolor != newsize) { if (ncolor > 1) { if (newsize > 0) { arrayptr = (u8*) realloc(arrayptr, sizeof(u8)*4*newsize); for(unsigned int i=ncolor;i #ifdef HAVE_FREETYPE #include "FTGL/ftgl.h" #include "R.h" #endif #include "types.h" #include "glgui.h" #include "gl2ps.h" #include "opengl.h" #include "RenderContext.h" #include "subscene.h" #include "platform.h" using namespace rgl; // // CLASS // GLFont // GLboolean GLFont::justify(double twidth, double theight, double adjx, double adjy, double adjz, int pos, const RenderContext& rc) { #ifndef RGL_NO_OPENGL GLdouble pos1[4], pos2[4]; double basex = 0.0, basey = 0.0, basez = 0.5, scaling = 1.0; GLboolean valid; gl2ps_centering = GL2PS_TEXT_BL; if (pos) { double offset = adjx, w = width("m"); switch(pos) { case 0: case 1: case 3: case 5: case 6: adjx = 0.5; break; case 2: adjx = 1.0 + w*offset/twidth; break; case 4: adjx = -w*offset/twidth; break; } switch(pos) { case 0: case 2: case 4: case 5: case 6: adjy = 0.5; break; case 1: adjy = 1.0 + offset; break; case 3: adjy = -offset; break; } switch(pos) { case 0: case 1: case 2: case 3: case 4: adjz = 0.5; break; case 5: adjz = 1.0 + offset; break; case 6: adjz = -offset; break; } } if (adjx > 0) { if (rc.gl2psActive > GL2PS_NONE) scaling = GL2PS_SCALING; if ( adjx > 0.25 && rc.gl2psActive == GL2PS_POSITIONAL) { if (adjx < 0.75) { basex = 0.5; gl2ps_centering = GL2PS_TEXT_B; } else { basex = 1.0; gl2ps_centering = GL2PS_TEXT_BR; } } } if ((adjx != basex) || (adjy != basey) || (adjz != basez)) { glGetDoublev(GL_CURRENT_RASTER_POSITION, pos1); pos1[0] = pos1[0] - scaling*twidth*(adjx-basex); pos1[1] = pos1[1] - scaling*theight*(adjy-basey); pos1[2] = pos1[2] - scaling*theight*(adjz-basez)/1000.0; GLint pviewport[4] = {rc.subscene->pviewport.x, rc.subscene->pviewport.y, rc.subscene->pviewport.width, rc.subscene->pviewport.height}; GLdouble modelMatrix[16], projMatrix[16]; rc.subscene->modelMatrix.getData(modelMatrix); rc.subscene->projMatrix.getData(projMatrix); gluUnProject( pos1[0], pos1[1], pos1[2], modelMatrix, projMatrix, pviewport, pos2, pos2 + 1, pos2 + 2); glRasterPos3dv(pos2); } glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid); return valid; #else return 0; #endif } // // CLASS // GLBitmapFont // GLBitmapFont::~GLBitmapFont() { delete [] widths; #ifndef RGL_NO_OPENGL if (nglyph) glDeleteLists(listBase+GL_BITMAP_FONT_FIRST_GLYPH, nglyph); #endif } double GLBitmapFont::width(const char* text) { double result = 0.0; for(int i=0; text[i]; i++) { int c; if ((int)(text[i]) >= (int)firstGlyph && (c = (int)(text[i]) - (int)firstGlyph) < (int)nglyph) result += widths[(int)c]; } return result; } double GLBitmapFont::width(const wchar_t* text) { double result = 0.0; for(int i=0; text[i]; i++) { wchar_t c; if ((int)text[i] >= (int)firstGlyph && (c = (int)(text[i]) - (int)firstGlyph) < (int)nglyph) result += widths[c]; } return result; } double GLBitmapFont::height() { return ascent; } bool GLBitmapFont::valid(const char* text) { for (int i=0; text[i]; i++) if ((int)text[i] < (int)firstGlyph || (int)text[i] - (int)firstGlyph >= (int)nglyph) return false; return true; } void GLBitmapFont::draw(const char* text, int length, double adjx, double adjy, double adjz, int pos, const RenderContext& rc) { #ifndef RGL_NO_OPENGL if (justify(width(text), height(), adjx, adjy, adjz, pos, rc)) { if (rc.gl2psActive == GL2PS_NONE) { glListBase(listBase); glCallLists(length, GL_UNSIGNED_BYTE, text); } else gl2psTextOpt(text, GL2PS_FONT, static_cast(GL2PS_FONTSIZE*cex), gl2ps_centering, 0.0); } #endif } void GLBitmapFont::draw(const wchar_t* text, int length, double adjx, double adjy, double adjz, int pos, const RenderContext& rc) { #ifndef RGL_NO_OPENGL if (justify(width(text), height(), adjx, adjy, adjz, pos, rc)) { GLenum type = sizeof(wchar_t) == 4 ? GL_UNSIGNED_INT : sizeof(wchar_t) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_BYTE ; if (rc.gl2psActive == GL2PS_NONE) { glListBase(listBase); glCallLists(length, type, text); } // gl2ps doesn't support wchar_t? Should convert? } #endif } #ifdef HAVE_FREETYPE GLFTFont::GLFTFont(const char* in_family, int in_style, double in_cex, const char* in_fontname) : GLFont(in_family, in_style, in_cex, in_fontname, true) { font=new FTGLPixmapFont(fontname); if (font->Error()) { errmsg = "Cannot create Freetype font"; delete font; font = NULL; } else { unsigned int size = static_cast(16*cex + 0.5); if (size<1) { size=1; } if (!font->FaceSize(size)) { errmsg = "Cannot create Freetype font of requested size"; delete font; font = NULL; } } /* font->CharMap(ft_encoding_unicode); if (font->Error()) { Rf_error("Cannot set unicode encoding."); }*/ } GLFTFont::~GLFTFont() { if (font) delete font; } double GLFTFont::width(const char* text) { return font->Advance(text); } double GLFTFont::width(const wchar_t* text) { return font->Advance(text); } double GLFTFont::height() { return font->Ascender(); } void GLFTFont::draw(const char* text, int length, double adjx, double adjy, double adjz, int pos, const RenderContext& rc) { if ( justify( width(text), height(), adjx, adjy, adjz, pos, rc ) ) { if (rc.gl2psActive == GL2PS_NONE) font->Render(text); else gl2psTextOpt(text, GL2PS_FONT, static_cast(GL2PS_FONTSIZE*cex), gl2ps_centering, 0.0); } } void GLFTFont::draw(const wchar_t* text, int length, double adjx, double adjy, double adjz, int pos, const RenderContext& rc) { if ( justify( width(text), height(), adjx, adjy, adjz, pos, rc ) ) { if (rc.gl2psActive == GL2PS_NONE) font->Render(text); } } #endif rgl/src/opengl.h0000644000176200001440000000154514771520323013273 0ustar liggesusers#ifndef RGL_OPENGL_H #define RGL_OPENGL_H #include "config.h" #ifdef RGL_NO_OPENGL #include "OpenGL/gl.h" #else // Use glad #include #ifdef RGL_W32 #define WIN32_LEAN_AND_MEAN #include #include #include #include #else // --------------------------------------------------------------------------- // Using OpenGL and GLU // --------------------------------------------------------------------------- #ifdef RGL_OSX #include #endif // --------------------------------------------------------------------------- // --------------------------------------------------------------------------- #ifdef RGL_X11 #include #endif #endif // not RGL_W32 #endif // RGL_NO_OPENGL // --------------------------------------------------------------------------- #endif // RGL_OPENGL_H rgl/src/Background.cpp0000644000176200001440000001665015011677075014431 0ustar liggesusers#include "Background.h" #include "Viewpoint.h" #include "scene.h" #include "rglmath.h" #include "R.h" using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // Background // Material Background::defaultMaterial( Color(0.3f,0.3f,0.3f), Color(1.0f,0.0f,0.0f) ); Background::Background(Material& in_material, bool in_sphere, int in_fogtype, float in_fogScale) : Shape(in_material, true, BACKGROUND), sphere(in_sphere), fogtype(in_fogtype), fogScale(in_fogScale), quad(NULL) { clearColorBuffer = true; if (sphere) { material.colors.recycle(2); material.front = Material::CULL_FACE; material.colorPerVertex(false); if (material.back == Material::FILL_FACE) clearColorBuffer = false; if ( (material.lit) || ( (material.texture) && (material.texture->is_envmap() ) ) ) sphereMesh.setGenNormal(true); if ( (material.texture) && (!material.texture->is_envmap() ) ) sphereMesh.setGenTexCoord(true); material.depth_mask = false; material.depth_test = false; sphereMesh.setGlobe (16,16); sphereMesh.setCenter( Vertex(0.0f,0.0f,0.0f) ); sphereMesh.setRadius( 1.0f ); sphereMesh.update(); } else if (material.texture) { double vertices[12] = { -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1 }; double texcoords[8] = { 0, 0, 1, 0, 1, 1, 0, 1 }; material.colorPerVertex(false); material.colors.recycle(1); quad = new QuadSet(material, 4, vertices, NULL, texcoords, true, 0, NULL, 0, 1); quad->owner = this; } else material.colors.recycle(1); } Background::~Background() { if (quad) { quad->owner = NULL; quad = NULL; } } GLbitfield Background::getClearFlags(RenderContext* renderContext) { if (clearColorBuffer) { material.colors.getColor(0).useClearColor(); return GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT; } else return GL_DEPTH_BUFFER_BIT; } // FIXME: this doesn't follow the pattern of other render methods. void Background::render(RenderContext* renderContext) { #ifndef RGL_NO_OPENGL Subscene* subscene = renderContext->subscene; UserViewpoint* userviewpoint = subscene->getUserViewpoint(); const AABox& bbox = subscene->getBoundingBox(); // setup fog if ((fogtype != FOG_NONE) && (bbox.isValid() )) { // Sphere bsphere(bbox); glFogfv(GL_FOG_COLOR, material.colors.getColor(0).getFloatPtr() ); switch(fogtype) { case FOG_LINEAR: glFogi(GL_FOG_MODE, GL_LINEAR); glFogf(GL_FOG_START, userviewpoint->frustum.znear /*bsphere.radius*2*/); // glFogf(GL_FOG_END, userviewpoint->frustum.zfar /*bsphere.radius*3*/ ); // Scale fog density up by fogScale glFogf(GL_FOG_END, (userviewpoint->frustum.zfar - userviewpoint->frustum.znear)/fogScale + userviewpoint->frustum.znear); break; case FOG_EXP: glFogi(GL_FOG_MODE, GL_EXP); // glFogf(GL_FOG_DENSITY, 1.0f/userviewpoint->frustum.zfar /*(bsphere.radius*3)*/ ); // Multiply fog density parameter by fogScale glFogf(GL_FOG_DENSITY, fogScale*1.0f/userviewpoint->frustum.zfar /*(bsphere.radius*3)*/ ); break; case FOG_EXP2: glFogi(GL_FOG_MODE, GL_EXP2); // Multiply fog density parameter by fogScale glFogf(GL_FOG_DENSITY, fogScale*1.0f/userviewpoint->frustum.zfar /*(bsphere.radius*3)*/ ); break; } glEnable(GL_FOG); } else { glDisable(GL_FOG); } // render bg sphere if (sphere) { /* The way we draw a background sphere is to start by rotating * the sphere so the pole is at (0, 1, 0) instead of (0, 0, 1), * then scale it to 4 times the radius of the bounding box, * then translate it to the center of the bbox and apply * the model-view transformation to it. After that, * flatten it to zero thickness in the z direction. */ Matrix4x4 savedModelMatrix = subscene->modelMatrix; AABox bbox = subscene->getBoundingBox(); Vec3 center = bbox.getCenter(); Vec3 scale = subscene->getModelViewpoint()->scale; double zoom = subscene->getUserViewpoint()->getZoom(); Matrix4x4 m; m.setRotate(0, 90); /* This calculation gets the aspect ratio * from the scale and range, by undoing aspect3d() */ Vec3 ranges = bbox.vmax - bbox.vmin; float avgscale = ranges.getLength()/sqrtf(3.0f); Vec3 aspect(ranges.x*scale.x/avgscale, ranges.y*scale.y/avgscale, ranges.z*scale.z/avgscale); float maxaspect = std::max(aspect.x, std::max(aspect.y, aspect.z)); m.multLeft(Matrix4x4::scaleMatrix(zoom*2.0*maxaspect*ranges.x/aspect.x, zoom*2.0*maxaspect*ranges.y/aspect.y, zoom*2.0*maxaspect*ranges.z/aspect.z)); m.multLeft(Matrix4x4::translationMatrix(center.x, center.y, center.z)); m.multLeft(savedModelMatrix); center = savedModelMatrix * center; m.multLeft(Matrix4x4::translationMatrix(-center.x, -center.y, -center.z)); m.multLeft(Matrix4x4::scaleMatrix(1.0, 1.0, 0.25/zoom)); m.multLeft(Matrix4x4::translationMatrix(center.x, center.y, center.z)); subscene->modelMatrix.loadData(m); subscene->loadMatrices(); Shape::render(renderContext); subscene->modelMatrix.loadData(savedModelMatrix); subscene->loadMatrices(); } else if (quad) { glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); quad->draw(renderContext); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } #endif } void Background::drawPrimitive(RenderContext* renderContext, int index) { #ifndef RGL_NO_OPENGL glPushAttrib(GL_ENABLE_BIT); material.beginUse(renderContext); material.useColor(1); glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); sphereMesh.draw(renderContext); material.endUse(renderContext); glPopAttrib(); #endif } int Background::getAttributeCount(SceneNode* subscene, AttribID attrib) { switch (attrib) { case FLAGS: return 4; case FOGSCALE: return 1; case TYPES: case IDS: if (quad) return 1; else return 0; } return Shape::getAttributeCount(subscene, attrib); } void Background::getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result) { int n = getAttributeCount(subscene, attrib); if (first + count < n) n = first + count; if (first < n) { switch(attrib) { case FLAGS: if (first <= 0) *result++ = (double) sphere; if (first <= 1) *result++ = (double) fogtype == FOG_LINEAR; if (first <= 2) *result++ = (double) fogtype == FOG_EXP; if (first <= 3) *result++ = (double) fogtype == FOG_EXP2; return; case FOGSCALE: if (first <= 0) *result++ = fogScale; return; case IDS: if (quad) *result++ = quad->getObjID(); return; } Shape::getAttribute(subscene, attrib, first, count, result); } } std::string Background::getTextAttribute(SceneNode* subscene, AttribID attrib, int index) { int n = getAttributeCount(subscene, attrib); if (index < n && attrib == TYPES) return quad->getTypeName(); else return Shape::getTextAttribute(subscene, attrib, index); } rgl/src/gl.c0000644000176200001440000027411015011677075012411 0ustar liggesusers/** * SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0 */ #include #include #include /* put this here to avoid warning about empty file */ #ifndef RGL_NO_OPENGL #include #ifndef GLAD_IMPL_UTIL_C_ #define GLAD_IMPL_UTIL_C_ #ifdef _MSC_VER #define GLAD_IMPL_UTIL_SSCANF sscanf_s #else #define GLAD_IMPL_UTIL_SSCANF sscanf #endif #endif /* GLAD_IMPL_UTIL_C_ */ #ifdef __cplusplus extern "C" { #endif int GLAD_GL_VERSION_1_0 = 0; int GLAD_GL_VERSION_1_1 = 0; int GLAD_GL_VERSION_1_2 = 0; int GLAD_GL_VERSION_1_3 = 0; int GLAD_GL_VERSION_1_4 = 0; int GLAD_GL_VERSION_1_5 = 0; int GLAD_GL_VERSION_2_0 = 0; int GLAD_GL_VERSION_2_1 = 0; int GLAD_GL_VERSION_3_0 = 0; PFNGLACCUMPROC glad_glAccum = NULL; PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL; PFNGLALPHAFUNCPROC glad_glAlphaFunc = NULL; PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident = NULL; PFNGLARRAYELEMENTPROC glad_glArrayElement = NULL; PFNGLATTACHSHADERPROC glad_glAttachShader = NULL; PFNGLBEGINPROC glad_glBegin = NULL; PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender = NULL; PFNGLBEGINQUERYPROC glad_glBeginQuery = NULL; PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback = NULL; PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation = NULL; PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL; PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase = NULL; PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange = NULL; PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation = NULL; PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer = NULL; PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer = NULL; PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL; PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL; PFNGLBITMAPPROC glad_glBitmap = NULL; PFNGLBLENDCOLORPROC glad_glBlendColor = NULL; PFNGLBLENDEQUATIONPROC glad_glBlendEquation = NULL; PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate = NULL; PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL; PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate = NULL; PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer = NULL; PFNGLBUFFERDATAPROC glad_glBufferData = NULL; PFNGLBUFFERSUBDATAPROC glad_glBufferSubData = NULL; PFNGLCALLLISTPROC glad_glCallList = NULL; PFNGLCALLLISTSPROC glad_glCallLists = NULL; PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus = NULL; PFNGLCLAMPCOLORPROC glad_glClampColor = NULL; PFNGLCLEARPROC glad_glClear = NULL; PFNGLCLEARACCUMPROC glad_glClearAccum = NULL; PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi = NULL; PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv = NULL; PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv = NULL; PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv = NULL; PFNGLCLEARCOLORPROC glad_glClearColor = NULL; PFNGLCLEARDEPTHPROC glad_glClearDepth = NULL; PFNGLCLEARINDEXPROC glad_glClearIndex = NULL; PFNGLCLEARSTENCILPROC glad_glClearStencil = NULL; PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture = NULL; PFNGLCLIPPLANEPROC glad_glClipPlane = NULL; PFNGLCOLOR3BPROC glad_glColor3b = NULL; PFNGLCOLOR3BVPROC glad_glColor3bv = NULL; PFNGLCOLOR3DPROC glad_glColor3d = NULL; PFNGLCOLOR3DVPROC glad_glColor3dv = NULL; PFNGLCOLOR3FPROC glad_glColor3f = NULL; PFNGLCOLOR3FVPROC glad_glColor3fv = NULL; PFNGLCOLOR3IPROC glad_glColor3i = NULL; PFNGLCOLOR3IVPROC glad_glColor3iv = NULL; PFNGLCOLOR3SPROC glad_glColor3s = NULL; PFNGLCOLOR3SVPROC glad_glColor3sv = NULL; PFNGLCOLOR3UBPROC glad_glColor3ub = NULL; PFNGLCOLOR3UBVPROC glad_glColor3ubv = NULL; PFNGLCOLOR3UIPROC glad_glColor3ui = NULL; PFNGLCOLOR3UIVPROC glad_glColor3uiv = NULL; PFNGLCOLOR3USPROC glad_glColor3us = NULL; PFNGLCOLOR3USVPROC glad_glColor3usv = NULL; PFNGLCOLOR4BPROC glad_glColor4b = NULL; PFNGLCOLOR4BVPROC glad_glColor4bv = NULL; PFNGLCOLOR4DPROC glad_glColor4d = NULL; PFNGLCOLOR4DVPROC glad_glColor4dv = NULL; PFNGLCOLOR4FPROC glad_glColor4f = NULL; PFNGLCOLOR4FVPROC glad_glColor4fv = NULL; PFNGLCOLOR4IPROC glad_glColor4i = NULL; PFNGLCOLOR4IVPROC glad_glColor4iv = NULL; PFNGLCOLOR4SPROC glad_glColor4s = NULL; PFNGLCOLOR4SVPROC glad_glColor4sv = NULL; PFNGLCOLOR4UBPROC glad_glColor4ub = NULL; PFNGLCOLOR4UBVPROC glad_glColor4ubv = NULL; PFNGLCOLOR4UIPROC glad_glColor4ui = NULL; PFNGLCOLOR4UIVPROC glad_glColor4uiv = NULL; PFNGLCOLOR4USPROC glad_glColor4us = NULL; PFNGLCOLOR4USVPROC glad_glColor4usv = NULL; PFNGLCOLORMASKPROC glad_glColorMask = NULL; PFNGLCOLORMASKIPROC glad_glColorMaski = NULL; PFNGLCOLORMATERIALPROC glad_glColorMaterial = NULL; PFNGLCOLORPOINTERPROC glad_glColorPointer = NULL; PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL; PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D = NULL; PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D = NULL; PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D = NULL; PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D = NULL; PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D = NULL; PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D = NULL; PFNGLCOPYPIXELSPROC glad_glCopyPixels = NULL; PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D = NULL; PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D = NULL; PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D = NULL; PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D = NULL; PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D = NULL; PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL; PFNGLCREATESHADERPROC glad_glCreateShader = NULL; PFNGLCULLFACEPROC glad_glCullFace = NULL; PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL; PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers = NULL; PFNGLDELETELISTSPROC glad_glDeleteLists = NULL; PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL; PFNGLDELETEQUERIESPROC glad_glDeleteQueries = NULL; PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers = NULL; PFNGLDELETESHADERPROC glad_glDeleteShader = NULL; PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL; PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL; PFNGLDEPTHFUNCPROC glad_glDepthFunc = NULL; PFNGLDEPTHMASKPROC glad_glDepthMask = NULL; PFNGLDEPTHRANGEPROC glad_glDepthRange = NULL; PFNGLDETACHSHADERPROC glad_glDetachShader = NULL; PFNGLDISABLEPROC glad_glDisable = NULL; PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState = NULL; PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL; PFNGLDISABLEIPROC glad_glDisablei = NULL; PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL; PFNGLDRAWBUFFERPROC glad_glDrawBuffer = NULL; PFNGLDRAWBUFFERSPROC glad_glDrawBuffers = NULL; PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL; PFNGLDRAWPIXELSPROC glad_glDrawPixels = NULL; PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements = NULL; PFNGLEDGEFLAGPROC glad_glEdgeFlag = NULL; PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer = NULL; PFNGLEDGEFLAGVPROC glad_glEdgeFlagv = NULL; PFNGLENABLEPROC glad_glEnable = NULL; PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState = NULL; PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL; PFNGLENABLEIPROC glad_glEnablei = NULL; PFNGLENDPROC glad_glEnd = NULL; PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender = NULL; PFNGLENDLISTPROC glad_glEndList = NULL; PFNGLENDQUERYPROC glad_glEndQuery = NULL; PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback = NULL; PFNGLEVALCOORD1DPROC glad_glEvalCoord1d = NULL; PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv = NULL; PFNGLEVALCOORD1FPROC glad_glEvalCoord1f = NULL; PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv = NULL; PFNGLEVALCOORD2DPROC glad_glEvalCoord2d = NULL; PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv = NULL; PFNGLEVALCOORD2FPROC glad_glEvalCoord2f = NULL; PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv = NULL; PFNGLEVALMESH1PROC glad_glEvalMesh1 = NULL; PFNGLEVALMESH2PROC glad_glEvalMesh2 = NULL; PFNGLEVALPOINT1PROC glad_glEvalPoint1 = NULL; PFNGLEVALPOINT2PROC glad_glEvalPoint2 = NULL; PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer = NULL; PFNGLFINISHPROC glad_glFinish = NULL; PFNGLFLUSHPROC glad_glFlush = NULL; PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange = NULL; PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer = NULL; PFNGLFOGCOORDDPROC glad_glFogCoordd = NULL; PFNGLFOGCOORDDVPROC glad_glFogCoorddv = NULL; PFNGLFOGCOORDFPROC glad_glFogCoordf = NULL; PFNGLFOGCOORDFVPROC glad_glFogCoordfv = NULL; PFNGLFOGFPROC glad_glFogf = NULL; PFNGLFOGFVPROC glad_glFogfv = NULL; PFNGLFOGIPROC glad_glFogi = NULL; PFNGLFOGIVPROC glad_glFogiv = NULL; PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer = NULL; PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D = NULL; PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D = NULL; PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D = NULL; PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer = NULL; PFNGLFRONTFACEPROC glad_glFrontFace = NULL; PFNGLFRUSTUMPROC glad_glFrustum = NULL; PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL; PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers = NULL; PFNGLGENLISTSPROC glad_glGenLists = NULL; PFNGLGENQUERIESPROC glad_glGenQueries = NULL; PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers = NULL; PFNGLGENTEXTURESPROC glad_glGenTextures = NULL; PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL; PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap = NULL; PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib = NULL; PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform = NULL; PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders = NULL; PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation = NULL; PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v = NULL; PFNGLGETBOOLEANVPROC glad_glGetBooleanv = NULL; PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv = NULL; PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv = NULL; PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData = NULL; PFNGLGETCLIPPLANEPROC glad_glGetClipPlane = NULL; PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage = NULL; PFNGLGETDOUBLEVPROC glad_glGetDoublev = NULL; PFNGLGETERRORPROC glad_glGetError = NULL; PFNGLGETFLOATVPROC glad_glGetFloatv = NULL; PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation = NULL; PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv = NULL; PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v = NULL; PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL; PFNGLGETLIGHTFVPROC glad_glGetLightfv = NULL; PFNGLGETLIGHTIVPROC glad_glGetLightiv = NULL; PFNGLGETMAPDVPROC glad_glGetMapdv = NULL; PFNGLGETMAPFVPROC glad_glGetMapfv = NULL; PFNGLGETMAPIVPROC glad_glGetMapiv = NULL; PFNGLGETMATERIALFVPROC glad_glGetMaterialfv = NULL; PFNGLGETMATERIALIVPROC glad_glGetMaterialiv = NULL; PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv = NULL; PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv = NULL; PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv = NULL; PFNGLGETPOINTERVPROC glad_glGetPointerv = NULL; PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple = NULL; PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL; PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL; PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv = NULL; PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv = NULL; PFNGLGETQUERYIVPROC glad_glGetQueryiv = NULL; PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv = NULL; PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL; PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource = NULL; PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL; PFNGLGETSTRINGPROC glad_glGetString = NULL; PFNGLGETSTRINGIPROC glad_glGetStringi = NULL; PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv = NULL; PFNGLGETTEXENVIVPROC glad_glGetTexEnviv = NULL; PFNGLGETTEXGENDVPROC glad_glGetTexGendv = NULL; PFNGLGETTEXGENFVPROC glad_glGetTexGenfv = NULL; PFNGLGETTEXGENIVPROC glad_glGetTexGeniv = NULL; PFNGLGETTEXIMAGEPROC glad_glGetTexImage = NULL; PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv = NULL; PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv = NULL; PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv = NULL; PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv = NULL; PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv = NULL; PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv = NULL; PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying = NULL; PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL; PFNGLGETUNIFORMFVPROC glad_glGetUniformfv = NULL; PFNGLGETUNIFORMIVPROC glad_glGetUniformiv = NULL; PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv = NULL; PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv = NULL; PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv = NULL; PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv = NULL; PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv = NULL; PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv = NULL; PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv = NULL; PFNGLHINTPROC glad_glHint = NULL; PFNGLINDEXMASKPROC glad_glIndexMask = NULL; PFNGLINDEXPOINTERPROC glad_glIndexPointer = NULL; PFNGLINDEXDPROC glad_glIndexd = NULL; PFNGLINDEXDVPROC glad_glIndexdv = NULL; PFNGLINDEXFPROC glad_glIndexf = NULL; PFNGLINDEXFVPROC glad_glIndexfv = NULL; PFNGLINDEXIPROC glad_glIndexi = NULL; PFNGLINDEXIVPROC glad_glIndexiv = NULL; PFNGLINDEXSPROC glad_glIndexs = NULL; PFNGLINDEXSVPROC glad_glIndexsv = NULL; PFNGLINDEXUBPROC glad_glIndexub = NULL; PFNGLINDEXUBVPROC glad_glIndexubv = NULL; PFNGLINITNAMESPROC glad_glInitNames = NULL; PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays = NULL; PFNGLISBUFFERPROC glad_glIsBuffer = NULL; PFNGLISENABLEDPROC glad_glIsEnabled = NULL; PFNGLISENABLEDIPROC glad_glIsEnabledi = NULL; PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer = NULL; PFNGLISLISTPROC glad_glIsList = NULL; PFNGLISPROGRAMPROC glad_glIsProgram = NULL; PFNGLISQUERYPROC glad_glIsQuery = NULL; PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer = NULL; PFNGLISSHADERPROC glad_glIsShader = NULL; PFNGLISTEXTUREPROC glad_glIsTexture = NULL; PFNGLISVERTEXARRAYPROC glad_glIsVertexArray = NULL; PFNGLLIGHTMODELFPROC glad_glLightModelf = NULL; PFNGLLIGHTMODELFVPROC glad_glLightModelfv = NULL; PFNGLLIGHTMODELIPROC glad_glLightModeli = NULL; PFNGLLIGHTMODELIVPROC glad_glLightModeliv = NULL; PFNGLLIGHTFPROC glad_glLightf = NULL; PFNGLLIGHTFVPROC glad_glLightfv = NULL; PFNGLLIGHTIPROC glad_glLighti = NULL; PFNGLLIGHTIVPROC glad_glLightiv = NULL; PFNGLLINESTIPPLEPROC glad_glLineStipple = NULL; PFNGLLINEWIDTHPROC glad_glLineWidth = NULL; PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL; PFNGLLISTBASEPROC glad_glListBase = NULL; PFNGLLOADIDENTITYPROC glad_glLoadIdentity = NULL; PFNGLLOADMATRIXDPROC glad_glLoadMatrixd = NULL; PFNGLLOADMATRIXFPROC glad_glLoadMatrixf = NULL; PFNGLLOADNAMEPROC glad_glLoadName = NULL; PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd = NULL; PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf = NULL; PFNGLLOGICOPPROC glad_glLogicOp = NULL; PFNGLMAP1DPROC glad_glMap1d = NULL; PFNGLMAP1FPROC glad_glMap1f = NULL; PFNGLMAP2DPROC glad_glMap2d = NULL; PFNGLMAP2FPROC glad_glMap2f = NULL; PFNGLMAPBUFFERPROC glad_glMapBuffer = NULL; PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange = NULL; PFNGLMAPGRID1DPROC glad_glMapGrid1d = NULL; PFNGLMAPGRID1FPROC glad_glMapGrid1f = NULL; PFNGLMAPGRID2DPROC glad_glMapGrid2d = NULL; PFNGLMAPGRID2FPROC glad_glMapGrid2f = NULL; PFNGLMATERIALFPROC glad_glMaterialf = NULL; PFNGLMATERIALFVPROC glad_glMaterialfv = NULL; PFNGLMATERIALIPROC glad_glMateriali = NULL; PFNGLMATERIALIVPROC glad_glMaterialiv = NULL; PFNGLMATRIXMODEPROC glad_glMatrixMode = NULL; PFNGLMULTMATRIXDPROC glad_glMultMatrixd = NULL; PFNGLMULTMATRIXFPROC glad_glMultMatrixf = NULL; PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd = NULL; PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf = NULL; PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays = NULL; PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements = NULL; PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d = NULL; PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv = NULL; PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f = NULL; PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv = NULL; PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i = NULL; PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv = NULL; PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s = NULL; PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv = NULL; PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d = NULL; PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv = NULL; PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f = NULL; PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv = NULL; PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i = NULL; PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv = NULL; PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s = NULL; PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv = NULL; PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d = NULL; PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv = NULL; PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f = NULL; PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv = NULL; PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i = NULL; PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv = NULL; PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s = NULL; PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv = NULL; PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d = NULL; PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv = NULL; PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f = NULL; PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv = NULL; PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i = NULL; PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv = NULL; PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s = NULL; PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv = NULL; PFNGLNEWLISTPROC glad_glNewList = NULL; PFNGLNORMAL3BPROC glad_glNormal3b = NULL; PFNGLNORMAL3BVPROC glad_glNormal3bv = NULL; PFNGLNORMAL3DPROC glad_glNormal3d = NULL; PFNGLNORMAL3DVPROC glad_glNormal3dv = NULL; PFNGLNORMAL3FPROC glad_glNormal3f = NULL; PFNGLNORMAL3FVPROC glad_glNormal3fv = NULL; PFNGLNORMAL3IPROC glad_glNormal3i = NULL; PFNGLNORMAL3IVPROC glad_glNormal3iv = NULL; PFNGLNORMAL3SPROC glad_glNormal3s = NULL; PFNGLNORMAL3SVPROC glad_glNormal3sv = NULL; PFNGLNORMALPOINTERPROC glad_glNormalPointer = NULL; PFNGLORTHOPROC glad_glOrtho = NULL; PFNGLPASSTHROUGHPROC glad_glPassThrough = NULL; PFNGLPIXELMAPFVPROC glad_glPixelMapfv = NULL; PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv = NULL; PFNGLPIXELMAPUSVPROC glad_glPixelMapusv = NULL; PFNGLPIXELSTOREFPROC glad_glPixelStoref = NULL; PFNGLPIXELSTOREIPROC glad_glPixelStorei = NULL; PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf = NULL; PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi = NULL; PFNGLPIXELZOOMPROC glad_glPixelZoom = NULL; PFNGLPOINTPARAMETERFPROC glad_glPointParameterf = NULL; PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv = NULL; PFNGLPOINTPARAMETERIPROC glad_glPointParameteri = NULL; PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv = NULL; PFNGLPOINTSIZEPROC glad_glPointSize = NULL; PFNGLPOLYGONMODEPROC glad_glPolygonMode = NULL; PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset = NULL; PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple = NULL; PFNGLPOPATTRIBPROC glad_glPopAttrib = NULL; PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib = NULL; PFNGLPOPMATRIXPROC glad_glPopMatrix = NULL; PFNGLPOPNAMEPROC glad_glPopName = NULL; PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures = NULL; PFNGLPUSHATTRIBPROC glad_glPushAttrib = NULL; PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib = NULL; PFNGLPUSHMATRIXPROC glad_glPushMatrix = NULL; PFNGLPUSHNAMEPROC glad_glPushName = NULL; PFNGLRASTERPOS2DPROC glad_glRasterPos2d = NULL; PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv = NULL; PFNGLRASTERPOS2FPROC glad_glRasterPos2f = NULL; PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv = NULL; PFNGLRASTERPOS2IPROC glad_glRasterPos2i = NULL; PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv = NULL; PFNGLRASTERPOS2SPROC glad_glRasterPos2s = NULL; PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv = NULL; PFNGLRASTERPOS3DPROC glad_glRasterPos3d = NULL; PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv = NULL; PFNGLRASTERPOS3FPROC glad_glRasterPos3f = NULL; PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv = NULL; PFNGLRASTERPOS3IPROC glad_glRasterPos3i = NULL; PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv = NULL; PFNGLRASTERPOS3SPROC glad_glRasterPos3s = NULL; PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv = NULL; PFNGLRASTERPOS4DPROC glad_glRasterPos4d = NULL; PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv = NULL; PFNGLRASTERPOS4FPROC glad_glRasterPos4f = NULL; PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv = NULL; PFNGLRASTERPOS4IPROC glad_glRasterPos4i = NULL; PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv = NULL; PFNGLRASTERPOS4SPROC glad_glRasterPos4s = NULL; PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv = NULL; PFNGLREADBUFFERPROC glad_glReadBuffer = NULL; PFNGLREADPIXELSPROC glad_glReadPixels = NULL; PFNGLRECTDPROC glad_glRectd = NULL; PFNGLRECTDVPROC glad_glRectdv = NULL; PFNGLRECTFPROC glad_glRectf = NULL; PFNGLRECTFVPROC glad_glRectfv = NULL; PFNGLRECTIPROC glad_glRecti = NULL; PFNGLRECTIVPROC glad_glRectiv = NULL; PFNGLRECTSPROC glad_glRects = NULL; PFNGLRECTSVPROC glad_glRectsv = NULL; PFNGLRENDERMODEPROC glad_glRenderMode = NULL; PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage = NULL; PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample = NULL; PFNGLROTATEDPROC glad_glRotated = NULL; PFNGLROTATEFPROC glad_glRotatef = NULL; PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage = NULL; PFNGLSCALEDPROC glad_glScaled = NULL; PFNGLSCALEFPROC glad_glScalef = NULL; PFNGLSCISSORPROC glad_glScissor = NULL; PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b = NULL; PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv = NULL; PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d = NULL; PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv = NULL; PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f = NULL; PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv = NULL; PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i = NULL; PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv = NULL; PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s = NULL; PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv = NULL; PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub = NULL; PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv = NULL; PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui = NULL; PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv = NULL; PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us = NULL; PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv = NULL; PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer = NULL; PFNGLSELECTBUFFERPROC glad_glSelectBuffer = NULL; PFNGLSHADEMODELPROC glad_glShadeModel = NULL; PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL; PFNGLSTENCILFUNCPROC glad_glStencilFunc = NULL; PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate = NULL; PFNGLSTENCILMASKPROC glad_glStencilMask = NULL; PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate = NULL; PFNGLSTENCILOPPROC glad_glStencilOp = NULL; PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate = NULL; PFNGLTEXCOORD1DPROC glad_glTexCoord1d = NULL; PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv = NULL; PFNGLTEXCOORD1FPROC glad_glTexCoord1f = NULL; PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv = NULL; PFNGLTEXCOORD1IPROC glad_glTexCoord1i = NULL; PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv = NULL; PFNGLTEXCOORD1SPROC glad_glTexCoord1s = NULL; PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv = NULL; PFNGLTEXCOORD2DPROC glad_glTexCoord2d = NULL; PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv = NULL; PFNGLTEXCOORD2FPROC glad_glTexCoord2f = NULL; PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv = NULL; PFNGLTEXCOORD2IPROC glad_glTexCoord2i = NULL; PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv = NULL; PFNGLTEXCOORD2SPROC glad_glTexCoord2s = NULL; PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv = NULL; PFNGLTEXCOORD3DPROC glad_glTexCoord3d = NULL; PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv = NULL; PFNGLTEXCOORD3FPROC glad_glTexCoord3f = NULL; PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv = NULL; PFNGLTEXCOORD3IPROC glad_glTexCoord3i = NULL; PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv = NULL; PFNGLTEXCOORD3SPROC glad_glTexCoord3s = NULL; PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv = NULL; PFNGLTEXCOORD4DPROC glad_glTexCoord4d = NULL; PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv = NULL; PFNGLTEXCOORD4FPROC glad_glTexCoord4f = NULL; PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv = NULL; PFNGLTEXCOORD4IPROC glad_glTexCoord4i = NULL; PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv = NULL; PFNGLTEXCOORD4SPROC glad_glTexCoord4s = NULL; PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv = NULL; PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer = NULL; PFNGLTEXENVFPROC glad_glTexEnvf = NULL; PFNGLTEXENVFVPROC glad_glTexEnvfv = NULL; PFNGLTEXENVIPROC glad_glTexEnvi = NULL; PFNGLTEXENVIVPROC glad_glTexEnviv = NULL; PFNGLTEXGENDPROC glad_glTexGend = NULL; PFNGLTEXGENDVPROC glad_glTexGendv = NULL; PFNGLTEXGENFPROC glad_glTexGenf = NULL; PFNGLTEXGENFVPROC glad_glTexGenfv = NULL; PFNGLTEXGENIPROC glad_glTexGeni = NULL; PFNGLTEXGENIVPROC glad_glTexGeniv = NULL; PFNGLTEXIMAGE1DPROC glad_glTexImage1D = NULL; PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL; PFNGLTEXIMAGE3DPROC glad_glTexImage3D = NULL; PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv = NULL; PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv = NULL; PFNGLTEXPARAMETERFPROC glad_glTexParameterf = NULL; PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv = NULL; PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL; PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv = NULL; PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D = NULL; PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D = NULL; PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D = NULL; PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings = NULL; PFNGLTRANSLATEDPROC glad_glTranslated = NULL; PFNGLTRANSLATEFPROC glad_glTranslatef = NULL; PFNGLUNIFORM1FPROC glad_glUniform1f = NULL; PFNGLUNIFORM1FVPROC glad_glUniform1fv = NULL; PFNGLUNIFORM1IPROC glad_glUniform1i = NULL; PFNGLUNIFORM1IVPROC glad_glUniform1iv = NULL; PFNGLUNIFORM1UIPROC glad_glUniform1ui = NULL; PFNGLUNIFORM1UIVPROC glad_glUniform1uiv = NULL; PFNGLUNIFORM2FPROC glad_glUniform2f = NULL; PFNGLUNIFORM2FVPROC glad_glUniform2fv = NULL; PFNGLUNIFORM2IPROC glad_glUniform2i = NULL; PFNGLUNIFORM2IVPROC glad_glUniform2iv = NULL; PFNGLUNIFORM2UIPROC glad_glUniform2ui = NULL; PFNGLUNIFORM2UIVPROC glad_glUniform2uiv = NULL; PFNGLUNIFORM3FPROC glad_glUniform3f = NULL; PFNGLUNIFORM3FVPROC glad_glUniform3fv = NULL; PFNGLUNIFORM3IPROC glad_glUniform3i = NULL; PFNGLUNIFORM3IVPROC glad_glUniform3iv = NULL; PFNGLUNIFORM3UIPROC glad_glUniform3ui = NULL; PFNGLUNIFORM3UIVPROC glad_glUniform3uiv = NULL; PFNGLUNIFORM4FPROC glad_glUniform4f = NULL; PFNGLUNIFORM4FVPROC glad_glUniform4fv = NULL; PFNGLUNIFORM4IPROC glad_glUniform4i = NULL; PFNGLUNIFORM4IVPROC glad_glUniform4iv = NULL; PFNGLUNIFORM4UIPROC glad_glUniform4ui = NULL; PFNGLUNIFORM4UIVPROC glad_glUniform4uiv = NULL; PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv = NULL; PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv = NULL; PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv = NULL; PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv = NULL; PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv = NULL; PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv = NULL; PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL; PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv = NULL; PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv = NULL; PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer = NULL; PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL; PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram = NULL; PFNGLVERTEX2DPROC glad_glVertex2d = NULL; PFNGLVERTEX2DVPROC glad_glVertex2dv = NULL; PFNGLVERTEX2FPROC glad_glVertex2f = NULL; PFNGLVERTEX2FVPROC glad_glVertex2fv = NULL; PFNGLVERTEX2IPROC glad_glVertex2i = NULL; PFNGLVERTEX2IVPROC glad_glVertex2iv = NULL; PFNGLVERTEX2SPROC glad_glVertex2s = NULL; PFNGLVERTEX2SVPROC glad_glVertex2sv = NULL; PFNGLVERTEX3DPROC glad_glVertex3d = NULL; PFNGLVERTEX3DVPROC glad_glVertex3dv = NULL; PFNGLVERTEX3FPROC glad_glVertex3f = NULL; PFNGLVERTEX3FVPROC glad_glVertex3fv = NULL; PFNGLVERTEX3IPROC glad_glVertex3i = NULL; PFNGLVERTEX3IVPROC glad_glVertex3iv = NULL; PFNGLVERTEX3SPROC glad_glVertex3s = NULL; PFNGLVERTEX3SVPROC glad_glVertex3sv = NULL; PFNGLVERTEX4DPROC glad_glVertex4d = NULL; PFNGLVERTEX4DVPROC glad_glVertex4dv = NULL; PFNGLVERTEX4FPROC glad_glVertex4f = NULL; PFNGLVERTEX4FVPROC glad_glVertex4fv = NULL; PFNGLVERTEX4IPROC glad_glVertex4i = NULL; PFNGLVERTEX4IVPROC glad_glVertex4iv = NULL; PFNGLVERTEX4SPROC glad_glVertex4s = NULL; PFNGLVERTEX4SVPROC glad_glVertex4sv = NULL; PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d = NULL; PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv = NULL; PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f = NULL; PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv = NULL; PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s = NULL; PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv = NULL; PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d = NULL; PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv = NULL; PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f = NULL; PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv = NULL; PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s = NULL; PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv = NULL; PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d = NULL; PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv = NULL; PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f = NULL; PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv = NULL; PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s = NULL; PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv = NULL; PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv = NULL; PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv = NULL; PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv = NULL; PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub = NULL; PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv = NULL; PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv = NULL; PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv = NULL; PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv = NULL; PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d = NULL; PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv = NULL; PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f = NULL; PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv = NULL; PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv = NULL; PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s = NULL; PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv = NULL; PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv = NULL; PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv = NULL; PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv = NULL; PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i = NULL; PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv = NULL; PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui = NULL; PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv = NULL; PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i = NULL; PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv = NULL; PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui = NULL; PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv = NULL; PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i = NULL; PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv = NULL; PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui = NULL; PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv = NULL; PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv = NULL; PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i = NULL; PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv = NULL; PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv = NULL; PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv = NULL; PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui = NULL; PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv = NULL; PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv = NULL; PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer = NULL; PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL; PFNGLVERTEXPOINTERPROC glad_glVertexPointer = NULL; PFNGLVIEWPORTPROC glad_glViewport = NULL; PFNGLWINDOWPOS2DPROC glad_glWindowPos2d = NULL; PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv = NULL; PFNGLWINDOWPOS2FPROC glad_glWindowPos2f = NULL; PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv = NULL; PFNGLWINDOWPOS2IPROC glad_glWindowPos2i = NULL; PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv = NULL; PFNGLWINDOWPOS2SPROC glad_glWindowPos2s = NULL; PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv = NULL; PFNGLWINDOWPOS3DPROC glad_glWindowPos3d = NULL; PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv = NULL; PFNGLWINDOWPOS3FPROC glad_glWindowPos3f = NULL; PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv = NULL; PFNGLWINDOWPOS3IPROC glad_glWindowPos3i = NULL; PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv = NULL; PFNGLWINDOWPOS3SPROC glad_glWindowPos3s = NULL; PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv = NULL; static void glad_gl_load_GL_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_1_0) return; glad_glAccum = (PFNGLACCUMPROC) load(userptr, "glAccum"); glad_glAlphaFunc = (PFNGLALPHAFUNCPROC) load(userptr, "glAlphaFunc"); glad_glBegin = (PFNGLBEGINPROC) load(userptr, "glBegin"); glad_glBitmap = (PFNGLBITMAPPROC) load(userptr, "glBitmap"); glad_glBlendFunc = (PFNGLBLENDFUNCPROC) load(userptr, "glBlendFunc"); glad_glCallList = (PFNGLCALLLISTPROC) load(userptr, "glCallList"); glad_glCallLists = (PFNGLCALLLISTSPROC) load(userptr, "glCallLists"); glad_glClear = (PFNGLCLEARPROC) load(userptr, "glClear"); glad_glClearAccum = (PFNGLCLEARACCUMPROC) load(userptr, "glClearAccum"); glad_glClearColor = (PFNGLCLEARCOLORPROC) load(userptr, "glClearColor"); glad_glClearDepth = (PFNGLCLEARDEPTHPROC) load(userptr, "glClearDepth"); glad_glClearIndex = (PFNGLCLEARINDEXPROC) load(userptr, "glClearIndex"); glad_glClearStencil = (PFNGLCLEARSTENCILPROC) load(userptr, "glClearStencil"); glad_glClipPlane = (PFNGLCLIPPLANEPROC) load(userptr, "glClipPlane"); glad_glColor3b = (PFNGLCOLOR3BPROC) load(userptr, "glColor3b"); glad_glColor3bv = (PFNGLCOLOR3BVPROC) load(userptr, "glColor3bv"); glad_glColor3d = (PFNGLCOLOR3DPROC) load(userptr, "glColor3d"); glad_glColor3dv = (PFNGLCOLOR3DVPROC) load(userptr, "glColor3dv"); glad_glColor3f = (PFNGLCOLOR3FPROC) load(userptr, "glColor3f"); glad_glColor3fv = (PFNGLCOLOR3FVPROC) load(userptr, "glColor3fv"); glad_glColor3i = (PFNGLCOLOR3IPROC) load(userptr, "glColor3i"); glad_glColor3iv = (PFNGLCOLOR3IVPROC) load(userptr, "glColor3iv"); glad_glColor3s = (PFNGLCOLOR3SPROC) load(userptr, "glColor3s"); glad_glColor3sv = (PFNGLCOLOR3SVPROC) load(userptr, "glColor3sv"); glad_glColor3ub = (PFNGLCOLOR3UBPROC) load(userptr, "glColor3ub"); glad_glColor3ubv = (PFNGLCOLOR3UBVPROC) load(userptr, "glColor3ubv"); glad_glColor3ui = (PFNGLCOLOR3UIPROC) load(userptr, "glColor3ui"); glad_glColor3uiv = (PFNGLCOLOR3UIVPROC) load(userptr, "glColor3uiv"); glad_glColor3us = (PFNGLCOLOR3USPROC) load(userptr, "glColor3us"); glad_glColor3usv = (PFNGLCOLOR3USVPROC) load(userptr, "glColor3usv"); glad_glColor4b = (PFNGLCOLOR4BPROC) load(userptr, "glColor4b"); glad_glColor4bv = (PFNGLCOLOR4BVPROC) load(userptr, "glColor4bv"); glad_glColor4d = (PFNGLCOLOR4DPROC) load(userptr, "glColor4d"); glad_glColor4dv = (PFNGLCOLOR4DVPROC) load(userptr, "glColor4dv"); glad_glColor4f = (PFNGLCOLOR4FPROC) load(userptr, "glColor4f"); glad_glColor4fv = (PFNGLCOLOR4FVPROC) load(userptr, "glColor4fv"); glad_glColor4i = (PFNGLCOLOR4IPROC) load(userptr, "glColor4i"); glad_glColor4iv = (PFNGLCOLOR4IVPROC) load(userptr, "glColor4iv"); glad_glColor4s = (PFNGLCOLOR4SPROC) load(userptr, "glColor4s"); glad_glColor4sv = (PFNGLCOLOR4SVPROC) load(userptr, "glColor4sv"); glad_glColor4ub = (PFNGLCOLOR4UBPROC) load(userptr, "glColor4ub"); glad_glColor4ubv = (PFNGLCOLOR4UBVPROC) load(userptr, "glColor4ubv"); glad_glColor4ui = (PFNGLCOLOR4UIPROC) load(userptr, "glColor4ui"); glad_glColor4uiv = (PFNGLCOLOR4UIVPROC) load(userptr, "glColor4uiv"); glad_glColor4us = (PFNGLCOLOR4USPROC) load(userptr, "glColor4us"); glad_glColor4usv = (PFNGLCOLOR4USVPROC) load(userptr, "glColor4usv"); glad_glColorMask = (PFNGLCOLORMASKPROC) load(userptr, "glColorMask"); glad_glColorMaterial = (PFNGLCOLORMATERIALPROC) load(userptr, "glColorMaterial"); glad_glCopyPixels = (PFNGLCOPYPIXELSPROC) load(userptr, "glCopyPixels"); glad_glCullFace = (PFNGLCULLFACEPROC) load(userptr, "glCullFace"); glad_glDeleteLists = (PFNGLDELETELISTSPROC) load(userptr, "glDeleteLists"); glad_glDepthFunc = (PFNGLDEPTHFUNCPROC) load(userptr, "glDepthFunc"); glad_glDepthMask = (PFNGLDEPTHMASKPROC) load(userptr, "glDepthMask"); glad_glDepthRange = (PFNGLDEPTHRANGEPROC) load(userptr, "glDepthRange"); glad_glDisable = (PFNGLDISABLEPROC) load(userptr, "glDisable"); glad_glDrawBuffer = (PFNGLDRAWBUFFERPROC) load(userptr, "glDrawBuffer"); glad_glDrawPixels = (PFNGLDRAWPIXELSPROC) load(userptr, "glDrawPixels"); glad_glEdgeFlag = (PFNGLEDGEFLAGPROC) load(userptr, "glEdgeFlag"); glad_glEdgeFlagv = (PFNGLEDGEFLAGVPROC) load(userptr, "glEdgeFlagv"); glad_glEnable = (PFNGLENABLEPROC) load(userptr, "glEnable"); glad_glEnd = (PFNGLENDPROC) load(userptr, "glEnd"); glad_glEndList = (PFNGLENDLISTPROC) load(userptr, "glEndList"); glad_glEvalCoord1d = (PFNGLEVALCOORD1DPROC) load(userptr, "glEvalCoord1d"); glad_glEvalCoord1dv = (PFNGLEVALCOORD1DVPROC) load(userptr, "glEvalCoord1dv"); glad_glEvalCoord1f = (PFNGLEVALCOORD1FPROC) load(userptr, "glEvalCoord1f"); glad_glEvalCoord1fv = (PFNGLEVALCOORD1FVPROC) load(userptr, "glEvalCoord1fv"); glad_glEvalCoord2d = (PFNGLEVALCOORD2DPROC) load(userptr, "glEvalCoord2d"); glad_glEvalCoord2dv = (PFNGLEVALCOORD2DVPROC) load(userptr, "glEvalCoord2dv"); glad_glEvalCoord2f = (PFNGLEVALCOORD2FPROC) load(userptr, "glEvalCoord2f"); glad_glEvalCoord2fv = (PFNGLEVALCOORD2FVPROC) load(userptr, "glEvalCoord2fv"); glad_glEvalMesh1 = (PFNGLEVALMESH1PROC) load(userptr, "glEvalMesh1"); glad_glEvalMesh2 = (PFNGLEVALMESH2PROC) load(userptr, "glEvalMesh2"); glad_glEvalPoint1 = (PFNGLEVALPOINT1PROC) load(userptr, "glEvalPoint1"); glad_glEvalPoint2 = (PFNGLEVALPOINT2PROC) load(userptr, "glEvalPoint2"); glad_glFeedbackBuffer = (PFNGLFEEDBACKBUFFERPROC) load(userptr, "glFeedbackBuffer"); glad_glFinish = (PFNGLFINISHPROC) load(userptr, "glFinish"); glad_glFlush = (PFNGLFLUSHPROC) load(userptr, "glFlush"); glad_glFogf = (PFNGLFOGFPROC) load(userptr, "glFogf"); glad_glFogfv = (PFNGLFOGFVPROC) load(userptr, "glFogfv"); glad_glFogi = (PFNGLFOGIPROC) load(userptr, "glFogi"); glad_glFogiv = (PFNGLFOGIVPROC) load(userptr, "glFogiv"); glad_glFrontFace = (PFNGLFRONTFACEPROC) load(userptr, "glFrontFace"); glad_glFrustum = (PFNGLFRUSTUMPROC) load(userptr, "glFrustum"); glad_glGenLists = (PFNGLGENLISTSPROC) load(userptr, "glGenLists"); glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC) load(userptr, "glGetBooleanv"); glad_glGetClipPlane = (PFNGLGETCLIPPLANEPROC) load(userptr, "glGetClipPlane"); glad_glGetDoublev = (PFNGLGETDOUBLEVPROC) load(userptr, "glGetDoublev"); glad_glGetError = (PFNGLGETERRORPROC) load(userptr, "glGetError"); glad_glGetFloatv = (PFNGLGETFLOATVPROC) load(userptr, "glGetFloatv"); glad_glGetIntegerv = (PFNGLGETINTEGERVPROC) load(userptr, "glGetIntegerv"); glad_glGetLightfv = (PFNGLGETLIGHTFVPROC) load(userptr, "glGetLightfv"); glad_glGetLightiv = (PFNGLGETLIGHTIVPROC) load(userptr, "glGetLightiv"); glad_glGetMapdv = (PFNGLGETMAPDVPROC) load(userptr, "glGetMapdv"); glad_glGetMapfv = (PFNGLGETMAPFVPROC) load(userptr, "glGetMapfv"); glad_glGetMapiv = (PFNGLGETMAPIVPROC) load(userptr, "glGetMapiv"); glad_glGetMaterialfv = (PFNGLGETMATERIALFVPROC) load(userptr, "glGetMaterialfv"); glad_glGetMaterialiv = (PFNGLGETMATERIALIVPROC) load(userptr, "glGetMaterialiv"); glad_glGetPixelMapfv = (PFNGLGETPIXELMAPFVPROC) load(userptr, "glGetPixelMapfv"); glad_glGetPixelMapuiv = (PFNGLGETPIXELMAPUIVPROC) load(userptr, "glGetPixelMapuiv"); glad_glGetPixelMapusv = (PFNGLGETPIXELMAPUSVPROC) load(userptr, "glGetPixelMapusv"); glad_glGetPolygonStipple = (PFNGLGETPOLYGONSTIPPLEPROC) load(userptr, "glGetPolygonStipple"); glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString"); glad_glGetTexEnvfv = (PFNGLGETTEXENVFVPROC) load(userptr, "glGetTexEnvfv"); glad_glGetTexEnviv = (PFNGLGETTEXENVIVPROC) load(userptr, "glGetTexEnviv"); glad_glGetTexGendv = (PFNGLGETTEXGENDVPROC) load(userptr, "glGetTexGendv"); glad_glGetTexGenfv = (PFNGLGETTEXGENFVPROC) load(userptr, "glGetTexGenfv"); glad_glGetTexGeniv = (PFNGLGETTEXGENIVPROC) load(userptr, "glGetTexGeniv"); glad_glGetTexImage = (PFNGLGETTEXIMAGEPROC) load(userptr, "glGetTexImage"); glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC) load(userptr, "glGetTexLevelParameterfv"); glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC) load(userptr, "glGetTexLevelParameteriv"); glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC) load(userptr, "glGetTexParameterfv"); glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC) load(userptr, "glGetTexParameteriv"); glad_glHint = (PFNGLHINTPROC) load(userptr, "glHint"); glad_glIndexMask = (PFNGLINDEXMASKPROC) load(userptr, "glIndexMask"); glad_glIndexd = (PFNGLINDEXDPROC) load(userptr, "glIndexd"); glad_glIndexdv = (PFNGLINDEXDVPROC) load(userptr, "glIndexdv"); glad_glIndexf = (PFNGLINDEXFPROC) load(userptr, "glIndexf"); glad_glIndexfv = (PFNGLINDEXFVPROC) load(userptr, "glIndexfv"); glad_glIndexi = (PFNGLINDEXIPROC) load(userptr, "glIndexi"); glad_glIndexiv = (PFNGLINDEXIVPROC) load(userptr, "glIndexiv"); glad_glIndexs = (PFNGLINDEXSPROC) load(userptr, "glIndexs"); glad_glIndexsv = (PFNGLINDEXSVPROC) load(userptr, "glIndexsv"); glad_glInitNames = (PFNGLINITNAMESPROC) load(userptr, "glInitNames"); glad_glIsEnabled = (PFNGLISENABLEDPROC) load(userptr, "glIsEnabled"); glad_glIsList = (PFNGLISLISTPROC) load(userptr, "glIsList"); glad_glLightModelf = (PFNGLLIGHTMODELFPROC) load(userptr, "glLightModelf"); glad_glLightModelfv = (PFNGLLIGHTMODELFVPROC) load(userptr, "glLightModelfv"); glad_glLightModeli = (PFNGLLIGHTMODELIPROC) load(userptr, "glLightModeli"); glad_glLightModeliv = (PFNGLLIGHTMODELIVPROC) load(userptr, "glLightModeliv"); glad_glLightf = (PFNGLLIGHTFPROC) load(userptr, "glLightf"); glad_glLightfv = (PFNGLLIGHTFVPROC) load(userptr, "glLightfv"); glad_glLighti = (PFNGLLIGHTIPROC) load(userptr, "glLighti"); glad_glLightiv = (PFNGLLIGHTIVPROC) load(userptr, "glLightiv"); glad_glLineStipple = (PFNGLLINESTIPPLEPROC) load(userptr, "glLineStipple"); glad_glLineWidth = (PFNGLLINEWIDTHPROC) load(userptr, "glLineWidth"); glad_glListBase = (PFNGLLISTBASEPROC) load(userptr, "glListBase"); glad_glLoadIdentity = (PFNGLLOADIDENTITYPROC) load(userptr, "glLoadIdentity"); glad_glLoadMatrixd = (PFNGLLOADMATRIXDPROC) load(userptr, "glLoadMatrixd"); glad_glLoadMatrixf = (PFNGLLOADMATRIXFPROC) load(userptr, "glLoadMatrixf"); glad_glLoadName = (PFNGLLOADNAMEPROC) load(userptr, "glLoadName"); glad_glLogicOp = (PFNGLLOGICOPPROC) load(userptr, "glLogicOp"); glad_glMap1d = (PFNGLMAP1DPROC) load(userptr, "glMap1d"); glad_glMap1f = (PFNGLMAP1FPROC) load(userptr, "glMap1f"); glad_glMap2d = (PFNGLMAP2DPROC) load(userptr, "glMap2d"); glad_glMap2f = (PFNGLMAP2FPROC) load(userptr, "glMap2f"); glad_glMapGrid1d = (PFNGLMAPGRID1DPROC) load(userptr, "glMapGrid1d"); glad_glMapGrid1f = (PFNGLMAPGRID1FPROC) load(userptr, "glMapGrid1f"); glad_glMapGrid2d = (PFNGLMAPGRID2DPROC) load(userptr, "glMapGrid2d"); glad_glMapGrid2f = (PFNGLMAPGRID2FPROC) load(userptr, "glMapGrid2f"); glad_glMaterialf = (PFNGLMATERIALFPROC) load(userptr, "glMaterialf"); glad_glMaterialfv = (PFNGLMATERIALFVPROC) load(userptr, "glMaterialfv"); glad_glMateriali = (PFNGLMATERIALIPROC) load(userptr, "glMateriali"); glad_glMaterialiv = (PFNGLMATERIALIVPROC) load(userptr, "glMaterialiv"); glad_glMatrixMode = (PFNGLMATRIXMODEPROC) load(userptr, "glMatrixMode"); glad_glMultMatrixd = (PFNGLMULTMATRIXDPROC) load(userptr, "glMultMatrixd"); glad_glMultMatrixf = (PFNGLMULTMATRIXFPROC) load(userptr, "glMultMatrixf"); glad_glNewList = (PFNGLNEWLISTPROC) load(userptr, "glNewList"); glad_glNormal3b = (PFNGLNORMAL3BPROC) load(userptr, "glNormal3b"); glad_glNormal3bv = (PFNGLNORMAL3BVPROC) load(userptr, "glNormal3bv"); glad_glNormal3d = (PFNGLNORMAL3DPROC) load(userptr, "glNormal3d"); glad_glNormal3dv = (PFNGLNORMAL3DVPROC) load(userptr, "glNormal3dv"); glad_glNormal3f = (PFNGLNORMAL3FPROC) load(userptr, "glNormal3f"); glad_glNormal3fv = (PFNGLNORMAL3FVPROC) load(userptr, "glNormal3fv"); glad_glNormal3i = (PFNGLNORMAL3IPROC) load(userptr, "glNormal3i"); glad_glNormal3iv = (PFNGLNORMAL3IVPROC) load(userptr, "glNormal3iv"); glad_glNormal3s = (PFNGLNORMAL3SPROC) load(userptr, "glNormal3s"); glad_glNormal3sv = (PFNGLNORMAL3SVPROC) load(userptr, "glNormal3sv"); glad_glOrtho = (PFNGLORTHOPROC) load(userptr, "glOrtho"); glad_glPassThrough = (PFNGLPASSTHROUGHPROC) load(userptr, "glPassThrough"); glad_glPixelMapfv = (PFNGLPIXELMAPFVPROC) load(userptr, "glPixelMapfv"); glad_glPixelMapuiv = (PFNGLPIXELMAPUIVPROC) load(userptr, "glPixelMapuiv"); glad_glPixelMapusv = (PFNGLPIXELMAPUSVPROC) load(userptr, "glPixelMapusv"); glad_glPixelStoref = (PFNGLPIXELSTOREFPROC) load(userptr, "glPixelStoref"); glad_glPixelStorei = (PFNGLPIXELSTOREIPROC) load(userptr, "glPixelStorei"); glad_glPixelTransferf = (PFNGLPIXELTRANSFERFPROC) load(userptr, "glPixelTransferf"); glad_glPixelTransferi = (PFNGLPIXELTRANSFERIPROC) load(userptr, "glPixelTransferi"); glad_glPixelZoom = (PFNGLPIXELZOOMPROC) load(userptr, "glPixelZoom"); glad_glPointSize = (PFNGLPOINTSIZEPROC) load(userptr, "glPointSize"); glad_glPolygonMode = (PFNGLPOLYGONMODEPROC) load(userptr, "glPolygonMode"); glad_glPolygonStipple = (PFNGLPOLYGONSTIPPLEPROC) load(userptr, "glPolygonStipple"); glad_glPopAttrib = (PFNGLPOPATTRIBPROC) load(userptr, "glPopAttrib"); glad_glPopMatrix = (PFNGLPOPMATRIXPROC) load(userptr, "glPopMatrix"); glad_glPopName = (PFNGLPOPNAMEPROC) load(userptr, "glPopName"); glad_glPushAttrib = (PFNGLPUSHATTRIBPROC) load(userptr, "glPushAttrib"); glad_glPushMatrix = (PFNGLPUSHMATRIXPROC) load(userptr, "glPushMatrix"); glad_glPushName = (PFNGLPUSHNAMEPROC) load(userptr, "glPushName"); glad_glRasterPos2d = (PFNGLRASTERPOS2DPROC) load(userptr, "glRasterPos2d"); glad_glRasterPos2dv = (PFNGLRASTERPOS2DVPROC) load(userptr, "glRasterPos2dv"); glad_glRasterPos2f = (PFNGLRASTERPOS2FPROC) load(userptr, "glRasterPos2f"); glad_glRasterPos2fv = (PFNGLRASTERPOS2FVPROC) load(userptr, "glRasterPos2fv"); glad_glRasterPos2i = (PFNGLRASTERPOS2IPROC) load(userptr, "glRasterPos2i"); glad_glRasterPos2iv = (PFNGLRASTERPOS2IVPROC) load(userptr, "glRasterPos2iv"); glad_glRasterPos2s = (PFNGLRASTERPOS2SPROC) load(userptr, "glRasterPos2s"); glad_glRasterPos2sv = (PFNGLRASTERPOS2SVPROC) load(userptr, "glRasterPos2sv"); glad_glRasterPos3d = (PFNGLRASTERPOS3DPROC) load(userptr, "glRasterPos3d"); glad_glRasterPos3dv = (PFNGLRASTERPOS3DVPROC) load(userptr, "glRasterPos3dv"); glad_glRasterPos3f = (PFNGLRASTERPOS3FPROC) load(userptr, "glRasterPos3f"); glad_glRasterPos3fv = (PFNGLRASTERPOS3FVPROC) load(userptr, "glRasterPos3fv"); glad_glRasterPos3i = (PFNGLRASTERPOS3IPROC) load(userptr, "glRasterPos3i"); glad_glRasterPos3iv = (PFNGLRASTERPOS3IVPROC) load(userptr, "glRasterPos3iv"); glad_glRasterPos3s = (PFNGLRASTERPOS3SPROC) load(userptr, "glRasterPos3s"); glad_glRasterPos3sv = (PFNGLRASTERPOS3SVPROC) load(userptr, "glRasterPos3sv"); glad_glRasterPos4d = (PFNGLRASTERPOS4DPROC) load(userptr, "glRasterPos4d"); glad_glRasterPos4dv = (PFNGLRASTERPOS4DVPROC) load(userptr, "glRasterPos4dv"); glad_glRasterPos4f = (PFNGLRASTERPOS4FPROC) load(userptr, "glRasterPos4f"); glad_glRasterPos4fv = (PFNGLRASTERPOS4FVPROC) load(userptr, "glRasterPos4fv"); glad_glRasterPos4i = (PFNGLRASTERPOS4IPROC) load(userptr, "glRasterPos4i"); glad_glRasterPos4iv = (PFNGLRASTERPOS4IVPROC) load(userptr, "glRasterPos4iv"); glad_glRasterPos4s = (PFNGLRASTERPOS4SPROC) load(userptr, "glRasterPos4s"); glad_glRasterPos4sv = (PFNGLRASTERPOS4SVPROC) load(userptr, "glRasterPos4sv"); glad_glReadBuffer = (PFNGLREADBUFFERPROC) load(userptr, "glReadBuffer"); glad_glReadPixels = (PFNGLREADPIXELSPROC) load(userptr, "glReadPixels"); glad_glRectd = (PFNGLRECTDPROC) load(userptr, "glRectd"); glad_glRectdv = (PFNGLRECTDVPROC) load(userptr, "glRectdv"); glad_glRectf = (PFNGLRECTFPROC) load(userptr, "glRectf"); glad_glRectfv = (PFNGLRECTFVPROC) load(userptr, "glRectfv"); glad_glRecti = (PFNGLRECTIPROC) load(userptr, "glRecti"); glad_glRectiv = (PFNGLRECTIVPROC) load(userptr, "glRectiv"); glad_glRects = (PFNGLRECTSPROC) load(userptr, "glRects"); glad_glRectsv = (PFNGLRECTSVPROC) load(userptr, "glRectsv"); glad_glRenderMode = (PFNGLRENDERMODEPROC) load(userptr, "glRenderMode"); glad_glRotated = (PFNGLROTATEDPROC) load(userptr, "glRotated"); glad_glRotatef = (PFNGLROTATEFPROC) load(userptr, "glRotatef"); glad_glScaled = (PFNGLSCALEDPROC) load(userptr, "glScaled"); glad_glScalef = (PFNGLSCALEFPROC) load(userptr, "glScalef"); glad_glScissor = (PFNGLSCISSORPROC) load(userptr, "glScissor"); glad_glSelectBuffer = (PFNGLSELECTBUFFERPROC) load(userptr, "glSelectBuffer"); glad_glShadeModel = (PFNGLSHADEMODELPROC) load(userptr, "glShadeModel"); glad_glStencilFunc = (PFNGLSTENCILFUNCPROC) load(userptr, "glStencilFunc"); glad_glStencilMask = (PFNGLSTENCILMASKPROC) load(userptr, "glStencilMask"); glad_glStencilOp = (PFNGLSTENCILOPPROC) load(userptr, "glStencilOp"); glad_glTexCoord1d = (PFNGLTEXCOORD1DPROC) load(userptr, "glTexCoord1d"); glad_glTexCoord1dv = (PFNGLTEXCOORD1DVPROC) load(userptr, "glTexCoord1dv"); glad_glTexCoord1f = (PFNGLTEXCOORD1FPROC) load(userptr, "glTexCoord1f"); glad_glTexCoord1fv = (PFNGLTEXCOORD1FVPROC) load(userptr, "glTexCoord1fv"); glad_glTexCoord1i = (PFNGLTEXCOORD1IPROC) load(userptr, "glTexCoord1i"); glad_glTexCoord1iv = (PFNGLTEXCOORD1IVPROC) load(userptr, "glTexCoord1iv"); glad_glTexCoord1s = (PFNGLTEXCOORD1SPROC) load(userptr, "glTexCoord1s"); glad_glTexCoord1sv = (PFNGLTEXCOORD1SVPROC) load(userptr, "glTexCoord1sv"); glad_glTexCoord2d = (PFNGLTEXCOORD2DPROC) load(userptr, "glTexCoord2d"); glad_glTexCoord2dv = (PFNGLTEXCOORD2DVPROC) load(userptr, "glTexCoord2dv"); glad_glTexCoord2f = (PFNGLTEXCOORD2FPROC) load(userptr, "glTexCoord2f"); glad_glTexCoord2fv = (PFNGLTEXCOORD2FVPROC) load(userptr, "glTexCoord2fv"); glad_glTexCoord2i = (PFNGLTEXCOORD2IPROC) load(userptr, "glTexCoord2i"); glad_glTexCoord2iv = (PFNGLTEXCOORD2IVPROC) load(userptr, "glTexCoord2iv"); glad_glTexCoord2s = (PFNGLTEXCOORD2SPROC) load(userptr, "glTexCoord2s"); glad_glTexCoord2sv = (PFNGLTEXCOORD2SVPROC) load(userptr, "glTexCoord2sv"); glad_glTexCoord3d = (PFNGLTEXCOORD3DPROC) load(userptr, "glTexCoord3d"); glad_glTexCoord3dv = (PFNGLTEXCOORD3DVPROC) load(userptr, "glTexCoord3dv"); glad_glTexCoord3f = (PFNGLTEXCOORD3FPROC) load(userptr, "glTexCoord3f"); glad_glTexCoord3fv = (PFNGLTEXCOORD3FVPROC) load(userptr, "glTexCoord3fv"); glad_glTexCoord3i = (PFNGLTEXCOORD3IPROC) load(userptr, "glTexCoord3i"); glad_glTexCoord3iv = (PFNGLTEXCOORD3IVPROC) load(userptr, "glTexCoord3iv"); glad_glTexCoord3s = (PFNGLTEXCOORD3SPROC) load(userptr, "glTexCoord3s"); glad_glTexCoord3sv = (PFNGLTEXCOORD3SVPROC) load(userptr, "glTexCoord3sv"); glad_glTexCoord4d = (PFNGLTEXCOORD4DPROC) load(userptr, "glTexCoord4d"); glad_glTexCoord4dv = (PFNGLTEXCOORD4DVPROC) load(userptr, "glTexCoord4dv"); glad_glTexCoord4f = (PFNGLTEXCOORD4FPROC) load(userptr, "glTexCoord4f"); glad_glTexCoord4fv = (PFNGLTEXCOORD4FVPROC) load(userptr, "glTexCoord4fv"); glad_glTexCoord4i = (PFNGLTEXCOORD4IPROC) load(userptr, "glTexCoord4i"); glad_glTexCoord4iv = (PFNGLTEXCOORD4IVPROC) load(userptr, "glTexCoord4iv"); glad_glTexCoord4s = (PFNGLTEXCOORD4SPROC) load(userptr, "glTexCoord4s"); glad_glTexCoord4sv = (PFNGLTEXCOORD4SVPROC) load(userptr, "glTexCoord4sv"); glad_glTexEnvf = (PFNGLTEXENVFPROC) load(userptr, "glTexEnvf"); glad_glTexEnvfv = (PFNGLTEXENVFVPROC) load(userptr, "glTexEnvfv"); glad_glTexEnvi = (PFNGLTEXENVIPROC) load(userptr, "glTexEnvi"); glad_glTexEnviv = (PFNGLTEXENVIVPROC) load(userptr, "glTexEnviv"); glad_glTexGend = (PFNGLTEXGENDPROC) load(userptr, "glTexGend"); glad_glTexGendv = (PFNGLTEXGENDVPROC) load(userptr, "glTexGendv"); glad_glTexGenf = (PFNGLTEXGENFPROC) load(userptr, "glTexGenf"); glad_glTexGenfv = (PFNGLTEXGENFVPROC) load(userptr, "glTexGenfv"); glad_glTexGeni = (PFNGLTEXGENIPROC) load(userptr, "glTexGeni"); glad_glTexGeniv = (PFNGLTEXGENIVPROC) load(userptr, "glTexGeniv"); glad_glTexImage1D = (PFNGLTEXIMAGE1DPROC) load(userptr, "glTexImage1D"); glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC) load(userptr, "glTexImage2D"); glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC) load(userptr, "glTexParameterf"); glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC) load(userptr, "glTexParameterfv"); glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC) load(userptr, "glTexParameteri"); glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC) load(userptr, "glTexParameteriv"); glad_glTranslated = (PFNGLTRANSLATEDPROC) load(userptr, "glTranslated"); glad_glTranslatef = (PFNGLTRANSLATEFPROC) load(userptr, "glTranslatef"); glad_glVertex2d = (PFNGLVERTEX2DPROC) load(userptr, "glVertex2d"); glad_glVertex2dv = (PFNGLVERTEX2DVPROC) load(userptr, "glVertex2dv"); glad_glVertex2f = (PFNGLVERTEX2FPROC) load(userptr, "glVertex2f"); glad_glVertex2fv = (PFNGLVERTEX2FVPROC) load(userptr, "glVertex2fv"); glad_glVertex2i = (PFNGLVERTEX2IPROC) load(userptr, "glVertex2i"); glad_glVertex2iv = (PFNGLVERTEX2IVPROC) load(userptr, "glVertex2iv"); glad_glVertex2s = (PFNGLVERTEX2SPROC) load(userptr, "glVertex2s"); glad_glVertex2sv = (PFNGLVERTEX2SVPROC) load(userptr, "glVertex2sv"); glad_glVertex3d = (PFNGLVERTEX3DPROC) load(userptr, "glVertex3d"); glad_glVertex3dv = (PFNGLVERTEX3DVPROC) load(userptr, "glVertex3dv"); glad_glVertex3f = (PFNGLVERTEX3FPROC) load(userptr, "glVertex3f"); glad_glVertex3fv = (PFNGLVERTEX3FVPROC) load(userptr, "glVertex3fv"); glad_glVertex3i = (PFNGLVERTEX3IPROC) load(userptr, "glVertex3i"); glad_glVertex3iv = (PFNGLVERTEX3IVPROC) load(userptr, "glVertex3iv"); glad_glVertex3s = (PFNGLVERTEX3SPROC) load(userptr, "glVertex3s"); glad_glVertex3sv = (PFNGLVERTEX3SVPROC) load(userptr, "glVertex3sv"); glad_glVertex4d = (PFNGLVERTEX4DPROC) load(userptr, "glVertex4d"); glad_glVertex4dv = (PFNGLVERTEX4DVPROC) load(userptr, "glVertex4dv"); glad_glVertex4f = (PFNGLVERTEX4FPROC) load(userptr, "glVertex4f"); glad_glVertex4fv = (PFNGLVERTEX4FVPROC) load(userptr, "glVertex4fv"); glad_glVertex4i = (PFNGLVERTEX4IPROC) load(userptr, "glVertex4i"); glad_glVertex4iv = (PFNGLVERTEX4IVPROC) load(userptr, "glVertex4iv"); glad_glVertex4s = (PFNGLVERTEX4SPROC) load(userptr, "glVertex4s"); glad_glVertex4sv = (PFNGLVERTEX4SVPROC) load(userptr, "glVertex4sv"); glad_glViewport = (PFNGLVIEWPORTPROC) load(userptr, "glViewport"); } static void glad_gl_load_GL_VERSION_1_1( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_1_1) return; glad_glAreTexturesResident = (PFNGLARETEXTURESRESIDENTPROC) load(userptr, "glAreTexturesResident"); glad_glArrayElement = (PFNGLARRAYELEMENTPROC) load(userptr, "glArrayElement"); glad_glBindTexture = (PFNGLBINDTEXTUREPROC) load(userptr, "glBindTexture"); glad_glColorPointer = (PFNGLCOLORPOINTERPROC) load(userptr, "glColorPointer"); glad_glCopyTexImage1D = (PFNGLCOPYTEXIMAGE1DPROC) load(userptr, "glCopyTexImage1D"); glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC) load(userptr, "glCopyTexImage2D"); glad_glCopyTexSubImage1D = (PFNGLCOPYTEXSUBIMAGE1DPROC) load(userptr, "glCopyTexSubImage1D"); glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC) load(userptr, "glCopyTexSubImage2D"); glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC) load(userptr, "glDeleteTextures"); glad_glDisableClientState = (PFNGLDISABLECLIENTSTATEPROC) load(userptr, "glDisableClientState"); glad_glDrawArrays = (PFNGLDRAWARRAYSPROC) load(userptr, "glDrawArrays"); glad_glDrawElements = (PFNGLDRAWELEMENTSPROC) load(userptr, "glDrawElements"); glad_glEdgeFlagPointer = (PFNGLEDGEFLAGPOINTERPROC) load(userptr, "glEdgeFlagPointer"); glad_glEnableClientState = (PFNGLENABLECLIENTSTATEPROC) load(userptr, "glEnableClientState"); glad_glGenTextures = (PFNGLGENTEXTURESPROC) load(userptr, "glGenTextures"); glad_glGetPointerv = (PFNGLGETPOINTERVPROC) load(userptr, "glGetPointerv"); glad_glIndexPointer = (PFNGLINDEXPOINTERPROC) load(userptr, "glIndexPointer"); glad_glIndexub = (PFNGLINDEXUBPROC) load(userptr, "glIndexub"); glad_glIndexubv = (PFNGLINDEXUBVPROC) load(userptr, "glIndexubv"); glad_glInterleavedArrays = (PFNGLINTERLEAVEDARRAYSPROC) load(userptr, "glInterleavedArrays"); glad_glIsTexture = (PFNGLISTEXTUREPROC) load(userptr, "glIsTexture"); glad_glNormalPointer = (PFNGLNORMALPOINTERPROC) load(userptr, "glNormalPointer"); glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC) load(userptr, "glPolygonOffset"); glad_glPopClientAttrib = (PFNGLPOPCLIENTATTRIBPROC) load(userptr, "glPopClientAttrib"); glad_glPrioritizeTextures = (PFNGLPRIORITIZETEXTURESPROC) load(userptr, "glPrioritizeTextures"); glad_glPushClientAttrib = (PFNGLPUSHCLIENTATTRIBPROC) load(userptr, "glPushClientAttrib"); glad_glTexCoordPointer = (PFNGLTEXCOORDPOINTERPROC) load(userptr, "glTexCoordPointer"); glad_glTexSubImage1D = (PFNGLTEXSUBIMAGE1DPROC) load(userptr, "glTexSubImage1D"); glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC) load(userptr, "glTexSubImage2D"); glad_glVertexPointer = (PFNGLVERTEXPOINTERPROC) load(userptr, "glVertexPointer"); } static void glad_gl_load_GL_VERSION_1_2( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_1_2) return; glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC) load(userptr, "glCopyTexSubImage3D"); glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC) load(userptr, "glDrawRangeElements"); glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC) load(userptr, "glTexImage3D"); glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC) load(userptr, "glTexSubImage3D"); } static void glad_gl_load_GL_VERSION_1_3( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_1_3) return; glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC) load(userptr, "glActiveTexture"); glad_glClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC) load(userptr, "glClientActiveTexture"); glad_glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC) load(userptr, "glCompressedTexImage1D"); glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) load(userptr, "glCompressedTexImage2D"); glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC) load(userptr, "glCompressedTexImage3D"); glad_glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC) load(userptr, "glCompressedTexSubImage1D"); glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) load(userptr, "glCompressedTexSubImage2D"); glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) load(userptr, "glCompressedTexSubImage3D"); glad_glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC) load(userptr, "glGetCompressedTexImage"); glad_glLoadTransposeMatrixd = (PFNGLLOADTRANSPOSEMATRIXDPROC) load(userptr, "glLoadTransposeMatrixd"); glad_glLoadTransposeMatrixf = (PFNGLLOADTRANSPOSEMATRIXFPROC) load(userptr, "glLoadTransposeMatrixf"); glad_glMultTransposeMatrixd = (PFNGLMULTTRANSPOSEMATRIXDPROC) load(userptr, "glMultTransposeMatrixd"); glad_glMultTransposeMatrixf = (PFNGLMULTTRANSPOSEMATRIXFPROC) load(userptr, "glMultTransposeMatrixf"); glad_glMultiTexCoord1d = (PFNGLMULTITEXCOORD1DPROC) load(userptr, "glMultiTexCoord1d"); glad_glMultiTexCoord1dv = (PFNGLMULTITEXCOORD1DVPROC) load(userptr, "glMultiTexCoord1dv"); glad_glMultiTexCoord1f = (PFNGLMULTITEXCOORD1FPROC) load(userptr, "glMultiTexCoord1f"); glad_glMultiTexCoord1fv = (PFNGLMULTITEXCOORD1FVPROC) load(userptr, "glMultiTexCoord1fv"); glad_glMultiTexCoord1i = (PFNGLMULTITEXCOORD1IPROC) load(userptr, "glMultiTexCoord1i"); glad_glMultiTexCoord1iv = (PFNGLMULTITEXCOORD1IVPROC) load(userptr, "glMultiTexCoord1iv"); glad_glMultiTexCoord1s = (PFNGLMULTITEXCOORD1SPROC) load(userptr, "glMultiTexCoord1s"); glad_glMultiTexCoord1sv = (PFNGLMULTITEXCOORD1SVPROC) load(userptr, "glMultiTexCoord1sv"); glad_glMultiTexCoord2d = (PFNGLMULTITEXCOORD2DPROC) load(userptr, "glMultiTexCoord2d"); glad_glMultiTexCoord2dv = (PFNGLMULTITEXCOORD2DVPROC) load(userptr, "glMultiTexCoord2dv"); glad_glMultiTexCoord2f = (PFNGLMULTITEXCOORD2FPROC) load(userptr, "glMultiTexCoord2f"); glad_glMultiTexCoord2fv = (PFNGLMULTITEXCOORD2FVPROC) load(userptr, "glMultiTexCoord2fv"); glad_glMultiTexCoord2i = (PFNGLMULTITEXCOORD2IPROC) load(userptr, "glMultiTexCoord2i"); glad_glMultiTexCoord2iv = (PFNGLMULTITEXCOORD2IVPROC) load(userptr, "glMultiTexCoord2iv"); glad_glMultiTexCoord2s = (PFNGLMULTITEXCOORD2SPROC) load(userptr, "glMultiTexCoord2s"); glad_glMultiTexCoord2sv = (PFNGLMULTITEXCOORD2SVPROC) load(userptr, "glMultiTexCoord2sv"); glad_glMultiTexCoord3d = (PFNGLMULTITEXCOORD3DPROC) load(userptr, "glMultiTexCoord3d"); glad_glMultiTexCoord3dv = (PFNGLMULTITEXCOORD3DVPROC) load(userptr, "glMultiTexCoord3dv"); glad_glMultiTexCoord3f = (PFNGLMULTITEXCOORD3FPROC) load(userptr, "glMultiTexCoord3f"); glad_glMultiTexCoord3fv = (PFNGLMULTITEXCOORD3FVPROC) load(userptr, "glMultiTexCoord3fv"); glad_glMultiTexCoord3i = (PFNGLMULTITEXCOORD3IPROC) load(userptr, "glMultiTexCoord3i"); glad_glMultiTexCoord3iv = (PFNGLMULTITEXCOORD3IVPROC) load(userptr, "glMultiTexCoord3iv"); glad_glMultiTexCoord3s = (PFNGLMULTITEXCOORD3SPROC) load(userptr, "glMultiTexCoord3s"); glad_glMultiTexCoord3sv = (PFNGLMULTITEXCOORD3SVPROC) load(userptr, "glMultiTexCoord3sv"); glad_glMultiTexCoord4d = (PFNGLMULTITEXCOORD4DPROC) load(userptr, "glMultiTexCoord4d"); glad_glMultiTexCoord4dv = (PFNGLMULTITEXCOORD4DVPROC) load(userptr, "glMultiTexCoord4dv"); glad_glMultiTexCoord4f = (PFNGLMULTITEXCOORD4FPROC) load(userptr, "glMultiTexCoord4f"); glad_glMultiTexCoord4fv = (PFNGLMULTITEXCOORD4FVPROC) load(userptr, "glMultiTexCoord4fv"); glad_glMultiTexCoord4i = (PFNGLMULTITEXCOORD4IPROC) load(userptr, "glMultiTexCoord4i"); glad_glMultiTexCoord4iv = (PFNGLMULTITEXCOORD4IVPROC) load(userptr, "glMultiTexCoord4iv"); glad_glMultiTexCoord4s = (PFNGLMULTITEXCOORD4SPROC) load(userptr, "glMultiTexCoord4s"); glad_glMultiTexCoord4sv = (PFNGLMULTITEXCOORD4SVPROC) load(userptr, "glMultiTexCoord4sv"); glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC) load(userptr, "glSampleCoverage"); } static void glad_gl_load_GL_VERSION_1_4( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_1_4) return; glad_glBlendColor = (PFNGLBLENDCOLORPROC) load(userptr, "glBlendColor"); glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC) load(userptr, "glBlendEquation"); glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC) load(userptr, "glBlendFuncSeparate"); glad_glFogCoordPointer = (PFNGLFOGCOORDPOINTERPROC) load(userptr, "glFogCoordPointer"); glad_glFogCoordd = (PFNGLFOGCOORDDPROC) load(userptr, "glFogCoordd"); glad_glFogCoorddv = (PFNGLFOGCOORDDVPROC) load(userptr, "glFogCoorddv"); glad_glFogCoordf = (PFNGLFOGCOORDFPROC) load(userptr, "glFogCoordf"); glad_glFogCoordfv = (PFNGLFOGCOORDFVPROC) load(userptr, "glFogCoordfv"); glad_glMultiDrawArrays = (PFNGLMULTIDRAWARRAYSPROC) load(userptr, "glMultiDrawArrays"); glad_glMultiDrawElements = (PFNGLMULTIDRAWELEMENTSPROC) load(userptr, "glMultiDrawElements"); glad_glPointParameterf = (PFNGLPOINTPARAMETERFPROC) load(userptr, "glPointParameterf"); glad_glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC) load(userptr, "glPointParameterfv"); glad_glPointParameteri = (PFNGLPOINTPARAMETERIPROC) load(userptr, "glPointParameteri"); glad_glPointParameteriv = (PFNGLPOINTPARAMETERIVPROC) load(userptr, "glPointParameteriv"); glad_glSecondaryColor3b = (PFNGLSECONDARYCOLOR3BPROC) load(userptr, "glSecondaryColor3b"); glad_glSecondaryColor3bv = (PFNGLSECONDARYCOLOR3BVPROC) load(userptr, "glSecondaryColor3bv"); glad_glSecondaryColor3d = (PFNGLSECONDARYCOLOR3DPROC) load(userptr, "glSecondaryColor3d"); glad_glSecondaryColor3dv = (PFNGLSECONDARYCOLOR3DVPROC) load(userptr, "glSecondaryColor3dv"); glad_glSecondaryColor3f = (PFNGLSECONDARYCOLOR3FPROC) load(userptr, "glSecondaryColor3f"); glad_glSecondaryColor3fv = (PFNGLSECONDARYCOLOR3FVPROC) load(userptr, "glSecondaryColor3fv"); glad_glSecondaryColor3i = (PFNGLSECONDARYCOLOR3IPROC) load(userptr, "glSecondaryColor3i"); glad_glSecondaryColor3iv = (PFNGLSECONDARYCOLOR3IVPROC) load(userptr, "glSecondaryColor3iv"); glad_glSecondaryColor3s = (PFNGLSECONDARYCOLOR3SPROC) load(userptr, "glSecondaryColor3s"); glad_glSecondaryColor3sv = (PFNGLSECONDARYCOLOR3SVPROC) load(userptr, "glSecondaryColor3sv"); glad_glSecondaryColor3ub = (PFNGLSECONDARYCOLOR3UBPROC) load(userptr, "glSecondaryColor3ub"); glad_glSecondaryColor3ubv = (PFNGLSECONDARYCOLOR3UBVPROC) load(userptr, "glSecondaryColor3ubv"); glad_glSecondaryColor3ui = (PFNGLSECONDARYCOLOR3UIPROC) load(userptr, "glSecondaryColor3ui"); glad_glSecondaryColor3uiv = (PFNGLSECONDARYCOLOR3UIVPROC) load(userptr, "glSecondaryColor3uiv"); glad_glSecondaryColor3us = (PFNGLSECONDARYCOLOR3USPROC) load(userptr, "glSecondaryColor3us"); glad_glSecondaryColor3usv = (PFNGLSECONDARYCOLOR3USVPROC) load(userptr, "glSecondaryColor3usv"); glad_glSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC) load(userptr, "glSecondaryColorPointer"); glad_glWindowPos2d = (PFNGLWINDOWPOS2DPROC) load(userptr, "glWindowPos2d"); glad_glWindowPos2dv = (PFNGLWINDOWPOS2DVPROC) load(userptr, "glWindowPos2dv"); glad_glWindowPos2f = (PFNGLWINDOWPOS2FPROC) load(userptr, "glWindowPos2f"); glad_glWindowPos2fv = (PFNGLWINDOWPOS2FVPROC) load(userptr, "glWindowPos2fv"); glad_glWindowPos2i = (PFNGLWINDOWPOS2IPROC) load(userptr, "glWindowPos2i"); glad_glWindowPos2iv = (PFNGLWINDOWPOS2IVPROC) load(userptr, "glWindowPos2iv"); glad_glWindowPos2s = (PFNGLWINDOWPOS2SPROC) load(userptr, "glWindowPos2s"); glad_glWindowPos2sv = (PFNGLWINDOWPOS2SVPROC) load(userptr, "glWindowPos2sv"); glad_glWindowPos3d = (PFNGLWINDOWPOS3DPROC) load(userptr, "glWindowPos3d"); glad_glWindowPos3dv = (PFNGLWINDOWPOS3DVPROC) load(userptr, "glWindowPos3dv"); glad_glWindowPos3f = (PFNGLWINDOWPOS3FPROC) load(userptr, "glWindowPos3f"); glad_glWindowPos3fv = (PFNGLWINDOWPOS3FVPROC) load(userptr, "glWindowPos3fv"); glad_glWindowPos3i = (PFNGLWINDOWPOS3IPROC) load(userptr, "glWindowPos3i"); glad_glWindowPos3iv = (PFNGLWINDOWPOS3IVPROC) load(userptr, "glWindowPos3iv"); glad_glWindowPos3s = (PFNGLWINDOWPOS3SPROC) load(userptr, "glWindowPos3s"); glad_glWindowPos3sv = (PFNGLWINDOWPOS3SVPROC) load(userptr, "glWindowPos3sv"); } static void glad_gl_load_GL_VERSION_1_5( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_1_5) return; glad_glBeginQuery = (PFNGLBEGINQUERYPROC) load(userptr, "glBeginQuery"); glad_glBindBuffer = (PFNGLBINDBUFFERPROC) load(userptr, "glBindBuffer"); glad_glBufferData = (PFNGLBUFFERDATAPROC) load(userptr, "glBufferData"); glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC) load(userptr, "glBufferSubData"); glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) load(userptr, "glDeleteBuffers"); glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC) load(userptr, "glDeleteQueries"); glad_glEndQuery = (PFNGLENDQUERYPROC) load(userptr, "glEndQuery"); glad_glGenBuffers = (PFNGLGENBUFFERSPROC) load(userptr, "glGenBuffers"); glad_glGenQueries = (PFNGLGENQUERIESPROC) load(userptr, "glGenQueries"); glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC) load(userptr, "glGetBufferParameteriv"); glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC) load(userptr, "glGetBufferPointerv"); glad_glGetBufferSubData = (PFNGLGETBUFFERSUBDATAPROC) load(userptr, "glGetBufferSubData"); glad_glGetQueryObjectiv = (PFNGLGETQUERYOBJECTIVPROC) load(userptr, "glGetQueryObjectiv"); glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC) load(userptr, "glGetQueryObjectuiv"); glad_glGetQueryiv = (PFNGLGETQUERYIVPROC) load(userptr, "glGetQueryiv"); glad_glIsBuffer = (PFNGLISBUFFERPROC) load(userptr, "glIsBuffer"); glad_glIsQuery = (PFNGLISQUERYPROC) load(userptr, "glIsQuery"); glad_glMapBuffer = (PFNGLMAPBUFFERPROC) load(userptr, "glMapBuffer"); glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC) load(userptr, "glUnmapBuffer"); } static void glad_gl_load_GL_VERSION_2_0( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_2_0) return; glad_glAttachShader = (PFNGLATTACHSHADERPROC) load(userptr, "glAttachShader"); glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) load(userptr, "glBindAttribLocation"); glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC) load(userptr, "glBlendEquationSeparate"); glad_glCompileShader = (PFNGLCOMPILESHADERPROC) load(userptr, "glCompileShader"); glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC) load(userptr, "glCreateProgram"); glad_glCreateShader = (PFNGLCREATESHADERPROC) load(userptr, "glCreateShader"); glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC) load(userptr, "glDeleteProgram"); glad_glDeleteShader = (PFNGLDELETESHADERPROC) load(userptr, "glDeleteShader"); glad_glDetachShader = (PFNGLDETACHSHADERPROC) load(userptr, "glDetachShader"); glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) load(userptr, "glDisableVertexAttribArray"); glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC) load(userptr, "glDrawBuffers"); glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) load(userptr, "glEnableVertexAttribArray"); glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC) load(userptr, "glGetActiveAttrib"); glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) load(userptr, "glGetActiveUniform"); glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC) load(userptr, "glGetAttachedShaders"); glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) load(userptr, "glGetAttribLocation"); glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) load(userptr, "glGetProgramInfoLog"); glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC) load(userptr, "glGetProgramiv"); glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) load(userptr, "glGetShaderInfoLog"); glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC) load(userptr, "glGetShaderSource"); glad_glGetShaderiv = (PFNGLGETSHADERIVPROC) load(userptr, "glGetShaderiv"); glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) load(userptr, "glGetUniformLocation"); glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC) load(userptr, "glGetUniformfv"); glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC) load(userptr, "glGetUniformiv"); glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC) load(userptr, "glGetVertexAttribPointerv"); glad_glGetVertexAttribdv = (PFNGLGETVERTEXATTRIBDVPROC) load(userptr, "glGetVertexAttribdv"); glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC) load(userptr, "glGetVertexAttribfv"); glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC) load(userptr, "glGetVertexAttribiv"); glad_glIsProgram = (PFNGLISPROGRAMPROC) load(userptr, "glIsProgram"); glad_glIsShader = (PFNGLISSHADERPROC) load(userptr, "glIsShader"); glad_glLinkProgram = (PFNGLLINKPROGRAMPROC) load(userptr, "glLinkProgram"); glad_glShaderSource = (PFNGLSHADERSOURCEPROC) load(userptr, "glShaderSource"); glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC) load(userptr, "glStencilFuncSeparate"); glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC) load(userptr, "glStencilMaskSeparate"); glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC) load(userptr, "glStencilOpSeparate"); glad_glUniform1f = (PFNGLUNIFORM1FPROC) load(userptr, "glUniform1f"); glad_glUniform1fv = (PFNGLUNIFORM1FVPROC) load(userptr, "glUniform1fv"); glad_glUniform1i = (PFNGLUNIFORM1IPROC) load(userptr, "glUniform1i"); glad_glUniform1iv = (PFNGLUNIFORM1IVPROC) load(userptr, "glUniform1iv"); glad_glUniform2f = (PFNGLUNIFORM2FPROC) load(userptr, "glUniform2f"); glad_glUniform2fv = (PFNGLUNIFORM2FVPROC) load(userptr, "glUniform2fv"); glad_glUniform2i = (PFNGLUNIFORM2IPROC) load(userptr, "glUniform2i"); glad_glUniform2iv = (PFNGLUNIFORM2IVPROC) load(userptr, "glUniform2iv"); glad_glUniform3f = (PFNGLUNIFORM3FPROC) load(userptr, "glUniform3f"); glad_glUniform3fv = (PFNGLUNIFORM3FVPROC) load(userptr, "glUniform3fv"); glad_glUniform3i = (PFNGLUNIFORM3IPROC) load(userptr, "glUniform3i"); glad_glUniform3iv = (PFNGLUNIFORM3IVPROC) load(userptr, "glUniform3iv"); glad_glUniform4f = (PFNGLUNIFORM4FPROC) load(userptr, "glUniform4f"); glad_glUniform4fv = (PFNGLUNIFORM4FVPROC) load(userptr, "glUniform4fv"); glad_glUniform4i = (PFNGLUNIFORM4IPROC) load(userptr, "glUniform4i"); glad_glUniform4iv = (PFNGLUNIFORM4IVPROC) load(userptr, "glUniform4iv"); glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC) load(userptr, "glUniformMatrix2fv"); glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) load(userptr, "glUniformMatrix3fv"); glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) load(userptr, "glUniformMatrix4fv"); glad_glUseProgram = (PFNGLUSEPROGRAMPROC) load(userptr, "glUseProgram"); glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC) load(userptr, "glValidateProgram"); glad_glVertexAttrib1d = (PFNGLVERTEXATTRIB1DPROC) load(userptr, "glVertexAttrib1d"); glad_glVertexAttrib1dv = (PFNGLVERTEXATTRIB1DVPROC) load(userptr, "glVertexAttrib1dv"); glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC) load(userptr, "glVertexAttrib1f"); glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC) load(userptr, "glVertexAttrib1fv"); glad_glVertexAttrib1s = (PFNGLVERTEXATTRIB1SPROC) load(userptr, "glVertexAttrib1s"); glad_glVertexAttrib1sv = (PFNGLVERTEXATTRIB1SVPROC) load(userptr, "glVertexAttrib1sv"); glad_glVertexAttrib2d = (PFNGLVERTEXATTRIB2DPROC) load(userptr, "glVertexAttrib2d"); glad_glVertexAttrib2dv = (PFNGLVERTEXATTRIB2DVPROC) load(userptr, "glVertexAttrib2dv"); glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC) load(userptr, "glVertexAttrib2f"); glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC) load(userptr, "glVertexAttrib2fv"); glad_glVertexAttrib2s = (PFNGLVERTEXATTRIB2SPROC) load(userptr, "glVertexAttrib2s"); glad_glVertexAttrib2sv = (PFNGLVERTEXATTRIB2SVPROC) load(userptr, "glVertexAttrib2sv"); glad_glVertexAttrib3d = (PFNGLVERTEXATTRIB3DPROC) load(userptr, "glVertexAttrib3d"); glad_glVertexAttrib3dv = (PFNGLVERTEXATTRIB3DVPROC) load(userptr, "glVertexAttrib3dv"); glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC) load(userptr, "glVertexAttrib3f"); glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC) load(userptr, "glVertexAttrib3fv"); glad_glVertexAttrib3s = (PFNGLVERTEXATTRIB3SPROC) load(userptr, "glVertexAttrib3s"); glad_glVertexAttrib3sv = (PFNGLVERTEXATTRIB3SVPROC) load(userptr, "glVertexAttrib3sv"); glad_glVertexAttrib4Nbv = (PFNGLVERTEXATTRIB4NBVPROC) load(userptr, "glVertexAttrib4Nbv"); glad_glVertexAttrib4Niv = (PFNGLVERTEXATTRIB4NIVPROC) load(userptr, "glVertexAttrib4Niv"); glad_glVertexAttrib4Nsv = (PFNGLVERTEXATTRIB4NSVPROC) load(userptr, "glVertexAttrib4Nsv"); glad_glVertexAttrib4Nub = (PFNGLVERTEXATTRIB4NUBPROC) load(userptr, "glVertexAttrib4Nub"); glad_glVertexAttrib4Nubv = (PFNGLVERTEXATTRIB4NUBVPROC) load(userptr, "glVertexAttrib4Nubv"); glad_glVertexAttrib4Nuiv = (PFNGLVERTEXATTRIB4NUIVPROC) load(userptr, "glVertexAttrib4Nuiv"); glad_glVertexAttrib4Nusv = (PFNGLVERTEXATTRIB4NUSVPROC) load(userptr, "glVertexAttrib4Nusv"); glad_glVertexAttrib4bv = (PFNGLVERTEXATTRIB4BVPROC) load(userptr, "glVertexAttrib4bv"); glad_glVertexAttrib4d = (PFNGLVERTEXATTRIB4DPROC) load(userptr, "glVertexAttrib4d"); glad_glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC) load(userptr, "glVertexAttrib4dv"); glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC) load(userptr, "glVertexAttrib4f"); glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC) load(userptr, "glVertexAttrib4fv"); glad_glVertexAttrib4iv = (PFNGLVERTEXATTRIB4IVPROC) load(userptr, "glVertexAttrib4iv"); glad_glVertexAttrib4s = (PFNGLVERTEXATTRIB4SPROC) load(userptr, "glVertexAttrib4s"); glad_glVertexAttrib4sv = (PFNGLVERTEXATTRIB4SVPROC) load(userptr, "glVertexAttrib4sv"); glad_glVertexAttrib4ubv = (PFNGLVERTEXATTRIB4UBVPROC) load(userptr, "glVertexAttrib4ubv"); glad_glVertexAttrib4uiv = (PFNGLVERTEXATTRIB4UIVPROC) load(userptr, "glVertexAttrib4uiv"); glad_glVertexAttrib4usv = (PFNGLVERTEXATTRIB4USVPROC) load(userptr, "glVertexAttrib4usv"); glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) load(userptr, "glVertexAttribPointer"); } static void glad_gl_load_GL_VERSION_2_1( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_2_1) return; glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC) load(userptr, "glUniformMatrix2x3fv"); glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC) load(userptr, "glUniformMatrix2x4fv"); glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC) load(userptr, "glUniformMatrix3x2fv"); glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC) load(userptr, "glUniformMatrix3x4fv"); glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC) load(userptr, "glUniformMatrix4x2fv"); glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC) load(userptr, "glUniformMatrix4x3fv"); } static void glad_gl_load_GL_VERSION_3_0( GLADuserptrloadfunc load, void* userptr) { if(!GLAD_GL_VERSION_3_0) return; glad_glBeginConditionalRender = (PFNGLBEGINCONDITIONALRENDERPROC) load(userptr, "glBeginConditionalRender"); glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) load(userptr, "glBeginTransformFeedback"); glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) load(userptr, "glBindBufferBase"); glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) load(userptr, "glBindBufferRange"); glad_glBindFragDataLocation = (PFNGLBINDFRAGDATALOCATIONPROC) load(userptr, "glBindFragDataLocation"); glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) load(userptr, "glBindFramebuffer"); glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) load(userptr, "glBindRenderbuffer"); glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) load(userptr, "glBindVertexArray"); glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC) load(userptr, "glBlitFramebuffer"); glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) load(userptr, "glCheckFramebufferStatus"); glad_glClampColor = (PFNGLCLAMPCOLORPROC) load(userptr, "glClampColor"); glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC) load(userptr, "glClearBufferfi"); glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC) load(userptr, "glClearBufferfv"); glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC) load(userptr, "glClearBufferiv"); glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC) load(userptr, "glClearBufferuiv"); glad_glColorMaski = (PFNGLCOLORMASKIPROC) load(userptr, "glColorMaski"); glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) load(userptr, "glDeleteFramebuffers"); glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) load(userptr, "glDeleteRenderbuffers"); glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) load(userptr, "glDeleteVertexArrays"); glad_glDisablei = (PFNGLDISABLEIPROC) load(userptr, "glDisablei"); glad_glEnablei = (PFNGLENABLEIPROC) load(userptr, "glEnablei"); glad_glEndConditionalRender = (PFNGLENDCONDITIONALRENDERPROC) load(userptr, "glEndConditionalRender"); glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) load(userptr, "glEndTransformFeedback"); glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC) load(userptr, "glFlushMappedBufferRange"); glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) load(userptr, "glFramebufferRenderbuffer"); glad_glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC) load(userptr, "glFramebufferTexture1D"); glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) load(userptr, "glFramebufferTexture2D"); glad_glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC) load(userptr, "glFramebufferTexture3D"); glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC) load(userptr, "glFramebufferTextureLayer"); glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) load(userptr, "glGenFramebuffers"); glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) load(userptr, "glGenRenderbuffers"); glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) load(userptr, "glGenVertexArrays"); glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) load(userptr, "glGenerateMipmap"); glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC) load(userptr, "glGetBooleani_v"); glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC) load(userptr, "glGetFragDataLocation"); glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) load(userptr, "glGetFramebufferAttachmentParameteriv"); glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC) load(userptr, "glGetIntegeri_v"); glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) load(userptr, "glGetRenderbufferParameteriv"); glad_glGetStringi = (PFNGLGETSTRINGIPROC) load(userptr, "glGetStringi"); glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC) load(userptr, "glGetTexParameterIiv"); glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC) load(userptr, "glGetTexParameterIuiv"); glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) load(userptr, "glGetTransformFeedbackVarying"); glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC) load(userptr, "glGetUniformuiv"); glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC) load(userptr, "glGetVertexAttribIiv"); glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC) load(userptr, "glGetVertexAttribIuiv"); glad_glIsEnabledi = (PFNGLISENABLEDIPROC) load(userptr, "glIsEnabledi"); glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) load(userptr, "glIsFramebuffer"); glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) load(userptr, "glIsRenderbuffer"); glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC) load(userptr, "glIsVertexArray"); glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC) load(userptr, "glMapBufferRange"); glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) load(userptr, "glRenderbufferStorage"); glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) load(userptr, "glRenderbufferStorageMultisample"); glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC) load(userptr, "glTexParameterIiv"); glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC) load(userptr, "glTexParameterIuiv"); glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) load(userptr, "glTransformFeedbackVaryings"); glad_glUniform1ui = (PFNGLUNIFORM1UIPROC) load(userptr, "glUniform1ui"); glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC) load(userptr, "glUniform1uiv"); glad_glUniform2ui = (PFNGLUNIFORM2UIPROC) load(userptr, "glUniform2ui"); glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC) load(userptr, "glUniform2uiv"); glad_glUniform3ui = (PFNGLUNIFORM3UIPROC) load(userptr, "glUniform3ui"); glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC) load(userptr, "glUniform3uiv"); glad_glUniform4ui = (PFNGLUNIFORM4UIPROC) load(userptr, "glUniform4ui"); glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC) load(userptr, "glUniform4uiv"); glad_glVertexAttribI1i = (PFNGLVERTEXATTRIBI1IPROC) load(userptr, "glVertexAttribI1i"); glad_glVertexAttribI1iv = (PFNGLVERTEXATTRIBI1IVPROC) load(userptr, "glVertexAttribI1iv"); glad_glVertexAttribI1ui = (PFNGLVERTEXATTRIBI1UIPROC) load(userptr, "glVertexAttribI1ui"); glad_glVertexAttribI1uiv = (PFNGLVERTEXATTRIBI1UIVPROC) load(userptr, "glVertexAttribI1uiv"); glad_glVertexAttribI2i = (PFNGLVERTEXATTRIBI2IPROC) load(userptr, "glVertexAttribI2i"); glad_glVertexAttribI2iv = (PFNGLVERTEXATTRIBI2IVPROC) load(userptr, "glVertexAttribI2iv"); glad_glVertexAttribI2ui = (PFNGLVERTEXATTRIBI2UIPROC) load(userptr, "glVertexAttribI2ui"); glad_glVertexAttribI2uiv = (PFNGLVERTEXATTRIBI2UIVPROC) load(userptr, "glVertexAttribI2uiv"); glad_glVertexAttribI3i = (PFNGLVERTEXATTRIBI3IPROC) load(userptr, "glVertexAttribI3i"); glad_glVertexAttribI3iv = (PFNGLVERTEXATTRIBI3IVPROC) load(userptr, "glVertexAttribI3iv"); glad_glVertexAttribI3ui = (PFNGLVERTEXATTRIBI3UIPROC) load(userptr, "glVertexAttribI3ui"); glad_glVertexAttribI3uiv = (PFNGLVERTEXATTRIBI3UIVPROC) load(userptr, "glVertexAttribI3uiv"); glad_glVertexAttribI4bv = (PFNGLVERTEXATTRIBI4BVPROC) load(userptr, "glVertexAttribI4bv"); glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC) load(userptr, "glVertexAttribI4i"); glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC) load(userptr, "glVertexAttribI4iv"); glad_glVertexAttribI4sv = (PFNGLVERTEXATTRIBI4SVPROC) load(userptr, "glVertexAttribI4sv"); glad_glVertexAttribI4ubv = (PFNGLVERTEXATTRIBI4UBVPROC) load(userptr, "glVertexAttribI4ubv"); glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC) load(userptr, "glVertexAttribI4ui"); glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC) load(userptr, "glVertexAttribI4uiv"); glad_glVertexAttribI4usv = (PFNGLVERTEXATTRIBI4USVPROC) load(userptr, "glVertexAttribI4usv"); glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC) load(userptr, "glVertexAttribIPointer"); } static void glad_gl_free_extensions(char **exts_i) { if (exts_i != NULL) { unsigned int index; for(index = 0; exts_i[index]; index++) { free((void *) (exts_i[index])); } free((void *)exts_i); exts_i = NULL; } } static int glad_gl_get_extensions( const char **out_exts, char ***out_exts_i) { #if defined(GL_ES_VERSION_3_0) || defined(GL_VERSION_3_0) if (glad_glGetStringi != NULL && glad_glGetIntegerv != NULL) { unsigned int index = 0; unsigned int num_exts_i = 0; char **exts_i = NULL; glad_glGetIntegerv(GL_NUM_EXTENSIONS, (int*) &num_exts_i); exts_i = (char **) malloc((num_exts_i + 1) * (sizeof *exts_i)); if (exts_i == NULL) { return 0; } for(index = 0; index < num_exts_i; index++) { const char *gl_str_tmp = (const char*) glad_glGetStringi(GL_EXTENSIONS, index); size_t len = strlen(gl_str_tmp) + 1; char *local_str = (char*) malloc(len * sizeof(char)); if(local_str == NULL) { exts_i[index] = NULL; glad_gl_free_extensions(exts_i); return 0; } memcpy(local_str, gl_str_tmp, len * sizeof(char)); exts_i[index] = local_str; } exts_i[index] = NULL; *out_exts_i = exts_i; return 1; } #else GLAD_UNUSED(out_exts_i); #endif if (glad_glGetString == NULL) { return 0; } *out_exts = (const char *)glad_glGetString(GL_EXTENSIONS); return 1; } static int glad_gl_has_extension(const char *exts, char **exts_i, const char *ext) { if(exts_i) { unsigned int index; for(index = 0; exts_i[index]; index++) { const char *e = exts_i[index]; if(strcmp(e, ext) == 0) { return 1; } } } else { const char *extensions; const char *loc; const char *terminator; extensions = exts; if(extensions == NULL || ext == NULL) { return 0; } while(1) { loc = strstr(extensions, ext); if(loc == NULL) { return 0; } terminator = loc + strlen(ext); if((loc == extensions || *(loc - 1) == ' ') && (*terminator == ' ' || *terminator == '\0')) { return 1; } extensions = terminator; } } return 0; } static GLADapiproc glad_gl_get_proc_from_userptr(void *userptr, const char* name) { return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name); } static int glad_gl_find_extensions_gl(void) { const char *exts = NULL; char **exts_i = NULL; if (!glad_gl_get_extensions(&exts, &exts_i)) return 0; GLAD_UNUSED(&glad_gl_has_extension); glad_gl_free_extensions(exts_i); return 1; } static int glad_gl_find_core_gl(void) { int i; const char* version; const char* prefixes[] = { "OpenGL ES-CM ", "OpenGL ES-CL ", "OpenGL ES ", "OpenGL SC ", NULL }; int major = 0; int minor = 0; version = (const char*) glad_glGetString(GL_VERSION); if (!version) return 0; for (i = 0; prefixes[i]; i++) { const size_t length = strlen(prefixes[i]); if (strncmp(version, prefixes[i], length) == 0) { version += length; break; } } GLAD_IMPL_UTIL_SSCANF(version, "%d.%d", &major, &minor); GLAD_GL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1; GLAD_GL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1; GLAD_GL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1; GLAD_GL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1; GLAD_GL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1; GLAD_GL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1; GLAD_GL_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2; GLAD_GL_VERSION_2_1 = (major == 2 && minor >= 1) || major > 2; GLAD_GL_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3; return GLAD_MAKE_VERSION(major, minor); } int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr) { int version; glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString"); if(glad_glGetString == NULL) return 0; version = glad_gl_find_core_gl(); glad_gl_load_GL_VERSION_1_0(load, userptr); glad_gl_load_GL_VERSION_1_1(load, userptr); glad_gl_load_GL_VERSION_1_2(load, userptr); glad_gl_load_GL_VERSION_1_3(load, userptr); glad_gl_load_GL_VERSION_1_4(load, userptr); glad_gl_load_GL_VERSION_1_5(load, userptr); glad_gl_load_GL_VERSION_2_0(load, userptr); glad_gl_load_GL_VERSION_2_1(load, userptr); glad_gl_load_GL_VERSION_3_0(load, userptr); if (!glad_gl_find_extensions_gl()) return 0; return version; } int gladLoadGL( GLADloadfunc load) { return gladLoadGLUserPtr( glad_gl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load); } #ifdef GLAD_GL #ifndef GLAD_LOADER_LIBRARY_C_ #define GLAD_LOADER_LIBRARY_C_ #include #include #if GLAD_PLATFORM_WIN32 #include #else #include #endif static void* glad_get_dlopen_handle(const char *lib_names[], int length) { void *handle = NULL; int i; for (i = 0; i < length; ++i) { #if GLAD_PLATFORM_WIN32 #if GLAD_PLATFORM_UWP size_t buffer_size = (strlen(lib_names[i]) + 1) * sizeof(WCHAR); LPWSTR buffer = (LPWSTR) malloc(buffer_size); if (buffer != NULL) { int ret = MultiByteToWideChar(CP_ACP, 0, lib_names[i], -1, buffer, buffer_size); if (ret != 0) { handle = (void*) LoadPackagedLibrary(buffer, 0); } free((void*) buffer); } #else handle = (void*) LoadLibraryA(lib_names[i]); #endif #else handle = dlopen(lib_names[i], RTLD_LAZY | RTLD_LOCAL); #endif if (handle != NULL) { return handle; } } return NULL; } static void glad_close_dlopen_handle(void* handle) { if (handle != NULL) { #if GLAD_PLATFORM_WIN32 FreeLibrary((HMODULE) handle); #else dlclose(handle); #endif } } static GLADapiproc glad_dlsym_handle(void* handle, const char *name) { if (handle == NULL) { return NULL; } #if GLAD_PLATFORM_WIN32 return (GLADapiproc) GetProcAddress((HMODULE) handle, name); #else return GLAD_GNUC_EXTENSION (GLADapiproc) dlsym(handle, name); #endif } #endif /* GLAD_LOADER_LIBRARY_C_ */ typedef void* (GLAD_API_PTR *GLADglprocaddrfunc)(const char*); struct _glad_gl_userptr { void *handle; GLADglprocaddrfunc gl_get_proc_address_ptr; }; static GLADapiproc glad_gl_get_proc(void *vuserptr, const char *name) { struct _glad_gl_userptr userptr = *(struct _glad_gl_userptr*) vuserptr; GLADapiproc result = NULL; if(userptr.gl_get_proc_address_ptr != NULL) { result = GLAD_GNUC_EXTENSION (GLADapiproc) userptr.gl_get_proc_address_ptr(name); } if(result == NULL) { result = glad_dlsym_handle(userptr.handle, name); } return result; } static void* _glad_GL_loader_handle = NULL; static void* glad_gl_dlopen_handle(void) { #if GLAD_PLATFORM_APPLE static const char *NAMES[] = { "../Frameworks/OpenGL.framework/OpenGL", "/Library/Frameworks/OpenGL.framework/OpenGL", "/System/Library/Frameworks/OpenGL.framework/OpenGL", "/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL" }; #elif GLAD_PLATFORM_WIN32 static const char *NAMES[] = {"opengl32.dll"}; #else static const char *NAMES[] = { #if defined(__CYGWIN__) "libGL-1.so", #endif "libGL.so.1", "libGL.so" }; #endif if (_glad_GL_loader_handle == NULL) { _glad_GL_loader_handle = glad_get_dlopen_handle(NAMES, sizeof(NAMES) / sizeof(NAMES[0])); } return _glad_GL_loader_handle; } static struct _glad_gl_userptr glad_gl_build_userptr(void *handle) { struct _glad_gl_userptr userptr; userptr.handle = handle; #if GLAD_PLATFORM_APPLE || defined(__HAIKU__) userptr.gl_get_proc_address_ptr = NULL; #elif GLAD_PLATFORM_WIN32 userptr.gl_get_proc_address_ptr = (GLADglprocaddrfunc) glad_dlsym_handle(handle, "wglGetProcAddress"); #else userptr.gl_get_proc_address_ptr = (GLADglprocaddrfunc) glad_dlsym_handle(handle, "glXGetProcAddressARB"); #endif return userptr; } int gladLoaderLoadGL(void) { int version = 0; void *handle; int did_load = 0; struct _glad_gl_userptr userptr; did_load = _glad_GL_loader_handle == NULL; handle = glad_gl_dlopen_handle(); if (handle) { userptr = glad_gl_build_userptr(handle); version = gladLoadGLUserPtr(glad_gl_get_proc, &userptr); if (did_load) { gladLoaderUnloadGL(); } } return version; } void gladLoaderUnloadGL(void) { if (_glad_GL_loader_handle != NULL) { glad_close_dlopen_handle(_glad_GL_loader_handle); _glad_GL_loader_handle = NULL; } } #endif /* GLAD_GL */ #ifdef __cplusplus } #endif #endif rgl/src/ext/0000755000176200001440000000000015026603601012424 5ustar liggesusersrgl/src/ext/glad/0000755000176200001440000000000015026603601013333 5ustar liggesusersrgl/src/ext/glad/include/0000755000176200001440000000000015026603601014756 5ustar liggesusersrgl/src/ext/glad/include/KHR/0000755000176200001440000000000014771520323015407 5ustar liggesusersrgl/src/ext/glad/include/KHR/khrplatform.h0000644000176200001440000002557314771520323020125 0ustar liggesusers#ifndef __khrplatform_h_ #define __khrplatform_h_ /* ** Copyright (c) 2008-2018 The Khronos Group Inc. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and/or associated documentation files (the ** "Materials"), to deal in the Materials without restriction, including ** without limitation the rights to use, copy, modify, merge, publish, ** distribute, sublicense, and/or sell copies of the Materials, and to ** permit persons to whom the Materials are furnished to do so, subject to ** the following conditions: ** ** The above copyright notice and this permission notice shall be included ** in all copies or substantial portions of the Materials. ** ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. */ /* Khronos platform-specific types and definitions. * * The master copy of khrplatform.h is maintained in the Khronos EGL * Registry repository at https://github.com/KhronosGroup/EGL-Registry * The last semantic modification to khrplatform.h was at commit ID: * 67a3e0864c2d75ea5287b9f3d2eb74a745936692 * * Adopters may modify this file to suit their platform. Adopters are * encouraged to submit platform specific modifications to the Khronos * group so that they can be included in future versions of this file. * Please submit changes by filing pull requests or issues on * the EGL Registry repository linked above. * * * See the Implementer's Guidelines for information about where this file * should be located on your system and for more details of its use: * http://www.khronos.org/registry/implementers_guide.pdf * * This file should be included as * #include * by Khronos client API header files that use its types and defines. * * The types in khrplatform.h should only be used to define API-specific types. * * Types defined in khrplatform.h: * khronos_int8_t signed 8 bit * khronos_uint8_t unsigned 8 bit * khronos_int16_t signed 16 bit * khronos_uint16_t unsigned 16 bit * khronos_int32_t signed 32 bit * khronos_uint32_t unsigned 32 bit * khronos_int64_t signed 64 bit * khronos_uint64_t unsigned 64 bit * khronos_intptr_t signed same number of bits as a pointer * khronos_uintptr_t unsigned same number of bits as a pointer * khronos_ssize_t signed size * khronos_usize_t unsigned size * khronos_float_t signed 32 bit floating point * khronos_time_ns_t unsigned 64 bit time in nanoseconds * khronos_utime_nanoseconds_t unsigned time interval or absolute time in * nanoseconds * khronos_stime_nanoseconds_t signed time interval in nanoseconds * khronos_boolean_enum_t enumerated boolean type. This should * only be used as a base type when a client API's boolean type is * an enum. Client APIs which use an integer or other type for * booleans cannot use this as the base type for their boolean. * * Tokens defined in khrplatform.h: * * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. * * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. * * Calling convention macros defined in this file: * KHRONOS_APICALL * KHRONOS_APIENTRY * KHRONOS_APIATTRIBUTES * * These may be used in function prototypes as: * * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( * int arg1, * int arg2) KHRONOS_APIATTRIBUTES; */ #if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC) # define KHRONOS_STATIC 1 #endif /*------------------------------------------------------------------------- * Definition of KHRONOS_APICALL *------------------------------------------------------------------------- * This precedes the return type of the function in the function prototype. */ #if defined(KHRONOS_STATIC) /* If the preprocessor constant KHRONOS_STATIC is defined, make the * header compatible with static linking. */ # define KHRONOS_APICALL #elif defined(_WIN32) # define KHRONOS_APICALL __declspec(dllimport) #elif defined (__SYMBIAN32__) # define KHRONOS_APICALL IMPORT_C #elif defined(__ANDROID__) # define KHRONOS_APICALL __attribute__((visibility("default"))) #else # define KHRONOS_APICALL #endif /*------------------------------------------------------------------------- * Definition of KHRONOS_APIENTRY *------------------------------------------------------------------------- * This follows the return type of the function and precedes the function * name in the function prototype. */ #if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) /* Win32 but not WinCE */ # define KHRONOS_APIENTRY __stdcall #else # define KHRONOS_APIENTRY #endif /*------------------------------------------------------------------------- * Definition of KHRONOS_APIATTRIBUTES *------------------------------------------------------------------------- * This follows the closing parenthesis of the function prototype arguments. */ #if defined (__ARMCC_2__) #define KHRONOS_APIATTRIBUTES __softfp #else #define KHRONOS_APIATTRIBUTES #endif /*------------------------------------------------------------------------- * basic type definitions *-----------------------------------------------------------------------*/ #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) /* * Using */ #include typedef int32_t khronos_int32_t; typedef uint32_t khronos_uint32_t; typedef int64_t khronos_int64_t; typedef uint64_t khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 /* * To support platform where unsigned long cannot be used interchangeably with * inptr_t (e.g. CHERI-extended ISAs), we can use the stdint.h intptr_t. * Ideally, we could just use (u)intptr_t everywhere, but this could result in * ABI breakage if khronos_uintptr_t is changed from unsigned long to * unsigned long long or similar (this results in different C++ name mangling). * To avoid changes for existing platforms, we restrict usage of intptr_t to * platforms where the size of a pointer is larger than the size of long. */ #if defined(__SIZEOF_LONG__) && defined(__SIZEOF_POINTER__) #if __SIZEOF_POINTER__ > __SIZEOF_LONG__ #define KHRONOS_USE_INTPTR_T #endif #endif #elif defined(__VMS ) || defined(__sgi) /* * Using */ #include typedef int32_t khronos_int32_t; typedef uint32_t khronos_uint32_t; typedef int64_t khronos_int64_t; typedef uint64_t khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #elif defined(_WIN32) && !defined(__SCITECH_SNAP__) /* * Win32 */ typedef __int32 khronos_int32_t; typedef unsigned __int32 khronos_uint32_t; typedef __int64 khronos_int64_t; typedef unsigned __int64 khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #elif defined(__sun__) || defined(__digital__) /* * Sun or Digital */ typedef int khronos_int32_t; typedef unsigned int khronos_uint32_t; #if defined(__arch64__) || defined(_LP64) typedef long int khronos_int64_t; typedef unsigned long int khronos_uint64_t; #else typedef long long int khronos_int64_t; typedef unsigned long long int khronos_uint64_t; #endif /* __arch64__ */ #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #elif 0 /* * Hypothetical platform with no float or int64 support */ typedef int khronos_int32_t; typedef unsigned int khronos_uint32_t; #define KHRONOS_SUPPORT_INT64 0 #define KHRONOS_SUPPORT_FLOAT 0 #else /* * Generic fallback */ #include typedef int32_t khronos_int32_t; typedef uint32_t khronos_uint32_t; typedef int64_t khronos_int64_t; typedef uint64_t khronos_uint64_t; #define KHRONOS_SUPPORT_INT64 1 #define KHRONOS_SUPPORT_FLOAT 1 #endif /* * Types that are (so far) the same on all platforms */ typedef signed char khronos_int8_t; typedef unsigned char khronos_uint8_t; typedef signed short int khronos_int16_t; typedef unsigned short int khronos_uint16_t; /* * Types that differ between LLP64 and LP64 architectures - in LLP64, * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears * to be the only LLP64 architecture in current use. */ #ifdef KHRONOS_USE_INTPTR_T typedef intptr_t khronos_intptr_t; typedef uintptr_t khronos_uintptr_t; #elif defined(_WIN64) typedef signed long long int khronos_intptr_t; typedef unsigned long long int khronos_uintptr_t; #else typedef signed long int khronos_intptr_t; typedef unsigned long int khronos_uintptr_t; #endif #if defined(_WIN64) typedef signed long long int khronos_ssize_t; typedef unsigned long long int khronos_usize_t; #else typedef signed long int khronos_ssize_t; typedef unsigned long int khronos_usize_t; #endif #if KHRONOS_SUPPORT_FLOAT /* * Float type */ typedef float khronos_float_t; #endif #if KHRONOS_SUPPORT_INT64 /* Time types * * These types can be used to represent a time interval in nanoseconds or * an absolute Unadjusted System Time. Unadjusted System Time is the number * of nanoseconds since some arbitrary system event (e.g. since the last * time the system booted). The Unadjusted System Time is an unsigned * 64 bit value that wraps back to 0 every 584 years. Time intervals * may be either signed or unsigned. */ typedef khronos_uint64_t khronos_utime_nanoseconds_t; typedef khronos_int64_t khronos_stime_nanoseconds_t; #endif /* * Dummy value used to pad enum types to 32 bits. */ #ifndef KHRONOS_MAX_ENUM #define KHRONOS_MAX_ENUM 0x7FFFFFFF #endif /* * Enumerated boolean type * * Values other than zero should be considered to be true. Therefore * comparisons should not be made against KHRONOS_TRUE. */ typedef enum { KHRONOS_FALSE = 0, KHRONOS_TRUE = 1, KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM } khronos_boolean_enum_t; #endif /* __khrplatform_h_ */ rgl/src/ext/glad/include/glad/0000755000176200001440000000000015011677075015677 5ustar liggesusersrgl/src/ext/glad/include/glad/gl.h0000644000176200001440000050650115011677075016461 0ustar liggesusers/** * Loader generated by glad 2.0.8 on Thu Mar 27 00:25:40 2025 * * SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0 * * Generator: C/C++ * Specification: gl * Extensions: 0 * * APIs: * - gl:compatibility=3.0 * * Options: * - ALIAS = False * - DEBUG = False * - HEADER_ONLY = False * - LOADER = True * - MX = False * - ON_DEMAND = False * * Commandline: * --api='gl:compatibility=3.0' --extensions='' c --loader * * Online: * http://glad.sh/#api=gl%3Acompatibility%3D3.0&extensions=&generator=c&options=LOADER * */ #ifndef GLAD_GL_H_ #define GLAD_GL_H_ #ifdef __clang__ #pragma clang diagnostic push // #pragma clang diagnostic ignored "-Wreserved-id-macro" #endif #ifdef __gl_h_ #error OpenGL (gl.h) header already included (API: gl), remove previous include! #endif #define __gl_h_ 1 #ifdef __gl3_h_ #error OpenGL (gl3.h) header already included (API: gl), remove previous include! #endif #define __gl3_h_ 1 #ifdef __glext_h_ #error OpenGL (glext.h) header already included (API: gl), remove previous include! #endif #define __glext_h_ 1 #ifdef __gl3ext_h_ #error OpenGL (gl3ext.h) header already included (API: gl), remove previous include! #endif #define __gl3ext_h_ 1 #ifdef __clang__ #pragma clang diagnostic pop #endif #define GLAD_GL #define GLAD_OPTION_GL_LOADER #ifdef __cplusplus extern "C" { #endif #ifndef GLAD_PLATFORM_H_ #define GLAD_PLATFORM_H_ #ifndef GLAD_PLATFORM_WIN32 #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__) #define GLAD_PLATFORM_WIN32 1 #else #define GLAD_PLATFORM_WIN32 0 #endif #endif #ifndef GLAD_PLATFORM_APPLE #ifdef __APPLE__ #define GLAD_PLATFORM_APPLE 1 #else #define GLAD_PLATFORM_APPLE 0 #endif #endif #ifndef GLAD_PLATFORM_EMSCRIPTEN #ifdef __EMSCRIPTEN__ #define GLAD_PLATFORM_EMSCRIPTEN 1 #else #define GLAD_PLATFORM_EMSCRIPTEN 0 #endif #endif #ifndef GLAD_PLATFORM_UWP #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY) #ifdef __has_include #if __has_include() #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 #endif #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_ #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1 #endif #endif #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY #include #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) #define GLAD_PLATFORM_UWP 1 #endif #endif #ifndef GLAD_PLATFORM_UWP #define GLAD_PLATFORM_UWP 0 #endif #endif #ifdef __GNUC__ #define GLAD_GNUC_EXTENSION __extension__ #else #define GLAD_GNUC_EXTENSION #endif #define GLAD_UNUSED(x) (void)(x) #ifndef GLAD_API_CALL #if defined(GLAD_API_CALL_EXPORT) #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__) #if defined(GLAD_API_CALL_EXPORT_BUILD) #if defined(__GNUC__) #define GLAD_API_CALL __attribute__ ((dllexport)) extern #else #define GLAD_API_CALL __declspec(dllexport) extern #endif #else #if defined(__GNUC__) #define GLAD_API_CALL __attribute__ ((dllimport)) extern #else #define GLAD_API_CALL __declspec(dllimport) extern #endif #endif #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD) #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern #else #define GLAD_API_CALL extern #endif #else #define GLAD_API_CALL extern #endif #endif #ifdef APIENTRY #define GLAD_API_PTR APIENTRY #elif GLAD_PLATFORM_WIN32 #define GLAD_API_PTR __stdcall #else #define GLAD_API_PTR #endif #ifndef GLAPI #define GLAPI GLAD_API_CALL #endif #ifndef GLAPIENTRY #define GLAPIENTRY GLAD_API_PTR #endif #define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor) #define GLAD_VERSION_MAJOR(version) (version / 10000) #define GLAD_VERSION_MINOR(version) (version % 10000) #define GLAD_GENERATOR_VERSION "2.0.8" typedef void (*GLADapiproc)(void); typedef GLADapiproc (*GLADloadfunc)(const char *name); typedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name); typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...); typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...); #endif /* GLAD_PLATFORM_H_ */ #define GL_2D 0x0600 #define GL_2_BYTES 0x1407 #define GL_3D 0x0601 #define GL_3D_COLOR 0x0602 #define GL_3D_COLOR_TEXTURE 0x0603 #define GL_3_BYTES 0x1408 #define GL_4D_COLOR_TEXTURE 0x0604 #define GL_4_BYTES 0x1409 #define GL_ACCUM 0x0100 #define GL_ACCUM_ALPHA_BITS 0x0D5B #define GL_ACCUM_BLUE_BITS 0x0D5A #define GL_ACCUM_BUFFER_BIT 0x00000200 #define GL_ACCUM_CLEAR_VALUE 0x0B80 #define GL_ACCUM_GREEN_BITS 0x0D59 #define GL_ACCUM_RED_BITS 0x0D58 #define GL_ACTIVE_ATTRIBUTES 0x8B89 #define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A #define GL_ACTIVE_TEXTURE 0x84E0 #define GL_ACTIVE_UNIFORMS 0x8B86 #define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 #define GL_ADD 0x0104 #define GL_ADD_SIGNED 0x8574 #define GL_ALIASED_LINE_WIDTH_RANGE 0x846E #define GL_ALIASED_POINT_SIZE_RANGE 0x846D #define GL_ALL_ATTRIB_BITS 0xFFFFFFFF #define GL_ALPHA 0x1906 #define GL_ALPHA12 0x803D #define GL_ALPHA16 0x803E #define GL_ALPHA4 0x803B #define GL_ALPHA8 0x803C #define GL_ALPHA_BIAS 0x0D1D #define GL_ALPHA_BITS 0x0D55 #define GL_ALPHA_INTEGER 0x8D97 #define GL_ALPHA_SCALE 0x0D1C #define GL_ALPHA_TEST 0x0BC0 #define GL_ALPHA_TEST_FUNC 0x0BC1 #define GL_ALPHA_TEST_REF 0x0BC2 #define GL_ALWAYS 0x0207 #define GL_AMBIENT 0x1200 #define GL_AMBIENT_AND_DIFFUSE 0x1602 #define GL_AND 0x1501 #define GL_AND_INVERTED 0x1504 #define GL_AND_REVERSE 0x1502 #define GL_ARRAY_BUFFER 0x8892 #define GL_ARRAY_BUFFER_BINDING 0x8894 #define GL_ATTACHED_SHADERS 0x8B85 #define GL_ATTRIB_STACK_DEPTH 0x0BB0 #define GL_AUTO_NORMAL 0x0D80 #define GL_AUX0 0x0409 #define GL_AUX1 0x040A #define GL_AUX2 0x040B #define GL_AUX3 0x040C #define GL_AUX_BUFFERS 0x0C00 #define GL_BACK 0x0405 #define GL_BACK_LEFT 0x0402 #define GL_BACK_RIGHT 0x0403 #define GL_BGR 0x80E0 #define GL_BGRA 0x80E1 #define GL_BGRA_INTEGER 0x8D9B #define GL_BGR_INTEGER 0x8D9A #define GL_BITMAP 0x1A00 #define GL_BITMAP_TOKEN 0x0704 #define GL_BLEND 0x0BE2 #define GL_BLEND_COLOR 0x8005 #define GL_BLEND_DST 0x0BE0 #define GL_BLEND_DST_ALPHA 0x80CA #define GL_BLEND_DST_RGB 0x80C8 #define GL_BLEND_EQUATION 0x8009 #define GL_BLEND_EQUATION_ALPHA 0x883D #define GL_BLEND_EQUATION_RGB 0x8009 #define GL_BLEND_SRC 0x0BE1 #define GL_BLEND_SRC_ALPHA 0x80CB #define GL_BLEND_SRC_RGB 0x80C9 #define GL_BLUE 0x1905 #define GL_BLUE_BIAS 0x0D1B #define GL_BLUE_BITS 0x0D54 #define GL_BLUE_INTEGER 0x8D96 #define GL_BLUE_SCALE 0x0D1A #define GL_BOOL 0x8B56 #define GL_BOOL_VEC2 0x8B57 #define GL_BOOL_VEC3 0x8B58 #define GL_BOOL_VEC4 0x8B59 #define GL_BUFFER_ACCESS 0x88BB #define GL_BUFFER_ACCESS_FLAGS 0x911F #define GL_BUFFER_MAPPED 0x88BC #define GL_BUFFER_MAP_LENGTH 0x9120 #define GL_BUFFER_MAP_OFFSET 0x9121 #define GL_BUFFER_MAP_POINTER 0x88BD #define GL_BUFFER_SIZE 0x8764 #define GL_BUFFER_USAGE 0x8765 #define GL_BYTE 0x1400 #define GL_C3F_V3F 0x2A24 #define GL_C4F_N3F_V3F 0x2A26 #define GL_C4UB_V2F 0x2A22 #define GL_C4UB_V3F 0x2A23 #define GL_CCW 0x0901 #define GL_CLAMP 0x2900 #define GL_CLAMP_FRAGMENT_COLOR 0x891B #define GL_CLAMP_READ_COLOR 0x891C #define GL_CLAMP_TO_BORDER 0x812D #define GL_CLAMP_TO_EDGE 0x812F #define GL_CLAMP_VERTEX_COLOR 0x891A #define GL_CLEAR 0x1500 #define GL_CLIENT_ACTIVE_TEXTURE 0x84E1 #define GL_CLIENT_ALL_ATTRIB_BITS 0xFFFFFFFF #define GL_CLIENT_ATTRIB_STACK_DEPTH 0x0BB1 #define GL_CLIENT_PIXEL_STORE_BIT 0x00000001 #define GL_CLIENT_VERTEX_ARRAY_BIT 0x00000002 #define GL_CLIP_DISTANCE0 0x3000 #define GL_CLIP_DISTANCE1 0x3001 #define GL_CLIP_DISTANCE2 0x3002 #define GL_CLIP_DISTANCE3 0x3003 #define GL_CLIP_DISTANCE4 0x3004 #define GL_CLIP_DISTANCE5 0x3005 #define GL_CLIP_DISTANCE6 0x3006 #define GL_CLIP_DISTANCE7 0x3007 #define GL_CLIP_PLANE0 0x3000 #define GL_CLIP_PLANE1 0x3001 #define GL_CLIP_PLANE2 0x3002 #define GL_CLIP_PLANE3 0x3003 #define GL_CLIP_PLANE4 0x3004 #define GL_CLIP_PLANE5 0x3005 #define GL_COEFF 0x0A00 #define GL_COLOR 0x1800 #define GL_COLOR_ARRAY 0x8076 #define GL_COLOR_ARRAY_BUFFER_BINDING 0x8898 #define GL_COLOR_ARRAY_POINTER 0x8090 #define GL_COLOR_ARRAY_SIZE 0x8081 #define GL_COLOR_ARRAY_STRIDE 0x8083 #define GL_COLOR_ARRAY_TYPE 0x8082 #define GL_COLOR_ATTACHMENT0 0x8CE0 #define GL_COLOR_ATTACHMENT1 0x8CE1 #define GL_COLOR_ATTACHMENT10 0x8CEA #define GL_COLOR_ATTACHMENT11 0x8CEB #define GL_COLOR_ATTACHMENT12 0x8CEC #define GL_COLOR_ATTACHMENT13 0x8CED #define GL_COLOR_ATTACHMENT14 0x8CEE #define GL_COLOR_ATTACHMENT15 0x8CEF #define GL_COLOR_ATTACHMENT16 0x8CF0 #define GL_COLOR_ATTACHMENT17 0x8CF1 #define GL_COLOR_ATTACHMENT18 0x8CF2 #define GL_COLOR_ATTACHMENT19 0x8CF3 #define GL_COLOR_ATTACHMENT2 0x8CE2 #define GL_COLOR_ATTACHMENT20 0x8CF4 #define GL_COLOR_ATTACHMENT21 0x8CF5 #define GL_COLOR_ATTACHMENT22 0x8CF6 #define GL_COLOR_ATTACHMENT23 0x8CF7 #define GL_COLOR_ATTACHMENT24 0x8CF8 #define GL_COLOR_ATTACHMENT25 0x8CF9 #define GL_COLOR_ATTACHMENT26 0x8CFA #define GL_COLOR_ATTACHMENT27 0x8CFB #define GL_COLOR_ATTACHMENT28 0x8CFC #define GL_COLOR_ATTACHMENT29 0x8CFD #define GL_COLOR_ATTACHMENT3 0x8CE3 #define GL_COLOR_ATTACHMENT30 0x8CFE #define GL_COLOR_ATTACHMENT31 0x8CFF #define GL_COLOR_ATTACHMENT4 0x8CE4 #define GL_COLOR_ATTACHMENT5 0x8CE5 #define GL_COLOR_ATTACHMENT6 0x8CE6 #define GL_COLOR_ATTACHMENT7 0x8CE7 #define GL_COLOR_ATTACHMENT8 0x8CE8 #define GL_COLOR_ATTACHMENT9 0x8CE9 #define GL_COLOR_BUFFER_BIT 0x00004000 #define GL_COLOR_CLEAR_VALUE 0x0C22 #define GL_COLOR_INDEX 0x1900 #define GL_COLOR_INDEXES 0x1603 #define GL_COLOR_LOGIC_OP 0x0BF2 #define GL_COLOR_MATERIAL 0x0B57 #define GL_COLOR_MATERIAL_FACE 0x0B55 #define GL_COLOR_MATERIAL_PARAMETER 0x0B56 #define GL_COLOR_SUM 0x8458 #define GL_COLOR_WRITEMASK 0x0C23 #define GL_COMBINE 0x8570 #define GL_COMBINE_ALPHA 0x8572 #define GL_COMBINE_RGB 0x8571 #define GL_COMPARE_REF_TO_TEXTURE 0x884E #define GL_COMPARE_R_TO_TEXTURE 0x884E #define GL_COMPILE 0x1300 #define GL_COMPILE_AND_EXECUTE 0x1301 #define GL_COMPILE_STATUS 0x8B81 #define GL_COMPRESSED_ALPHA 0x84E9 #define GL_COMPRESSED_INTENSITY 0x84EC #define GL_COMPRESSED_LUMINANCE 0x84EA #define GL_COMPRESSED_LUMINANCE_ALPHA 0x84EB #define GL_COMPRESSED_RED 0x8225 #define GL_COMPRESSED_RED_RGTC1 0x8DBB #define GL_COMPRESSED_RG 0x8226 #define GL_COMPRESSED_RGB 0x84ED #define GL_COMPRESSED_RGBA 0x84EE #define GL_COMPRESSED_RG_RGTC2 0x8DBD #define GL_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC #define GL_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE #define GL_COMPRESSED_SLUMINANCE 0x8C4A #define GL_COMPRESSED_SLUMINANCE_ALPHA 0x8C4B #define GL_COMPRESSED_SRGB 0x8C48 #define GL_COMPRESSED_SRGB_ALPHA 0x8C49 #define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 #define GL_CONSTANT 0x8576 #define GL_CONSTANT_ALPHA 0x8003 #define GL_CONSTANT_ATTENUATION 0x1207 #define GL_CONSTANT_COLOR 0x8001 #define GL_CONTEXT_FLAGS 0x821E #define GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT 0x00000001 #define GL_COORD_REPLACE 0x8862 #define GL_COPY 0x1503 #define GL_COPY_INVERTED 0x150C #define GL_COPY_PIXEL_TOKEN 0x0706 #define GL_CULL_FACE 0x0B44 #define GL_CULL_FACE_MODE 0x0B45 #define GL_CURRENT_BIT 0x00000001 #define GL_CURRENT_COLOR 0x0B00 #define GL_CURRENT_FOG_COORD 0x8453 #define GL_CURRENT_FOG_COORDINATE 0x8453 #define GL_CURRENT_INDEX 0x0B01 #define GL_CURRENT_NORMAL 0x0B02 #define GL_CURRENT_PROGRAM 0x8B8D #define GL_CURRENT_QUERY 0x8865 #define GL_CURRENT_RASTER_COLOR 0x0B04 #define GL_CURRENT_RASTER_DISTANCE 0x0B09 #define GL_CURRENT_RASTER_INDEX 0x0B05 #define GL_CURRENT_RASTER_POSITION 0x0B07 #define GL_CURRENT_RASTER_POSITION_VALID 0x0B08 #define GL_CURRENT_RASTER_SECONDARY_COLOR 0x845F #define GL_CURRENT_RASTER_TEXTURE_COORDS 0x0B06 #define GL_CURRENT_SECONDARY_COLOR 0x8459 #define GL_CURRENT_TEXTURE_COORDS 0x0B03 #define GL_CURRENT_VERTEX_ATTRIB 0x8626 #define GL_CW 0x0900 #define GL_DECAL 0x2101 #define GL_DECR 0x1E03 #define GL_DECR_WRAP 0x8508 #define GL_DELETE_STATUS 0x8B80 #define GL_DEPTH 0x1801 #define GL_DEPTH24_STENCIL8 0x88F0 #define GL_DEPTH32F_STENCIL8 0x8CAD #define GL_DEPTH_ATTACHMENT 0x8D00 #define GL_DEPTH_BIAS 0x0D1F #define GL_DEPTH_BITS 0x0D56 #define GL_DEPTH_BUFFER_BIT 0x00000100 #define GL_DEPTH_CLEAR_VALUE 0x0B73 #define GL_DEPTH_COMPONENT 0x1902 #define GL_DEPTH_COMPONENT16 0x81A5 #define GL_DEPTH_COMPONENT24 0x81A6 #define GL_DEPTH_COMPONENT32 0x81A7 #define GL_DEPTH_COMPONENT32F 0x8CAC #define GL_DEPTH_FUNC 0x0B74 #define GL_DEPTH_RANGE 0x0B70 #define GL_DEPTH_SCALE 0x0D1E #define GL_DEPTH_STENCIL 0x84F9 #define GL_DEPTH_STENCIL_ATTACHMENT 0x821A #define GL_DEPTH_TEST 0x0B71 #define GL_DEPTH_TEXTURE_MODE 0x884B #define GL_DEPTH_WRITEMASK 0x0B72 #define GL_DIFFUSE 0x1201 #define GL_DITHER 0x0BD0 #define GL_DOMAIN 0x0A02 #define GL_DONT_CARE 0x1100 #define GL_DOT3_RGB 0x86AE #define GL_DOT3_RGBA 0x86AF #define GL_DOUBLE 0x140A #define GL_DOUBLEBUFFER 0x0C32 #define GL_DRAW_BUFFER 0x0C01 #define GL_DRAW_BUFFER0 0x8825 #define GL_DRAW_BUFFER1 0x8826 #define GL_DRAW_BUFFER10 0x882F #define GL_DRAW_BUFFER11 0x8830 #define GL_DRAW_BUFFER12 0x8831 #define GL_DRAW_BUFFER13 0x8832 #define GL_DRAW_BUFFER14 0x8833 #define GL_DRAW_BUFFER15 0x8834 #define GL_DRAW_BUFFER2 0x8827 #define GL_DRAW_BUFFER3 0x8828 #define GL_DRAW_BUFFER4 0x8829 #define GL_DRAW_BUFFER5 0x882A #define GL_DRAW_BUFFER6 0x882B #define GL_DRAW_BUFFER7 0x882C #define GL_DRAW_BUFFER8 0x882D #define GL_DRAW_BUFFER9 0x882E #define GL_DRAW_FRAMEBUFFER 0x8CA9 #define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 #define GL_DRAW_PIXEL_TOKEN 0x0705 #define GL_DST_ALPHA 0x0304 #define GL_DST_COLOR 0x0306 #define GL_DYNAMIC_COPY 0x88EA #define GL_DYNAMIC_DRAW 0x88E8 #define GL_DYNAMIC_READ 0x88E9 #define GL_EDGE_FLAG 0x0B43 #define GL_EDGE_FLAG_ARRAY 0x8079 #define GL_EDGE_FLAG_ARRAY_BUFFER_BINDING 0x889B #define GL_EDGE_FLAG_ARRAY_POINTER 0x8093 #define GL_EDGE_FLAG_ARRAY_STRIDE 0x808C #define GL_ELEMENT_ARRAY_BUFFER 0x8893 #define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 #define GL_EMISSION 0x1600 #define GL_ENABLE_BIT 0x00002000 #define GL_EQUAL 0x0202 #define GL_EQUIV 0x1509 #define GL_EVAL_BIT 0x00010000 #define GL_EXP 0x0800 #define GL_EXP2 0x0801 #define GL_EXTENSIONS 0x1F03 #define GL_EYE_LINEAR 0x2400 #define GL_EYE_PLANE 0x2502 #define GL_FALSE 0 #define GL_FASTEST 0x1101 #define GL_FEEDBACK 0x1C01 #define GL_FEEDBACK_BUFFER_POINTER 0x0DF0 #define GL_FEEDBACK_BUFFER_SIZE 0x0DF1 #define GL_FEEDBACK_BUFFER_TYPE 0x0DF2 #define GL_FILL 0x1B02 #define GL_FIXED_ONLY 0x891D #define GL_FLAT 0x1D00 #define GL_FLOAT 0x1406 #define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD #define GL_FLOAT_MAT2 0x8B5A #define GL_FLOAT_MAT2x3 0x8B65 #define GL_FLOAT_MAT2x4 0x8B66 #define GL_FLOAT_MAT3 0x8B5B #define GL_FLOAT_MAT3x2 0x8B67 #define GL_FLOAT_MAT3x4 0x8B68 #define GL_FLOAT_MAT4 0x8B5C #define GL_FLOAT_MAT4x2 0x8B69 #define GL_FLOAT_MAT4x3 0x8B6A #define GL_FLOAT_VEC2 0x8B50 #define GL_FLOAT_VEC3 0x8B51 #define GL_FLOAT_VEC4 0x8B52 #define GL_FOG 0x0B60 #define GL_FOG_BIT 0x00000080 #define GL_FOG_COLOR 0x0B66 #define GL_FOG_COORD 0x8451 #define GL_FOG_COORDINATE 0x8451 #define GL_FOG_COORDINATE_ARRAY 0x8457 #define GL_FOG_COORDINATE_ARRAY_BUFFER_BINDING 0x889D #define GL_FOG_COORDINATE_ARRAY_POINTER 0x8456 #define GL_FOG_COORDINATE_ARRAY_STRIDE 0x8455 #define GL_FOG_COORDINATE_ARRAY_TYPE 0x8454 #define GL_FOG_COORDINATE_SOURCE 0x8450 #define GL_FOG_COORD_ARRAY 0x8457 #define GL_FOG_COORD_ARRAY_BUFFER_BINDING 0x889D #define GL_FOG_COORD_ARRAY_POINTER 0x8456 #define GL_FOG_COORD_ARRAY_STRIDE 0x8455 #define GL_FOG_COORD_ARRAY_TYPE 0x8454 #define GL_FOG_COORD_SRC 0x8450 #define GL_FOG_DENSITY 0x0B62 #define GL_FOG_END 0x0B64 #define GL_FOG_HINT 0x0C54 #define GL_FOG_INDEX 0x0B61 #define GL_FOG_MODE 0x0B65 #define GL_FOG_START 0x0B63 #define GL_FRAGMENT_DEPTH 0x8452 #define GL_FRAGMENT_SHADER 0x8B30 #define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B #define GL_FRAMEBUFFER 0x8D40 #define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 #define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 #define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 #define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 #define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 #define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 #define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 #define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 #define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 #define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 #define GL_FRAMEBUFFER_BINDING 0x8CA6 #define GL_FRAMEBUFFER_COMPLETE 0x8CD5 #define GL_FRAMEBUFFER_DEFAULT 0x8218 #define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 #define GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER 0x8CDB #define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 #define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 #define GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER 0x8CDC #define GL_FRAMEBUFFER_SRGB 0x8DB9 #define GL_FRAMEBUFFER_UNDEFINED 0x8219 #define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD #define GL_FRONT 0x0404 #define GL_FRONT_AND_BACK 0x0408 #define GL_FRONT_FACE 0x0B46 #define GL_FRONT_LEFT 0x0400 #define GL_FRONT_RIGHT 0x0401 #define GL_FUNC_ADD 0x8006 #define GL_FUNC_REVERSE_SUBTRACT 0x800B #define GL_FUNC_SUBTRACT 0x800A #define GL_GENERATE_MIPMAP 0x8191 #define GL_GENERATE_MIPMAP_HINT 0x8192 #define GL_GEQUAL 0x0206 #define GL_GREATER 0x0204 #define GL_GREEN 0x1904 #define GL_GREEN_BIAS 0x0D19 #define GL_GREEN_BITS 0x0D53 #define GL_GREEN_INTEGER 0x8D95 #define GL_GREEN_SCALE 0x0D18 #define GL_HALF_FLOAT 0x140B #define GL_HINT_BIT 0x00008000 #define GL_INCR 0x1E02 #define GL_INCR_WRAP 0x8507 #define GL_INDEX 0x8222 #define GL_INDEX_ARRAY 0x8077 #define GL_INDEX_ARRAY_BUFFER_BINDING 0x8899 #define GL_INDEX_ARRAY_POINTER 0x8091 #define GL_INDEX_ARRAY_STRIDE 0x8086 #define GL_INDEX_ARRAY_TYPE 0x8085 #define GL_INDEX_BITS 0x0D51 #define GL_INDEX_CLEAR_VALUE 0x0C20 #define GL_INDEX_LOGIC_OP 0x0BF1 #define GL_INDEX_MODE 0x0C30 #define GL_INDEX_OFFSET 0x0D13 #define GL_INDEX_SHIFT 0x0D12 #define GL_INDEX_WRITEMASK 0x0C21 #define GL_INFO_LOG_LENGTH 0x8B84 #define GL_INT 0x1404 #define GL_INTENSITY 0x8049 #define GL_INTENSITY12 0x804C #define GL_INTENSITY16 0x804D #define GL_INTENSITY4 0x804A #define GL_INTENSITY8 0x804B #define GL_INTERLEAVED_ATTRIBS 0x8C8C #define GL_INTERPOLATE 0x8575 #define GL_INT_SAMPLER_1D 0x8DC9 #define GL_INT_SAMPLER_1D_ARRAY 0x8DCE #define GL_INT_SAMPLER_2D 0x8DCA #define GL_INT_SAMPLER_2D_ARRAY 0x8DCF #define GL_INT_SAMPLER_3D 0x8DCB #define GL_INT_SAMPLER_CUBE 0x8DCC #define GL_INT_VEC2 0x8B53 #define GL_INT_VEC3 0x8B54 #define GL_INT_VEC4 0x8B55 #define GL_INVALID_ENUM 0x0500 #define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 #define GL_INVALID_OPERATION 0x0502 #define GL_INVALID_VALUE 0x0501 #define GL_INVERT 0x150A #define GL_KEEP 0x1E00 #define GL_LEFT 0x0406 #define GL_LEQUAL 0x0203 #define GL_LESS 0x0201 #define GL_LIGHT0 0x4000 #define GL_LIGHT1 0x4001 #define GL_LIGHT2 0x4002 #define GL_LIGHT3 0x4003 #define GL_LIGHT4 0x4004 #define GL_LIGHT5 0x4005 #define GL_LIGHT6 0x4006 #define GL_LIGHT7 0x4007 #define GL_LIGHTING 0x0B50 #define GL_LIGHTING_BIT 0x00000040 #define GL_LIGHT_MODEL_AMBIENT 0x0B53 #define GL_LIGHT_MODEL_COLOR_CONTROL 0x81F8 #define GL_LIGHT_MODEL_LOCAL_VIEWER 0x0B51 #define GL_LIGHT_MODEL_TWO_SIDE 0x0B52 #define GL_LINE 0x1B01 #define GL_LINEAR 0x2601 #define GL_LINEAR_ATTENUATION 0x1208 #define GL_LINEAR_MIPMAP_LINEAR 0x2703 #define GL_LINEAR_MIPMAP_NEAREST 0x2701 #define GL_LINES 0x0001 #define GL_LINE_BIT 0x00000004 #define GL_LINE_LOOP 0x0002 #define GL_LINE_RESET_TOKEN 0x0707 #define GL_LINE_SMOOTH 0x0B20 #define GL_LINE_SMOOTH_HINT 0x0C52 #define GL_LINE_STIPPLE 0x0B24 #define GL_LINE_STIPPLE_PATTERN 0x0B25 #define GL_LINE_STIPPLE_REPEAT 0x0B26 #define GL_LINE_STRIP 0x0003 #define GL_LINE_TOKEN 0x0702 #define GL_LINE_WIDTH 0x0B21 #define GL_LINE_WIDTH_GRANULARITY 0x0B23 #define GL_LINE_WIDTH_RANGE 0x0B22 #define GL_LINK_STATUS 0x8B82 #define GL_LIST_BASE 0x0B32 #define GL_LIST_BIT 0x00020000 #define GL_LIST_INDEX 0x0B33 #define GL_LIST_MODE 0x0B30 #define GL_LOAD 0x0101 #define GL_LOGIC_OP 0x0BF1 #define GL_LOGIC_OP_MODE 0x0BF0 #define GL_LOWER_LEFT 0x8CA1 #define GL_LUMINANCE 0x1909 #define GL_LUMINANCE12 0x8041 #define GL_LUMINANCE12_ALPHA12 0x8047 #define GL_LUMINANCE12_ALPHA4 0x8046 #define GL_LUMINANCE16 0x8042 #define GL_LUMINANCE16_ALPHA16 0x8048 #define GL_LUMINANCE4 0x803F #define GL_LUMINANCE4_ALPHA4 0x8043 #define GL_LUMINANCE6_ALPHA2 0x8044 #define GL_LUMINANCE8 0x8040 #define GL_LUMINANCE8_ALPHA8 0x8045 #define GL_LUMINANCE_ALPHA 0x190A #define GL_MAJOR_VERSION 0x821B #define GL_MAP1_COLOR_4 0x0D90 #define GL_MAP1_GRID_DOMAIN 0x0DD0 #define GL_MAP1_GRID_SEGMENTS 0x0DD1 #define GL_MAP1_INDEX 0x0D91 #define GL_MAP1_NORMAL 0x0D92 #define GL_MAP1_TEXTURE_COORD_1 0x0D93 #define GL_MAP1_TEXTURE_COORD_2 0x0D94 #define GL_MAP1_TEXTURE_COORD_3 0x0D95 #define GL_MAP1_TEXTURE_COORD_4 0x0D96 #define GL_MAP1_VERTEX_3 0x0D97 #define GL_MAP1_VERTEX_4 0x0D98 #define GL_MAP2_COLOR_4 0x0DB0 #define GL_MAP2_GRID_DOMAIN 0x0DD2 #define GL_MAP2_GRID_SEGMENTS 0x0DD3 #define GL_MAP2_INDEX 0x0DB1 #define GL_MAP2_NORMAL 0x0DB2 #define GL_MAP2_TEXTURE_COORD_1 0x0DB3 #define GL_MAP2_TEXTURE_COORD_2 0x0DB4 #define GL_MAP2_TEXTURE_COORD_3 0x0DB5 #define GL_MAP2_TEXTURE_COORD_4 0x0DB6 #define GL_MAP2_VERTEX_3 0x0DB7 #define GL_MAP2_VERTEX_4 0x0DB8 #define GL_MAP_COLOR 0x0D10 #define GL_MAP_FLUSH_EXPLICIT_BIT 0x0010 #define GL_MAP_INVALIDATE_BUFFER_BIT 0x0008 #define GL_MAP_INVALIDATE_RANGE_BIT 0x0004 #define GL_MAP_READ_BIT 0x0001 #define GL_MAP_STENCIL 0x0D11 #define GL_MAP_UNSYNCHRONIZED_BIT 0x0020 #define GL_MAP_WRITE_BIT 0x0002 #define GL_MATRIX_MODE 0x0BA0 #define GL_MAX 0x8008 #define GL_MAX_3D_TEXTURE_SIZE 0x8073 #define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF #define GL_MAX_ATTRIB_STACK_DEPTH 0x0D35 #define GL_MAX_CLIENT_ATTRIB_STACK_DEPTH 0x0D3B #define GL_MAX_CLIP_DISTANCES 0x0D32 #define GL_MAX_CLIP_PLANES 0x0D32 #define GL_MAX_COLOR_ATTACHMENTS 0x8CDF #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D #define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C #define GL_MAX_DRAW_BUFFERS 0x8824 #define GL_MAX_ELEMENTS_INDICES 0x80E9 #define GL_MAX_ELEMENTS_VERTICES 0x80E8 #define GL_MAX_EVAL_ORDER 0x0D30 #define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 #define GL_MAX_LIGHTS 0x0D31 #define GL_MAX_LIST_NESTING 0x0B31 #define GL_MAX_MODELVIEW_STACK_DEPTH 0x0D36 #define GL_MAX_NAME_STACK_DEPTH 0x0D37 #define GL_MAX_PIXEL_MAP_TABLE 0x0D34 #define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 #define GL_MAX_PROJECTION_STACK_DEPTH 0x0D38 #define GL_MAX_RENDERBUFFER_SIZE 0x84E8 #define GL_MAX_SAMPLES 0x8D57 #define GL_MAX_TEXTURE_COORDS 0x8871 #define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 #define GL_MAX_TEXTURE_LOD_BIAS 0x84FD #define GL_MAX_TEXTURE_SIZE 0x0D33 #define GL_MAX_TEXTURE_STACK_DEPTH 0x0D39 #define GL_MAX_TEXTURE_UNITS 0x84E2 #define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B #define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 #define GL_MAX_VARYING_COMPONENTS 0x8B4B #define GL_MAX_VARYING_FLOATS 0x8B4B #define GL_MAX_VERTEX_ATTRIBS 0x8869 #define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C #define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A #define GL_MAX_VIEWPORT_DIMS 0x0D3A #define GL_MIN 0x8007 #define GL_MINOR_VERSION 0x821C #define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 #define GL_MIRRORED_REPEAT 0x8370 #define GL_MODELVIEW 0x1700 #define GL_MODELVIEW_MATRIX 0x0BA6 #define GL_MODELVIEW_STACK_DEPTH 0x0BA3 #define GL_MODULATE 0x2100 #define GL_MULT 0x0103 #define GL_MULTISAMPLE 0x809D #define GL_MULTISAMPLE_BIT 0x20000000 #define GL_N3F_V3F 0x2A25 #define GL_NAME_STACK_DEPTH 0x0D70 #define GL_NAND 0x150E #define GL_NEAREST 0x2600 #define GL_NEAREST_MIPMAP_LINEAR 0x2702 #define GL_NEAREST_MIPMAP_NEAREST 0x2700 #define GL_NEVER 0x0200 #define GL_NICEST 0x1102 #define GL_NONE 0 #define GL_NOOP 0x1505 #define GL_NOR 0x1508 #define GL_NORMALIZE 0x0BA1 #define GL_NORMAL_ARRAY 0x8075 #define GL_NORMAL_ARRAY_BUFFER_BINDING 0x8897 #define GL_NORMAL_ARRAY_POINTER 0x808F #define GL_NORMAL_ARRAY_STRIDE 0x807F #define GL_NORMAL_ARRAY_TYPE 0x807E #define GL_NORMAL_MAP 0x8511 #define GL_NOTEQUAL 0x0205 #define GL_NO_ERROR 0 #define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 #define GL_NUM_EXTENSIONS 0x821D #define GL_OBJECT_LINEAR 0x2401 #define GL_OBJECT_PLANE 0x2501 #define GL_ONE 1 #define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 #define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 #define GL_ONE_MINUS_DST_ALPHA 0x0305 #define GL_ONE_MINUS_DST_COLOR 0x0307 #define GL_ONE_MINUS_SRC_ALPHA 0x0303 #define GL_ONE_MINUS_SRC_COLOR 0x0301 #define GL_OPERAND0_ALPHA 0x8598 #define GL_OPERAND0_RGB 0x8590 #define GL_OPERAND1_ALPHA 0x8599 #define GL_OPERAND1_RGB 0x8591 #define GL_OPERAND2_ALPHA 0x859A #define GL_OPERAND2_RGB 0x8592 #define GL_OR 0x1507 #define GL_ORDER 0x0A01 #define GL_OR_INVERTED 0x150D #define GL_OR_REVERSE 0x150B #define GL_OUT_OF_MEMORY 0x0505 #define GL_PACK_ALIGNMENT 0x0D05 #define GL_PACK_IMAGE_HEIGHT 0x806C #define GL_PACK_LSB_FIRST 0x0D01 #define GL_PACK_ROW_LENGTH 0x0D02 #define GL_PACK_SKIP_IMAGES 0x806B #define GL_PACK_SKIP_PIXELS 0x0D04 #define GL_PACK_SKIP_ROWS 0x0D03 #define GL_PACK_SWAP_BYTES 0x0D00 #define GL_PASS_THROUGH_TOKEN 0x0700 #define GL_PERSPECTIVE_CORRECTION_HINT 0x0C50 #define GL_PIXEL_MAP_A_TO_A 0x0C79 #define GL_PIXEL_MAP_A_TO_A_SIZE 0x0CB9 #define GL_PIXEL_MAP_B_TO_B 0x0C78 #define GL_PIXEL_MAP_B_TO_B_SIZE 0x0CB8 #define GL_PIXEL_MAP_G_TO_G 0x0C77 #define GL_PIXEL_MAP_G_TO_G_SIZE 0x0CB7 #define GL_PIXEL_MAP_I_TO_A 0x0C75 #define GL_PIXEL_MAP_I_TO_A_SIZE 0x0CB5 #define GL_PIXEL_MAP_I_TO_B 0x0C74 #define GL_PIXEL_MAP_I_TO_B_SIZE 0x0CB4 #define GL_PIXEL_MAP_I_TO_G 0x0C73 #define GL_PIXEL_MAP_I_TO_G_SIZE 0x0CB3 #define GL_PIXEL_MAP_I_TO_I 0x0C70 #define GL_PIXEL_MAP_I_TO_I_SIZE 0x0CB0 #define GL_PIXEL_MAP_I_TO_R 0x0C72 #define GL_PIXEL_MAP_I_TO_R_SIZE 0x0CB2 #define GL_PIXEL_MAP_R_TO_R 0x0C76 #define GL_PIXEL_MAP_R_TO_R_SIZE 0x0CB6 #define GL_PIXEL_MAP_S_TO_S 0x0C71 #define GL_PIXEL_MAP_S_TO_S_SIZE 0x0CB1 #define GL_PIXEL_MODE_BIT 0x00000020 #define GL_PIXEL_PACK_BUFFER 0x88EB #define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED #define GL_PIXEL_UNPACK_BUFFER 0x88EC #define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF #define GL_POINT 0x1B00 #define GL_POINTS 0x0000 #define GL_POINT_BIT 0x00000002 #define GL_POINT_DISTANCE_ATTENUATION 0x8129 #define GL_POINT_FADE_THRESHOLD_SIZE 0x8128 #define GL_POINT_SIZE 0x0B11 #define GL_POINT_SIZE_GRANULARITY 0x0B13 #define GL_POINT_SIZE_MAX 0x8127 #define GL_POINT_SIZE_MIN 0x8126 #define GL_POINT_SIZE_RANGE 0x0B12 #define GL_POINT_SMOOTH 0x0B10 #define GL_POINT_SMOOTH_HINT 0x0C51 #define GL_POINT_SPRITE 0x8861 #define GL_POINT_SPRITE_COORD_ORIGIN 0x8CA0 #define GL_POINT_TOKEN 0x0701 #define GL_POLYGON 0x0009 #define GL_POLYGON_BIT 0x00000008 #define GL_POLYGON_MODE 0x0B40 #define GL_POLYGON_OFFSET_FACTOR 0x8038 #define GL_POLYGON_OFFSET_FILL 0x8037 #define GL_POLYGON_OFFSET_LINE 0x2A02 #define GL_POLYGON_OFFSET_POINT 0x2A01 #define GL_POLYGON_OFFSET_UNITS 0x2A00 #define GL_POLYGON_SMOOTH 0x0B41 #define GL_POLYGON_SMOOTH_HINT 0x0C53 #define GL_POLYGON_STIPPLE 0x0B42 #define GL_POLYGON_STIPPLE_BIT 0x00000010 #define GL_POLYGON_TOKEN 0x0703 #define GL_POSITION 0x1203 #define GL_PREVIOUS 0x8578 #define GL_PRIMARY_COLOR 0x8577 #define GL_PRIMITIVES_GENERATED 0x8C87 #define GL_PROJECTION 0x1701 #define GL_PROJECTION_MATRIX 0x0BA7 #define GL_PROJECTION_STACK_DEPTH 0x0BA4 #define GL_PROXY_TEXTURE_1D 0x8063 #define GL_PROXY_TEXTURE_1D_ARRAY 0x8C19 #define GL_PROXY_TEXTURE_2D 0x8064 #define GL_PROXY_TEXTURE_2D_ARRAY 0x8C1B #define GL_PROXY_TEXTURE_3D 0x8070 #define GL_PROXY_TEXTURE_CUBE_MAP 0x851B #define GL_Q 0x2003 #define GL_QUADRATIC_ATTENUATION 0x1209 #define GL_QUADS 0x0007 #define GL_QUAD_STRIP 0x0008 #define GL_QUERY_BY_REGION_NO_WAIT 0x8E16 #define GL_QUERY_BY_REGION_WAIT 0x8E15 #define GL_QUERY_COUNTER_BITS 0x8864 #define GL_QUERY_NO_WAIT 0x8E14 #define GL_QUERY_RESULT 0x8866 #define GL_QUERY_RESULT_AVAILABLE 0x8867 #define GL_QUERY_WAIT 0x8E13 #define GL_R 0x2002 #define GL_R11F_G11F_B10F 0x8C3A #define GL_R16 0x822A #define GL_R16F 0x822D #define GL_R16I 0x8233 #define GL_R16UI 0x8234 #define GL_R32F 0x822E #define GL_R32I 0x8235 #define GL_R32UI 0x8236 #define GL_R3_G3_B2 0x2A10 #define GL_R8 0x8229 #define GL_R8I 0x8231 #define GL_R8UI 0x8232 #define GL_RASTERIZER_DISCARD 0x8C89 #define GL_READ_BUFFER 0x0C02 #define GL_READ_FRAMEBUFFER 0x8CA8 #define GL_READ_FRAMEBUFFER_BINDING 0x8CAA #define GL_READ_ONLY 0x88B8 #define GL_READ_WRITE 0x88BA #define GL_RED 0x1903 #define GL_RED_BIAS 0x0D15 #define GL_RED_BITS 0x0D52 #define GL_RED_INTEGER 0x8D94 #define GL_RED_SCALE 0x0D14 #define GL_REFLECTION_MAP 0x8512 #define GL_RENDER 0x1C00 #define GL_RENDERBUFFER 0x8D41 #define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 #define GL_RENDERBUFFER_BINDING 0x8CA7 #define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 #define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 #define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 #define GL_RENDERBUFFER_HEIGHT 0x8D43 #define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 #define GL_RENDERBUFFER_RED_SIZE 0x8D50 #define GL_RENDERBUFFER_SAMPLES 0x8CAB #define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 #define GL_RENDERBUFFER_WIDTH 0x8D42 #define GL_RENDERER 0x1F01 #define GL_RENDER_MODE 0x0C40 #define GL_REPEAT 0x2901 #define GL_REPLACE 0x1E01 #define GL_RESCALE_NORMAL 0x803A #define GL_RETURN 0x0102 #define GL_RG 0x8227 #define GL_RG16 0x822C #define GL_RG16F 0x822F #define GL_RG16I 0x8239 #define GL_RG16UI 0x823A #define GL_RG32F 0x8230 #define GL_RG32I 0x823B #define GL_RG32UI 0x823C #define GL_RG8 0x822B #define GL_RG8I 0x8237 #define GL_RG8UI 0x8238 #define GL_RGB 0x1907 #define GL_RGB10 0x8052 #define GL_RGB10_A2 0x8059 #define GL_RGB12 0x8053 #define GL_RGB16 0x8054 #define GL_RGB16F 0x881B #define GL_RGB16I 0x8D89 #define GL_RGB16UI 0x8D77 #define GL_RGB32F 0x8815 #define GL_RGB32I 0x8D83 #define GL_RGB32UI 0x8D71 #define GL_RGB4 0x804F #define GL_RGB5 0x8050 #define GL_RGB5_A1 0x8057 #define GL_RGB8 0x8051 #define GL_RGB8I 0x8D8F #define GL_RGB8UI 0x8D7D #define GL_RGB9_E5 0x8C3D #define GL_RGBA 0x1908 #define GL_RGBA12 0x805A #define GL_RGBA16 0x805B #define GL_RGBA16F 0x881A #define GL_RGBA16I 0x8D88 #define GL_RGBA16UI 0x8D76 #define GL_RGBA2 0x8055 #define GL_RGBA32F 0x8814 #define GL_RGBA32I 0x8D82 #define GL_RGBA32UI 0x8D70 #define GL_RGBA4 0x8056 #define GL_RGBA8 0x8058 #define GL_RGBA8I 0x8D8E #define GL_RGBA8UI 0x8D7C #define GL_RGBA_INTEGER 0x8D99 #define GL_RGBA_MODE 0x0C31 #define GL_RGB_INTEGER 0x8D98 #define GL_RGB_SCALE 0x8573 #define GL_RG_INTEGER 0x8228 #define GL_RIGHT 0x0407 #define GL_S 0x2000 #define GL_SAMPLER_1D 0x8B5D #define GL_SAMPLER_1D_ARRAY 0x8DC0 #define GL_SAMPLER_1D_ARRAY_SHADOW 0x8DC3 #define GL_SAMPLER_1D_SHADOW 0x8B61 #define GL_SAMPLER_2D 0x8B5E #define GL_SAMPLER_2D_ARRAY 0x8DC1 #define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 #define GL_SAMPLER_2D_SHADOW 0x8B62 #define GL_SAMPLER_3D 0x8B5F #define GL_SAMPLER_CUBE 0x8B60 #define GL_SAMPLER_CUBE_SHADOW 0x8DC5 #define GL_SAMPLES 0x80A9 #define GL_SAMPLES_PASSED 0x8914 #define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E #define GL_SAMPLE_ALPHA_TO_ONE 0x809F #define GL_SAMPLE_BUFFERS 0x80A8 #define GL_SAMPLE_COVERAGE 0x80A0 #define GL_SAMPLE_COVERAGE_INVERT 0x80AB #define GL_SAMPLE_COVERAGE_VALUE 0x80AA #define GL_SCISSOR_BIT 0x00080000 #define GL_SCISSOR_BOX 0x0C10 #define GL_SCISSOR_TEST 0x0C11 #define GL_SECONDARY_COLOR_ARRAY 0x845E #define GL_SECONDARY_COLOR_ARRAY_BUFFER_BINDING 0x889C #define GL_SECONDARY_COLOR_ARRAY_POINTER 0x845D #define GL_SECONDARY_COLOR_ARRAY_SIZE 0x845A #define GL_SECONDARY_COLOR_ARRAY_STRIDE 0x845C #define GL_SECONDARY_COLOR_ARRAY_TYPE 0x845B #define GL_SELECT 0x1C02 #define GL_SELECTION_BUFFER_POINTER 0x0DF3 #define GL_SELECTION_BUFFER_SIZE 0x0DF4 #define GL_SEPARATE_ATTRIBS 0x8C8D #define GL_SEPARATE_SPECULAR_COLOR 0x81FA #define GL_SET 0x150F #define GL_SHADER_SOURCE_LENGTH 0x8B88 #define GL_SHADER_TYPE 0x8B4F #define GL_SHADE_MODEL 0x0B54 #define GL_SHADING_LANGUAGE_VERSION 0x8B8C #define GL_SHININESS 0x1601 #define GL_SHORT 0x1402 #define GL_SINGLE_COLOR 0x81F9 #define GL_SLUMINANCE 0x8C46 #define GL_SLUMINANCE8 0x8C47 #define GL_SLUMINANCE8_ALPHA8 0x8C45 #define GL_SLUMINANCE_ALPHA 0x8C44 #define GL_SMOOTH 0x1D01 #define GL_SMOOTH_LINE_WIDTH_GRANULARITY 0x0B23 #define GL_SMOOTH_LINE_WIDTH_RANGE 0x0B22 #define GL_SMOOTH_POINT_SIZE_GRANULARITY 0x0B13 #define GL_SMOOTH_POINT_SIZE_RANGE 0x0B12 #define GL_SOURCE0_ALPHA 0x8588 #define GL_SOURCE0_RGB 0x8580 #define GL_SOURCE1_ALPHA 0x8589 #define GL_SOURCE1_RGB 0x8581 #define GL_SOURCE2_ALPHA 0x858A #define GL_SOURCE2_RGB 0x8582 #define GL_SPECULAR 0x1202 #define GL_SPHERE_MAP 0x2402 #define GL_SPOT_CUTOFF 0x1206 #define GL_SPOT_DIRECTION 0x1204 #define GL_SPOT_EXPONENT 0x1205 #define GL_SRC0_ALPHA 0x8588 #define GL_SRC0_RGB 0x8580 #define GL_SRC1_ALPHA 0x8589 #define GL_SRC1_RGB 0x8581 #define GL_SRC2_ALPHA 0x858A #define GL_SRC2_RGB 0x8582 #define GL_SRC_ALPHA 0x0302 #define GL_SRC_ALPHA_SATURATE 0x0308 #define GL_SRC_COLOR 0x0300 #define GL_SRGB 0x8C40 #define GL_SRGB8 0x8C41 #define GL_SRGB8_ALPHA8 0x8C43 #define GL_SRGB_ALPHA 0x8C42 #define GL_STACK_OVERFLOW 0x0503 #define GL_STACK_UNDERFLOW 0x0504 #define GL_STATIC_COPY 0x88E6 #define GL_STATIC_DRAW 0x88E4 #define GL_STATIC_READ 0x88E5 #define GL_STENCIL 0x1802 #define GL_STENCIL_ATTACHMENT 0x8D20 #define GL_STENCIL_BACK_FAIL 0x8801 #define GL_STENCIL_BACK_FUNC 0x8800 #define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 #define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 #define GL_STENCIL_BACK_REF 0x8CA3 #define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 #define GL_STENCIL_BACK_WRITEMASK 0x8CA5 #define GL_STENCIL_BITS 0x0D57 #define GL_STENCIL_BUFFER_BIT 0x00000400 #define GL_STENCIL_CLEAR_VALUE 0x0B91 #define GL_STENCIL_FAIL 0x0B94 #define GL_STENCIL_FUNC 0x0B92 #define GL_STENCIL_INDEX 0x1901 #define GL_STENCIL_INDEX1 0x8D46 #define GL_STENCIL_INDEX16 0x8D49 #define GL_STENCIL_INDEX4 0x8D47 #define GL_STENCIL_INDEX8 0x8D48 #define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 #define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 #define GL_STENCIL_REF 0x0B97 #define GL_STENCIL_TEST 0x0B90 #define GL_STENCIL_VALUE_MASK 0x0B93 #define GL_STENCIL_WRITEMASK 0x0B98 #define GL_STEREO 0x0C33 #define GL_STREAM_COPY 0x88E2 #define GL_STREAM_DRAW 0x88E0 #define GL_STREAM_READ 0x88E1 #define GL_SUBPIXEL_BITS 0x0D50 #define GL_SUBTRACT 0x84E7 #define GL_T 0x2001 #define GL_T2F_C3F_V3F 0x2A2A #define GL_T2F_C4F_N3F_V3F 0x2A2C #define GL_T2F_C4UB_V3F 0x2A29 #define GL_T2F_N3F_V3F 0x2A2B #define GL_T2F_V3F 0x2A27 #define GL_T4F_C4F_N3F_V4F 0x2A2D #define GL_T4F_V4F 0x2A28 #define GL_TEXTURE 0x1702 #define GL_TEXTURE0 0x84C0 #define GL_TEXTURE1 0x84C1 #define GL_TEXTURE10 0x84CA #define GL_TEXTURE11 0x84CB #define GL_TEXTURE12 0x84CC #define GL_TEXTURE13 0x84CD #define GL_TEXTURE14 0x84CE #define GL_TEXTURE15 0x84CF #define GL_TEXTURE16 0x84D0 #define GL_TEXTURE17 0x84D1 #define GL_TEXTURE18 0x84D2 #define GL_TEXTURE19 0x84D3 #define GL_TEXTURE2 0x84C2 #define GL_TEXTURE20 0x84D4 #define GL_TEXTURE21 0x84D5 #define GL_TEXTURE22 0x84D6 #define GL_TEXTURE23 0x84D7 #define GL_TEXTURE24 0x84D8 #define GL_TEXTURE25 0x84D9 #define GL_TEXTURE26 0x84DA #define GL_TEXTURE27 0x84DB #define GL_TEXTURE28 0x84DC #define GL_TEXTURE29 0x84DD #define GL_TEXTURE3 0x84C3 #define GL_TEXTURE30 0x84DE #define GL_TEXTURE31 0x84DF #define GL_TEXTURE4 0x84C4 #define GL_TEXTURE5 0x84C5 #define GL_TEXTURE6 0x84C6 #define GL_TEXTURE7 0x84C7 #define GL_TEXTURE8 0x84C8 #define GL_TEXTURE9 0x84C9 #define GL_TEXTURE_1D 0x0DE0 #define GL_TEXTURE_1D_ARRAY 0x8C18 #define GL_TEXTURE_2D 0x0DE1 #define GL_TEXTURE_2D_ARRAY 0x8C1A #define GL_TEXTURE_3D 0x806F #define GL_TEXTURE_ALPHA_SIZE 0x805F #define GL_TEXTURE_ALPHA_TYPE 0x8C13 #define GL_TEXTURE_BASE_LEVEL 0x813C #define GL_TEXTURE_BINDING_1D 0x8068 #define GL_TEXTURE_BINDING_1D_ARRAY 0x8C1C #define GL_TEXTURE_BINDING_2D 0x8069 #define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D #define GL_TEXTURE_BINDING_3D 0x806A #define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 #define GL_TEXTURE_BIT 0x00040000 #define GL_TEXTURE_BLUE_SIZE 0x805E #define GL_TEXTURE_BLUE_TYPE 0x8C12 #define GL_TEXTURE_BORDER 0x1005 #define GL_TEXTURE_BORDER_COLOR 0x1004 #define GL_TEXTURE_COMPARE_FUNC 0x884D #define GL_TEXTURE_COMPARE_MODE 0x884C #define GL_TEXTURE_COMPONENTS 0x1003 #define GL_TEXTURE_COMPRESSED 0x86A1 #define GL_TEXTURE_COMPRESSED_IMAGE_SIZE 0x86A0 #define GL_TEXTURE_COMPRESSION_HINT 0x84EF #define GL_TEXTURE_COORD_ARRAY 0x8078 #define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A #define GL_TEXTURE_COORD_ARRAY_POINTER 0x8092 #define GL_TEXTURE_COORD_ARRAY_SIZE 0x8088 #define GL_TEXTURE_COORD_ARRAY_STRIDE 0x808A #define GL_TEXTURE_COORD_ARRAY_TYPE 0x8089 #define GL_TEXTURE_CUBE_MAP 0x8513 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A #define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 #define GL_TEXTURE_DEPTH 0x8071 #define GL_TEXTURE_DEPTH_SIZE 0x884A #define GL_TEXTURE_DEPTH_TYPE 0x8C16 #define GL_TEXTURE_ENV 0x2300 #define GL_TEXTURE_ENV_COLOR 0x2201 #define GL_TEXTURE_ENV_MODE 0x2200 #define GL_TEXTURE_FILTER_CONTROL 0x8500 #define GL_TEXTURE_GEN_MODE 0x2500 #define GL_TEXTURE_GEN_Q 0x0C63 #define GL_TEXTURE_GEN_R 0x0C62 #define GL_TEXTURE_GEN_S 0x0C60 #define GL_TEXTURE_GEN_T 0x0C61 #define GL_TEXTURE_GREEN_SIZE 0x805D #define GL_TEXTURE_GREEN_TYPE 0x8C11 #define GL_TEXTURE_HEIGHT 0x1001 #define GL_TEXTURE_INTENSITY_SIZE 0x8061 #define GL_TEXTURE_INTENSITY_TYPE 0x8C15 #define GL_TEXTURE_INTERNAL_FORMAT 0x1003 #define GL_TEXTURE_LOD_BIAS 0x8501 #define GL_TEXTURE_LUMINANCE_SIZE 0x8060 #define GL_TEXTURE_LUMINANCE_TYPE 0x8C14 #define GL_TEXTURE_MAG_FILTER 0x2800 #define GL_TEXTURE_MATRIX 0x0BA8 #define GL_TEXTURE_MAX_LEVEL 0x813D #define GL_TEXTURE_MAX_LOD 0x813B #define GL_TEXTURE_MIN_FILTER 0x2801 #define GL_TEXTURE_MIN_LOD 0x813A #define GL_TEXTURE_PRIORITY 0x8066 #define GL_TEXTURE_RED_SIZE 0x805C #define GL_TEXTURE_RED_TYPE 0x8C10 #define GL_TEXTURE_RESIDENT 0x8067 #define GL_TEXTURE_SHARED_SIZE 0x8C3F #define GL_TEXTURE_STACK_DEPTH 0x0BA5 #define GL_TEXTURE_STENCIL_SIZE 0x88F1 #define GL_TEXTURE_WIDTH 0x1000 #define GL_TEXTURE_WRAP_R 0x8072 #define GL_TEXTURE_WRAP_S 0x2802 #define GL_TEXTURE_WRAP_T 0x2803 #define GL_TRANSFORM_BIT 0x00001000 #define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E #define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F #define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F #define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 #define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 #define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 #define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 #define GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH 0x8C76 #define GL_TRANSPOSE_COLOR_MATRIX 0x84E6 #define GL_TRANSPOSE_MODELVIEW_MATRIX 0x84E3 #define GL_TRANSPOSE_PROJECTION_MATRIX 0x84E4 #define GL_TRANSPOSE_TEXTURE_MATRIX 0x84E5 #define GL_TRIANGLES 0x0004 #define GL_TRIANGLE_FAN 0x0006 #define GL_TRIANGLE_STRIP 0x0005 #define GL_TRUE 1 #define GL_UNPACK_ALIGNMENT 0x0CF5 #define GL_UNPACK_IMAGE_HEIGHT 0x806E #define GL_UNPACK_LSB_FIRST 0x0CF1 #define GL_UNPACK_ROW_LENGTH 0x0CF2 #define GL_UNPACK_SKIP_IMAGES 0x806D #define GL_UNPACK_SKIP_PIXELS 0x0CF4 #define GL_UNPACK_SKIP_ROWS 0x0CF3 #define GL_UNPACK_SWAP_BYTES 0x0CF0 #define GL_UNSIGNED_BYTE 0x1401 #define GL_UNSIGNED_BYTE_2_3_3_REV 0x8362 #define GL_UNSIGNED_BYTE_3_3_2 0x8032 #define GL_UNSIGNED_INT 0x1405 #define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B #define GL_UNSIGNED_INT_10_10_10_2 0x8036 #define GL_UNSIGNED_INT_24_8 0x84FA #define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 #define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E #define GL_UNSIGNED_INT_8_8_8_8 0x8035 #define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 #define GL_UNSIGNED_INT_SAMPLER_1D 0x8DD1 #define GL_UNSIGNED_INT_SAMPLER_1D_ARRAY 0x8DD6 #define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 #define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 #define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 #define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 #define GL_UNSIGNED_INT_VEC2 0x8DC6 #define GL_UNSIGNED_INT_VEC3 0x8DC7 #define GL_UNSIGNED_INT_VEC4 0x8DC8 #define GL_UNSIGNED_NORMALIZED 0x8C17 #define GL_UNSIGNED_SHORT 0x1403 #define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 #define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 #define GL_UNSIGNED_SHORT_5_6_5 0x8363 #define GL_UNSIGNED_SHORT_5_6_5_REV 0x8364 #define GL_UPPER_LEFT 0x8CA2 #define GL_V2F 0x2A20 #define GL_V3F 0x2A21 #define GL_VALIDATE_STATUS 0x8B83 #define GL_VENDOR 0x1F00 #define GL_VERSION 0x1F02 #define GL_VERTEX_ARRAY 0x8074 #define GL_VERTEX_ARRAY_BINDING 0x85B5 #define GL_VERTEX_ARRAY_BUFFER_BINDING 0x8896 #define GL_VERTEX_ARRAY_POINTER 0x808E #define GL_VERTEX_ARRAY_SIZE 0x807A #define GL_VERTEX_ARRAY_STRIDE 0x807C #define GL_VERTEX_ARRAY_TYPE 0x807B #define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F #define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 #define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD #define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A #define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 #define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 #define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 #define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 #define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642 #define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643 #define GL_VERTEX_SHADER 0x8B31 #define GL_VIEWPORT 0x0BA2 #define GL_VIEWPORT_BIT 0x00000800 #define GL_WEIGHT_ARRAY_BUFFER_BINDING 0x889E #define GL_WRITE_ONLY 0x88B9 #define GL_XOR 0x1506 #define GL_ZERO 0 #define GL_ZOOM_X 0x0D16 #define GL_ZOOM_Y 0x0D17 #include typedef unsigned int GLenum; typedef unsigned char GLboolean; typedef unsigned int GLbitfield; typedef void GLvoid; typedef khronos_int8_t GLbyte; typedef khronos_uint8_t GLubyte; typedef khronos_int16_t GLshort; typedef khronos_uint16_t GLushort; typedef int GLint; typedef unsigned int GLuint; typedef khronos_int32_t GLclampx; typedef int GLsizei; typedef khronos_float_t GLfloat; typedef khronos_float_t GLclampf; typedef double GLdouble; typedef double GLclampd; typedef void *GLeglClientBufferEXT; typedef void *GLeglImageOES; typedef char GLchar; typedef char GLcharARB; #ifdef __APPLE__ typedef void *GLhandleARB; #else typedef unsigned int GLhandleARB; #endif typedef khronos_uint16_t GLhalf; typedef khronos_uint16_t GLhalfARB; typedef khronos_int32_t GLfixed; #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) typedef khronos_intptr_t GLintptr; #else typedef khronos_intptr_t GLintptr; #endif #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) typedef khronos_intptr_t GLintptrARB; #else typedef khronos_intptr_t GLintptrARB; #endif #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) typedef khronos_ssize_t GLsizeiptr; #else typedef khronos_ssize_t GLsizeiptr; #endif #if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && (__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ > 1060) typedef khronos_ssize_t GLsizeiptrARB; #else typedef khronos_ssize_t GLsizeiptrARB; #endif typedef khronos_int64_t GLint64; typedef khronos_int64_t GLint64EXT; typedef khronos_uint64_t GLuint64; typedef khronos_uint64_t GLuint64EXT; typedef struct __GLsync *GLsync; struct _cl_context; struct _cl_event; typedef void (GLAD_API_PTR *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); typedef void (GLAD_API_PTR *GLDEBUGPROCARB)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); typedef void (GLAD_API_PTR *GLDEBUGPROCKHR)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const void *userParam); typedef void (GLAD_API_PTR *GLDEBUGPROCAMD)(GLuint id,GLenum category,GLenum severity,GLsizei length,const GLchar *message,void *userParam); typedef unsigned short GLhalfNV; typedef GLintptr GLvdpauSurfaceNV; typedef void (GLAD_API_PTR *GLVULKANPROCNV)(void); #define GL_VERSION_1_0 1 GLAD_API_CALL int GLAD_GL_VERSION_1_0; #define GL_VERSION_1_1 1 GLAD_API_CALL int GLAD_GL_VERSION_1_1; #define GL_VERSION_1_2 1 GLAD_API_CALL int GLAD_GL_VERSION_1_2; #define GL_VERSION_1_3 1 GLAD_API_CALL int GLAD_GL_VERSION_1_3; #define GL_VERSION_1_4 1 GLAD_API_CALL int GLAD_GL_VERSION_1_4; #define GL_VERSION_1_5 1 GLAD_API_CALL int GLAD_GL_VERSION_1_5; #define GL_VERSION_2_0 1 GLAD_API_CALL int GLAD_GL_VERSION_2_0; #define GL_VERSION_2_1 1 GLAD_API_CALL int GLAD_GL_VERSION_2_1; #define GL_VERSION_3_0 1 GLAD_API_CALL int GLAD_GL_VERSION_3_0; typedef void (GLAD_API_PTR *PFNGLACCUMPROC)(GLenum op, GLfloat value); typedef void (GLAD_API_PTR *PFNGLACTIVETEXTUREPROC)(GLenum texture); typedef void (GLAD_API_PTR *PFNGLALPHAFUNCPROC)(GLenum func, GLfloat ref); typedef GLboolean (GLAD_API_PTR *PFNGLARETEXTURESRESIDENTPROC)(GLsizei n, const GLuint * textures, GLboolean * residences); typedef void (GLAD_API_PTR *PFNGLARRAYELEMENTPROC)(GLint i); typedef void (GLAD_API_PTR *PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader); typedef void (GLAD_API_PTR *PFNGLBEGINPROC)(GLenum mode); typedef void (GLAD_API_PTR *PFNGLBEGINCONDITIONALRENDERPROC)(GLuint id, GLenum mode); typedef void (GLAD_API_PTR *PFNGLBEGINQUERYPROC)(GLenum target, GLuint id); typedef void (GLAD_API_PTR *PFNGLBEGINTRANSFORMFEEDBACKPROC)(GLenum primitiveMode); typedef void (GLAD_API_PTR *PFNGLBINDATTRIBLOCATIONPROC)(GLuint program, GLuint index, const GLchar * name); typedef void (GLAD_API_PTR *PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer); typedef void (GLAD_API_PTR *PFNGLBINDBUFFERBASEPROC)(GLenum target, GLuint index, GLuint buffer); typedef void (GLAD_API_PTR *PFNGLBINDBUFFERRANGEPROC)(GLenum target, GLuint index, GLuint buffer, GLintptr offset, GLsizeiptr size); typedef void (GLAD_API_PTR *PFNGLBINDFRAGDATALOCATIONPROC)(GLuint program, GLuint color, const GLchar * name); typedef void (GLAD_API_PTR *PFNGLBINDFRAMEBUFFERPROC)(GLenum target, GLuint framebuffer); typedef void (GLAD_API_PTR *PFNGLBINDRENDERBUFFERPROC)(GLenum target, GLuint renderbuffer); typedef void (GLAD_API_PTR *PFNGLBINDTEXTUREPROC)(GLenum target, GLuint texture); typedef void (GLAD_API_PTR *PFNGLBINDVERTEXARRAYPROC)(GLuint array); typedef void (GLAD_API_PTR *PFNGLBITMAPPROC)(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte * bitmap); typedef void (GLAD_API_PTR *PFNGLBLENDCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONPROC)(GLenum mode); typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEPROC)(GLenum modeRGB, GLenum modeAlpha); typedef void (GLAD_API_PTR *PFNGLBLENDFUNCPROC)(GLenum sfactor, GLenum dfactor); typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEPROC)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha); typedef void (GLAD_API_PTR *PFNGLBLITFRAMEBUFFERPROC)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter); typedef void (GLAD_API_PTR *PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void * data, GLenum usage); typedef void (GLAD_API_PTR *PFNGLBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, const void * data); typedef void (GLAD_API_PTR *PFNGLCALLLISTPROC)(GLuint list); typedef void (GLAD_API_PTR *PFNGLCALLLISTSPROC)(GLsizei n, GLenum type, const void * lists); typedef GLenum (GLAD_API_PTR *PFNGLCHECKFRAMEBUFFERSTATUSPROC)(GLenum target); typedef void (GLAD_API_PTR *PFNGLCLAMPCOLORPROC)(GLenum target, GLenum clamp); typedef void (GLAD_API_PTR *PFNGLCLEARPROC)(GLbitfield mask); typedef void (GLAD_API_PTR *PFNGLCLEARACCUMPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERFIPROC)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil); typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERFVPROC)(GLenum buffer, GLint drawbuffer, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERIVPROC)(GLenum buffer, GLint drawbuffer, const GLint * value); typedef void (GLAD_API_PTR *PFNGLCLEARBUFFERUIVPROC)(GLenum buffer, GLint drawbuffer, const GLuint * value); typedef void (GLAD_API_PTR *PFNGLCLEARCOLORPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); typedef void (GLAD_API_PTR *PFNGLCLEARDEPTHPROC)(GLdouble depth); typedef void (GLAD_API_PTR *PFNGLCLEARINDEXPROC)(GLfloat c); typedef void (GLAD_API_PTR *PFNGLCLEARSTENCILPROC)(GLint s); typedef void (GLAD_API_PTR *PFNGLCLIENTACTIVETEXTUREPROC)(GLenum texture); typedef void (GLAD_API_PTR *PFNGLCLIPPLANEPROC)(GLenum plane, const GLdouble * equation); typedef void (GLAD_API_PTR *PFNGLCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue); typedef void (GLAD_API_PTR *PFNGLCOLOR3BVPROC)(const GLbyte * v); typedef void (GLAD_API_PTR *PFNGLCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue); typedef void (GLAD_API_PTR *PFNGLCOLOR3DVPROC)(const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue); typedef void (GLAD_API_PTR *PFNGLCOLOR3FVPROC)(const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLCOLOR3IPROC)(GLint red, GLint green, GLint blue); typedef void (GLAD_API_PTR *PFNGLCOLOR3IVPROC)(const GLint * v); typedef void (GLAD_API_PTR *PFNGLCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue); typedef void (GLAD_API_PTR *PFNGLCOLOR3SVPROC)(const GLshort * v); typedef void (GLAD_API_PTR *PFNGLCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue); typedef void (GLAD_API_PTR *PFNGLCOLOR3UBVPROC)(const GLubyte * v); typedef void (GLAD_API_PTR *PFNGLCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue); typedef void (GLAD_API_PTR *PFNGLCOLOR3UIVPROC)(const GLuint * v); typedef void (GLAD_API_PTR *PFNGLCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue); typedef void (GLAD_API_PTR *PFNGLCOLOR3USVPROC)(const GLushort * v); typedef void (GLAD_API_PTR *PFNGLCOLOR4BPROC)(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); typedef void (GLAD_API_PTR *PFNGLCOLOR4BVPROC)(const GLbyte * v); typedef void (GLAD_API_PTR *PFNGLCOLOR4DPROC)(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); typedef void (GLAD_API_PTR *PFNGLCOLOR4DVPROC)(const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLCOLOR4FPROC)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); typedef void (GLAD_API_PTR *PFNGLCOLOR4FVPROC)(const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLCOLOR4IPROC)(GLint red, GLint green, GLint blue, GLint alpha); typedef void (GLAD_API_PTR *PFNGLCOLOR4IVPROC)(const GLint * v); typedef void (GLAD_API_PTR *PFNGLCOLOR4SPROC)(GLshort red, GLshort green, GLshort blue, GLshort alpha); typedef void (GLAD_API_PTR *PFNGLCOLOR4SVPROC)(const GLshort * v); typedef void (GLAD_API_PTR *PFNGLCOLOR4UBPROC)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); typedef void (GLAD_API_PTR *PFNGLCOLOR4UBVPROC)(const GLubyte * v); typedef void (GLAD_API_PTR *PFNGLCOLOR4UIPROC)(GLuint red, GLuint green, GLuint blue, GLuint alpha); typedef void (GLAD_API_PTR *PFNGLCOLOR4UIVPROC)(const GLuint * v); typedef void (GLAD_API_PTR *PFNGLCOLOR4USPROC)(GLushort red, GLushort green, GLushort blue, GLushort alpha); typedef void (GLAD_API_PTR *PFNGLCOLOR4USVPROC)(const GLushort * v); typedef void (GLAD_API_PTR *PFNGLCOLORMASKPROC)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); typedef void (GLAD_API_PTR *PFNGLCOLORMASKIPROC)(GLuint index, GLboolean r, GLboolean g, GLboolean b, GLboolean a); typedef void (GLAD_API_PTR *PFNGLCOLORMATERIALPROC)(GLenum face, GLenum mode); typedef void (GLAD_API_PTR *PFNGLCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void * pointer); typedef void (GLAD_API_PTR *PFNGLCOMPILESHADERPROC)(GLuint shader); typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const void * data); typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data); typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXIMAGE3DPROC)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data); typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const void * data); typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void * data); typedef void (GLAD_API_PTR *PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void * data); typedef void (GLAD_API_PTR *PFNGLCOPYPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE1DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLint border); typedef void (GLAD_API_PTR *PFNGLCOPYTEXIMAGE2DPROC)(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef void (GLAD_API_PTR *PFNGLCOPYTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); typedef GLuint (GLAD_API_PTR *PFNGLCREATEPROGRAMPROC)(void); typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROC)(GLenum type); typedef void (GLAD_API_PTR *PFNGLCULLFACEPROC)(GLenum mode); typedef void (GLAD_API_PTR *PFNGLDELETEBUFFERSPROC)(GLsizei n, const GLuint * buffers); typedef void (GLAD_API_PTR *PFNGLDELETEFRAMEBUFFERSPROC)(GLsizei n, const GLuint * framebuffers); typedef void (GLAD_API_PTR *PFNGLDELETELISTSPROC)(GLuint list, GLsizei range); typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPROC)(GLuint program); typedef void (GLAD_API_PTR *PFNGLDELETEQUERIESPROC)(GLsizei n, const GLuint * ids); typedef void (GLAD_API_PTR *PFNGLDELETERENDERBUFFERSPROC)(GLsizei n, const GLuint * renderbuffers); typedef void (GLAD_API_PTR *PFNGLDELETESHADERPROC)(GLuint shader); typedef void (GLAD_API_PTR *PFNGLDELETETEXTURESPROC)(GLsizei n, const GLuint * textures); typedef void (GLAD_API_PTR *PFNGLDELETEVERTEXARRAYSPROC)(GLsizei n, const GLuint * arrays); typedef void (GLAD_API_PTR *PFNGLDEPTHFUNCPROC)(GLenum func); typedef void (GLAD_API_PTR *PFNGLDEPTHMASKPROC)(GLboolean flag); typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEPROC)(GLdouble n, GLdouble f); typedef void (GLAD_API_PTR *PFNGLDETACHSHADERPROC)(GLuint program, GLuint shader); typedef void (GLAD_API_PTR *PFNGLDISABLEPROC)(GLenum cap); typedef void (GLAD_API_PTR *PFNGLDISABLECLIENTSTATEPROC)(GLenum array); typedef void (GLAD_API_PTR *PFNGLDISABLEVERTEXATTRIBARRAYPROC)(GLuint index); typedef void (GLAD_API_PTR *PFNGLDISABLEIPROC)(GLenum target, GLuint index); typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSPROC)(GLenum mode, GLint first, GLsizei count); typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERPROC)(GLenum buf); typedef void (GLAD_API_PTR *PFNGLDRAWBUFFERSPROC)(GLsizei n, const GLenum * bufs); typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSPROC)(GLenum mode, GLsizei count, GLenum type, const void * indices); typedef void (GLAD_API_PTR *PFNGLDRAWPIXELSPROC)(GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels); typedef void (GLAD_API_PTR *PFNGLDRAWRANGEELEMENTSPROC)(GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const void * indices); typedef void (GLAD_API_PTR *PFNGLEDGEFLAGPROC)(GLboolean flag); typedef void (GLAD_API_PTR *PFNGLEDGEFLAGPOINTERPROC)(GLsizei stride, const void * pointer); typedef void (GLAD_API_PTR *PFNGLEDGEFLAGVPROC)(const GLboolean * flag); typedef void (GLAD_API_PTR *PFNGLENABLEPROC)(GLenum cap); typedef void (GLAD_API_PTR *PFNGLENABLECLIENTSTATEPROC)(GLenum array); typedef void (GLAD_API_PTR *PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index); typedef void (GLAD_API_PTR *PFNGLENABLEIPROC)(GLenum target, GLuint index); typedef void (GLAD_API_PTR *PFNGLENDPROC)(void); typedef void (GLAD_API_PTR *PFNGLENDCONDITIONALRENDERPROC)(void); typedef void (GLAD_API_PTR *PFNGLENDLISTPROC)(void); typedef void (GLAD_API_PTR *PFNGLENDQUERYPROC)(GLenum target); typedef void (GLAD_API_PTR *PFNGLENDTRANSFORMFEEDBACKPROC)(void); typedef void (GLAD_API_PTR *PFNGLEVALCOORD1DPROC)(GLdouble u); typedef void (GLAD_API_PTR *PFNGLEVALCOORD1DVPROC)(const GLdouble * u); typedef void (GLAD_API_PTR *PFNGLEVALCOORD1FPROC)(GLfloat u); typedef void (GLAD_API_PTR *PFNGLEVALCOORD1FVPROC)(const GLfloat * u); typedef void (GLAD_API_PTR *PFNGLEVALCOORD2DPROC)(GLdouble u, GLdouble v); typedef void (GLAD_API_PTR *PFNGLEVALCOORD2DVPROC)(const GLdouble * u); typedef void (GLAD_API_PTR *PFNGLEVALCOORD2FPROC)(GLfloat u, GLfloat v); typedef void (GLAD_API_PTR *PFNGLEVALCOORD2FVPROC)(const GLfloat * u); typedef void (GLAD_API_PTR *PFNGLEVALMESH1PROC)(GLenum mode, GLint i1, GLint i2); typedef void (GLAD_API_PTR *PFNGLEVALMESH2PROC)(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); typedef void (GLAD_API_PTR *PFNGLEVALPOINT1PROC)(GLint i); typedef void (GLAD_API_PTR *PFNGLEVALPOINT2PROC)(GLint i, GLint j); typedef void (GLAD_API_PTR *PFNGLFEEDBACKBUFFERPROC)(GLsizei size, GLenum type, GLfloat * buffer); typedef void (GLAD_API_PTR *PFNGLFINISHPROC)(void); typedef void (GLAD_API_PTR *PFNGLFLUSHPROC)(void); typedef void (GLAD_API_PTR *PFNGLFLUSHMAPPEDBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length); typedef void (GLAD_API_PTR *PFNGLFOGCOORDPOINTERPROC)(GLenum type, GLsizei stride, const void * pointer); typedef void (GLAD_API_PTR *PFNGLFOGCOORDDPROC)(GLdouble coord); typedef void (GLAD_API_PTR *PFNGLFOGCOORDDVPROC)(const GLdouble * coord); typedef void (GLAD_API_PTR *PFNGLFOGCOORDFPROC)(GLfloat coord); typedef void (GLAD_API_PTR *PFNGLFOGCOORDFVPROC)(const GLfloat * coord); typedef void (GLAD_API_PTR *PFNGLFOGFPROC)(GLenum pname, GLfloat param); typedef void (GLAD_API_PTR *PFNGLFOGFVPROC)(GLenum pname, const GLfloat * params); typedef void (GLAD_API_PTR *PFNGLFOGIPROC)(GLenum pname, GLint param); typedef void (GLAD_API_PTR *PFNGLFOGIVPROC)(GLenum pname, const GLint * params); typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERRENDERBUFFERPROC)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE1DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE2DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURE3DPROC)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERTEXTURELAYERPROC)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer); typedef void (GLAD_API_PTR *PFNGLFRONTFACEPROC)(GLenum mode); typedef void (GLAD_API_PTR *PFNGLFRUSTUMPROC)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); typedef void (GLAD_API_PTR *PFNGLGENBUFFERSPROC)(GLsizei n, GLuint * buffers); typedef void (GLAD_API_PTR *PFNGLGENFRAMEBUFFERSPROC)(GLsizei n, GLuint * framebuffers); typedef GLuint (GLAD_API_PTR *PFNGLGENLISTSPROC)(GLsizei range); typedef void (GLAD_API_PTR *PFNGLGENQUERIESPROC)(GLsizei n, GLuint * ids); typedef void (GLAD_API_PTR *PFNGLGENRENDERBUFFERSPROC)(GLsizei n, GLuint * renderbuffers); typedef void (GLAD_API_PTR *PFNGLGENTEXTURESPROC)(GLsizei n, GLuint * textures); typedef void (GLAD_API_PTR *PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint * arrays); typedef void (GLAD_API_PTR *PFNGLGENERATEMIPMAPPROC)(GLenum target); typedef void (GLAD_API_PTR *PFNGLGETACTIVEATTRIBPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name); typedef void (GLAD_API_PTR *PFNGLGETACTIVEUNIFORMPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLint * size, GLenum * type, GLchar * name); typedef void (GLAD_API_PTR *PFNGLGETATTACHEDSHADERSPROC)(GLuint program, GLsizei maxCount, GLsizei * count, GLuint * shaders); typedef GLint (GLAD_API_PTR *PFNGLGETATTRIBLOCATIONPROC)(GLuint program, const GLchar * name); typedef void (GLAD_API_PTR *PFNGLGETBOOLEANI_VPROC)(GLenum target, GLuint index, GLboolean * data); typedef void (GLAD_API_PTR *PFNGLGETBOOLEANVPROC)(GLenum pname, GLboolean * data); typedef void (GLAD_API_PTR *PFNGLGETBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETBUFFERPOINTERVPROC)(GLenum target, GLenum pname, void ** params); typedef void (GLAD_API_PTR *PFNGLGETBUFFERSUBDATAPROC)(GLenum target, GLintptr offset, GLsizeiptr size, void * data); typedef void (GLAD_API_PTR *PFNGLGETCLIPPLANEPROC)(GLenum plane, GLdouble * equation); typedef void (GLAD_API_PTR *PFNGLGETCOMPRESSEDTEXIMAGEPROC)(GLenum target, GLint level, void * img); typedef void (GLAD_API_PTR *PFNGLGETDOUBLEVPROC)(GLenum pname, GLdouble * data); typedef GLenum (GLAD_API_PTR *PFNGLGETERRORPROC)(void); typedef void (GLAD_API_PTR *PFNGLGETFLOATVPROC)(GLenum pname, GLfloat * data); typedef GLint (GLAD_API_PTR *PFNGLGETFRAGDATALOCATIONPROC)(GLuint program, const GLchar * name); typedef void (GLAD_API_PTR *PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)(GLenum target, GLenum attachment, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETINTEGERI_VPROC)(GLenum target, GLuint index, GLint * data); typedef void (GLAD_API_PTR *PFNGLGETINTEGERVPROC)(GLenum pname, GLint * data); typedef void (GLAD_API_PTR *PFNGLGETLIGHTFVPROC)(GLenum light, GLenum pname, GLfloat * params); typedef void (GLAD_API_PTR *PFNGLGETLIGHTIVPROC)(GLenum light, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETMAPDVPROC)(GLenum target, GLenum query, GLdouble * v); typedef void (GLAD_API_PTR *PFNGLGETMAPFVPROC)(GLenum target, GLenum query, GLfloat * v); typedef void (GLAD_API_PTR *PFNGLGETMAPIVPROC)(GLenum target, GLenum query, GLint * v); typedef void (GLAD_API_PTR *PFNGLGETMATERIALFVPROC)(GLenum face, GLenum pname, GLfloat * params); typedef void (GLAD_API_PTR *PFNGLGETMATERIALIVPROC)(GLenum face, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETPIXELMAPFVPROC)(GLenum map, GLfloat * values); typedef void (GLAD_API_PTR *PFNGLGETPIXELMAPUIVPROC)(GLenum map, GLuint * values); typedef void (GLAD_API_PTR *PFNGLGETPIXELMAPUSVPROC)(GLenum map, GLushort * values); typedef void (GLAD_API_PTR *PFNGLGETPOINTERVPROC)(GLenum pname, void ** params); typedef void (GLAD_API_PTR *PFNGLGETPOLYGONSTIPPLEPROC)(GLubyte * mask); typedef void (GLAD_API_PTR *PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog); typedef void (GLAD_API_PTR *PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTIVPROC)(GLuint id, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETQUERYOBJECTUIVPROC)(GLuint id, GLenum pname, GLuint * params); typedef void (GLAD_API_PTR *PFNGLGETQUERYIVPROC)(GLenum target, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETRENDERBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog); typedef void (GLAD_API_PTR *PFNGLGETSHADERSOURCEPROC)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * source); typedef void (GLAD_API_PTR *PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint * params); typedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGPROC)(GLenum name); typedef const GLubyte * (GLAD_API_PTR *PFNGLGETSTRINGIPROC)(GLenum name, GLuint index); typedef void (GLAD_API_PTR *PFNGLGETTEXENVFVPROC)(GLenum target, GLenum pname, GLfloat * params); typedef void (GLAD_API_PTR *PFNGLGETTEXENVIVPROC)(GLenum target, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETTEXGENDVPROC)(GLenum coord, GLenum pname, GLdouble * params); typedef void (GLAD_API_PTR *PFNGLGETTEXGENFVPROC)(GLenum coord, GLenum pname, GLfloat * params); typedef void (GLAD_API_PTR *PFNGLGETTEXGENIVPROC)(GLenum coord, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETTEXIMAGEPROC)(GLenum target, GLint level, GLenum format, GLenum type, void * pixels); typedef void (GLAD_API_PTR *PFNGLGETTEXLEVELPARAMETERFVPROC)(GLenum target, GLint level, GLenum pname, GLfloat * params); typedef void (GLAD_API_PTR *PFNGLGETTEXLEVELPARAMETERIVPROC)(GLenum target, GLint level, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, GLuint * params); typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERFVPROC)(GLenum target, GLenum pname, GLfloat * params); typedef void (GLAD_API_PTR *PFNGLGETTEXPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETTRANSFORMFEEDBACKVARYINGPROC)(GLuint program, GLuint index, GLsizei bufSize, GLsizei * length, GLsizei * size, GLenum * type, GLchar * name); typedef GLint (GLAD_API_PTR *PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar * name); typedef void (GLAD_API_PTR *PFNGLGETUNIFORMFVPROC)(GLuint program, GLint location, GLfloat * params); typedef void (GLAD_API_PTR *PFNGLGETUNIFORMIVPROC)(GLuint program, GLint location, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETUNIFORMUIVPROC)(GLuint program, GLint location, GLuint * params); typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIIVPROC)(GLuint index, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIUIVPROC)(GLuint index, GLenum pname, GLuint * params); typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBPOINTERVPROC)(GLuint index, GLenum pname, void ** pointer); typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBDVPROC)(GLuint index, GLenum pname, GLdouble * params); typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBFVPROC)(GLuint index, GLenum pname, GLfloat * params); typedef void (GLAD_API_PTR *PFNGLGETVERTEXATTRIBIVPROC)(GLuint index, GLenum pname, GLint * params); typedef void (GLAD_API_PTR *PFNGLHINTPROC)(GLenum target, GLenum mode); typedef void (GLAD_API_PTR *PFNGLINDEXMASKPROC)(GLuint mask); typedef void (GLAD_API_PTR *PFNGLINDEXPOINTERPROC)(GLenum type, GLsizei stride, const void * pointer); typedef void (GLAD_API_PTR *PFNGLINDEXDPROC)(GLdouble c); typedef void (GLAD_API_PTR *PFNGLINDEXDVPROC)(const GLdouble * c); typedef void (GLAD_API_PTR *PFNGLINDEXFPROC)(GLfloat c); typedef void (GLAD_API_PTR *PFNGLINDEXFVPROC)(const GLfloat * c); typedef void (GLAD_API_PTR *PFNGLINDEXIPROC)(GLint c); typedef void (GLAD_API_PTR *PFNGLINDEXIVPROC)(const GLint * c); typedef void (GLAD_API_PTR *PFNGLINDEXSPROC)(GLshort c); typedef void (GLAD_API_PTR *PFNGLINDEXSVPROC)(const GLshort * c); typedef void (GLAD_API_PTR *PFNGLINDEXUBPROC)(GLubyte c); typedef void (GLAD_API_PTR *PFNGLINDEXUBVPROC)(const GLubyte * c); typedef void (GLAD_API_PTR *PFNGLINITNAMESPROC)(void); typedef void (GLAD_API_PTR *PFNGLINTERLEAVEDARRAYSPROC)(GLenum format, GLsizei stride, const void * pointer); typedef GLboolean (GLAD_API_PTR *PFNGLISBUFFERPROC)(GLuint buffer); typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDPROC)(GLenum cap); typedef GLboolean (GLAD_API_PTR *PFNGLISENABLEDIPROC)(GLenum target, GLuint index); typedef GLboolean (GLAD_API_PTR *PFNGLISFRAMEBUFFERPROC)(GLuint framebuffer); typedef GLboolean (GLAD_API_PTR *PFNGLISLISTPROC)(GLuint list); typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPROC)(GLuint program); typedef GLboolean (GLAD_API_PTR *PFNGLISQUERYPROC)(GLuint id); typedef GLboolean (GLAD_API_PTR *PFNGLISRENDERBUFFERPROC)(GLuint renderbuffer); typedef GLboolean (GLAD_API_PTR *PFNGLISSHADERPROC)(GLuint shader); typedef GLboolean (GLAD_API_PTR *PFNGLISTEXTUREPROC)(GLuint texture); typedef GLboolean (GLAD_API_PTR *PFNGLISVERTEXARRAYPROC)(GLuint array); typedef void (GLAD_API_PTR *PFNGLLIGHTMODELFPROC)(GLenum pname, GLfloat param); typedef void (GLAD_API_PTR *PFNGLLIGHTMODELFVPROC)(GLenum pname, const GLfloat * params); typedef void (GLAD_API_PTR *PFNGLLIGHTMODELIPROC)(GLenum pname, GLint param); typedef void (GLAD_API_PTR *PFNGLLIGHTMODELIVPROC)(GLenum pname, const GLint * params); typedef void (GLAD_API_PTR *PFNGLLIGHTFPROC)(GLenum light, GLenum pname, GLfloat param); typedef void (GLAD_API_PTR *PFNGLLIGHTFVPROC)(GLenum light, GLenum pname, const GLfloat * params); typedef void (GLAD_API_PTR *PFNGLLIGHTIPROC)(GLenum light, GLenum pname, GLint param); typedef void (GLAD_API_PTR *PFNGLLIGHTIVPROC)(GLenum light, GLenum pname, const GLint * params); typedef void (GLAD_API_PTR *PFNGLLINESTIPPLEPROC)(GLint factor, GLushort pattern); typedef void (GLAD_API_PTR *PFNGLLINEWIDTHPROC)(GLfloat width); typedef void (GLAD_API_PTR *PFNGLLINKPROGRAMPROC)(GLuint program); typedef void (GLAD_API_PTR *PFNGLLISTBASEPROC)(GLuint base); typedef void (GLAD_API_PTR *PFNGLLOADIDENTITYPROC)(void); typedef void (GLAD_API_PTR *PFNGLLOADMATRIXDPROC)(const GLdouble * m); typedef void (GLAD_API_PTR *PFNGLLOADMATRIXFPROC)(const GLfloat * m); typedef void (GLAD_API_PTR *PFNGLLOADNAMEPROC)(GLuint name); typedef void (GLAD_API_PTR *PFNGLLOADTRANSPOSEMATRIXDPROC)(const GLdouble * m); typedef void (GLAD_API_PTR *PFNGLLOADTRANSPOSEMATRIXFPROC)(const GLfloat * m); typedef void (GLAD_API_PTR *PFNGLLOGICOPPROC)(GLenum opcode); typedef void (GLAD_API_PTR *PFNGLMAP1DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble * points); typedef void (GLAD_API_PTR *PFNGLMAP1FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat * points); typedef void (GLAD_API_PTR *PFNGLMAP2DPROC)(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble * points); typedef void (GLAD_API_PTR *PFNGLMAP2FPROC)(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat * points); typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERPROC)(GLenum target, GLenum access); typedef void * (GLAD_API_PTR *PFNGLMAPBUFFERRANGEPROC)(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access); typedef void (GLAD_API_PTR *PFNGLMAPGRID1DPROC)(GLint un, GLdouble u1, GLdouble u2); typedef void (GLAD_API_PTR *PFNGLMAPGRID1FPROC)(GLint un, GLfloat u1, GLfloat u2); typedef void (GLAD_API_PTR *PFNGLMAPGRID2DPROC)(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); typedef void (GLAD_API_PTR *PFNGLMAPGRID2FPROC)(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); typedef void (GLAD_API_PTR *PFNGLMATERIALFPROC)(GLenum face, GLenum pname, GLfloat param); typedef void (GLAD_API_PTR *PFNGLMATERIALFVPROC)(GLenum face, GLenum pname, const GLfloat * params); typedef void (GLAD_API_PTR *PFNGLMATERIALIPROC)(GLenum face, GLenum pname, GLint param); typedef void (GLAD_API_PTR *PFNGLMATERIALIVPROC)(GLenum face, GLenum pname, const GLint * params); typedef void (GLAD_API_PTR *PFNGLMATRIXMODEPROC)(GLenum mode); typedef void (GLAD_API_PTR *PFNGLMULTMATRIXDPROC)(const GLdouble * m); typedef void (GLAD_API_PTR *PFNGLMULTMATRIXFPROC)(const GLfloat * m); typedef void (GLAD_API_PTR *PFNGLMULTTRANSPOSEMATRIXDPROC)(const GLdouble * m); typedef void (GLAD_API_PTR *PFNGLMULTTRANSPOSEMATRIXFPROC)(const GLfloat * m); typedef void (GLAD_API_PTR *PFNGLMULTIDRAWARRAYSPROC)(GLenum mode, const GLint * first, const GLsizei * count, GLsizei drawcount); typedef void (GLAD_API_PTR *PFNGLMULTIDRAWELEMENTSPROC)(GLenum mode, const GLsizei * count, GLenum type, const void *const* indices, GLsizei drawcount); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1DPROC)(GLenum target, GLdouble s); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1DVPROC)(GLenum target, const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1FPROC)(GLenum target, GLfloat s); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1FVPROC)(GLenum target, const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1IPROC)(GLenum target, GLint s); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1IVPROC)(GLenum target, const GLint * v); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1SPROC)(GLenum target, GLshort s); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD1SVPROC)(GLenum target, const GLshort * v); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2DPROC)(GLenum target, GLdouble s, GLdouble t); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2DVPROC)(GLenum target, const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2FPROC)(GLenum target, GLfloat s, GLfloat t); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2FVPROC)(GLenum target, const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2IPROC)(GLenum target, GLint s, GLint t); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2IVPROC)(GLenum target, const GLint * v); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2SPROC)(GLenum target, GLshort s, GLshort t); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD2SVPROC)(GLenum target, const GLshort * v); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3DPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3DVPROC)(GLenum target, const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3FPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3FVPROC)(GLenum target, const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3IPROC)(GLenum target, GLint s, GLint t, GLint r); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3IVPROC)(GLenum target, const GLint * v); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3SPROC)(GLenum target, GLshort s, GLshort t, GLshort r); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD3SVPROC)(GLenum target, const GLshort * v); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4DPROC)(GLenum target, GLdouble s, GLdouble t, GLdouble r, GLdouble q); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4DVPROC)(GLenum target, const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4FPROC)(GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4FVPROC)(GLenum target, const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4IPROC)(GLenum target, GLint s, GLint t, GLint r, GLint q); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4IVPROC)(GLenum target, const GLint * v); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4SPROC)(GLenum target, GLshort s, GLshort t, GLshort r, GLshort q); typedef void (GLAD_API_PTR *PFNGLMULTITEXCOORD4SVPROC)(GLenum target, const GLshort * v); typedef void (GLAD_API_PTR *PFNGLNEWLISTPROC)(GLuint list, GLenum mode); typedef void (GLAD_API_PTR *PFNGLNORMAL3BPROC)(GLbyte nx, GLbyte ny, GLbyte nz); typedef void (GLAD_API_PTR *PFNGLNORMAL3BVPROC)(const GLbyte * v); typedef void (GLAD_API_PTR *PFNGLNORMAL3DPROC)(GLdouble nx, GLdouble ny, GLdouble nz); typedef void (GLAD_API_PTR *PFNGLNORMAL3DVPROC)(const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLNORMAL3FPROC)(GLfloat nx, GLfloat ny, GLfloat nz); typedef void (GLAD_API_PTR *PFNGLNORMAL3FVPROC)(const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLNORMAL3IPROC)(GLint nx, GLint ny, GLint nz); typedef void (GLAD_API_PTR *PFNGLNORMAL3IVPROC)(const GLint * v); typedef void (GLAD_API_PTR *PFNGLNORMAL3SPROC)(GLshort nx, GLshort ny, GLshort nz); typedef void (GLAD_API_PTR *PFNGLNORMAL3SVPROC)(const GLshort * v); typedef void (GLAD_API_PTR *PFNGLNORMALPOINTERPROC)(GLenum type, GLsizei stride, const void * pointer); typedef void (GLAD_API_PTR *PFNGLORTHOPROC)(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); typedef void (GLAD_API_PTR *PFNGLPASSTHROUGHPROC)(GLfloat token); typedef void (GLAD_API_PTR *PFNGLPIXELMAPFVPROC)(GLenum map, GLsizei mapsize, const GLfloat * values); typedef void (GLAD_API_PTR *PFNGLPIXELMAPUIVPROC)(GLenum map, GLsizei mapsize, const GLuint * values); typedef void (GLAD_API_PTR *PFNGLPIXELMAPUSVPROC)(GLenum map, GLsizei mapsize, const GLushort * values); typedef void (GLAD_API_PTR *PFNGLPIXELSTOREFPROC)(GLenum pname, GLfloat param); typedef void (GLAD_API_PTR *PFNGLPIXELSTOREIPROC)(GLenum pname, GLint param); typedef void (GLAD_API_PTR *PFNGLPIXELTRANSFERFPROC)(GLenum pname, GLfloat param); typedef void (GLAD_API_PTR *PFNGLPIXELTRANSFERIPROC)(GLenum pname, GLint param); typedef void (GLAD_API_PTR *PFNGLPIXELZOOMPROC)(GLfloat xfactor, GLfloat yfactor); typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERFPROC)(GLenum pname, GLfloat param); typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERFVPROC)(GLenum pname, const GLfloat * params); typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERIPROC)(GLenum pname, GLint param); typedef void (GLAD_API_PTR *PFNGLPOINTPARAMETERIVPROC)(GLenum pname, const GLint * params); typedef void (GLAD_API_PTR *PFNGLPOINTSIZEPROC)(GLfloat size); typedef void (GLAD_API_PTR *PFNGLPOLYGONMODEPROC)(GLenum face, GLenum mode); typedef void (GLAD_API_PTR *PFNGLPOLYGONOFFSETPROC)(GLfloat factor, GLfloat units); typedef void (GLAD_API_PTR *PFNGLPOLYGONSTIPPLEPROC)(const GLubyte * mask); typedef void (GLAD_API_PTR *PFNGLPOPATTRIBPROC)(void); typedef void (GLAD_API_PTR *PFNGLPOPCLIENTATTRIBPROC)(void); typedef void (GLAD_API_PTR *PFNGLPOPMATRIXPROC)(void); typedef void (GLAD_API_PTR *PFNGLPOPNAMEPROC)(void); typedef void (GLAD_API_PTR *PFNGLPRIORITIZETEXTURESPROC)(GLsizei n, const GLuint * textures, const GLfloat * priorities); typedef void (GLAD_API_PTR *PFNGLPUSHATTRIBPROC)(GLbitfield mask); typedef void (GLAD_API_PTR *PFNGLPUSHCLIENTATTRIBPROC)(GLbitfield mask); typedef void (GLAD_API_PTR *PFNGLPUSHMATRIXPROC)(void); typedef void (GLAD_API_PTR *PFNGLPUSHNAMEPROC)(GLuint name); typedef void (GLAD_API_PTR *PFNGLRASTERPOS2DPROC)(GLdouble x, GLdouble y); typedef void (GLAD_API_PTR *PFNGLRASTERPOS2DVPROC)(const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLRASTERPOS2FPROC)(GLfloat x, GLfloat y); typedef void (GLAD_API_PTR *PFNGLRASTERPOS2FVPROC)(const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLRASTERPOS2IPROC)(GLint x, GLint y); typedef void (GLAD_API_PTR *PFNGLRASTERPOS2IVPROC)(const GLint * v); typedef void (GLAD_API_PTR *PFNGLRASTERPOS2SPROC)(GLshort x, GLshort y); typedef void (GLAD_API_PTR *PFNGLRASTERPOS2SVPROC)(const GLshort * v); typedef void (GLAD_API_PTR *PFNGLRASTERPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z); typedef void (GLAD_API_PTR *PFNGLRASTERPOS3DVPROC)(const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLRASTERPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z); typedef void (GLAD_API_PTR *PFNGLRASTERPOS3FVPROC)(const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLRASTERPOS3IPROC)(GLint x, GLint y, GLint z); typedef void (GLAD_API_PTR *PFNGLRASTERPOS3IVPROC)(const GLint * v); typedef void (GLAD_API_PTR *PFNGLRASTERPOS3SPROC)(GLshort x, GLshort y, GLshort z); typedef void (GLAD_API_PTR *PFNGLRASTERPOS3SVPROC)(const GLshort * v); typedef void (GLAD_API_PTR *PFNGLRASTERPOS4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (GLAD_API_PTR *PFNGLRASTERPOS4DVPROC)(const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLRASTERPOS4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (GLAD_API_PTR *PFNGLRASTERPOS4FVPROC)(const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLRASTERPOS4IPROC)(GLint x, GLint y, GLint z, GLint w); typedef void (GLAD_API_PTR *PFNGLRASTERPOS4IVPROC)(const GLint * v); typedef void (GLAD_API_PTR *PFNGLRASTERPOS4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w); typedef void (GLAD_API_PTR *PFNGLRASTERPOS4SVPROC)(const GLshort * v); typedef void (GLAD_API_PTR *PFNGLREADBUFFERPROC)(GLenum src); typedef void (GLAD_API_PTR *PFNGLREADPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * pixels); typedef void (GLAD_API_PTR *PFNGLRECTDPROC)(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); typedef void (GLAD_API_PTR *PFNGLRECTDVPROC)(const GLdouble * v1, const GLdouble * v2); typedef void (GLAD_API_PTR *PFNGLRECTFPROC)(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); typedef void (GLAD_API_PTR *PFNGLRECTFVPROC)(const GLfloat * v1, const GLfloat * v2); typedef void (GLAD_API_PTR *PFNGLRECTIPROC)(GLint x1, GLint y1, GLint x2, GLint y2); typedef void (GLAD_API_PTR *PFNGLRECTIVPROC)(const GLint * v1, const GLint * v2); typedef void (GLAD_API_PTR *PFNGLRECTSPROC)(GLshort x1, GLshort y1, GLshort x2, GLshort y2); typedef void (GLAD_API_PTR *PFNGLRECTSVPROC)(const GLshort * v1, const GLshort * v2); typedef GLint (GLAD_API_PTR *PFNGLRENDERMODEPROC)(GLenum mode); typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEPROC)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GLAD_API_PTR *PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height); typedef void (GLAD_API_PTR *PFNGLROTATEDPROC)(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); typedef void (GLAD_API_PTR *PFNGLROTATEFPROC)(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); typedef void (GLAD_API_PTR *PFNGLSAMPLECOVERAGEPROC)(GLfloat value, GLboolean invert); typedef void (GLAD_API_PTR *PFNGLSCALEDPROC)(GLdouble x, GLdouble y, GLdouble z); typedef void (GLAD_API_PTR *PFNGLSCALEFPROC)(GLfloat x, GLfloat y, GLfloat z); typedef void (GLAD_API_PTR *PFNGLSCISSORPROC)(GLint x, GLint y, GLsizei width, GLsizei height); typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3BPROC)(GLbyte red, GLbyte green, GLbyte blue); typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3BVPROC)(const GLbyte * v); typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3DPROC)(GLdouble red, GLdouble green, GLdouble blue); typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3DVPROC)(const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3FPROC)(GLfloat red, GLfloat green, GLfloat blue); typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3FVPROC)(const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3IPROC)(GLint red, GLint green, GLint blue); typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3IVPROC)(const GLint * v); typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3SPROC)(GLshort red, GLshort green, GLshort blue); typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3SVPROC)(const GLshort * v); typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3UBPROC)(GLubyte red, GLubyte green, GLubyte blue); typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3UBVPROC)(const GLubyte * v); typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3UIPROC)(GLuint red, GLuint green, GLuint blue); typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3UIVPROC)(const GLuint * v); typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3USPROC)(GLushort red, GLushort green, GLushort blue); typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLOR3USVPROC)(const GLushort * v); typedef void (GLAD_API_PTR *PFNGLSECONDARYCOLORPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void * pointer); typedef void (GLAD_API_PTR *PFNGLSELECTBUFFERPROC)(GLsizei size, GLuint * buffer); typedef void (GLAD_API_PTR *PFNGLSHADEMODELPROC)(GLenum mode); typedef void (GLAD_API_PTR *PFNGLSHADERSOURCEPROC)(GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length); typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCPROC)(GLenum func, GLint ref, GLuint mask); typedef void (GLAD_API_PTR *PFNGLSTENCILFUNCSEPARATEPROC)(GLenum face, GLenum func, GLint ref, GLuint mask); typedef void (GLAD_API_PTR *PFNGLSTENCILMASKPROC)(GLuint mask); typedef void (GLAD_API_PTR *PFNGLSTENCILMASKSEPARATEPROC)(GLenum face, GLuint mask); typedef void (GLAD_API_PTR *PFNGLSTENCILOPPROC)(GLenum fail, GLenum zfail, GLenum zpass); typedef void (GLAD_API_PTR *PFNGLSTENCILOPSEPARATEPROC)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass); typedef void (GLAD_API_PTR *PFNGLTEXCOORD1DPROC)(GLdouble s); typedef void (GLAD_API_PTR *PFNGLTEXCOORD1DVPROC)(const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLTEXCOORD1FPROC)(GLfloat s); typedef void (GLAD_API_PTR *PFNGLTEXCOORD1FVPROC)(const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLTEXCOORD1IPROC)(GLint s); typedef void (GLAD_API_PTR *PFNGLTEXCOORD1IVPROC)(const GLint * v); typedef void (GLAD_API_PTR *PFNGLTEXCOORD1SPROC)(GLshort s); typedef void (GLAD_API_PTR *PFNGLTEXCOORD1SVPROC)(const GLshort * v); typedef void (GLAD_API_PTR *PFNGLTEXCOORD2DPROC)(GLdouble s, GLdouble t); typedef void (GLAD_API_PTR *PFNGLTEXCOORD2DVPROC)(const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLTEXCOORD2FPROC)(GLfloat s, GLfloat t); typedef void (GLAD_API_PTR *PFNGLTEXCOORD2FVPROC)(const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLTEXCOORD2IPROC)(GLint s, GLint t); typedef void (GLAD_API_PTR *PFNGLTEXCOORD2IVPROC)(const GLint * v); typedef void (GLAD_API_PTR *PFNGLTEXCOORD2SPROC)(GLshort s, GLshort t); typedef void (GLAD_API_PTR *PFNGLTEXCOORD2SVPROC)(const GLshort * v); typedef void (GLAD_API_PTR *PFNGLTEXCOORD3DPROC)(GLdouble s, GLdouble t, GLdouble r); typedef void (GLAD_API_PTR *PFNGLTEXCOORD3DVPROC)(const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLTEXCOORD3FPROC)(GLfloat s, GLfloat t, GLfloat r); typedef void (GLAD_API_PTR *PFNGLTEXCOORD3FVPROC)(const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLTEXCOORD3IPROC)(GLint s, GLint t, GLint r); typedef void (GLAD_API_PTR *PFNGLTEXCOORD3IVPROC)(const GLint * v); typedef void (GLAD_API_PTR *PFNGLTEXCOORD3SPROC)(GLshort s, GLshort t, GLshort r); typedef void (GLAD_API_PTR *PFNGLTEXCOORD3SVPROC)(const GLshort * v); typedef void (GLAD_API_PTR *PFNGLTEXCOORD4DPROC)(GLdouble s, GLdouble t, GLdouble r, GLdouble q); typedef void (GLAD_API_PTR *PFNGLTEXCOORD4DVPROC)(const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLTEXCOORD4FPROC)(GLfloat s, GLfloat t, GLfloat r, GLfloat q); typedef void (GLAD_API_PTR *PFNGLTEXCOORD4FVPROC)(const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLTEXCOORD4IPROC)(GLint s, GLint t, GLint r, GLint q); typedef void (GLAD_API_PTR *PFNGLTEXCOORD4IVPROC)(const GLint * v); typedef void (GLAD_API_PTR *PFNGLTEXCOORD4SPROC)(GLshort s, GLshort t, GLshort r, GLshort q); typedef void (GLAD_API_PTR *PFNGLTEXCOORD4SVPROC)(const GLshort * v); typedef void (GLAD_API_PTR *PFNGLTEXCOORDPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void * pointer); typedef void (GLAD_API_PTR *PFNGLTEXENVFPROC)(GLenum target, GLenum pname, GLfloat param); typedef void (GLAD_API_PTR *PFNGLTEXENVFVPROC)(GLenum target, GLenum pname, const GLfloat * params); typedef void (GLAD_API_PTR *PFNGLTEXENVIPROC)(GLenum target, GLenum pname, GLint param); typedef void (GLAD_API_PTR *PFNGLTEXENVIVPROC)(GLenum target, GLenum pname, const GLint * params); typedef void (GLAD_API_PTR *PFNGLTEXGENDPROC)(GLenum coord, GLenum pname, GLdouble param); typedef void (GLAD_API_PTR *PFNGLTEXGENDVPROC)(GLenum coord, GLenum pname, const GLdouble * params); typedef void (GLAD_API_PTR *PFNGLTEXGENFPROC)(GLenum coord, GLenum pname, GLfloat param); typedef void (GLAD_API_PTR *PFNGLTEXGENFVPROC)(GLenum coord, GLenum pname, const GLfloat * params); typedef void (GLAD_API_PTR *PFNGLTEXGENIPROC)(GLenum coord, GLenum pname, GLint param); typedef void (GLAD_API_PTR *PFNGLTEXGENIVPROC)(GLenum coord, GLenum pname, const GLint * params); typedef void (GLAD_API_PTR *PFNGLTEXIMAGE1DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const void * pixels); typedef void (GLAD_API_PTR *PFNGLTEXIMAGE2DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels); typedef void (GLAD_API_PTR *PFNGLTEXIMAGE3DPROC)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * pixels); typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIIVPROC)(GLenum target, GLenum pname, const GLint * params); typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIUIVPROC)(GLenum target, GLenum pname, const GLuint * params); typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFPROC)(GLenum target, GLenum pname, GLfloat param); typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERFVPROC)(GLenum target, GLenum pname, const GLfloat * params); typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIPROC)(GLenum target, GLenum pname, GLint param); typedef void (GLAD_API_PTR *PFNGLTEXPARAMETERIVPROC)(GLenum target, GLenum pname, const GLint * params); typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE1DPROC)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const void * pixels); typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE2DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels); typedef void (GLAD_API_PTR *PFNGLTEXSUBIMAGE3DPROC)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels); typedef void (GLAD_API_PTR *PFNGLTRANSFORMFEEDBACKVARYINGSPROC)(GLuint program, GLsizei count, const GLchar *const* varyings, GLenum bufferMode); typedef void (GLAD_API_PTR *PFNGLTRANSLATEDPROC)(GLdouble x, GLdouble y, GLdouble z); typedef void (GLAD_API_PTR *PFNGLTRANSLATEFPROC)(GLfloat x, GLfloat y, GLfloat z); typedef void (GLAD_API_PTR *PFNGLUNIFORM1FPROC)(GLint location, GLfloat v0); typedef void (GLAD_API_PTR *PFNGLUNIFORM1FVPROC)(GLint location, GLsizei count, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM1IPROC)(GLint location, GLint v0); typedef void (GLAD_API_PTR *PFNGLUNIFORM1IVPROC)(GLint location, GLsizei count, const GLint * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM1UIPROC)(GLint location, GLuint v0); typedef void (GLAD_API_PTR *PFNGLUNIFORM1UIVPROC)(GLint location, GLsizei count, const GLuint * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM2FPROC)(GLint location, GLfloat v0, GLfloat v1); typedef void (GLAD_API_PTR *PFNGLUNIFORM2FVPROC)(GLint location, GLsizei count, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM2IPROC)(GLint location, GLint v0, GLint v1); typedef void (GLAD_API_PTR *PFNGLUNIFORM2IVPROC)(GLint location, GLsizei count, const GLint * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM2UIPROC)(GLint location, GLuint v0, GLuint v1); typedef void (GLAD_API_PTR *PFNGLUNIFORM2UIVPROC)(GLint location, GLsizei count, const GLuint * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM3FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); typedef void (GLAD_API_PTR *PFNGLUNIFORM3FVPROC)(GLint location, GLsizei count, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM3IPROC)(GLint location, GLint v0, GLint v1, GLint v2); typedef void (GLAD_API_PTR *PFNGLUNIFORM3IVPROC)(GLint location, GLsizei count, const GLint * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM3UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2); typedef void (GLAD_API_PTR *PFNGLUNIFORM3UIVPROC)(GLint location, GLsizei count, const GLuint * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); typedef void (GLAD_API_PTR *PFNGLUNIFORM4FVPROC)(GLint location, GLsizei count, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM4IPROC)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); typedef void (GLAD_API_PTR *PFNGLUNIFORM4IVPROC)(GLint location, GLsizei count, const GLint * value); typedef void (GLAD_API_PTR *PFNGLUNIFORM4UIPROC)(GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3); typedef void (GLAD_API_PTR *PFNGLUNIFORM4UIVPROC)(GLint location, GLsizei count, const GLuint * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX2X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX3X4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X2FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef void (GLAD_API_PTR *PFNGLUNIFORMMATRIX4X3FVPROC)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value); typedef GLboolean (GLAD_API_PTR *PFNGLUNMAPBUFFERPROC)(GLenum target); typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMPROC)(GLuint program); typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPROC)(GLuint program); typedef void (GLAD_API_PTR *PFNGLVERTEX2DPROC)(GLdouble x, GLdouble y); typedef void (GLAD_API_PTR *PFNGLVERTEX2DVPROC)(const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLVERTEX2FPROC)(GLfloat x, GLfloat y); typedef void (GLAD_API_PTR *PFNGLVERTEX2FVPROC)(const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLVERTEX2IPROC)(GLint x, GLint y); typedef void (GLAD_API_PTR *PFNGLVERTEX2IVPROC)(const GLint * v); typedef void (GLAD_API_PTR *PFNGLVERTEX2SPROC)(GLshort x, GLshort y); typedef void (GLAD_API_PTR *PFNGLVERTEX2SVPROC)(const GLshort * v); typedef void (GLAD_API_PTR *PFNGLVERTEX3DPROC)(GLdouble x, GLdouble y, GLdouble z); typedef void (GLAD_API_PTR *PFNGLVERTEX3DVPROC)(const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLVERTEX3FPROC)(GLfloat x, GLfloat y, GLfloat z); typedef void (GLAD_API_PTR *PFNGLVERTEX3FVPROC)(const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLVERTEX3IPROC)(GLint x, GLint y, GLint z); typedef void (GLAD_API_PTR *PFNGLVERTEX3IVPROC)(const GLint * v); typedef void (GLAD_API_PTR *PFNGLVERTEX3SPROC)(GLshort x, GLshort y, GLshort z); typedef void (GLAD_API_PTR *PFNGLVERTEX3SVPROC)(const GLshort * v); typedef void (GLAD_API_PTR *PFNGLVERTEX4DPROC)(GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (GLAD_API_PTR *PFNGLVERTEX4DVPROC)(const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLVERTEX4FPROC)(GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (GLAD_API_PTR *PFNGLVERTEX4FVPROC)(const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLVERTEX4IPROC)(GLint x, GLint y, GLint z, GLint w); typedef void (GLAD_API_PTR *PFNGLVERTEX4IVPROC)(const GLint * v); typedef void (GLAD_API_PTR *PFNGLVERTEX4SPROC)(GLshort x, GLshort y, GLshort z, GLshort w); typedef void (GLAD_API_PTR *PFNGLVERTEX4SVPROC)(const GLshort * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DPROC)(GLuint index, GLdouble x); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1DVPROC)(GLuint index, const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FPROC)(GLuint index, GLfloat x); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1FVPROC)(GLuint index, const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SPROC)(GLuint index, GLshort x); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB1SVPROC)(GLuint index, const GLshort * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DPROC)(GLuint index, GLdouble x, GLdouble y); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2DVPROC)(GLuint index, const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FPROC)(GLuint index, GLfloat x, GLfloat y); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2FVPROC)(GLuint index, const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SPROC)(GLuint index, GLshort x, GLshort y); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB2SVPROC)(GLuint index, const GLshort * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3DVPROC)(GLuint index, const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3FVPROC)(GLuint index, const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SPROC)(GLuint index, GLshort x, GLshort y, GLshort z); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB3SVPROC)(GLuint index, const GLshort * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NBVPROC)(GLuint index, const GLbyte * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NIVPROC)(GLuint index, const GLint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NSVPROC)(GLuint index, const GLshort * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBPROC)(GLuint index, GLubyte x, GLubyte y, GLubyte z, GLubyte w); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUBVPROC)(GLuint index, const GLubyte * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUIVPROC)(GLuint index, const GLuint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4NUSVPROC)(GLuint index, const GLushort * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4BVPROC)(GLuint index, const GLbyte * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DPROC)(GLuint index, GLdouble x, GLdouble y, GLdouble z, GLdouble w); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4DVPROC)(GLuint index, const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FPROC)(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4FVPROC)(GLuint index, const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4IVPROC)(GLuint index, const GLint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SPROC)(GLuint index, GLshort x, GLshort y, GLshort z, GLshort w); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4SVPROC)(GLuint index, const GLshort * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UBVPROC)(GLuint index, const GLubyte * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4UIVPROC)(GLuint index, const GLuint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIB4USVPROC)(GLuint index, const GLushort * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1IPROC)(GLuint index, GLint x); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1IVPROC)(GLuint index, const GLint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1UIPROC)(GLuint index, GLuint x); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI1UIVPROC)(GLuint index, const GLuint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2IPROC)(GLuint index, GLint x, GLint y); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2IVPROC)(GLuint index, const GLint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2UIPROC)(GLuint index, GLuint x, GLuint y); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI2UIVPROC)(GLuint index, const GLuint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3IPROC)(GLuint index, GLint x, GLint y, GLint z); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3IVPROC)(GLuint index, const GLint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI3UIVPROC)(GLuint index, const GLuint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4BVPROC)(GLuint index, const GLbyte * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4IPROC)(GLuint index, GLint x, GLint y, GLint z, GLint w); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4IVPROC)(GLuint index, const GLint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4SVPROC)(GLuint index, const GLshort * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UBVPROC)(GLuint index, const GLubyte * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UIPROC)(GLuint index, GLuint x, GLuint y, GLuint z, GLuint w); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4UIVPROC)(GLuint index, const GLuint * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBI4USVPROC)(GLuint index, const GLushort * v); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBIPOINTERPROC)(GLuint index, GLint size, GLenum type, GLsizei stride, const void * pointer); typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer); typedef void (GLAD_API_PTR *PFNGLVERTEXPOINTERPROC)(GLint size, GLenum type, GLsizei stride, const void * pointer); typedef void (GLAD_API_PTR *PFNGLVIEWPORTPROC)(GLint x, GLint y, GLsizei width, GLsizei height); typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2DPROC)(GLdouble x, GLdouble y); typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2DVPROC)(const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2FPROC)(GLfloat x, GLfloat y); typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2FVPROC)(const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2IPROC)(GLint x, GLint y); typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2IVPROC)(const GLint * v); typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2SPROC)(GLshort x, GLshort y); typedef void (GLAD_API_PTR *PFNGLWINDOWPOS2SVPROC)(const GLshort * v); typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3DPROC)(GLdouble x, GLdouble y, GLdouble z); typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3DVPROC)(const GLdouble * v); typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3FPROC)(GLfloat x, GLfloat y, GLfloat z); typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3FVPROC)(const GLfloat * v); typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3IPROC)(GLint x, GLint y, GLint z); typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3IVPROC)(const GLint * v); typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3SPROC)(GLshort x, GLshort y, GLshort z); typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3SVPROC)(const GLshort * v); GLAD_API_CALL PFNGLACCUMPROC glad_glAccum; #define glAccum glad_glAccum GLAD_API_CALL PFNGLACTIVETEXTUREPROC glad_glActiveTexture; #define glActiveTexture glad_glActiveTexture GLAD_API_CALL PFNGLALPHAFUNCPROC glad_glAlphaFunc; #define glAlphaFunc glad_glAlphaFunc GLAD_API_CALL PFNGLARETEXTURESRESIDENTPROC glad_glAreTexturesResident; #define glAreTexturesResident glad_glAreTexturesResident GLAD_API_CALL PFNGLARRAYELEMENTPROC glad_glArrayElement; #define glArrayElement glad_glArrayElement GLAD_API_CALL PFNGLATTACHSHADERPROC glad_glAttachShader; #define glAttachShader glad_glAttachShader GLAD_API_CALL PFNGLBEGINPROC glad_glBegin; #define glBegin glad_glBegin GLAD_API_CALL PFNGLBEGINCONDITIONALRENDERPROC glad_glBeginConditionalRender; #define glBeginConditionalRender glad_glBeginConditionalRender GLAD_API_CALL PFNGLBEGINQUERYPROC glad_glBeginQuery; #define glBeginQuery glad_glBeginQuery GLAD_API_CALL PFNGLBEGINTRANSFORMFEEDBACKPROC glad_glBeginTransformFeedback; #define glBeginTransformFeedback glad_glBeginTransformFeedback GLAD_API_CALL PFNGLBINDATTRIBLOCATIONPROC glad_glBindAttribLocation; #define glBindAttribLocation glad_glBindAttribLocation GLAD_API_CALL PFNGLBINDBUFFERPROC glad_glBindBuffer; #define glBindBuffer glad_glBindBuffer GLAD_API_CALL PFNGLBINDBUFFERBASEPROC glad_glBindBufferBase; #define glBindBufferBase glad_glBindBufferBase GLAD_API_CALL PFNGLBINDBUFFERRANGEPROC glad_glBindBufferRange; #define glBindBufferRange glad_glBindBufferRange GLAD_API_CALL PFNGLBINDFRAGDATALOCATIONPROC glad_glBindFragDataLocation; #define glBindFragDataLocation glad_glBindFragDataLocation GLAD_API_CALL PFNGLBINDFRAMEBUFFERPROC glad_glBindFramebuffer; #define glBindFramebuffer glad_glBindFramebuffer GLAD_API_CALL PFNGLBINDRENDERBUFFERPROC glad_glBindRenderbuffer; #define glBindRenderbuffer glad_glBindRenderbuffer GLAD_API_CALL PFNGLBINDTEXTUREPROC glad_glBindTexture; #define glBindTexture glad_glBindTexture GLAD_API_CALL PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray; #define glBindVertexArray glad_glBindVertexArray GLAD_API_CALL PFNGLBITMAPPROC glad_glBitmap; #define glBitmap glad_glBitmap GLAD_API_CALL PFNGLBLENDCOLORPROC glad_glBlendColor; #define glBlendColor glad_glBlendColor GLAD_API_CALL PFNGLBLENDEQUATIONPROC glad_glBlendEquation; #define glBlendEquation glad_glBlendEquation GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEPROC glad_glBlendEquationSeparate; #define glBlendEquationSeparate glad_glBlendEquationSeparate GLAD_API_CALL PFNGLBLENDFUNCPROC glad_glBlendFunc; #define glBlendFunc glad_glBlendFunc GLAD_API_CALL PFNGLBLENDFUNCSEPARATEPROC glad_glBlendFuncSeparate; #define glBlendFuncSeparate glad_glBlendFuncSeparate GLAD_API_CALL PFNGLBLITFRAMEBUFFERPROC glad_glBlitFramebuffer; #define glBlitFramebuffer glad_glBlitFramebuffer GLAD_API_CALL PFNGLBUFFERDATAPROC glad_glBufferData; #define glBufferData glad_glBufferData GLAD_API_CALL PFNGLBUFFERSUBDATAPROC glad_glBufferSubData; #define glBufferSubData glad_glBufferSubData GLAD_API_CALL PFNGLCALLLISTPROC glad_glCallList; #define glCallList glad_glCallList GLAD_API_CALL PFNGLCALLLISTSPROC glad_glCallLists; #define glCallLists glad_glCallLists GLAD_API_CALL PFNGLCHECKFRAMEBUFFERSTATUSPROC glad_glCheckFramebufferStatus; #define glCheckFramebufferStatus glad_glCheckFramebufferStatus GLAD_API_CALL PFNGLCLAMPCOLORPROC glad_glClampColor; #define glClampColor glad_glClampColor GLAD_API_CALL PFNGLCLEARPROC glad_glClear; #define glClear glad_glClear GLAD_API_CALL PFNGLCLEARACCUMPROC glad_glClearAccum; #define glClearAccum glad_glClearAccum GLAD_API_CALL PFNGLCLEARBUFFERFIPROC glad_glClearBufferfi; #define glClearBufferfi glad_glClearBufferfi GLAD_API_CALL PFNGLCLEARBUFFERFVPROC glad_glClearBufferfv; #define glClearBufferfv glad_glClearBufferfv GLAD_API_CALL PFNGLCLEARBUFFERIVPROC glad_glClearBufferiv; #define glClearBufferiv glad_glClearBufferiv GLAD_API_CALL PFNGLCLEARBUFFERUIVPROC glad_glClearBufferuiv; #define glClearBufferuiv glad_glClearBufferuiv GLAD_API_CALL PFNGLCLEARCOLORPROC glad_glClearColor; #define glClearColor glad_glClearColor GLAD_API_CALL PFNGLCLEARDEPTHPROC glad_glClearDepth; #define glClearDepth glad_glClearDepth GLAD_API_CALL PFNGLCLEARINDEXPROC glad_glClearIndex; #define glClearIndex glad_glClearIndex GLAD_API_CALL PFNGLCLEARSTENCILPROC glad_glClearStencil; #define glClearStencil glad_glClearStencil GLAD_API_CALL PFNGLCLIENTACTIVETEXTUREPROC glad_glClientActiveTexture; #define glClientActiveTexture glad_glClientActiveTexture GLAD_API_CALL PFNGLCLIPPLANEPROC glad_glClipPlane; #define glClipPlane glad_glClipPlane GLAD_API_CALL PFNGLCOLOR3BPROC glad_glColor3b; #define glColor3b glad_glColor3b GLAD_API_CALL PFNGLCOLOR3BVPROC glad_glColor3bv; #define glColor3bv glad_glColor3bv GLAD_API_CALL PFNGLCOLOR3DPROC glad_glColor3d; #define glColor3d glad_glColor3d GLAD_API_CALL PFNGLCOLOR3DVPROC glad_glColor3dv; #define glColor3dv glad_glColor3dv GLAD_API_CALL PFNGLCOLOR3FPROC glad_glColor3f; #define glColor3f glad_glColor3f GLAD_API_CALL PFNGLCOLOR3FVPROC glad_glColor3fv; #define glColor3fv glad_glColor3fv GLAD_API_CALL PFNGLCOLOR3IPROC glad_glColor3i; #define glColor3i glad_glColor3i GLAD_API_CALL PFNGLCOLOR3IVPROC glad_glColor3iv; #define glColor3iv glad_glColor3iv GLAD_API_CALL PFNGLCOLOR3SPROC glad_glColor3s; #define glColor3s glad_glColor3s GLAD_API_CALL PFNGLCOLOR3SVPROC glad_glColor3sv; #define glColor3sv glad_glColor3sv GLAD_API_CALL PFNGLCOLOR3UBPROC glad_glColor3ub; #define glColor3ub glad_glColor3ub GLAD_API_CALL PFNGLCOLOR3UBVPROC glad_glColor3ubv; #define glColor3ubv glad_glColor3ubv GLAD_API_CALL PFNGLCOLOR3UIPROC glad_glColor3ui; #define glColor3ui glad_glColor3ui GLAD_API_CALL PFNGLCOLOR3UIVPROC glad_glColor3uiv; #define glColor3uiv glad_glColor3uiv GLAD_API_CALL PFNGLCOLOR3USPROC glad_glColor3us; #define glColor3us glad_glColor3us GLAD_API_CALL PFNGLCOLOR3USVPROC glad_glColor3usv; #define glColor3usv glad_glColor3usv GLAD_API_CALL PFNGLCOLOR4BPROC glad_glColor4b; #define glColor4b glad_glColor4b GLAD_API_CALL PFNGLCOLOR4BVPROC glad_glColor4bv; #define glColor4bv glad_glColor4bv GLAD_API_CALL PFNGLCOLOR4DPROC glad_glColor4d; #define glColor4d glad_glColor4d GLAD_API_CALL PFNGLCOLOR4DVPROC glad_glColor4dv; #define glColor4dv glad_glColor4dv GLAD_API_CALL PFNGLCOLOR4FPROC glad_glColor4f; #define glColor4f glad_glColor4f GLAD_API_CALL PFNGLCOLOR4FVPROC glad_glColor4fv; #define glColor4fv glad_glColor4fv GLAD_API_CALL PFNGLCOLOR4IPROC glad_glColor4i; #define glColor4i glad_glColor4i GLAD_API_CALL PFNGLCOLOR4IVPROC glad_glColor4iv; #define glColor4iv glad_glColor4iv GLAD_API_CALL PFNGLCOLOR4SPROC glad_glColor4s; #define glColor4s glad_glColor4s GLAD_API_CALL PFNGLCOLOR4SVPROC glad_glColor4sv; #define glColor4sv glad_glColor4sv GLAD_API_CALL PFNGLCOLOR4UBPROC glad_glColor4ub; #define glColor4ub glad_glColor4ub GLAD_API_CALL PFNGLCOLOR4UBVPROC glad_glColor4ubv; #define glColor4ubv glad_glColor4ubv GLAD_API_CALL PFNGLCOLOR4UIPROC glad_glColor4ui; #define glColor4ui glad_glColor4ui GLAD_API_CALL PFNGLCOLOR4UIVPROC glad_glColor4uiv; #define glColor4uiv glad_glColor4uiv GLAD_API_CALL PFNGLCOLOR4USPROC glad_glColor4us; #define glColor4us glad_glColor4us GLAD_API_CALL PFNGLCOLOR4USVPROC glad_glColor4usv; #define glColor4usv glad_glColor4usv GLAD_API_CALL PFNGLCOLORMASKPROC glad_glColorMask; #define glColorMask glad_glColorMask GLAD_API_CALL PFNGLCOLORMASKIPROC glad_glColorMaski; #define glColorMaski glad_glColorMaski GLAD_API_CALL PFNGLCOLORMATERIALPROC glad_glColorMaterial; #define glColorMaterial glad_glColorMaterial GLAD_API_CALL PFNGLCOLORPOINTERPROC glad_glColorPointer; #define glColorPointer glad_glColorPointer GLAD_API_CALL PFNGLCOMPILESHADERPROC glad_glCompileShader; #define glCompileShader glad_glCompileShader GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE1DPROC glad_glCompressedTexImage1D; #define glCompressedTexImage1D glad_glCompressedTexImage1D GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE2DPROC glad_glCompressedTexImage2D; #define glCompressedTexImage2D glad_glCompressedTexImage2D GLAD_API_CALL PFNGLCOMPRESSEDTEXIMAGE3DPROC glad_glCompressedTexImage3D; #define glCompressedTexImage3D glad_glCompressedTexImage3D GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glad_glCompressedTexSubImage1D; #define glCompressedTexSubImage1D glad_glCompressedTexSubImage1D GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glad_glCompressedTexSubImage2D; #define glCompressedTexSubImage2D glad_glCompressedTexSubImage2D GLAD_API_CALL PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glad_glCompressedTexSubImage3D; #define glCompressedTexSubImage3D glad_glCompressedTexSubImage3D GLAD_API_CALL PFNGLCOPYPIXELSPROC glad_glCopyPixels; #define glCopyPixels glad_glCopyPixels GLAD_API_CALL PFNGLCOPYTEXIMAGE1DPROC glad_glCopyTexImage1D; #define glCopyTexImage1D glad_glCopyTexImage1D GLAD_API_CALL PFNGLCOPYTEXIMAGE2DPROC glad_glCopyTexImage2D; #define glCopyTexImage2D glad_glCopyTexImage2D GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE1DPROC glad_glCopyTexSubImage1D; #define glCopyTexSubImage1D glad_glCopyTexSubImage1D GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE2DPROC glad_glCopyTexSubImage2D; #define glCopyTexSubImage2D glad_glCopyTexSubImage2D GLAD_API_CALL PFNGLCOPYTEXSUBIMAGE3DPROC glad_glCopyTexSubImage3D; #define glCopyTexSubImage3D glad_glCopyTexSubImage3D GLAD_API_CALL PFNGLCREATEPROGRAMPROC glad_glCreateProgram; #define glCreateProgram glad_glCreateProgram GLAD_API_CALL PFNGLCREATESHADERPROC glad_glCreateShader; #define glCreateShader glad_glCreateShader GLAD_API_CALL PFNGLCULLFACEPROC glad_glCullFace; #define glCullFace glad_glCullFace GLAD_API_CALL PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers; #define glDeleteBuffers glad_glDeleteBuffers GLAD_API_CALL PFNGLDELETEFRAMEBUFFERSPROC glad_glDeleteFramebuffers; #define glDeleteFramebuffers glad_glDeleteFramebuffers GLAD_API_CALL PFNGLDELETELISTSPROC glad_glDeleteLists; #define glDeleteLists glad_glDeleteLists GLAD_API_CALL PFNGLDELETEPROGRAMPROC glad_glDeleteProgram; #define glDeleteProgram glad_glDeleteProgram GLAD_API_CALL PFNGLDELETEQUERIESPROC glad_glDeleteQueries; #define glDeleteQueries glad_glDeleteQueries GLAD_API_CALL PFNGLDELETERENDERBUFFERSPROC glad_glDeleteRenderbuffers; #define glDeleteRenderbuffers glad_glDeleteRenderbuffers GLAD_API_CALL PFNGLDELETESHADERPROC glad_glDeleteShader; #define glDeleteShader glad_glDeleteShader GLAD_API_CALL PFNGLDELETETEXTURESPROC glad_glDeleteTextures; #define glDeleteTextures glad_glDeleteTextures GLAD_API_CALL PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays; #define glDeleteVertexArrays glad_glDeleteVertexArrays GLAD_API_CALL PFNGLDEPTHFUNCPROC glad_glDepthFunc; #define glDepthFunc glad_glDepthFunc GLAD_API_CALL PFNGLDEPTHMASKPROC glad_glDepthMask; #define glDepthMask glad_glDepthMask GLAD_API_CALL PFNGLDEPTHRANGEPROC glad_glDepthRange; #define glDepthRange glad_glDepthRange GLAD_API_CALL PFNGLDETACHSHADERPROC glad_glDetachShader; #define glDetachShader glad_glDetachShader GLAD_API_CALL PFNGLDISABLEPROC glad_glDisable; #define glDisable glad_glDisable GLAD_API_CALL PFNGLDISABLECLIENTSTATEPROC glad_glDisableClientState; #define glDisableClientState glad_glDisableClientState GLAD_API_CALL PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray; #define glDisableVertexAttribArray glad_glDisableVertexAttribArray GLAD_API_CALL PFNGLDISABLEIPROC glad_glDisablei; #define glDisablei glad_glDisablei GLAD_API_CALL PFNGLDRAWARRAYSPROC glad_glDrawArrays; #define glDrawArrays glad_glDrawArrays GLAD_API_CALL PFNGLDRAWBUFFERPROC glad_glDrawBuffer; #define glDrawBuffer glad_glDrawBuffer GLAD_API_CALL PFNGLDRAWBUFFERSPROC glad_glDrawBuffers; #define glDrawBuffers glad_glDrawBuffers GLAD_API_CALL PFNGLDRAWELEMENTSPROC glad_glDrawElements; #define glDrawElements glad_glDrawElements GLAD_API_CALL PFNGLDRAWPIXELSPROC glad_glDrawPixels; #define glDrawPixels glad_glDrawPixels GLAD_API_CALL PFNGLDRAWRANGEELEMENTSPROC glad_glDrawRangeElements; #define glDrawRangeElements glad_glDrawRangeElements GLAD_API_CALL PFNGLEDGEFLAGPROC glad_glEdgeFlag; #define glEdgeFlag glad_glEdgeFlag GLAD_API_CALL PFNGLEDGEFLAGPOINTERPROC glad_glEdgeFlagPointer; #define glEdgeFlagPointer glad_glEdgeFlagPointer GLAD_API_CALL PFNGLEDGEFLAGVPROC glad_glEdgeFlagv; #define glEdgeFlagv glad_glEdgeFlagv GLAD_API_CALL PFNGLENABLEPROC glad_glEnable; #define glEnable glad_glEnable GLAD_API_CALL PFNGLENABLECLIENTSTATEPROC glad_glEnableClientState; #define glEnableClientState glad_glEnableClientState GLAD_API_CALL PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray; #define glEnableVertexAttribArray glad_glEnableVertexAttribArray GLAD_API_CALL PFNGLENABLEIPROC glad_glEnablei; #define glEnablei glad_glEnablei GLAD_API_CALL PFNGLENDPROC glad_glEnd; #define glEnd glad_glEnd GLAD_API_CALL PFNGLENDCONDITIONALRENDERPROC glad_glEndConditionalRender; #define glEndConditionalRender glad_glEndConditionalRender GLAD_API_CALL PFNGLENDLISTPROC glad_glEndList; #define glEndList glad_glEndList GLAD_API_CALL PFNGLENDQUERYPROC glad_glEndQuery; #define glEndQuery glad_glEndQuery GLAD_API_CALL PFNGLENDTRANSFORMFEEDBACKPROC glad_glEndTransformFeedback; #define glEndTransformFeedback glad_glEndTransformFeedback GLAD_API_CALL PFNGLEVALCOORD1DPROC glad_glEvalCoord1d; #define glEvalCoord1d glad_glEvalCoord1d GLAD_API_CALL PFNGLEVALCOORD1DVPROC glad_glEvalCoord1dv; #define glEvalCoord1dv glad_glEvalCoord1dv GLAD_API_CALL PFNGLEVALCOORD1FPROC glad_glEvalCoord1f; #define glEvalCoord1f glad_glEvalCoord1f GLAD_API_CALL PFNGLEVALCOORD1FVPROC glad_glEvalCoord1fv; #define glEvalCoord1fv glad_glEvalCoord1fv GLAD_API_CALL PFNGLEVALCOORD2DPROC glad_glEvalCoord2d; #define glEvalCoord2d glad_glEvalCoord2d GLAD_API_CALL PFNGLEVALCOORD2DVPROC glad_glEvalCoord2dv; #define glEvalCoord2dv glad_glEvalCoord2dv GLAD_API_CALL PFNGLEVALCOORD2FPROC glad_glEvalCoord2f; #define glEvalCoord2f glad_glEvalCoord2f GLAD_API_CALL PFNGLEVALCOORD2FVPROC glad_glEvalCoord2fv; #define glEvalCoord2fv glad_glEvalCoord2fv GLAD_API_CALL PFNGLEVALMESH1PROC glad_glEvalMesh1; #define glEvalMesh1 glad_glEvalMesh1 GLAD_API_CALL PFNGLEVALMESH2PROC glad_glEvalMesh2; #define glEvalMesh2 glad_glEvalMesh2 GLAD_API_CALL PFNGLEVALPOINT1PROC glad_glEvalPoint1; #define glEvalPoint1 glad_glEvalPoint1 GLAD_API_CALL PFNGLEVALPOINT2PROC glad_glEvalPoint2; #define glEvalPoint2 glad_glEvalPoint2 GLAD_API_CALL PFNGLFEEDBACKBUFFERPROC glad_glFeedbackBuffer; #define glFeedbackBuffer glad_glFeedbackBuffer GLAD_API_CALL PFNGLFINISHPROC glad_glFinish; #define glFinish glad_glFinish GLAD_API_CALL PFNGLFLUSHPROC glad_glFlush; #define glFlush glad_glFlush GLAD_API_CALL PFNGLFLUSHMAPPEDBUFFERRANGEPROC glad_glFlushMappedBufferRange; #define glFlushMappedBufferRange glad_glFlushMappedBufferRange GLAD_API_CALL PFNGLFOGCOORDPOINTERPROC glad_glFogCoordPointer; #define glFogCoordPointer glad_glFogCoordPointer GLAD_API_CALL PFNGLFOGCOORDDPROC glad_glFogCoordd; #define glFogCoordd glad_glFogCoordd GLAD_API_CALL PFNGLFOGCOORDDVPROC glad_glFogCoorddv; #define glFogCoorddv glad_glFogCoorddv GLAD_API_CALL PFNGLFOGCOORDFPROC glad_glFogCoordf; #define glFogCoordf glad_glFogCoordf GLAD_API_CALL PFNGLFOGCOORDFVPROC glad_glFogCoordfv; #define glFogCoordfv glad_glFogCoordfv GLAD_API_CALL PFNGLFOGFPROC glad_glFogf; #define glFogf glad_glFogf GLAD_API_CALL PFNGLFOGFVPROC glad_glFogfv; #define glFogfv glad_glFogfv GLAD_API_CALL PFNGLFOGIPROC glad_glFogi; #define glFogi glad_glFogi GLAD_API_CALL PFNGLFOGIVPROC glad_glFogiv; #define glFogiv glad_glFogiv GLAD_API_CALL PFNGLFRAMEBUFFERRENDERBUFFERPROC glad_glFramebufferRenderbuffer; #define glFramebufferRenderbuffer glad_glFramebufferRenderbuffer GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE1DPROC glad_glFramebufferTexture1D; #define glFramebufferTexture1D glad_glFramebufferTexture1D GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE2DPROC glad_glFramebufferTexture2D; #define glFramebufferTexture2D glad_glFramebufferTexture2D GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURE3DPROC glad_glFramebufferTexture3D; #define glFramebufferTexture3D glad_glFramebufferTexture3D GLAD_API_CALL PFNGLFRAMEBUFFERTEXTURELAYERPROC glad_glFramebufferTextureLayer; #define glFramebufferTextureLayer glad_glFramebufferTextureLayer GLAD_API_CALL PFNGLFRONTFACEPROC glad_glFrontFace; #define glFrontFace glad_glFrontFace GLAD_API_CALL PFNGLFRUSTUMPROC glad_glFrustum; #define glFrustum glad_glFrustum GLAD_API_CALL PFNGLGENBUFFERSPROC glad_glGenBuffers; #define glGenBuffers glad_glGenBuffers GLAD_API_CALL PFNGLGENFRAMEBUFFERSPROC glad_glGenFramebuffers; #define glGenFramebuffers glad_glGenFramebuffers GLAD_API_CALL PFNGLGENLISTSPROC glad_glGenLists; #define glGenLists glad_glGenLists GLAD_API_CALL PFNGLGENQUERIESPROC glad_glGenQueries; #define glGenQueries glad_glGenQueries GLAD_API_CALL PFNGLGENRENDERBUFFERSPROC glad_glGenRenderbuffers; #define glGenRenderbuffers glad_glGenRenderbuffers GLAD_API_CALL PFNGLGENTEXTURESPROC glad_glGenTextures; #define glGenTextures glad_glGenTextures GLAD_API_CALL PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays; #define glGenVertexArrays glad_glGenVertexArrays GLAD_API_CALL PFNGLGENERATEMIPMAPPROC glad_glGenerateMipmap; #define glGenerateMipmap glad_glGenerateMipmap GLAD_API_CALL PFNGLGETACTIVEATTRIBPROC glad_glGetActiveAttrib; #define glGetActiveAttrib glad_glGetActiveAttrib GLAD_API_CALL PFNGLGETACTIVEUNIFORMPROC glad_glGetActiveUniform; #define glGetActiveUniform glad_glGetActiveUniform GLAD_API_CALL PFNGLGETATTACHEDSHADERSPROC glad_glGetAttachedShaders; #define glGetAttachedShaders glad_glGetAttachedShaders GLAD_API_CALL PFNGLGETATTRIBLOCATIONPROC glad_glGetAttribLocation; #define glGetAttribLocation glad_glGetAttribLocation GLAD_API_CALL PFNGLGETBOOLEANI_VPROC glad_glGetBooleani_v; #define glGetBooleani_v glad_glGetBooleani_v GLAD_API_CALL PFNGLGETBOOLEANVPROC glad_glGetBooleanv; #define glGetBooleanv glad_glGetBooleanv GLAD_API_CALL PFNGLGETBUFFERPARAMETERIVPROC glad_glGetBufferParameteriv; #define glGetBufferParameteriv glad_glGetBufferParameteriv GLAD_API_CALL PFNGLGETBUFFERPOINTERVPROC glad_glGetBufferPointerv; #define glGetBufferPointerv glad_glGetBufferPointerv GLAD_API_CALL PFNGLGETBUFFERSUBDATAPROC glad_glGetBufferSubData; #define glGetBufferSubData glad_glGetBufferSubData GLAD_API_CALL PFNGLGETCLIPPLANEPROC glad_glGetClipPlane; #define glGetClipPlane glad_glGetClipPlane GLAD_API_CALL PFNGLGETCOMPRESSEDTEXIMAGEPROC glad_glGetCompressedTexImage; #define glGetCompressedTexImage glad_glGetCompressedTexImage GLAD_API_CALL PFNGLGETDOUBLEVPROC glad_glGetDoublev; #define glGetDoublev glad_glGetDoublev GLAD_API_CALL PFNGLGETERRORPROC glad_glGetError; #define glGetError glad_glGetError GLAD_API_CALL PFNGLGETFLOATVPROC glad_glGetFloatv; #define glGetFloatv glad_glGetFloatv GLAD_API_CALL PFNGLGETFRAGDATALOCATIONPROC glad_glGetFragDataLocation; #define glGetFragDataLocation glad_glGetFragDataLocation GLAD_API_CALL PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glad_glGetFramebufferAttachmentParameteriv; #define glGetFramebufferAttachmentParameteriv glad_glGetFramebufferAttachmentParameteriv GLAD_API_CALL PFNGLGETINTEGERI_VPROC glad_glGetIntegeri_v; #define glGetIntegeri_v glad_glGetIntegeri_v GLAD_API_CALL PFNGLGETINTEGERVPROC glad_glGetIntegerv; #define glGetIntegerv glad_glGetIntegerv GLAD_API_CALL PFNGLGETLIGHTFVPROC glad_glGetLightfv; #define glGetLightfv glad_glGetLightfv GLAD_API_CALL PFNGLGETLIGHTIVPROC glad_glGetLightiv; #define glGetLightiv glad_glGetLightiv GLAD_API_CALL PFNGLGETMAPDVPROC glad_glGetMapdv; #define glGetMapdv glad_glGetMapdv GLAD_API_CALL PFNGLGETMAPFVPROC glad_glGetMapfv; #define glGetMapfv glad_glGetMapfv GLAD_API_CALL PFNGLGETMAPIVPROC glad_glGetMapiv; #define glGetMapiv glad_glGetMapiv GLAD_API_CALL PFNGLGETMATERIALFVPROC glad_glGetMaterialfv; #define glGetMaterialfv glad_glGetMaterialfv GLAD_API_CALL PFNGLGETMATERIALIVPROC glad_glGetMaterialiv; #define glGetMaterialiv glad_glGetMaterialiv GLAD_API_CALL PFNGLGETPIXELMAPFVPROC glad_glGetPixelMapfv; #define glGetPixelMapfv glad_glGetPixelMapfv GLAD_API_CALL PFNGLGETPIXELMAPUIVPROC glad_glGetPixelMapuiv; #define glGetPixelMapuiv glad_glGetPixelMapuiv GLAD_API_CALL PFNGLGETPIXELMAPUSVPROC glad_glGetPixelMapusv; #define glGetPixelMapusv glad_glGetPixelMapusv GLAD_API_CALL PFNGLGETPOINTERVPROC glad_glGetPointerv; #define glGetPointerv glad_glGetPointerv GLAD_API_CALL PFNGLGETPOLYGONSTIPPLEPROC glad_glGetPolygonStipple; #define glGetPolygonStipple glad_glGetPolygonStipple GLAD_API_CALL PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog; #define glGetProgramInfoLog glad_glGetProgramInfoLog GLAD_API_CALL PFNGLGETPROGRAMIVPROC glad_glGetProgramiv; #define glGetProgramiv glad_glGetProgramiv GLAD_API_CALL PFNGLGETQUERYOBJECTIVPROC glad_glGetQueryObjectiv; #define glGetQueryObjectiv glad_glGetQueryObjectiv GLAD_API_CALL PFNGLGETQUERYOBJECTUIVPROC glad_glGetQueryObjectuiv; #define glGetQueryObjectuiv glad_glGetQueryObjectuiv GLAD_API_CALL PFNGLGETQUERYIVPROC glad_glGetQueryiv; #define glGetQueryiv glad_glGetQueryiv GLAD_API_CALL PFNGLGETRENDERBUFFERPARAMETERIVPROC glad_glGetRenderbufferParameteriv; #define glGetRenderbufferParameteriv glad_glGetRenderbufferParameteriv GLAD_API_CALL PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog; #define glGetShaderInfoLog glad_glGetShaderInfoLog GLAD_API_CALL PFNGLGETSHADERSOURCEPROC glad_glGetShaderSource; #define glGetShaderSource glad_glGetShaderSource GLAD_API_CALL PFNGLGETSHADERIVPROC glad_glGetShaderiv; #define glGetShaderiv glad_glGetShaderiv GLAD_API_CALL PFNGLGETSTRINGPROC glad_glGetString; #define glGetString glad_glGetString GLAD_API_CALL PFNGLGETSTRINGIPROC glad_glGetStringi; #define glGetStringi glad_glGetStringi GLAD_API_CALL PFNGLGETTEXENVFVPROC glad_glGetTexEnvfv; #define glGetTexEnvfv glad_glGetTexEnvfv GLAD_API_CALL PFNGLGETTEXENVIVPROC glad_glGetTexEnviv; #define glGetTexEnviv glad_glGetTexEnviv GLAD_API_CALL PFNGLGETTEXGENDVPROC glad_glGetTexGendv; #define glGetTexGendv glad_glGetTexGendv GLAD_API_CALL PFNGLGETTEXGENFVPROC glad_glGetTexGenfv; #define glGetTexGenfv glad_glGetTexGenfv GLAD_API_CALL PFNGLGETTEXGENIVPROC glad_glGetTexGeniv; #define glGetTexGeniv glad_glGetTexGeniv GLAD_API_CALL PFNGLGETTEXIMAGEPROC glad_glGetTexImage; #define glGetTexImage glad_glGetTexImage GLAD_API_CALL PFNGLGETTEXLEVELPARAMETERFVPROC glad_glGetTexLevelParameterfv; #define glGetTexLevelParameterfv glad_glGetTexLevelParameterfv GLAD_API_CALL PFNGLGETTEXLEVELPARAMETERIVPROC glad_glGetTexLevelParameteriv; #define glGetTexLevelParameteriv glad_glGetTexLevelParameteriv GLAD_API_CALL PFNGLGETTEXPARAMETERIIVPROC glad_glGetTexParameterIiv; #define glGetTexParameterIiv glad_glGetTexParameterIiv GLAD_API_CALL PFNGLGETTEXPARAMETERIUIVPROC glad_glGetTexParameterIuiv; #define glGetTexParameterIuiv glad_glGetTexParameterIuiv GLAD_API_CALL PFNGLGETTEXPARAMETERFVPROC glad_glGetTexParameterfv; #define glGetTexParameterfv glad_glGetTexParameterfv GLAD_API_CALL PFNGLGETTEXPARAMETERIVPROC glad_glGetTexParameteriv; #define glGetTexParameteriv glad_glGetTexParameteriv GLAD_API_CALL PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glad_glGetTransformFeedbackVarying; #define glGetTransformFeedbackVarying glad_glGetTransformFeedbackVarying GLAD_API_CALL PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation; #define glGetUniformLocation glad_glGetUniformLocation GLAD_API_CALL PFNGLGETUNIFORMFVPROC glad_glGetUniformfv; #define glGetUniformfv glad_glGetUniformfv GLAD_API_CALL PFNGLGETUNIFORMIVPROC glad_glGetUniformiv; #define glGetUniformiv glad_glGetUniformiv GLAD_API_CALL PFNGLGETUNIFORMUIVPROC glad_glGetUniformuiv; #define glGetUniformuiv glad_glGetUniformuiv GLAD_API_CALL PFNGLGETVERTEXATTRIBIIVPROC glad_glGetVertexAttribIiv; #define glGetVertexAttribIiv glad_glGetVertexAttribIiv GLAD_API_CALL PFNGLGETVERTEXATTRIBIUIVPROC glad_glGetVertexAttribIuiv; #define glGetVertexAttribIuiv glad_glGetVertexAttribIuiv GLAD_API_CALL PFNGLGETVERTEXATTRIBPOINTERVPROC glad_glGetVertexAttribPointerv; #define glGetVertexAttribPointerv glad_glGetVertexAttribPointerv GLAD_API_CALL PFNGLGETVERTEXATTRIBDVPROC glad_glGetVertexAttribdv; #define glGetVertexAttribdv glad_glGetVertexAttribdv GLAD_API_CALL PFNGLGETVERTEXATTRIBFVPROC glad_glGetVertexAttribfv; #define glGetVertexAttribfv glad_glGetVertexAttribfv GLAD_API_CALL PFNGLGETVERTEXATTRIBIVPROC glad_glGetVertexAttribiv; #define glGetVertexAttribiv glad_glGetVertexAttribiv GLAD_API_CALL PFNGLHINTPROC glad_glHint; #define glHint glad_glHint GLAD_API_CALL PFNGLINDEXMASKPROC glad_glIndexMask; #define glIndexMask glad_glIndexMask GLAD_API_CALL PFNGLINDEXPOINTERPROC glad_glIndexPointer; #define glIndexPointer glad_glIndexPointer GLAD_API_CALL PFNGLINDEXDPROC glad_glIndexd; #define glIndexd glad_glIndexd GLAD_API_CALL PFNGLINDEXDVPROC glad_glIndexdv; #define glIndexdv glad_glIndexdv GLAD_API_CALL PFNGLINDEXFPROC glad_glIndexf; #define glIndexf glad_glIndexf GLAD_API_CALL PFNGLINDEXFVPROC glad_glIndexfv; #define glIndexfv glad_glIndexfv GLAD_API_CALL PFNGLINDEXIPROC glad_glIndexi; #define glIndexi glad_glIndexi GLAD_API_CALL PFNGLINDEXIVPROC glad_glIndexiv; #define glIndexiv glad_glIndexiv GLAD_API_CALL PFNGLINDEXSPROC glad_glIndexs; #define glIndexs glad_glIndexs GLAD_API_CALL PFNGLINDEXSVPROC glad_glIndexsv; #define glIndexsv glad_glIndexsv GLAD_API_CALL PFNGLINDEXUBPROC glad_glIndexub; #define glIndexub glad_glIndexub GLAD_API_CALL PFNGLINDEXUBVPROC glad_glIndexubv; #define glIndexubv glad_glIndexubv GLAD_API_CALL PFNGLINITNAMESPROC glad_glInitNames; #define glInitNames glad_glInitNames GLAD_API_CALL PFNGLINTERLEAVEDARRAYSPROC glad_glInterleavedArrays; #define glInterleavedArrays glad_glInterleavedArrays GLAD_API_CALL PFNGLISBUFFERPROC glad_glIsBuffer; #define glIsBuffer glad_glIsBuffer GLAD_API_CALL PFNGLISENABLEDPROC glad_glIsEnabled; #define glIsEnabled glad_glIsEnabled GLAD_API_CALL PFNGLISENABLEDIPROC glad_glIsEnabledi; #define glIsEnabledi glad_glIsEnabledi GLAD_API_CALL PFNGLISFRAMEBUFFERPROC glad_glIsFramebuffer; #define glIsFramebuffer glad_glIsFramebuffer GLAD_API_CALL PFNGLISLISTPROC glad_glIsList; #define glIsList glad_glIsList GLAD_API_CALL PFNGLISPROGRAMPROC glad_glIsProgram; #define glIsProgram glad_glIsProgram GLAD_API_CALL PFNGLISQUERYPROC glad_glIsQuery; #define glIsQuery glad_glIsQuery GLAD_API_CALL PFNGLISRENDERBUFFERPROC glad_glIsRenderbuffer; #define glIsRenderbuffer glad_glIsRenderbuffer GLAD_API_CALL PFNGLISSHADERPROC glad_glIsShader; #define glIsShader glad_glIsShader GLAD_API_CALL PFNGLISTEXTUREPROC glad_glIsTexture; #define glIsTexture glad_glIsTexture GLAD_API_CALL PFNGLISVERTEXARRAYPROC glad_glIsVertexArray; #define glIsVertexArray glad_glIsVertexArray GLAD_API_CALL PFNGLLIGHTMODELFPROC glad_glLightModelf; #define glLightModelf glad_glLightModelf GLAD_API_CALL PFNGLLIGHTMODELFVPROC glad_glLightModelfv; #define glLightModelfv glad_glLightModelfv GLAD_API_CALL PFNGLLIGHTMODELIPROC glad_glLightModeli; #define glLightModeli glad_glLightModeli GLAD_API_CALL PFNGLLIGHTMODELIVPROC glad_glLightModeliv; #define glLightModeliv glad_glLightModeliv GLAD_API_CALL PFNGLLIGHTFPROC glad_glLightf; #define glLightf glad_glLightf GLAD_API_CALL PFNGLLIGHTFVPROC glad_glLightfv; #define glLightfv glad_glLightfv GLAD_API_CALL PFNGLLIGHTIPROC glad_glLighti; #define glLighti glad_glLighti GLAD_API_CALL PFNGLLIGHTIVPROC glad_glLightiv; #define glLightiv glad_glLightiv GLAD_API_CALL PFNGLLINESTIPPLEPROC glad_glLineStipple; #define glLineStipple glad_glLineStipple GLAD_API_CALL PFNGLLINEWIDTHPROC glad_glLineWidth; #define glLineWidth glad_glLineWidth GLAD_API_CALL PFNGLLINKPROGRAMPROC glad_glLinkProgram; #define glLinkProgram glad_glLinkProgram GLAD_API_CALL PFNGLLISTBASEPROC glad_glListBase; #define glListBase glad_glListBase GLAD_API_CALL PFNGLLOADIDENTITYPROC glad_glLoadIdentity; #define glLoadIdentity glad_glLoadIdentity GLAD_API_CALL PFNGLLOADMATRIXDPROC glad_glLoadMatrixd; #define glLoadMatrixd glad_glLoadMatrixd GLAD_API_CALL PFNGLLOADMATRIXFPROC glad_glLoadMatrixf; #define glLoadMatrixf glad_glLoadMatrixf GLAD_API_CALL PFNGLLOADNAMEPROC glad_glLoadName; #define glLoadName glad_glLoadName GLAD_API_CALL PFNGLLOADTRANSPOSEMATRIXDPROC glad_glLoadTransposeMatrixd; #define glLoadTransposeMatrixd glad_glLoadTransposeMatrixd GLAD_API_CALL PFNGLLOADTRANSPOSEMATRIXFPROC glad_glLoadTransposeMatrixf; #define glLoadTransposeMatrixf glad_glLoadTransposeMatrixf GLAD_API_CALL PFNGLLOGICOPPROC glad_glLogicOp; #define glLogicOp glad_glLogicOp GLAD_API_CALL PFNGLMAP1DPROC glad_glMap1d; #define glMap1d glad_glMap1d GLAD_API_CALL PFNGLMAP1FPROC glad_glMap1f; #define glMap1f glad_glMap1f GLAD_API_CALL PFNGLMAP2DPROC glad_glMap2d; #define glMap2d glad_glMap2d GLAD_API_CALL PFNGLMAP2FPROC glad_glMap2f; #define glMap2f glad_glMap2f GLAD_API_CALL PFNGLMAPBUFFERPROC glad_glMapBuffer; #define glMapBuffer glad_glMapBuffer GLAD_API_CALL PFNGLMAPBUFFERRANGEPROC glad_glMapBufferRange; #define glMapBufferRange glad_glMapBufferRange GLAD_API_CALL PFNGLMAPGRID1DPROC glad_glMapGrid1d; #define glMapGrid1d glad_glMapGrid1d GLAD_API_CALL PFNGLMAPGRID1FPROC glad_glMapGrid1f; #define glMapGrid1f glad_glMapGrid1f GLAD_API_CALL PFNGLMAPGRID2DPROC glad_glMapGrid2d; #define glMapGrid2d glad_glMapGrid2d GLAD_API_CALL PFNGLMAPGRID2FPROC glad_glMapGrid2f; #define glMapGrid2f glad_glMapGrid2f GLAD_API_CALL PFNGLMATERIALFPROC glad_glMaterialf; #define glMaterialf glad_glMaterialf GLAD_API_CALL PFNGLMATERIALFVPROC glad_glMaterialfv; #define glMaterialfv glad_glMaterialfv GLAD_API_CALL PFNGLMATERIALIPROC glad_glMateriali; #define glMateriali glad_glMateriali GLAD_API_CALL PFNGLMATERIALIVPROC glad_glMaterialiv; #define glMaterialiv glad_glMaterialiv GLAD_API_CALL PFNGLMATRIXMODEPROC glad_glMatrixMode; #define glMatrixMode glad_glMatrixMode GLAD_API_CALL PFNGLMULTMATRIXDPROC glad_glMultMatrixd; #define glMultMatrixd glad_glMultMatrixd GLAD_API_CALL PFNGLMULTMATRIXFPROC glad_glMultMatrixf; #define glMultMatrixf glad_glMultMatrixf GLAD_API_CALL PFNGLMULTTRANSPOSEMATRIXDPROC glad_glMultTransposeMatrixd; #define glMultTransposeMatrixd glad_glMultTransposeMatrixd GLAD_API_CALL PFNGLMULTTRANSPOSEMATRIXFPROC glad_glMultTransposeMatrixf; #define glMultTransposeMatrixf glad_glMultTransposeMatrixf GLAD_API_CALL PFNGLMULTIDRAWARRAYSPROC glad_glMultiDrawArrays; #define glMultiDrawArrays glad_glMultiDrawArrays GLAD_API_CALL PFNGLMULTIDRAWELEMENTSPROC glad_glMultiDrawElements; #define glMultiDrawElements glad_glMultiDrawElements GLAD_API_CALL PFNGLMULTITEXCOORD1DPROC glad_glMultiTexCoord1d; #define glMultiTexCoord1d glad_glMultiTexCoord1d GLAD_API_CALL PFNGLMULTITEXCOORD1DVPROC glad_glMultiTexCoord1dv; #define glMultiTexCoord1dv glad_glMultiTexCoord1dv GLAD_API_CALL PFNGLMULTITEXCOORD1FPROC glad_glMultiTexCoord1f; #define glMultiTexCoord1f glad_glMultiTexCoord1f GLAD_API_CALL PFNGLMULTITEXCOORD1FVPROC glad_glMultiTexCoord1fv; #define glMultiTexCoord1fv glad_glMultiTexCoord1fv GLAD_API_CALL PFNGLMULTITEXCOORD1IPROC glad_glMultiTexCoord1i; #define glMultiTexCoord1i glad_glMultiTexCoord1i GLAD_API_CALL PFNGLMULTITEXCOORD1IVPROC glad_glMultiTexCoord1iv; #define glMultiTexCoord1iv glad_glMultiTexCoord1iv GLAD_API_CALL PFNGLMULTITEXCOORD1SPROC glad_glMultiTexCoord1s; #define glMultiTexCoord1s glad_glMultiTexCoord1s GLAD_API_CALL PFNGLMULTITEXCOORD1SVPROC glad_glMultiTexCoord1sv; #define glMultiTexCoord1sv glad_glMultiTexCoord1sv GLAD_API_CALL PFNGLMULTITEXCOORD2DPROC glad_glMultiTexCoord2d; #define glMultiTexCoord2d glad_glMultiTexCoord2d GLAD_API_CALL PFNGLMULTITEXCOORD2DVPROC glad_glMultiTexCoord2dv; #define glMultiTexCoord2dv glad_glMultiTexCoord2dv GLAD_API_CALL PFNGLMULTITEXCOORD2FPROC glad_glMultiTexCoord2f; #define glMultiTexCoord2f glad_glMultiTexCoord2f GLAD_API_CALL PFNGLMULTITEXCOORD2FVPROC glad_glMultiTexCoord2fv; #define glMultiTexCoord2fv glad_glMultiTexCoord2fv GLAD_API_CALL PFNGLMULTITEXCOORD2IPROC glad_glMultiTexCoord2i; #define glMultiTexCoord2i glad_glMultiTexCoord2i GLAD_API_CALL PFNGLMULTITEXCOORD2IVPROC glad_glMultiTexCoord2iv; #define glMultiTexCoord2iv glad_glMultiTexCoord2iv GLAD_API_CALL PFNGLMULTITEXCOORD2SPROC glad_glMultiTexCoord2s; #define glMultiTexCoord2s glad_glMultiTexCoord2s GLAD_API_CALL PFNGLMULTITEXCOORD2SVPROC glad_glMultiTexCoord2sv; #define glMultiTexCoord2sv glad_glMultiTexCoord2sv GLAD_API_CALL PFNGLMULTITEXCOORD3DPROC glad_glMultiTexCoord3d; #define glMultiTexCoord3d glad_glMultiTexCoord3d GLAD_API_CALL PFNGLMULTITEXCOORD3DVPROC glad_glMultiTexCoord3dv; #define glMultiTexCoord3dv glad_glMultiTexCoord3dv GLAD_API_CALL PFNGLMULTITEXCOORD3FPROC glad_glMultiTexCoord3f; #define glMultiTexCoord3f glad_glMultiTexCoord3f GLAD_API_CALL PFNGLMULTITEXCOORD3FVPROC glad_glMultiTexCoord3fv; #define glMultiTexCoord3fv glad_glMultiTexCoord3fv GLAD_API_CALL PFNGLMULTITEXCOORD3IPROC glad_glMultiTexCoord3i; #define glMultiTexCoord3i glad_glMultiTexCoord3i GLAD_API_CALL PFNGLMULTITEXCOORD3IVPROC glad_glMultiTexCoord3iv; #define glMultiTexCoord3iv glad_glMultiTexCoord3iv GLAD_API_CALL PFNGLMULTITEXCOORD3SPROC glad_glMultiTexCoord3s; #define glMultiTexCoord3s glad_glMultiTexCoord3s GLAD_API_CALL PFNGLMULTITEXCOORD3SVPROC glad_glMultiTexCoord3sv; #define glMultiTexCoord3sv glad_glMultiTexCoord3sv GLAD_API_CALL PFNGLMULTITEXCOORD4DPROC glad_glMultiTexCoord4d; #define glMultiTexCoord4d glad_glMultiTexCoord4d GLAD_API_CALL PFNGLMULTITEXCOORD4DVPROC glad_glMultiTexCoord4dv; #define glMultiTexCoord4dv glad_glMultiTexCoord4dv GLAD_API_CALL PFNGLMULTITEXCOORD4FPROC glad_glMultiTexCoord4f; #define glMultiTexCoord4f glad_glMultiTexCoord4f GLAD_API_CALL PFNGLMULTITEXCOORD4FVPROC glad_glMultiTexCoord4fv; #define glMultiTexCoord4fv glad_glMultiTexCoord4fv GLAD_API_CALL PFNGLMULTITEXCOORD4IPROC glad_glMultiTexCoord4i; #define glMultiTexCoord4i glad_glMultiTexCoord4i GLAD_API_CALL PFNGLMULTITEXCOORD4IVPROC glad_glMultiTexCoord4iv; #define glMultiTexCoord4iv glad_glMultiTexCoord4iv GLAD_API_CALL PFNGLMULTITEXCOORD4SPROC glad_glMultiTexCoord4s; #define glMultiTexCoord4s glad_glMultiTexCoord4s GLAD_API_CALL PFNGLMULTITEXCOORD4SVPROC glad_glMultiTexCoord4sv; #define glMultiTexCoord4sv glad_glMultiTexCoord4sv GLAD_API_CALL PFNGLNEWLISTPROC glad_glNewList; #define glNewList glad_glNewList GLAD_API_CALL PFNGLNORMAL3BPROC glad_glNormal3b; #define glNormal3b glad_glNormal3b GLAD_API_CALL PFNGLNORMAL3BVPROC glad_glNormal3bv; #define glNormal3bv glad_glNormal3bv GLAD_API_CALL PFNGLNORMAL3DPROC glad_glNormal3d; #define glNormal3d glad_glNormal3d GLAD_API_CALL PFNGLNORMAL3DVPROC glad_glNormal3dv; #define glNormal3dv glad_glNormal3dv GLAD_API_CALL PFNGLNORMAL3FPROC glad_glNormal3f; #define glNormal3f glad_glNormal3f GLAD_API_CALL PFNGLNORMAL3FVPROC glad_glNormal3fv; #define glNormal3fv glad_glNormal3fv GLAD_API_CALL PFNGLNORMAL3IPROC glad_glNormal3i; #define glNormal3i glad_glNormal3i GLAD_API_CALL PFNGLNORMAL3IVPROC glad_glNormal3iv; #define glNormal3iv glad_glNormal3iv GLAD_API_CALL PFNGLNORMAL3SPROC glad_glNormal3s; #define glNormal3s glad_glNormal3s GLAD_API_CALL PFNGLNORMAL3SVPROC glad_glNormal3sv; #define glNormal3sv glad_glNormal3sv GLAD_API_CALL PFNGLNORMALPOINTERPROC glad_glNormalPointer; #define glNormalPointer glad_glNormalPointer GLAD_API_CALL PFNGLORTHOPROC glad_glOrtho; #define glOrtho glad_glOrtho GLAD_API_CALL PFNGLPASSTHROUGHPROC glad_glPassThrough; #define glPassThrough glad_glPassThrough GLAD_API_CALL PFNGLPIXELMAPFVPROC glad_glPixelMapfv; #define glPixelMapfv glad_glPixelMapfv GLAD_API_CALL PFNGLPIXELMAPUIVPROC glad_glPixelMapuiv; #define glPixelMapuiv glad_glPixelMapuiv GLAD_API_CALL PFNGLPIXELMAPUSVPROC glad_glPixelMapusv; #define glPixelMapusv glad_glPixelMapusv GLAD_API_CALL PFNGLPIXELSTOREFPROC glad_glPixelStoref; #define glPixelStoref glad_glPixelStoref GLAD_API_CALL PFNGLPIXELSTOREIPROC glad_glPixelStorei; #define glPixelStorei glad_glPixelStorei GLAD_API_CALL PFNGLPIXELTRANSFERFPROC glad_glPixelTransferf; #define glPixelTransferf glad_glPixelTransferf GLAD_API_CALL PFNGLPIXELTRANSFERIPROC glad_glPixelTransferi; #define glPixelTransferi glad_glPixelTransferi GLAD_API_CALL PFNGLPIXELZOOMPROC glad_glPixelZoom; #define glPixelZoom glad_glPixelZoom GLAD_API_CALL PFNGLPOINTPARAMETERFPROC glad_glPointParameterf; #define glPointParameterf glad_glPointParameterf GLAD_API_CALL PFNGLPOINTPARAMETERFVPROC glad_glPointParameterfv; #define glPointParameterfv glad_glPointParameterfv GLAD_API_CALL PFNGLPOINTPARAMETERIPROC glad_glPointParameteri; #define glPointParameteri glad_glPointParameteri GLAD_API_CALL PFNGLPOINTPARAMETERIVPROC glad_glPointParameteriv; #define glPointParameteriv glad_glPointParameteriv GLAD_API_CALL PFNGLPOINTSIZEPROC glad_glPointSize; #define glPointSize glad_glPointSize GLAD_API_CALL PFNGLPOLYGONMODEPROC glad_glPolygonMode; #define glPolygonMode glad_glPolygonMode GLAD_API_CALL PFNGLPOLYGONOFFSETPROC glad_glPolygonOffset; #define glPolygonOffset glad_glPolygonOffset GLAD_API_CALL PFNGLPOLYGONSTIPPLEPROC glad_glPolygonStipple; #define glPolygonStipple glad_glPolygonStipple GLAD_API_CALL PFNGLPOPATTRIBPROC glad_glPopAttrib; #define glPopAttrib glad_glPopAttrib GLAD_API_CALL PFNGLPOPCLIENTATTRIBPROC glad_glPopClientAttrib; #define glPopClientAttrib glad_glPopClientAttrib GLAD_API_CALL PFNGLPOPMATRIXPROC glad_glPopMatrix; #define glPopMatrix glad_glPopMatrix GLAD_API_CALL PFNGLPOPNAMEPROC glad_glPopName; #define glPopName glad_glPopName GLAD_API_CALL PFNGLPRIORITIZETEXTURESPROC glad_glPrioritizeTextures; #define glPrioritizeTextures glad_glPrioritizeTextures GLAD_API_CALL PFNGLPUSHATTRIBPROC glad_glPushAttrib; #define glPushAttrib glad_glPushAttrib GLAD_API_CALL PFNGLPUSHCLIENTATTRIBPROC glad_glPushClientAttrib; #define glPushClientAttrib glad_glPushClientAttrib GLAD_API_CALL PFNGLPUSHMATRIXPROC glad_glPushMatrix; #define glPushMatrix glad_glPushMatrix GLAD_API_CALL PFNGLPUSHNAMEPROC glad_glPushName; #define glPushName glad_glPushName GLAD_API_CALL PFNGLRASTERPOS2DPROC glad_glRasterPos2d; #define glRasterPos2d glad_glRasterPos2d GLAD_API_CALL PFNGLRASTERPOS2DVPROC glad_glRasterPos2dv; #define glRasterPos2dv glad_glRasterPos2dv GLAD_API_CALL PFNGLRASTERPOS2FPROC glad_glRasterPos2f; #define glRasterPos2f glad_glRasterPos2f GLAD_API_CALL PFNGLRASTERPOS2FVPROC glad_glRasterPos2fv; #define glRasterPos2fv glad_glRasterPos2fv GLAD_API_CALL PFNGLRASTERPOS2IPROC glad_glRasterPos2i; #define glRasterPos2i glad_glRasterPos2i GLAD_API_CALL PFNGLRASTERPOS2IVPROC glad_glRasterPos2iv; #define glRasterPos2iv glad_glRasterPos2iv GLAD_API_CALL PFNGLRASTERPOS2SPROC glad_glRasterPos2s; #define glRasterPos2s glad_glRasterPos2s GLAD_API_CALL PFNGLRASTERPOS2SVPROC glad_glRasterPos2sv; #define glRasterPos2sv glad_glRasterPos2sv GLAD_API_CALL PFNGLRASTERPOS3DPROC glad_glRasterPos3d; #define glRasterPos3d glad_glRasterPos3d GLAD_API_CALL PFNGLRASTERPOS3DVPROC glad_glRasterPos3dv; #define glRasterPos3dv glad_glRasterPos3dv GLAD_API_CALL PFNGLRASTERPOS3FPROC glad_glRasterPos3f; #define glRasterPos3f glad_glRasterPos3f GLAD_API_CALL PFNGLRASTERPOS3FVPROC glad_glRasterPos3fv; #define glRasterPos3fv glad_glRasterPos3fv GLAD_API_CALL PFNGLRASTERPOS3IPROC glad_glRasterPos3i; #define glRasterPos3i glad_glRasterPos3i GLAD_API_CALL PFNGLRASTERPOS3IVPROC glad_glRasterPos3iv; #define glRasterPos3iv glad_glRasterPos3iv GLAD_API_CALL PFNGLRASTERPOS3SPROC glad_glRasterPos3s; #define glRasterPos3s glad_glRasterPos3s GLAD_API_CALL PFNGLRASTERPOS3SVPROC glad_glRasterPos3sv; #define glRasterPos3sv glad_glRasterPos3sv GLAD_API_CALL PFNGLRASTERPOS4DPROC glad_glRasterPos4d; #define glRasterPos4d glad_glRasterPos4d GLAD_API_CALL PFNGLRASTERPOS4DVPROC glad_glRasterPos4dv; #define glRasterPos4dv glad_glRasterPos4dv GLAD_API_CALL PFNGLRASTERPOS4FPROC glad_glRasterPos4f; #define glRasterPos4f glad_glRasterPos4f GLAD_API_CALL PFNGLRASTERPOS4FVPROC glad_glRasterPos4fv; #define glRasterPos4fv glad_glRasterPos4fv GLAD_API_CALL PFNGLRASTERPOS4IPROC glad_glRasterPos4i; #define glRasterPos4i glad_glRasterPos4i GLAD_API_CALL PFNGLRASTERPOS4IVPROC glad_glRasterPos4iv; #define glRasterPos4iv glad_glRasterPos4iv GLAD_API_CALL PFNGLRASTERPOS4SPROC glad_glRasterPos4s; #define glRasterPos4s glad_glRasterPos4s GLAD_API_CALL PFNGLRASTERPOS4SVPROC glad_glRasterPos4sv; #define glRasterPos4sv glad_glRasterPos4sv GLAD_API_CALL PFNGLREADBUFFERPROC glad_glReadBuffer; #define glReadBuffer glad_glReadBuffer GLAD_API_CALL PFNGLREADPIXELSPROC glad_glReadPixels; #define glReadPixels glad_glReadPixels GLAD_API_CALL PFNGLRECTDPROC glad_glRectd; #define glRectd glad_glRectd GLAD_API_CALL PFNGLRECTDVPROC glad_glRectdv; #define glRectdv glad_glRectdv GLAD_API_CALL PFNGLRECTFPROC glad_glRectf; #define glRectf glad_glRectf GLAD_API_CALL PFNGLRECTFVPROC glad_glRectfv; #define glRectfv glad_glRectfv GLAD_API_CALL PFNGLRECTIPROC glad_glRecti; #define glRecti glad_glRecti GLAD_API_CALL PFNGLRECTIVPROC glad_glRectiv; #define glRectiv glad_glRectiv GLAD_API_CALL PFNGLRECTSPROC glad_glRects; #define glRects glad_glRects GLAD_API_CALL PFNGLRECTSVPROC glad_glRectsv; #define glRectsv glad_glRectsv GLAD_API_CALL PFNGLRENDERMODEPROC glad_glRenderMode; #define glRenderMode glad_glRenderMode GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEPROC glad_glRenderbufferStorage; #define glRenderbufferStorage glad_glRenderbufferStorage GLAD_API_CALL PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glad_glRenderbufferStorageMultisample; #define glRenderbufferStorageMultisample glad_glRenderbufferStorageMultisample GLAD_API_CALL PFNGLROTATEDPROC glad_glRotated; #define glRotated glad_glRotated GLAD_API_CALL PFNGLROTATEFPROC glad_glRotatef; #define glRotatef glad_glRotatef GLAD_API_CALL PFNGLSAMPLECOVERAGEPROC glad_glSampleCoverage; #define glSampleCoverage glad_glSampleCoverage GLAD_API_CALL PFNGLSCALEDPROC glad_glScaled; #define glScaled glad_glScaled GLAD_API_CALL PFNGLSCALEFPROC glad_glScalef; #define glScalef glad_glScalef GLAD_API_CALL PFNGLSCISSORPROC glad_glScissor; #define glScissor glad_glScissor GLAD_API_CALL PFNGLSECONDARYCOLOR3BPROC glad_glSecondaryColor3b; #define glSecondaryColor3b glad_glSecondaryColor3b GLAD_API_CALL PFNGLSECONDARYCOLOR3BVPROC glad_glSecondaryColor3bv; #define glSecondaryColor3bv glad_glSecondaryColor3bv GLAD_API_CALL PFNGLSECONDARYCOLOR3DPROC glad_glSecondaryColor3d; #define glSecondaryColor3d glad_glSecondaryColor3d GLAD_API_CALL PFNGLSECONDARYCOLOR3DVPROC glad_glSecondaryColor3dv; #define glSecondaryColor3dv glad_glSecondaryColor3dv GLAD_API_CALL PFNGLSECONDARYCOLOR3FPROC glad_glSecondaryColor3f; #define glSecondaryColor3f glad_glSecondaryColor3f GLAD_API_CALL PFNGLSECONDARYCOLOR3FVPROC glad_glSecondaryColor3fv; #define glSecondaryColor3fv glad_glSecondaryColor3fv GLAD_API_CALL PFNGLSECONDARYCOLOR3IPROC glad_glSecondaryColor3i; #define glSecondaryColor3i glad_glSecondaryColor3i GLAD_API_CALL PFNGLSECONDARYCOLOR3IVPROC glad_glSecondaryColor3iv; #define glSecondaryColor3iv glad_glSecondaryColor3iv GLAD_API_CALL PFNGLSECONDARYCOLOR3SPROC glad_glSecondaryColor3s; #define glSecondaryColor3s glad_glSecondaryColor3s GLAD_API_CALL PFNGLSECONDARYCOLOR3SVPROC glad_glSecondaryColor3sv; #define glSecondaryColor3sv glad_glSecondaryColor3sv GLAD_API_CALL PFNGLSECONDARYCOLOR3UBPROC glad_glSecondaryColor3ub; #define glSecondaryColor3ub glad_glSecondaryColor3ub GLAD_API_CALL PFNGLSECONDARYCOLOR3UBVPROC glad_glSecondaryColor3ubv; #define glSecondaryColor3ubv glad_glSecondaryColor3ubv GLAD_API_CALL PFNGLSECONDARYCOLOR3UIPROC glad_glSecondaryColor3ui; #define glSecondaryColor3ui glad_glSecondaryColor3ui GLAD_API_CALL PFNGLSECONDARYCOLOR3UIVPROC glad_glSecondaryColor3uiv; #define glSecondaryColor3uiv glad_glSecondaryColor3uiv GLAD_API_CALL PFNGLSECONDARYCOLOR3USPROC glad_glSecondaryColor3us; #define glSecondaryColor3us glad_glSecondaryColor3us GLAD_API_CALL PFNGLSECONDARYCOLOR3USVPROC glad_glSecondaryColor3usv; #define glSecondaryColor3usv glad_glSecondaryColor3usv GLAD_API_CALL PFNGLSECONDARYCOLORPOINTERPROC glad_glSecondaryColorPointer; #define glSecondaryColorPointer glad_glSecondaryColorPointer GLAD_API_CALL PFNGLSELECTBUFFERPROC glad_glSelectBuffer; #define glSelectBuffer glad_glSelectBuffer GLAD_API_CALL PFNGLSHADEMODELPROC glad_glShadeModel; #define glShadeModel glad_glShadeModel GLAD_API_CALL PFNGLSHADERSOURCEPROC glad_glShaderSource; #define glShaderSource glad_glShaderSource GLAD_API_CALL PFNGLSTENCILFUNCPROC glad_glStencilFunc; #define glStencilFunc glad_glStencilFunc GLAD_API_CALL PFNGLSTENCILFUNCSEPARATEPROC glad_glStencilFuncSeparate; #define glStencilFuncSeparate glad_glStencilFuncSeparate GLAD_API_CALL PFNGLSTENCILMASKPROC glad_glStencilMask; #define glStencilMask glad_glStencilMask GLAD_API_CALL PFNGLSTENCILMASKSEPARATEPROC glad_glStencilMaskSeparate; #define glStencilMaskSeparate glad_glStencilMaskSeparate GLAD_API_CALL PFNGLSTENCILOPPROC glad_glStencilOp; #define glStencilOp glad_glStencilOp GLAD_API_CALL PFNGLSTENCILOPSEPARATEPROC glad_glStencilOpSeparate; #define glStencilOpSeparate glad_glStencilOpSeparate GLAD_API_CALL PFNGLTEXCOORD1DPROC glad_glTexCoord1d; #define glTexCoord1d glad_glTexCoord1d GLAD_API_CALL PFNGLTEXCOORD1DVPROC glad_glTexCoord1dv; #define glTexCoord1dv glad_glTexCoord1dv GLAD_API_CALL PFNGLTEXCOORD1FPROC glad_glTexCoord1f; #define glTexCoord1f glad_glTexCoord1f GLAD_API_CALL PFNGLTEXCOORD1FVPROC glad_glTexCoord1fv; #define glTexCoord1fv glad_glTexCoord1fv GLAD_API_CALL PFNGLTEXCOORD1IPROC glad_glTexCoord1i; #define glTexCoord1i glad_glTexCoord1i GLAD_API_CALL PFNGLTEXCOORD1IVPROC glad_glTexCoord1iv; #define glTexCoord1iv glad_glTexCoord1iv GLAD_API_CALL PFNGLTEXCOORD1SPROC glad_glTexCoord1s; #define glTexCoord1s glad_glTexCoord1s GLAD_API_CALL PFNGLTEXCOORD1SVPROC glad_glTexCoord1sv; #define glTexCoord1sv glad_glTexCoord1sv GLAD_API_CALL PFNGLTEXCOORD2DPROC glad_glTexCoord2d; #define glTexCoord2d glad_glTexCoord2d GLAD_API_CALL PFNGLTEXCOORD2DVPROC glad_glTexCoord2dv; #define glTexCoord2dv glad_glTexCoord2dv GLAD_API_CALL PFNGLTEXCOORD2FPROC glad_glTexCoord2f; #define glTexCoord2f glad_glTexCoord2f GLAD_API_CALL PFNGLTEXCOORD2FVPROC glad_glTexCoord2fv; #define glTexCoord2fv glad_glTexCoord2fv GLAD_API_CALL PFNGLTEXCOORD2IPROC glad_glTexCoord2i; #define glTexCoord2i glad_glTexCoord2i GLAD_API_CALL PFNGLTEXCOORD2IVPROC glad_glTexCoord2iv; #define glTexCoord2iv glad_glTexCoord2iv GLAD_API_CALL PFNGLTEXCOORD2SPROC glad_glTexCoord2s; #define glTexCoord2s glad_glTexCoord2s GLAD_API_CALL PFNGLTEXCOORD2SVPROC glad_glTexCoord2sv; #define glTexCoord2sv glad_glTexCoord2sv GLAD_API_CALL PFNGLTEXCOORD3DPROC glad_glTexCoord3d; #define glTexCoord3d glad_glTexCoord3d GLAD_API_CALL PFNGLTEXCOORD3DVPROC glad_glTexCoord3dv; #define glTexCoord3dv glad_glTexCoord3dv GLAD_API_CALL PFNGLTEXCOORD3FPROC glad_glTexCoord3f; #define glTexCoord3f glad_glTexCoord3f GLAD_API_CALL PFNGLTEXCOORD3FVPROC glad_glTexCoord3fv; #define glTexCoord3fv glad_glTexCoord3fv GLAD_API_CALL PFNGLTEXCOORD3IPROC glad_glTexCoord3i; #define glTexCoord3i glad_glTexCoord3i GLAD_API_CALL PFNGLTEXCOORD3IVPROC glad_glTexCoord3iv; #define glTexCoord3iv glad_glTexCoord3iv GLAD_API_CALL PFNGLTEXCOORD3SPROC glad_glTexCoord3s; #define glTexCoord3s glad_glTexCoord3s GLAD_API_CALL PFNGLTEXCOORD3SVPROC glad_glTexCoord3sv; #define glTexCoord3sv glad_glTexCoord3sv GLAD_API_CALL PFNGLTEXCOORD4DPROC glad_glTexCoord4d; #define glTexCoord4d glad_glTexCoord4d GLAD_API_CALL PFNGLTEXCOORD4DVPROC glad_glTexCoord4dv; #define glTexCoord4dv glad_glTexCoord4dv GLAD_API_CALL PFNGLTEXCOORD4FPROC glad_glTexCoord4f; #define glTexCoord4f glad_glTexCoord4f GLAD_API_CALL PFNGLTEXCOORD4FVPROC glad_glTexCoord4fv; #define glTexCoord4fv glad_glTexCoord4fv GLAD_API_CALL PFNGLTEXCOORD4IPROC glad_glTexCoord4i; #define glTexCoord4i glad_glTexCoord4i GLAD_API_CALL PFNGLTEXCOORD4IVPROC glad_glTexCoord4iv; #define glTexCoord4iv glad_glTexCoord4iv GLAD_API_CALL PFNGLTEXCOORD4SPROC glad_glTexCoord4s; #define glTexCoord4s glad_glTexCoord4s GLAD_API_CALL PFNGLTEXCOORD4SVPROC glad_glTexCoord4sv; #define glTexCoord4sv glad_glTexCoord4sv GLAD_API_CALL PFNGLTEXCOORDPOINTERPROC glad_glTexCoordPointer; #define glTexCoordPointer glad_glTexCoordPointer GLAD_API_CALL PFNGLTEXENVFPROC glad_glTexEnvf; #define glTexEnvf glad_glTexEnvf GLAD_API_CALL PFNGLTEXENVFVPROC glad_glTexEnvfv; #define glTexEnvfv glad_glTexEnvfv GLAD_API_CALL PFNGLTEXENVIPROC glad_glTexEnvi; #define glTexEnvi glad_glTexEnvi GLAD_API_CALL PFNGLTEXENVIVPROC glad_glTexEnviv; #define glTexEnviv glad_glTexEnviv GLAD_API_CALL PFNGLTEXGENDPROC glad_glTexGend; #define glTexGend glad_glTexGend GLAD_API_CALL PFNGLTEXGENDVPROC glad_glTexGendv; #define glTexGendv glad_glTexGendv GLAD_API_CALL PFNGLTEXGENFPROC glad_glTexGenf; #define glTexGenf glad_glTexGenf GLAD_API_CALL PFNGLTEXGENFVPROC glad_glTexGenfv; #define glTexGenfv glad_glTexGenfv GLAD_API_CALL PFNGLTEXGENIPROC glad_glTexGeni; #define glTexGeni glad_glTexGeni GLAD_API_CALL PFNGLTEXGENIVPROC glad_glTexGeniv; #define glTexGeniv glad_glTexGeniv GLAD_API_CALL PFNGLTEXIMAGE1DPROC glad_glTexImage1D; #define glTexImage1D glad_glTexImage1D GLAD_API_CALL PFNGLTEXIMAGE2DPROC glad_glTexImage2D; #define glTexImage2D glad_glTexImage2D GLAD_API_CALL PFNGLTEXIMAGE3DPROC glad_glTexImage3D; #define glTexImage3D glad_glTexImage3D GLAD_API_CALL PFNGLTEXPARAMETERIIVPROC glad_glTexParameterIiv; #define glTexParameterIiv glad_glTexParameterIiv GLAD_API_CALL PFNGLTEXPARAMETERIUIVPROC glad_glTexParameterIuiv; #define glTexParameterIuiv glad_glTexParameterIuiv GLAD_API_CALL PFNGLTEXPARAMETERFPROC glad_glTexParameterf; #define glTexParameterf glad_glTexParameterf GLAD_API_CALL PFNGLTEXPARAMETERFVPROC glad_glTexParameterfv; #define glTexParameterfv glad_glTexParameterfv GLAD_API_CALL PFNGLTEXPARAMETERIPROC glad_glTexParameteri; #define glTexParameteri glad_glTexParameteri GLAD_API_CALL PFNGLTEXPARAMETERIVPROC glad_glTexParameteriv; #define glTexParameteriv glad_glTexParameteriv GLAD_API_CALL PFNGLTEXSUBIMAGE1DPROC glad_glTexSubImage1D; #define glTexSubImage1D glad_glTexSubImage1D GLAD_API_CALL PFNGLTEXSUBIMAGE2DPROC glad_glTexSubImage2D; #define glTexSubImage2D glad_glTexSubImage2D GLAD_API_CALL PFNGLTEXSUBIMAGE3DPROC glad_glTexSubImage3D; #define glTexSubImage3D glad_glTexSubImage3D GLAD_API_CALL PFNGLTRANSFORMFEEDBACKVARYINGSPROC glad_glTransformFeedbackVaryings; #define glTransformFeedbackVaryings glad_glTransformFeedbackVaryings GLAD_API_CALL PFNGLTRANSLATEDPROC glad_glTranslated; #define glTranslated glad_glTranslated GLAD_API_CALL PFNGLTRANSLATEFPROC glad_glTranslatef; #define glTranslatef glad_glTranslatef GLAD_API_CALL PFNGLUNIFORM1FPROC glad_glUniform1f; #define glUniform1f glad_glUniform1f GLAD_API_CALL PFNGLUNIFORM1FVPROC glad_glUniform1fv; #define glUniform1fv glad_glUniform1fv GLAD_API_CALL PFNGLUNIFORM1IPROC glad_glUniform1i; #define glUniform1i glad_glUniform1i GLAD_API_CALL PFNGLUNIFORM1IVPROC glad_glUniform1iv; #define glUniform1iv glad_glUniform1iv GLAD_API_CALL PFNGLUNIFORM1UIPROC glad_glUniform1ui; #define glUniform1ui glad_glUniform1ui GLAD_API_CALL PFNGLUNIFORM1UIVPROC glad_glUniform1uiv; #define glUniform1uiv glad_glUniform1uiv GLAD_API_CALL PFNGLUNIFORM2FPROC glad_glUniform2f; #define glUniform2f glad_glUniform2f GLAD_API_CALL PFNGLUNIFORM2FVPROC glad_glUniform2fv; #define glUniform2fv glad_glUniform2fv GLAD_API_CALL PFNGLUNIFORM2IPROC glad_glUniform2i; #define glUniform2i glad_glUniform2i GLAD_API_CALL PFNGLUNIFORM2IVPROC glad_glUniform2iv; #define glUniform2iv glad_glUniform2iv GLAD_API_CALL PFNGLUNIFORM2UIPROC glad_glUniform2ui; #define glUniform2ui glad_glUniform2ui GLAD_API_CALL PFNGLUNIFORM2UIVPROC glad_glUniform2uiv; #define glUniform2uiv glad_glUniform2uiv GLAD_API_CALL PFNGLUNIFORM3FPROC glad_glUniform3f; #define glUniform3f glad_glUniform3f GLAD_API_CALL PFNGLUNIFORM3FVPROC glad_glUniform3fv; #define glUniform3fv glad_glUniform3fv GLAD_API_CALL PFNGLUNIFORM3IPROC glad_glUniform3i; #define glUniform3i glad_glUniform3i GLAD_API_CALL PFNGLUNIFORM3IVPROC glad_glUniform3iv; #define glUniform3iv glad_glUniform3iv GLAD_API_CALL PFNGLUNIFORM3UIPROC glad_glUniform3ui; #define glUniform3ui glad_glUniform3ui GLAD_API_CALL PFNGLUNIFORM3UIVPROC glad_glUniform3uiv; #define glUniform3uiv glad_glUniform3uiv GLAD_API_CALL PFNGLUNIFORM4FPROC glad_glUniform4f; #define glUniform4f glad_glUniform4f GLAD_API_CALL PFNGLUNIFORM4FVPROC glad_glUniform4fv; #define glUniform4fv glad_glUniform4fv GLAD_API_CALL PFNGLUNIFORM4IPROC glad_glUniform4i; #define glUniform4i glad_glUniform4i GLAD_API_CALL PFNGLUNIFORM4IVPROC glad_glUniform4iv; #define glUniform4iv glad_glUniform4iv GLAD_API_CALL PFNGLUNIFORM4UIPROC glad_glUniform4ui; #define glUniform4ui glad_glUniform4ui GLAD_API_CALL PFNGLUNIFORM4UIVPROC glad_glUniform4uiv; #define glUniform4uiv glad_glUniform4uiv GLAD_API_CALL PFNGLUNIFORMMATRIX2FVPROC glad_glUniformMatrix2fv; #define glUniformMatrix2fv glad_glUniformMatrix2fv GLAD_API_CALL PFNGLUNIFORMMATRIX2X3FVPROC glad_glUniformMatrix2x3fv; #define glUniformMatrix2x3fv glad_glUniformMatrix2x3fv GLAD_API_CALL PFNGLUNIFORMMATRIX2X4FVPROC glad_glUniformMatrix2x4fv; #define glUniformMatrix2x4fv glad_glUniformMatrix2x4fv GLAD_API_CALL PFNGLUNIFORMMATRIX3FVPROC glad_glUniformMatrix3fv; #define glUniformMatrix3fv glad_glUniformMatrix3fv GLAD_API_CALL PFNGLUNIFORMMATRIX3X2FVPROC glad_glUniformMatrix3x2fv; #define glUniformMatrix3x2fv glad_glUniformMatrix3x2fv GLAD_API_CALL PFNGLUNIFORMMATRIX3X4FVPROC glad_glUniformMatrix3x4fv; #define glUniformMatrix3x4fv glad_glUniformMatrix3x4fv GLAD_API_CALL PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv; #define glUniformMatrix4fv glad_glUniformMatrix4fv GLAD_API_CALL PFNGLUNIFORMMATRIX4X2FVPROC glad_glUniformMatrix4x2fv; #define glUniformMatrix4x2fv glad_glUniformMatrix4x2fv GLAD_API_CALL PFNGLUNIFORMMATRIX4X3FVPROC glad_glUniformMatrix4x3fv; #define glUniformMatrix4x3fv glad_glUniformMatrix4x3fv GLAD_API_CALL PFNGLUNMAPBUFFERPROC glad_glUnmapBuffer; #define glUnmapBuffer glad_glUnmapBuffer GLAD_API_CALL PFNGLUSEPROGRAMPROC glad_glUseProgram; #define glUseProgram glad_glUseProgram GLAD_API_CALL PFNGLVALIDATEPROGRAMPROC glad_glValidateProgram; #define glValidateProgram glad_glValidateProgram GLAD_API_CALL PFNGLVERTEX2DPROC glad_glVertex2d; #define glVertex2d glad_glVertex2d GLAD_API_CALL PFNGLVERTEX2DVPROC glad_glVertex2dv; #define glVertex2dv glad_glVertex2dv GLAD_API_CALL PFNGLVERTEX2FPROC glad_glVertex2f; #define glVertex2f glad_glVertex2f GLAD_API_CALL PFNGLVERTEX2FVPROC glad_glVertex2fv; #define glVertex2fv glad_glVertex2fv GLAD_API_CALL PFNGLVERTEX2IPROC glad_glVertex2i; #define glVertex2i glad_glVertex2i GLAD_API_CALL PFNGLVERTEX2IVPROC glad_glVertex2iv; #define glVertex2iv glad_glVertex2iv GLAD_API_CALL PFNGLVERTEX2SPROC glad_glVertex2s; #define glVertex2s glad_glVertex2s GLAD_API_CALL PFNGLVERTEX2SVPROC glad_glVertex2sv; #define glVertex2sv glad_glVertex2sv GLAD_API_CALL PFNGLVERTEX3DPROC glad_glVertex3d; #define glVertex3d glad_glVertex3d GLAD_API_CALL PFNGLVERTEX3DVPROC glad_glVertex3dv; #define glVertex3dv glad_glVertex3dv GLAD_API_CALL PFNGLVERTEX3FPROC glad_glVertex3f; #define glVertex3f glad_glVertex3f GLAD_API_CALL PFNGLVERTEX3FVPROC glad_glVertex3fv; #define glVertex3fv glad_glVertex3fv GLAD_API_CALL PFNGLVERTEX3IPROC glad_glVertex3i; #define glVertex3i glad_glVertex3i GLAD_API_CALL PFNGLVERTEX3IVPROC glad_glVertex3iv; #define glVertex3iv glad_glVertex3iv GLAD_API_CALL PFNGLVERTEX3SPROC glad_glVertex3s; #define glVertex3s glad_glVertex3s GLAD_API_CALL PFNGLVERTEX3SVPROC glad_glVertex3sv; #define glVertex3sv glad_glVertex3sv GLAD_API_CALL PFNGLVERTEX4DPROC glad_glVertex4d; #define glVertex4d glad_glVertex4d GLAD_API_CALL PFNGLVERTEX4DVPROC glad_glVertex4dv; #define glVertex4dv glad_glVertex4dv GLAD_API_CALL PFNGLVERTEX4FPROC glad_glVertex4f; #define glVertex4f glad_glVertex4f GLAD_API_CALL PFNGLVERTEX4FVPROC glad_glVertex4fv; #define glVertex4fv glad_glVertex4fv GLAD_API_CALL PFNGLVERTEX4IPROC glad_glVertex4i; #define glVertex4i glad_glVertex4i GLAD_API_CALL PFNGLVERTEX4IVPROC glad_glVertex4iv; #define glVertex4iv glad_glVertex4iv GLAD_API_CALL PFNGLVERTEX4SPROC glad_glVertex4s; #define glVertex4s glad_glVertex4s GLAD_API_CALL PFNGLVERTEX4SVPROC glad_glVertex4sv; #define glVertex4sv glad_glVertex4sv GLAD_API_CALL PFNGLVERTEXATTRIB1DPROC glad_glVertexAttrib1d; #define glVertexAttrib1d glad_glVertexAttrib1d GLAD_API_CALL PFNGLVERTEXATTRIB1DVPROC glad_glVertexAttrib1dv; #define glVertexAttrib1dv glad_glVertexAttrib1dv GLAD_API_CALL PFNGLVERTEXATTRIB1FPROC glad_glVertexAttrib1f; #define glVertexAttrib1f glad_glVertexAttrib1f GLAD_API_CALL PFNGLVERTEXATTRIB1FVPROC glad_glVertexAttrib1fv; #define glVertexAttrib1fv glad_glVertexAttrib1fv GLAD_API_CALL PFNGLVERTEXATTRIB1SPROC glad_glVertexAttrib1s; #define glVertexAttrib1s glad_glVertexAttrib1s GLAD_API_CALL PFNGLVERTEXATTRIB1SVPROC glad_glVertexAttrib1sv; #define glVertexAttrib1sv glad_glVertexAttrib1sv GLAD_API_CALL PFNGLVERTEXATTRIB2DPROC glad_glVertexAttrib2d; #define glVertexAttrib2d glad_glVertexAttrib2d GLAD_API_CALL PFNGLVERTEXATTRIB2DVPROC glad_glVertexAttrib2dv; #define glVertexAttrib2dv glad_glVertexAttrib2dv GLAD_API_CALL PFNGLVERTEXATTRIB2FPROC glad_glVertexAttrib2f; #define glVertexAttrib2f glad_glVertexAttrib2f GLAD_API_CALL PFNGLVERTEXATTRIB2FVPROC glad_glVertexAttrib2fv; #define glVertexAttrib2fv glad_glVertexAttrib2fv GLAD_API_CALL PFNGLVERTEXATTRIB2SPROC glad_glVertexAttrib2s; #define glVertexAttrib2s glad_glVertexAttrib2s GLAD_API_CALL PFNGLVERTEXATTRIB2SVPROC glad_glVertexAttrib2sv; #define glVertexAttrib2sv glad_glVertexAttrib2sv GLAD_API_CALL PFNGLVERTEXATTRIB3DPROC glad_glVertexAttrib3d; #define glVertexAttrib3d glad_glVertexAttrib3d GLAD_API_CALL PFNGLVERTEXATTRIB3DVPROC glad_glVertexAttrib3dv; #define glVertexAttrib3dv glad_glVertexAttrib3dv GLAD_API_CALL PFNGLVERTEXATTRIB3FPROC glad_glVertexAttrib3f; #define glVertexAttrib3f glad_glVertexAttrib3f GLAD_API_CALL PFNGLVERTEXATTRIB3FVPROC glad_glVertexAttrib3fv; #define glVertexAttrib3fv glad_glVertexAttrib3fv GLAD_API_CALL PFNGLVERTEXATTRIB3SPROC glad_glVertexAttrib3s; #define glVertexAttrib3s glad_glVertexAttrib3s GLAD_API_CALL PFNGLVERTEXATTRIB3SVPROC glad_glVertexAttrib3sv; #define glVertexAttrib3sv glad_glVertexAttrib3sv GLAD_API_CALL PFNGLVERTEXATTRIB4NBVPROC glad_glVertexAttrib4Nbv; #define glVertexAttrib4Nbv glad_glVertexAttrib4Nbv GLAD_API_CALL PFNGLVERTEXATTRIB4NIVPROC glad_glVertexAttrib4Niv; #define glVertexAttrib4Niv glad_glVertexAttrib4Niv GLAD_API_CALL PFNGLVERTEXATTRIB4NSVPROC glad_glVertexAttrib4Nsv; #define glVertexAttrib4Nsv glad_glVertexAttrib4Nsv GLAD_API_CALL PFNGLVERTEXATTRIB4NUBPROC glad_glVertexAttrib4Nub; #define glVertexAttrib4Nub glad_glVertexAttrib4Nub GLAD_API_CALL PFNGLVERTEXATTRIB4NUBVPROC glad_glVertexAttrib4Nubv; #define glVertexAttrib4Nubv glad_glVertexAttrib4Nubv GLAD_API_CALL PFNGLVERTEXATTRIB4NUIVPROC glad_glVertexAttrib4Nuiv; #define glVertexAttrib4Nuiv glad_glVertexAttrib4Nuiv GLAD_API_CALL PFNGLVERTEXATTRIB4NUSVPROC glad_glVertexAttrib4Nusv; #define glVertexAttrib4Nusv glad_glVertexAttrib4Nusv GLAD_API_CALL PFNGLVERTEXATTRIB4BVPROC glad_glVertexAttrib4bv; #define glVertexAttrib4bv glad_glVertexAttrib4bv GLAD_API_CALL PFNGLVERTEXATTRIB4DPROC glad_glVertexAttrib4d; #define glVertexAttrib4d glad_glVertexAttrib4d GLAD_API_CALL PFNGLVERTEXATTRIB4DVPROC glad_glVertexAttrib4dv; #define glVertexAttrib4dv glad_glVertexAttrib4dv GLAD_API_CALL PFNGLVERTEXATTRIB4FPROC glad_glVertexAttrib4f; #define glVertexAttrib4f glad_glVertexAttrib4f GLAD_API_CALL PFNGLVERTEXATTRIB4FVPROC glad_glVertexAttrib4fv; #define glVertexAttrib4fv glad_glVertexAttrib4fv GLAD_API_CALL PFNGLVERTEXATTRIB4IVPROC glad_glVertexAttrib4iv; #define glVertexAttrib4iv glad_glVertexAttrib4iv GLAD_API_CALL PFNGLVERTEXATTRIB4SPROC glad_glVertexAttrib4s; #define glVertexAttrib4s glad_glVertexAttrib4s GLAD_API_CALL PFNGLVERTEXATTRIB4SVPROC glad_glVertexAttrib4sv; #define glVertexAttrib4sv glad_glVertexAttrib4sv GLAD_API_CALL PFNGLVERTEXATTRIB4UBVPROC glad_glVertexAttrib4ubv; #define glVertexAttrib4ubv glad_glVertexAttrib4ubv GLAD_API_CALL PFNGLVERTEXATTRIB4UIVPROC glad_glVertexAttrib4uiv; #define glVertexAttrib4uiv glad_glVertexAttrib4uiv GLAD_API_CALL PFNGLVERTEXATTRIB4USVPROC glad_glVertexAttrib4usv; #define glVertexAttrib4usv glad_glVertexAttrib4usv GLAD_API_CALL PFNGLVERTEXATTRIBI1IPROC glad_glVertexAttribI1i; #define glVertexAttribI1i glad_glVertexAttribI1i GLAD_API_CALL PFNGLVERTEXATTRIBI1IVPROC glad_glVertexAttribI1iv; #define glVertexAttribI1iv glad_glVertexAttribI1iv GLAD_API_CALL PFNGLVERTEXATTRIBI1UIPROC glad_glVertexAttribI1ui; #define glVertexAttribI1ui glad_glVertexAttribI1ui GLAD_API_CALL PFNGLVERTEXATTRIBI1UIVPROC glad_glVertexAttribI1uiv; #define glVertexAttribI1uiv glad_glVertexAttribI1uiv GLAD_API_CALL PFNGLVERTEXATTRIBI2IPROC glad_glVertexAttribI2i; #define glVertexAttribI2i glad_glVertexAttribI2i GLAD_API_CALL PFNGLVERTEXATTRIBI2IVPROC glad_glVertexAttribI2iv; #define glVertexAttribI2iv glad_glVertexAttribI2iv GLAD_API_CALL PFNGLVERTEXATTRIBI2UIPROC glad_glVertexAttribI2ui; #define glVertexAttribI2ui glad_glVertexAttribI2ui GLAD_API_CALL PFNGLVERTEXATTRIBI2UIVPROC glad_glVertexAttribI2uiv; #define glVertexAttribI2uiv glad_glVertexAttribI2uiv GLAD_API_CALL PFNGLVERTEXATTRIBI3IPROC glad_glVertexAttribI3i; #define glVertexAttribI3i glad_glVertexAttribI3i GLAD_API_CALL PFNGLVERTEXATTRIBI3IVPROC glad_glVertexAttribI3iv; #define glVertexAttribI3iv glad_glVertexAttribI3iv GLAD_API_CALL PFNGLVERTEXATTRIBI3UIPROC glad_glVertexAttribI3ui; #define glVertexAttribI3ui glad_glVertexAttribI3ui GLAD_API_CALL PFNGLVERTEXATTRIBI3UIVPROC glad_glVertexAttribI3uiv; #define glVertexAttribI3uiv glad_glVertexAttribI3uiv GLAD_API_CALL PFNGLVERTEXATTRIBI4BVPROC glad_glVertexAttribI4bv; #define glVertexAttribI4bv glad_glVertexAttribI4bv GLAD_API_CALL PFNGLVERTEXATTRIBI4IPROC glad_glVertexAttribI4i; #define glVertexAttribI4i glad_glVertexAttribI4i GLAD_API_CALL PFNGLVERTEXATTRIBI4IVPROC glad_glVertexAttribI4iv; #define glVertexAttribI4iv glad_glVertexAttribI4iv GLAD_API_CALL PFNGLVERTEXATTRIBI4SVPROC glad_glVertexAttribI4sv; #define glVertexAttribI4sv glad_glVertexAttribI4sv GLAD_API_CALL PFNGLVERTEXATTRIBI4UBVPROC glad_glVertexAttribI4ubv; #define glVertexAttribI4ubv glad_glVertexAttribI4ubv GLAD_API_CALL PFNGLVERTEXATTRIBI4UIPROC glad_glVertexAttribI4ui; #define glVertexAttribI4ui glad_glVertexAttribI4ui GLAD_API_CALL PFNGLVERTEXATTRIBI4UIVPROC glad_glVertexAttribI4uiv; #define glVertexAttribI4uiv glad_glVertexAttribI4uiv GLAD_API_CALL PFNGLVERTEXATTRIBI4USVPROC glad_glVertexAttribI4usv; #define glVertexAttribI4usv glad_glVertexAttribI4usv GLAD_API_CALL PFNGLVERTEXATTRIBIPOINTERPROC glad_glVertexAttribIPointer; #define glVertexAttribIPointer glad_glVertexAttribIPointer GLAD_API_CALL PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer; #define glVertexAttribPointer glad_glVertexAttribPointer GLAD_API_CALL PFNGLVERTEXPOINTERPROC glad_glVertexPointer; #define glVertexPointer glad_glVertexPointer GLAD_API_CALL PFNGLVIEWPORTPROC glad_glViewport; #define glViewport glad_glViewport GLAD_API_CALL PFNGLWINDOWPOS2DPROC glad_glWindowPos2d; #define glWindowPos2d glad_glWindowPos2d GLAD_API_CALL PFNGLWINDOWPOS2DVPROC glad_glWindowPos2dv; #define glWindowPos2dv glad_glWindowPos2dv GLAD_API_CALL PFNGLWINDOWPOS2FPROC glad_glWindowPos2f; #define glWindowPos2f glad_glWindowPos2f GLAD_API_CALL PFNGLWINDOWPOS2FVPROC glad_glWindowPos2fv; #define glWindowPos2fv glad_glWindowPos2fv GLAD_API_CALL PFNGLWINDOWPOS2IPROC glad_glWindowPos2i; #define glWindowPos2i glad_glWindowPos2i GLAD_API_CALL PFNGLWINDOWPOS2IVPROC glad_glWindowPos2iv; #define glWindowPos2iv glad_glWindowPos2iv GLAD_API_CALL PFNGLWINDOWPOS2SPROC glad_glWindowPos2s; #define glWindowPos2s glad_glWindowPos2s GLAD_API_CALL PFNGLWINDOWPOS2SVPROC glad_glWindowPos2sv; #define glWindowPos2sv glad_glWindowPos2sv GLAD_API_CALL PFNGLWINDOWPOS3DPROC glad_glWindowPos3d; #define glWindowPos3d glad_glWindowPos3d GLAD_API_CALL PFNGLWINDOWPOS3DVPROC glad_glWindowPos3dv; #define glWindowPos3dv glad_glWindowPos3dv GLAD_API_CALL PFNGLWINDOWPOS3FPROC glad_glWindowPos3f; #define glWindowPos3f glad_glWindowPos3f GLAD_API_CALL PFNGLWINDOWPOS3FVPROC glad_glWindowPos3fv; #define glWindowPos3fv glad_glWindowPos3fv GLAD_API_CALL PFNGLWINDOWPOS3IPROC glad_glWindowPos3i; #define glWindowPos3i glad_glWindowPos3i GLAD_API_CALL PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv; #define glWindowPos3iv glad_glWindowPos3iv GLAD_API_CALL PFNGLWINDOWPOS3SPROC glad_glWindowPos3s; #define glWindowPos3s glad_glWindowPos3s GLAD_API_CALL PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv; #define glWindowPos3sv glad_glWindowPos3sv GLAD_API_CALL int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr); GLAD_API_CALL int gladLoadGL( GLADloadfunc load); #ifdef GLAD_GL GLAD_API_CALL int gladLoaderLoadGL(void); GLAD_API_CALL void gladLoaderUnloadGL(void); #endif #ifdef __cplusplus } #endif #endif rgl/src/ext/earcut/0000755000176200001440000000000015011677075013721 5ustar liggesusersrgl/src/ext/earcut/earcut.h0000644000176200001440000006062115011677075015362 0ustar liggesusers#pragma once #include #include #include #include #include #include #include #include namespace mapbox { namespace util { template struct nth { inline static typename std::tuple_element::type get(const T& t) { return std::get(t); }; }; } namespace detail { template class Earcut { public: std::vector indices; std::size_t vertices = 0; template void operator()(const Polygon& points); private: struct Node { Node(N index, double x_, double y_) : i(index), x(x_), y(y_) {} Node(const Node&) = delete; Node& operator=(const Node&) = delete; Node(Node&&) = delete; Node& operator=(Node&&) = delete; const N i; const double x; const double y; // previous and next vertice nodes in a polygon ring Node* prev = nullptr; Node* next = nullptr; // z-order curve value int32_t z = 0; // previous and next nodes in z-order Node* prevZ = nullptr; Node* nextZ = nullptr; // indicates whether this is a steiner point bool steiner = false; }; template Node* linkedList(const Ring& points, const bool clockwise); Node* filterPoints(Node* start, Node* end = nullptr); void earcutLinked(Node* ear, int pass = 0); bool isEar(Node* ear); bool isEarHashed(Node* ear); Node* cureLocalIntersections(Node* start); void splitEarcut(Node* start); template Node* eliminateHoles(const Polygon& points, Node* outerNode); Node* eliminateHole(Node* hole, Node* outerNode); Node* findHoleBridge(Node* hole, Node* outerNode); bool sectorContainsSector(const Node* m, const Node* p); void indexCurve(Node* start); Node* sortLinked(Node* list); int32_t zOrder(const double x_, const double y_); Node* getLeftmost(Node* start); bool pointInTriangle(double ax, double ay, double bx, double by, double cx, double cy, double px, double py) const; bool isValidDiagonal(Node* a, Node* b); double area(const Node* p, const Node* q, const Node* r) const; bool equals(const Node* p1, const Node* p2); bool intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2); bool onSegment(const Node* p, const Node* q, const Node* r); int sign(double val); bool intersectsPolygon(const Node* a, const Node* b); bool locallyInside(const Node* a, const Node* b); bool middleInside(const Node* a, const Node* b); Node* splitPolygon(Node* a, Node* b); template Node* insertNode(std::size_t i, const Point& p, Node* last); void removeNode(Node* p); bool hashing; double minX, maxX; double minY, maxY; double inv_size = 0; template > class ObjectPool { public: ObjectPool() { } ObjectPool(std::size_t blockSize_) { reset(blockSize_); } ~ObjectPool() { clear(); } template T* construct(Args&&... args) { if (currentIndex >= blockSize) { currentBlock = alloc_traits::allocate(alloc, blockSize); allocations.emplace_back(currentBlock); currentIndex = 0; } T* object = ¤tBlock[currentIndex++]; alloc_traits::construct(alloc, object, std::forward(args)...); return object; } void reset(std::size_t newBlockSize) { for (auto allocation : allocations) { alloc_traits::deallocate(alloc, allocation, blockSize); } allocations.clear(); blockSize = std::max(1, newBlockSize); currentBlock = nullptr; currentIndex = blockSize; } void clear() { reset(blockSize); } private: T* currentBlock = nullptr; std::size_t currentIndex = 1; std::size_t blockSize = 1; std::vector allocations; Alloc alloc; typedef typename std::allocator_traits alloc_traits; }; ObjectPool nodes; }; template template void Earcut::operator()(const Polygon& points) { // reset indices.clear(); vertices = 0; if (points.empty()) return; double x; double y; int threshold = 80; std::size_t len = 0; for (size_t i = 0; threshold >= 0 && i < points.size(); i++) { threshold -= static_cast(points[i].size()); len += points[i].size(); } //estimate size of nodes and indices nodes.reset(len * 3 / 2); indices.reserve(len + points[0].size()); Node* outerNode = linkedList(points[0], true); if (!outerNode || outerNode->prev == outerNode->next) return; if (points.size() > 1) outerNode = eliminateHoles(points, outerNode); // if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox hashing = threshold < 0; if (hashing) { Node* p = outerNode->next; minX = maxX = outerNode->x; minY = maxY = outerNode->y; do { x = p->x; y = p->y; minX = std::min(minX, x); minY = std::min(minY, y); maxX = std::max(maxX, x); maxY = std::max(maxY, y); p = p->next; } while (p != outerNode); // minX, minY and inv_size are later used to transform coords into integers for z-order calculation inv_size = std::max(maxX - minX, maxY - minY); inv_size = inv_size != .0 ? (32767. / inv_size) : .0; } earcutLinked(outerNode); nodes.clear(); } // create a circular doubly linked list from polygon points in the specified winding order template template typename Earcut::Node* Earcut::linkedList(const Ring& points, const bool clockwise) { using Point = typename Ring::value_type; double sum = 0; const std::size_t len = points.size(); std::size_t i, j; Node* last = nullptr; // calculate original winding order of a polygon ring for (i = 0, j = len > 0 ? len - 1 : 0; i < len; j = i++) { const auto& p1 = points[i]; const auto& p2 = points[j]; const double p20 = util::nth<0, Point>::get(p2); const double p10 = util::nth<0, Point>::get(p1); const double p11 = util::nth<1, Point>::get(p1); const double p21 = util::nth<1, Point>::get(p2); sum += (p20 - p10) * (p11 + p21); } // link points into circular doubly-linked list in the specified winding order if (clockwise == (sum > 0)) { for (i = 0; i < len; i++) last = insertNode(vertices + i, points[i], last); } else { for (i = len; i-- > 0;) last = insertNode(vertices + i, points[i], last); } if (last && equals(last, last->next)) { removeNode(last); last = last->next; } vertices += len; return last; } // eliminate colinear or duplicate points template typename Earcut::Node* Earcut::filterPoints(Node* start, Node* end) { if (!end) end = start; Node* p = start; bool again; do { again = false; if (!p->steiner && (equals(p, p->next) || area(p->prev, p, p->next) == 0)) { removeNode(p); p = end = p->prev; if (p == p->next) break; again = true; } else { p = p->next; } } while (again || p != end); return end; } // main ear slicing loop which triangulates a polygon (given as a linked list) template void Earcut::earcutLinked(Node* ear, int pass) { if (!ear) return; // interlink polygon nodes in z-order if (!pass && hashing) indexCurve(ear); Node* stop = ear; Node* prev; Node* next; // iterate through ears, slicing them one by one while (ear->prev != ear->next) { prev = ear->prev; next = ear->next; if (hashing ? isEarHashed(ear) : isEar(ear)) { // cut off the triangle indices.emplace_back(prev->i); indices.emplace_back(ear->i); indices.emplace_back(next->i); removeNode(ear); // skipping the next vertice leads to less sliver triangles ear = next->next; stop = next->next; continue; } ear = next; // if we looped through the whole remaining polygon and can't find any more ears if (ear == stop) { // try filtering points and slicing again if (!pass) earcutLinked(filterPoints(ear), 1); // if this didn't work, try curing all small self-intersections locally else if (pass == 1) { ear = cureLocalIntersections(filterPoints(ear)); earcutLinked(ear, 2); // as a last resort, try splitting the remaining polygon into two } else if (pass == 2) splitEarcut(ear); break; } } } // check whether a polygon node forms a valid ear with adjacent nodes template bool Earcut::isEar(Node* ear) { const Node* a = ear->prev; const Node* b = ear; const Node* c = ear->next; if (area(a, b, c) >= 0) return false; // reflex, can't be an ear // now make sure we don't have other points inside the potential ear Node* p = ear->next->next; while (p != ear->prev) { if (pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) && area(p->prev, p, p->next) >= 0) return false; p = p->next; } return true; } template bool Earcut::isEarHashed(Node* ear) { const Node* a = ear->prev; const Node* b = ear; const Node* c = ear->next; if (area(a, b, c) >= 0) return false; // reflex, can't be an ear // triangle bbox; min & max are calculated like this for speed const double minTX = std::min(a->x, std::min(b->x, c->x)); const double minTY = std::min(a->y, std::min(b->y, c->y)); const double maxTX = std::max(a->x, std::max(b->x, c->x)); const double maxTY = std::max(a->y, std::max(b->y, c->y)); // z-order range for the current triangle bbox; const int32_t minZ = zOrder(minTX, minTY); const int32_t maxZ = zOrder(maxTX, maxTY); // first look for points inside the triangle in increasing z-order Node* p = ear->nextZ; while (p && p->z <= maxZ) { if (p != ear->prev && p != ear->next && pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) && area(p->prev, p, p->next) >= 0) return false; p = p->nextZ; } // then look for points in decreasing z-order p = ear->prevZ; while (p && p->z >= minZ) { if (p != ear->prev && p != ear->next && pointInTriangle(a->x, a->y, b->x, b->y, c->x, c->y, p->x, p->y) && area(p->prev, p, p->next) >= 0) return false; p = p->prevZ; } return true; } // go through all polygon nodes and cure small local self-intersections template typename Earcut::Node* Earcut::cureLocalIntersections(Node* start) { Node* p = start; do { Node* a = p->prev; Node* b = p->next->next; // a self-intersection where edge (v[i-1],v[i]) intersects (v[i+1],v[i+2]) if (!equals(a, b) && intersects(a, p, p->next, b) && locallyInside(a, b) && locallyInside(b, a)) { indices.emplace_back(a->i); indices.emplace_back(p->i); indices.emplace_back(b->i); // remove two nodes involved removeNode(p); removeNode(p->next); p = start = b; } p = p->next; } while (p != start); return filterPoints(p); } // try splitting polygon into two and triangulate them independently template void Earcut::splitEarcut(Node* start) { // look for a valid diagonal that divides the polygon into two Node* a = start; do { Node* b = a->next->next; while (b != a->prev) { if (a->i != b->i && isValidDiagonal(a, b)) { // split the polygon in two by the diagonal Node* c = splitPolygon(a, b); // filter colinear points around the cuts a = filterPoints(a, a->next); c = filterPoints(c, c->next); // run earcut on each half earcutLinked(a); earcutLinked(c); return; } b = b->next; } a = a->next; } while (a != start); } // link every hole into the outer loop, producing a single-ring polygon without holes template template typename Earcut::Node* Earcut::eliminateHoles(const Polygon& points, Node* outerNode) { const size_t len = points.size(); std::vector queue; for (size_t i = 1; i < len; i++) { Node* list = linkedList(points[i], false); if (list) { if (list == list->next) list->steiner = true; queue.push_back(getLeftmost(list)); } } std::sort(queue.begin(), queue.end(), [](const Node* a, const Node* b) { return a->x < b->x; }); // process holes from left to right for (size_t i = 0; i < queue.size(); i++) { outerNode = eliminateHole(queue[i], outerNode); } return outerNode; } // find a bridge between vertices that connects hole with an outer ring and and link it template typename Earcut::Node* Earcut::eliminateHole(Node* hole, Node* outerNode) { Node* bridge = findHoleBridge(hole, outerNode); if (!bridge) { return outerNode; } Node* bridgeReverse = splitPolygon(bridge, hole); // filter collinear points around the cuts filterPoints(bridgeReverse, bridgeReverse->next); // Check if input node was removed by the filtering return filterPoints(bridge, bridge->next); } // David Eberly's algorithm for finding a bridge between hole and outer polygon template typename Earcut::Node* Earcut::findHoleBridge(Node* hole, Node* outerNode) { Node* p = outerNode; double hx = hole->x; double hy = hole->y; double qx = -std::numeric_limits::infinity(); Node* m = nullptr; // find a segment intersected by a ray from the hole's leftmost Vertex to the left; // segment's endpoint with lesser x will be potential connection Vertex do { if (hy <= p->y && hy >= p->next->y && p->next->y != p->y) { double x = p->x + (hy - p->y) * (p->next->x - p->x) / (p->next->y - p->y); if (x <= hx && x > qx) { qx = x; m = p->x < p->next->x ? p : p->next; if (x == hx) return m; // hole touches outer segment; pick leftmost endpoint } } p = p->next; } while (p != outerNode); if (!m) return 0; // look for points inside the triangle of hole Vertex, segment intersection and endpoint; // if there are no points found, we have a valid connection; // otherwise choose the Vertex of the minimum angle with the ray as connection Vertex const Node* stop = m; double tanMin = std::numeric_limits::infinity(); double tanCur = 0; p = m; double mx = m->x; double my = m->y; do { if (hx >= p->x && p->x >= mx && hx != p->x && pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p->x, p->y)) { tanCur = std::abs(hy - p->y) / (hx - p->x); // tangential if (locallyInside(p, hole) && (tanCur < tanMin || (tanCur == tanMin && (p->x > m->x || sectorContainsSector(m, p))))) { m = p; tanMin = tanCur; } } p = p->next; } while (p != stop); return m; } // whether sector in vertex m contains sector in vertex p in the same coordinates template bool Earcut::sectorContainsSector(const Node* m, const Node* p) { return area(m->prev, m, p->prev) < 0 && area(p->next, m, m->next) < 0; } // interlink polygon nodes in z-order template void Earcut::indexCurve(Node* start) { assert(start); Node* p = start; do { p->z = p->z ? p->z : zOrder(p->x, p->y); p->prevZ = p->prev; p->nextZ = p->next; p = p->next; } while (p != start); p->prevZ->nextZ = nullptr; p->prevZ = nullptr; sortLinked(p); } // Simon Tatham's linked list merge sort algorithm // http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html template typename Earcut::Node* Earcut::sortLinked(Node* list) { assert(list); Node* p; Node* q; Node* e; Node* tail; int i, numMerges, pSize, qSize; int inSize = 1; for (;;) { p = list; list = nullptr; tail = nullptr; numMerges = 0; while (p) { numMerges++; q = p; pSize = 0; for (i = 0; i < inSize; i++) { pSize++; q = q->nextZ; if (!q) break; } qSize = inSize; while (pSize > 0 || (qSize > 0 && q)) { if (pSize == 0) { e = q; q = q->nextZ; qSize--; } else if (qSize == 0 || !q) { e = p; p = p->nextZ; pSize--; } else if (p->z <= q->z) { e = p; p = p->nextZ; pSize--; } else { e = q; q = q->nextZ; qSize--; } if (tail) tail->nextZ = e; else list = e; e->prevZ = tail; tail = e; } p = q; } tail->nextZ = nullptr; if (numMerges <= 1) return list; inSize *= 2; } } // z-order of a Vertex given coords and size of the data bounding box template int32_t Earcut::zOrder(const double x_, const double y_) { // coords are transformed into non-negative 15-bit integer range int32_t x = static_cast((x_ - minX) * inv_size); int32_t y = static_cast((y_ - minY) * inv_size); x = (x | (x << 8)) & 0x00FF00FF; x = (x | (x << 4)) & 0x0F0F0F0F; x = (x | (x << 2)) & 0x33333333; x = (x | (x << 1)) & 0x55555555; y = (y | (y << 8)) & 0x00FF00FF; y = (y | (y << 4)) & 0x0F0F0F0F; y = (y | (y << 2)) & 0x33333333; y = (y | (y << 1)) & 0x55555555; return x | (y << 1); } // find the leftmost node of a polygon ring template typename Earcut::Node* Earcut::getLeftmost(Node* start) { Node* p = start; Node* leftmost = start; do { if (p->x < leftmost->x || (p->x == leftmost->x && p->y < leftmost->y)) leftmost = p; p = p->next; } while (p != start); return leftmost; } // check if a point lies within a convex triangle template bool Earcut::pointInTriangle(double ax, double ay, double bx, double by, double cx, double cy, double px, double py) const { return (cx - px) * (ay - py) >= (ax - px) * (cy - py) && (ax - px) * (by - py) >= (bx - px) * (ay - py) && (bx - px) * (cy - py) >= (cx - px) * (by - py); } // check if a diagonal between two polygon nodes is valid (lies in polygon interior) template bool Earcut::isValidDiagonal(Node* a, Node* b) { return a->next->i != b->i && a->prev->i != b->i && !intersectsPolygon(a, b) && // dones't intersect other edges ((locallyInside(a, b) && locallyInside(b, a) && middleInside(a, b) && // locally visible (area(a->prev, a, b->prev) != 0.0 || area(a, b->prev, b) != 0.0)) || // does not create opposite-facing sectors (equals(a, b) && area(a->prev, a, a->next) > 0 && area(b->prev, b, b->next) > 0)); // special zero-length case } // signed area of a triangle template double Earcut::area(const Node* p, const Node* q, const Node* r) const { return (q->y - p->y) * (r->x - q->x) - (q->x - p->x) * (r->y - q->y); } // check if two points are equal template bool Earcut::equals(const Node* p1, const Node* p2) { return p1->x == p2->x && p1->y == p2->y; } // check if two segments intersect template bool Earcut::intersects(const Node* p1, const Node* q1, const Node* p2, const Node* q2) { int o1 = sign(area(p1, q1, p2)); int o2 = sign(area(p1, q1, q2)); int o3 = sign(area(p2, q2, p1)); int o4 = sign(area(p2, q2, q1)); if (o1 != o2 && o3 != o4) return true; // general case if (o1 == 0 && onSegment(p1, p2, q1)) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1 if (o2 == 0 && onSegment(p1, q2, q1)) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1 if (o3 == 0 && onSegment(p2, p1, q2)) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2 if (o4 == 0 && onSegment(p2, q1, q2)) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2 return false; } // for collinear points p, q, r, check if point q lies on segment pr template bool Earcut::onSegment(const Node* p, const Node* q, const Node* r) { return q->x <= std::max(p->x, r->x) && q->x >= std::min(p->x, r->x) && q->y <= std::max(p->y, r->y) && q->y >= std::min(p->y, r->y); } template int Earcut::sign(double val) { return (0.0 < val) - (val < 0.0); } // check if a polygon diagonal intersects any polygon segments template bool Earcut::intersectsPolygon(const Node* a, const Node* b) { const Node* p = a; do { if (p->i != a->i && p->next->i != a->i && p->i != b->i && p->next->i != b->i && intersects(p, p->next, a, b)) return true; p = p->next; } while (p != a); return false; } // check if a polygon diagonal is locally inside the polygon template bool Earcut::locallyInside(const Node* a, const Node* b) { return area(a->prev, a, a->next) < 0 ? area(a, b, a->next) >= 0 && area(a, a->prev, b) >= 0 : area(a, b, a->prev) < 0 || area(a, a->next, b) < 0; } // check if the middle Vertex of a polygon diagonal is inside the polygon template bool Earcut::middleInside(const Node* a, const Node* b) { const Node* p = a; bool inside = false; double px = (a->x + b->x) / 2; double py = (a->y + b->y) / 2; do { if (((p->y > py) != (p->next->y > py)) && p->next->y != p->y && (px < (p->next->x - p->x) * (py - p->y) / (p->next->y - p->y) + p->x)) inside = !inside; p = p->next; } while (p != a); return inside; } // link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits // polygon into two; if one belongs to the outer ring and another to a hole, it merges it into a // single ring template typename Earcut::Node* Earcut::splitPolygon(Node* a, Node* b) { Node* a2 = nodes.construct(a->i, a->x, a->y); Node* b2 = nodes.construct(b->i, b->x, b->y); Node* an = a->next; Node* bp = b->prev; a->next = b; b->prev = a; a2->next = an; an->prev = a2; b2->next = a2; a2->prev = b2; bp->next = b2; b2->prev = bp; return b2; } // create a node and util::optionally link it with previous one (in a circular doubly linked list) template template typename Earcut::Node* Earcut::insertNode(std::size_t i, const Point& pt, Node* last) { Node* p = nodes.construct(static_cast(i), util::nth<0, Point>::get(pt), util::nth<1, Point>::get(pt)); if (!last) { p->prev = p; p->next = p; } else { assert(last); p->next = last->next; p->prev = last; last->next->prev = p; last->next = p; } return p; } template void Earcut::removeNode(Node* p) { p->next->prev = p->prev; p->prev->next = p->next; if (p->prevZ) p->prevZ->nextZ = p->nextZ; if (p->nextZ) p->nextZ->prevZ = p->prevZ; } } template std::vector earcut(const Polygon& poly) { mapbox::detail::Earcut earcut; earcut(poly); return std::move(earcut.indices); } } rgl/src/ext/earcut/LICENSE0000644000176200001440000000134215011677075014726 0ustar liggesusersISC License Copyright (c) 2015, Mapbox Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. rgl/src/ext/ftgl/0000755000176200001440000000000015011677075013372 5ustar liggesusersrgl/src/ext/ftgl/FTPoint.cpp0000644000176200001440000000363214531466703015425 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include #include "FTGL/ftgl.h" bool operator == (const FTPoint &a, const FTPoint &b) { return((a.values[0] == b.values[0]) && (a.values[1] == b.values[1]) && (a.values[2] == b.values[2])); } bool operator != (const FTPoint &a, const FTPoint &b) { return((a.values[0] != b.values[0]) || (a.values[1] != b.values[1]) || (a.values[2] != b.values[2])); } FTPoint FTPoint::Normalise() { double norm = sqrt(values[0] * values[0] + values[1] * values[1] + values[2] * values[2]); if(norm == 0.0) { return *this; } FTPoint temp(values[0] / norm, values[1] / norm, values[2] / norm); return temp; } rgl/src/ext/ftgl/FTSize.cpp0000644000176200001440000000560714265301465015247 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTSize.h" FTSize::FTSize() : ftFace(0), ftSize(0), size(0), xResolution(0), yResolution(0), err(0) {} FTSize::~FTSize() {} bool FTSize::CharSize(FT_Face* face, unsigned int pointSize, unsigned int xRes, unsigned int yRes) { if(size != pointSize || xResolution != xRes || yResolution != yRes) { err = FT_Set_Char_Size(*face, 0L, pointSize * 64, xResolution, yResolution); if(!err) { ftFace = face; size = pointSize; xResolution = xRes; yResolution = yRes; ftSize = (*ftFace)->size; } } return !err; } unsigned int FTSize::CharSize() const { return size; } float FTSize::Ascender() const { return ftSize == 0 ? 0.0f : static_cast(ftSize->metrics.ascender) / 64.0f; } float FTSize::Descender() const { return ftSize == 0 ? 0.0f : static_cast(ftSize->metrics.descender) / 64.0f; } float FTSize::Height() const { if(0 == ftSize) { return 0.0f; } if(FT_IS_SCALABLE((*ftFace))) { return ((*ftFace)->bbox.yMax - (*ftFace)->bbox.yMin) * ((float)ftSize->metrics.y_ppem / (float)(*ftFace)->units_per_EM); } else { return static_cast(ftSize->metrics.height) / 64.0f; } } float FTSize::Width() const { if(0 == ftSize) { return 0.0f; } if(FT_IS_SCALABLE((*ftFace))) { return ((*ftFace)->bbox.xMax - (*ftFace)->bbox.xMin) * (static_cast(ftSize->metrics.x_ppem) / static_cast((*ftFace)->units_per_EM)); } else { return static_cast(ftSize->metrics.max_advance) / 64.0f; } } float FTSize::Underline() const { return 0.0f; } rgl/src/ext/ftgl/FTFace.cpp0000644000176200001440000001343614555455305015177 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTFace.h" #include "FTLibrary.h" #include FT_TRUETYPE_TABLES_H FTFace::FTFace(const char* fontFilePath, bool precomputeKerning) : numGlyphs(0), fontEncodingList(0), kerningCache(0), err(0) { const FT_Long DEFAULT_FACE_INDEX = 0; ftFace = new FT_Face; err = FT_New_Face(*FTLibrary::Instance().GetLibrary(), fontFilePath, DEFAULT_FACE_INDEX, ftFace); if(err) { delete ftFace; ftFace = 0; return; } numGlyphs = static_cast((*ftFace)->num_glyphs); hasKerningTable = (FT_HAS_KERNING((*ftFace)) != 0); if(hasKerningTable && precomputeKerning) { BuildKerningCache(); } } FTFace::FTFace(const unsigned char *pBufferBytes, size_t bufferSizeInBytes, bool precomputeKerning) : numGlyphs(0), fontEncodingList(0), kerningCache(0), err(0) { const FT_Long DEFAULT_FACE_INDEX = 0; ftFace = new FT_Face; err = FT_New_Memory_Face(*FTLibrary::Instance().GetLibrary(), (FT_Byte const *)pBufferBytes, (FT_Long)bufferSizeInBytes, DEFAULT_FACE_INDEX, ftFace); if(err) { delete ftFace; ftFace = 0; return; } numGlyphs = static_cast((*ftFace)->num_glyphs); hasKerningTable = (FT_HAS_KERNING((*ftFace)) != 0); if(hasKerningTable && precomputeKerning) { BuildKerningCache(); } } FTFace::~FTFace() { if(kerningCache) { delete[] kerningCache; } if(ftFace) { FT_Done_Face(*ftFace); delete ftFace; ftFace = 0; } } bool FTFace::Attach(const char* fontFilePath) { err = FT_Attach_File(*ftFace, fontFilePath); return !err; } bool FTFace::Attach(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) { FT_Open_Args open; open.flags = FT_OPEN_MEMORY; open.memory_base = (FT_Byte const *)pBufferBytes; open.memory_size = (FT_Long)bufferSizeInBytes; err = FT_Attach_Stream(*ftFace, &open); return !err; } const FTSize& FTFace::Size(const unsigned int size, const unsigned int res) { charSize.CharSize(ftFace, size, res, res); err = charSize.Error(); return charSize; } unsigned int FTFace::CharMapCount() const { return (*ftFace)->num_charmaps; } FT_Encoding* FTFace::CharMapList() { if(0 == fontEncodingList) { fontEncodingList = new FT_Encoding[CharMapCount()]; for(size_t i = 0; i < CharMapCount(); ++i) { fontEncodingList[i] = (*ftFace)->charmaps[i]->encoding; } } return fontEncodingList; } FTPoint FTFace::KernAdvance(unsigned int index1, unsigned int index2) { float x, y; if(!hasKerningTable || !index1 || !index2) { return FTPoint(0.0f, 0.0f); } if(kerningCache && index1 < FTFace::MAX_PRECOMPUTED && index2 < FTFace::MAX_PRECOMPUTED) { x = kerningCache[2 * (index2 * FTFace::MAX_PRECOMPUTED + index1)]; y = kerningCache[2 * (index2 * FTFace::MAX_PRECOMPUTED + index1) + 1]; return FTPoint(x, y); } FT_Vector kernAdvance; kernAdvance.x = kernAdvance.y = 0; err = FT_Get_Kerning(*ftFace, index1, index2, ft_kerning_unfitted, &kernAdvance); if(err) { return FTPoint(0.0f, 0.0f); } x = static_cast(kernAdvance.x) / 64.0f; y = static_cast(kernAdvance.y) / 64.0f; return FTPoint(x, y); } FT_GlyphSlot FTFace::Glyph(unsigned int index, FT_Int load_flags) { err = FT_Load_Glyph(*ftFace, index, load_flags); if(err) { return NULL; } return (*ftFace)->glyph; } void FTFace::BuildKerningCache() { FT_Vector kernAdvance; kernAdvance.x = 0; kernAdvance.y = 0; kerningCache = new float[FTFace::MAX_PRECOMPUTED * FTFace::MAX_PRECOMPUTED * 2]; for(unsigned int j = 0; j < FTFace::MAX_PRECOMPUTED; j++) { for(unsigned int i = 0; i < FTFace::MAX_PRECOMPUTED; i++) { err = FT_Get_Kerning(*ftFace, i, j, ft_kerning_unfitted, &kernAdvance); if(err) { delete[] kerningCache; kerningCache = NULL; return; } kerningCache[2 * (j * FTFace::MAX_PRECOMPUTED + i)] = static_cast(kernAdvance.x) / 64.0f; kerningCache[2 * (j * FTFace::MAX_PRECOMPUTED + i) + 1] = static_cast(kernAdvance.y) / 64.0f; } } } rgl/src/ext/ftgl/FTFace.h0000644000176200001440000001223514265301465014633 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTFace__ #define __FTFace__ #include #include FT_FREETYPE_H #include FT_GLYPH_H #include "FTGL/ftgl.h" #include "FTSize.h" /** * FTFace class provides an abstraction layer for the Freetype Face. * * @see "Freetype 2 Documentation" * */ class FTFace { public: /** * Opens and reads a face file. Error is set. * * @param fontFilePath font file path. */ FTFace(const char* fontFilePath, bool precomputeKerning = true); /** * Read face data from an in-memory buffer. Error is set. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTFace(const unsigned char *pBufferBytes, size_t bufferSizeInBytes, bool precomputeKerning = true); /** * Destructor * * Disposes of the current Freetype Face. */ virtual ~FTFace(); /** * Attach auxilliary file to font (e.g., font metrics). * * @param fontFilePath auxilliary font file path. * @return true if file has opened * successfully. */ bool Attach(const char* fontFilePath); /** * Attach auxilliary data to font (e.g., font metrics) from memory * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes * @return true if file has opened * successfully. */ bool Attach(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Get the freetype face object.. * * @return pointer to an FT_Face. */ FT_Face* Face() const { return ftFace; } /** * Sets the char size for the current face. * * This doesn't guarantee that the size was set correctly. Clients * should check errors. * * @param size the face size in points (1/72 inch) * @param res the resolution of the target device. * @return FTSize object */ const FTSize& Size(const unsigned int size, const unsigned int res); /** * Get the number of character maps in this face. * * @return character map count. */ unsigned int CharMapCount() const; /** * Get a list of character maps in this face. * * @return pointer to the first encoding. */ FT_Encoding* CharMapList(); /** * Gets the kerning vector between two glyphs */ FTPoint KernAdvance(unsigned int index1, unsigned int index2); /** * Loads and creates a Freetype glyph. */ FT_GlyphSlot Glyph(unsigned int index, FT_Int load_flags); /** * Gets the number of glyphs in the current face. */ unsigned int GlyphCount() const { return numGlyphs; } /** * Queries for errors. * * @return The current error code. */ FT_Error Error() const { return err; } private: /** * The Freetype face */ FT_Face* ftFace; /** * The size object associated with this face */ FTSize charSize; /** * The number of glyphs in this face */ int numGlyphs; FT_Encoding* fontEncodingList; /** * This face has kerning tables */ bool hasKerningTable; /** * If this face has kerning tables, we can cache them. */ void BuildKerningCache(); static const unsigned int MAX_PRECOMPUTED = 128; float *kerningCache; /** * Current error code. Zero means no error. */ FT_Error err; }; #endif // __FTFace__ rgl/src/ext/ftgl/FTVector.h0000644000176200001440000001163714530124126015234 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTVector__ #define __FTVector__ #include "FTGL/ftgl.h" /** * Provides a non-STL alternative to the STL vector */ template class FTVector { public: typedef FT_VECTOR_ITEM_TYPE value_type; typedef value_type& reference; typedef const value_type& const_reference; typedef value_type* iterator; typedef const value_type* const_iterator; typedef size_t size_type; FTVector() { Capacity = Size = 0; Items = 0; } virtual ~FTVector() { clear(); } FTVector& operator =(const FTVector& v) { reserve(v.capacity()); iterator ptr = begin(); const_iterator vbegin = v.begin(); const_iterator vend = v.end(); while(vbegin != vend) { *ptr++ = *vbegin++; } Size = v.size(); return *this; } size_type size() const { return Size; } size_type capacity() const { return Capacity; } iterator begin() { return Items; } const_iterator begin() const { return Items; } iterator end() { return begin() + size(); } const_iterator end() const { return begin() + size(); } bool empty() const { return size() == 0; } reference operator [](size_type pos) { return(*(begin() + pos)); } const_reference operator [](size_type pos) const { return *(begin() + pos); } void clear() { if(Capacity) { delete [] Items; Capacity = Size = 0; Items = 0; } } void reserve(size_type n) { if(capacity() < n) { expand(n); } } void push_back(const value_type& x) { if(size() == capacity()) { expand(); } (*this)[size()] = x; ++Size; } void resize(size_type n, value_type x) { if(n == size()) { return; } reserve(n); iterator ibegin, iend; if(n >= Size) { ibegin = this->end(); iend = this->begin() + n; } else { ibegin = this->begin() + n; iend = this->end(); } while(ibegin != iend) { *ibegin++ = x; } Size = n; } private: void expand(size_type capacity_hint = 0) { size_type new_capacity = (capacity() == 0) ? 256 : capacity() * 2; if(capacity_hint) { while(new_capacity < capacity_hint) { new_capacity *= 2; } } value_type *new_items = new value_type[new_capacity]; iterator ibegin = this->begin(); iterator iend = this->end(); value_type *ptr = new_items; while(ibegin != iend) { *ptr++ = *ibegin++; } if(Capacity) { delete [] Items; } Items = new_items; Capacity = new_capacity; } size_type Capacity; size_type Size; value_type* Items; }; #endif // __FTVector__ rgl/src/ext/ftgl/FTGlyphContainer.cpp0000644000176200001440000000635214265301465017261 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTGL/ftgl.h" #include "FTGlyphContainer.h" #include "FTFace.h" #include "FTCharmap.h" FTGlyphContainer::FTGlyphContainer(FTFace* f) : face(f), err(0) { glyphs.push_back(NULL); charMap = new FTCharmap(face); } FTGlyphContainer::~FTGlyphContainer() { GlyphVector::iterator it; for(it = glyphs.begin(); it != glyphs.end(); ++it) { delete *it; } glyphs.clear(); delete charMap; } bool FTGlyphContainer::CharMap(FT_Encoding encoding) { bool result = charMap->CharMap(encoding); err = charMap->Error(); return result; } unsigned int FTGlyphContainer::FontIndex(const unsigned int charCode) const { return charMap->FontIndex(charCode); } void FTGlyphContainer::Add(FTGlyph* tempGlyph, const unsigned int charCode) { charMap->InsertIndex(charCode, glyphs.size()); glyphs.push_back(tempGlyph); } const FTGlyph* const FTGlyphContainer::Glyph(const unsigned int charCode) const { unsigned int index = charMap->GlyphListIndex(charCode); return glyphs[index]; } FTBBox FTGlyphContainer::BBox(const unsigned int charCode) const { return Glyph(charCode)->BBox(); } float FTGlyphContainer::Advance(const unsigned int charCode, const unsigned int nextCharCode) { unsigned int left = charMap->FontIndex(charCode); unsigned int right = charMap->FontIndex(nextCharCode); return face->KernAdvance(left, right).Xf() + Glyph(charCode)->Advance(); } FTPoint FTGlyphContainer::Render(const unsigned int charCode, const unsigned int nextCharCode, FTPoint penPosition, int renderMode) { unsigned int left = charMap->FontIndex(charCode); unsigned int right = charMap->FontIndex(nextCharCode); FTPoint kernAdvance = face->KernAdvance(left, right); if(!face->Error()) { unsigned int index = charMap->GlyphListIndex(charCode); kernAdvance += glyphs[index]->Render(penPosition, renderMode); } return kernAdvance; } rgl/src/ext/ftgl/FTGlyph/0000755000176200001440000000000014555455305014711 5ustar liggesusersrgl/src/ext/ftgl/FTGlyph/FTGlyph.cpp0000644000176200001440000000423414265301465016730 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTGlyphImpl.h" // // FTGlyph // FTGlyph::FTGlyph(FT_GlyphSlot glyph) { impl = new FTGlyphImpl(glyph); } FTGlyph::FTGlyph(FTGlyphImpl *pImpl) { impl = pImpl; } FTGlyph::~FTGlyph() { delete impl; } float FTGlyph::Advance() const { return impl->Advance(); } const FTBBox& FTGlyph::BBox() const { return impl->BBox(); } FT_Error FTGlyph::Error() const { return impl->Error(); } // // FTGlyphImpl // FTGlyphImpl::FTGlyphImpl(FT_GlyphSlot glyph, bool useList) : err(0) { if(glyph) { bBox = FTBBox(glyph); advance = FTPoint(glyph->advance.x / 64.0f, glyph->advance.y / 64.0f); } } FTGlyphImpl::~FTGlyphImpl() {} float FTGlyphImpl::Advance() const { return advance.Xf(); } const FTBBox& FTGlyphImpl::BBox() const { return bBox; } FT_Error FTGlyphImpl::Error() const { return err; } rgl/src/ext/ftgl/FTGlyph/FTTextureGlyph.cpp0000644000176200001440000001034614531466703020315 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTTextureGlyphImpl.h" // // FTGLTextureGlyph // FTTextureGlyph::FTTextureGlyph(FT_GlyphSlot glyph, int id, int xOffset, int yOffset, int width, int height) : FTGlyph(new FTTextureGlyphImpl(glyph, id, xOffset, yOffset, width, height)) {} FTTextureGlyph::~FTTextureGlyph() {} const FTPoint& FTTextureGlyph::Render(const FTPoint& pen, int renderMode) { FTTextureGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLTextureGlyphImpl // GLint FTTextureGlyphImpl::activeTextureID = 0; FTTextureGlyphImpl::FTTextureGlyphImpl(FT_GlyphSlot glyph, int id, int xOffset, int yOffset, int width, int height) : FTGlyphImpl(glyph), destWidth(0), destHeight(0), glTextureID(id) { /* FIXME: need to propagate the render mode all the way down to * here in order to get FT_RENDER_MODE_MONO aliased fonts. */ err = FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL); if(err || glyph->format != ft_glyph_format_bitmap) { return; } FT_Bitmap bitmap = glyph->bitmap; destWidth = bitmap.width; destHeight = bitmap.rows; if(destWidth && destHeight) { glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glBindTexture(GL_TEXTURE_2D, glTextureID); glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, destWidth, destHeight, GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.buffer); glPopClientAttrib(); } // 0 // +----+ // | | // | | // | | // +----+ // 1 uv[0].X(static_cast(xOffset) / static_cast(width)); uv[0].Y(static_cast(yOffset) / static_cast(height)); uv[1].X(static_cast(xOffset + destWidth) / static_cast(width)); uv[1].Y(static_cast(yOffset + destHeight) / static_cast(height)); corner = FTPoint(glyph->bitmap_left, glyph->bitmap_top); } FTTextureGlyphImpl::~FTTextureGlyphImpl() {} const FTPoint& FTTextureGlyphImpl::RenderImpl(const FTPoint& pen, int renderMode) { float dx, dy; if(activeTextureID != glTextureID) { glBindTexture(GL_TEXTURE_2D, (GLuint)glTextureID); activeTextureID = glTextureID; } dx = floor(pen.Xf() + corner.Xf()); dy = floor(pen.Yf() + corner.Yf()); glBegin(GL_QUADS); glTexCoord2f(uv[0].Xf(), uv[0].Yf()); glVertex2f(dx, dy); glTexCoord2f(uv[0].Xf(), uv[1].Yf()); glVertex2f(dx, dy - destHeight); glTexCoord2f(uv[1].Xf(), uv[1].Yf()); glVertex2f(dx + destWidth, dy - destHeight); glTexCoord2f(uv[1].Xf(), uv[0].Yf()); glVertex2f(dx + destWidth, dy); glEnd(); return advance; } rgl/src/ext/ftgl/FTGlyph/FTGlyphGlue.cpp0000644000176200001440000001473414531466703017556 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTGL/ftgl.h" #include "FTInternals.h" static const FTPoint static_ftpoint; static const FTBBox static_ftbbox; FTGL_BEGIN_C_DECLS #define C_TOR(cname, cargs, cxxname, cxxarg, cxxtype) \ FTGLglyph* cname cargs \ { \ cxxname *g = new cxxname cxxarg; \ if(g->Error()) \ { \ delete g; \ return NULL; \ } \ FTGLglyph *ftgl = (FTGLglyph *)malloc(sizeof(FTGLglyph)); \ ftgl->ptr = g; \ ftgl->type = cxxtype; \ return ftgl; \ } // FTBitmapGlyph::FTBitmapGlyph(); C_TOR(ftglCreateBitmapGlyph, (FT_GlyphSlot glyph), FTBitmapGlyph, (glyph), GLYPH_BITMAP); // FTBufferGlyph::FTBufferGlyph(); // FIXME: not implemented // FTExtrudeGlyph::FTExtrudeGlyph(); C_TOR(ftglCreateExtrudeGlyph, (FT_GlyphSlot glyph, float depth, float frontOutset, float backOutset, int useDisplayList), FTExtrudeGlyph, (glyph, depth, frontOutset, backOutset, (useDisplayList != 0)), GLYPH_EXTRUDE); // FTOutlineGlyph::FTOutlineGlyph(); C_TOR(ftglCreateOutlineGlyph, (FT_GlyphSlot glyph, float outset, int useDisplayList), FTOutlineGlyph, (glyph, outset, (useDisplayList != 0)), GLYPH_OUTLINE); // FTPixmapGlyph::FTPixmapGlyph(); C_TOR(ftglCreatePixmapGlyph, (FT_GlyphSlot glyph), FTPixmapGlyph, (glyph), GLYPH_PIXMAP); // FTPolygonGlyph::FTPolygonGlyph(); C_TOR(ftglCreatePolygonGlyph, (FT_GlyphSlot glyph, float outset, int useDisplayList), FTPolygonGlyph, (glyph, outset, (useDisplayList != 0)), GLYPH_POLYGON); // FTTextureGlyph::FTTextureGlyph(); C_TOR(ftglCreateTextureGlyph, (FT_GlyphSlot glyph, int id, int xOffset, int yOffset, int width, int height), FTTextureGlyph, (glyph, id, xOffset, yOffset, width, height), GLYPH_TEXTURE); // FTCustomGlyph::FTCustomGlyph(); class FTCustomGlyph : public FTGlyph { public: FTCustomGlyph(FTGLglyph *base, void *p, void (*render) (FTGLglyph *, void *, FTGL_DOUBLE, FTGL_DOUBLE, int, FTGL_DOUBLE *, FTGL_DOUBLE *), void (*destroy) (FTGLglyph *, void *)) : FTGlyph((FT_GlyphSlot)0), baseGlyph(base), data(p), renderCallback(render), destroyCallback(destroy) {} ~FTCustomGlyph() { destroyCallback(baseGlyph, data); } float Advance() const { return baseGlyph->ptr->Advance(); } const FTPoint& Render(const FTPoint& pen, int renderMode) { FTGL_DOUBLE advancex, advancey; renderCallback(baseGlyph, data, pen.X(), pen.Y(), renderMode, &advancex, &advancey); advance = FTPoint(advancex, advancey); return advance; } const FTBBox& BBox() const { return baseGlyph->ptr->BBox(); } FT_Error Error() const { return baseGlyph->ptr->Error(); } private: FTPoint advance; FTGLglyph *baseGlyph; void *data; void (*renderCallback) (FTGLglyph *, void *, FTGL_DOUBLE, FTGL_DOUBLE, int, FTGL_DOUBLE *, FTGL_DOUBLE *); void (*destroyCallback) (FTGLglyph *, void *); }; C_TOR(ftglCreateCustomGlyph, (FTGLglyph *base, void *data, void (*renderCallback) (FTGLglyph *, void *, FTGL_DOUBLE, FTGL_DOUBLE, int, FTGL_DOUBLE *, FTGL_DOUBLE *), void (*destroyCallback) (FTGLglyph *, void *)), FTCustomGlyph, (base, data, renderCallback, destroyCallback), GLYPH_CUSTOM); #define C_FUN(cret, cname, cargs, cxxerr, cxxname, cxxarg) \ cret cname cargs \ { \ if(!g || !g->ptr) \ { \ fprintf(stderr, "FTGL warning: NULL pointer in %s\n", #cname); \ cxxerr; \ } \ return g->ptr->cxxname cxxarg; \ } // FTGlyph::~FTGlyph(); void ftglDestroyGlyph(FTGLglyph *g) { if(!g || !g->ptr) { fprintf(stderr, "FTGL warning: NULL pointer in %s\n", __FUNCTION__); return; } delete g->ptr; free(g); } // const FTPoint& FTGlyph::Render(const FTPoint& pen, int renderMode); extern "C++" { C_FUN(static const FTPoint&, _ftglRenderGlyph, (FTGLglyph *g, const FTPoint& pen, int renderMode), return static_ftpoint, Render, (pen, renderMode)); } void ftglRenderGlyph(FTGLglyph *g, FTGL_DOUBLE penx, FTGL_DOUBLE peny, int renderMode, FTGL_DOUBLE *advancex, FTGL_DOUBLE *advancey) { FTPoint pen(penx, peny); FTPoint ret = _ftglRenderGlyph(g, pen, renderMode); *advancex = ret.X(); *advancey = ret.Y(); } // float FTGlyph::Advance() const; C_FUN(float, ftglGetGlyphAdvance, (FTGLglyph *g), return 0.0, Advance, ()); // const FTBBox& FTGlyph::BBox() const; extern "C++" { C_FUN(static const FTBBox&, _ftglGetGlyphBBox, (FTGLglyph *g), return static_ftbbox, BBox, ()); } void ftglGetGlyphBBox(FTGLglyph *g, float bounds[6]) { FTBBox ret = _ftglGetGlyphBBox(g); FTPoint lower = ret.Lower(), upper = ret.Upper(); bounds[0] = lower.Xf(); bounds[1] = lower.Yf(); bounds[2] = lower.Zf(); bounds[3] = upper.Xf(); bounds[4] = upper.Yf(); bounds[5] = upper.Zf(); } // FT_Error FTGlyph::Error() const; C_FUN(FT_Error, ftglGetGlyphError, (FTGLglyph *g), return -1, Error, ()); FTGL_END_C_DECLS rgl/src/ext/ftgl/FTGlyph/FTBufferGlyph.cpp0000644000176200001440000000641114555455305020066 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTBufferGlyphImpl.h" // // FTGLBufferGlyph // FTBufferGlyph::FTBufferGlyph(FT_GlyphSlot glyph, FTBuffer *buffer) : FTGlyph(new FTBufferGlyphImpl(glyph, buffer)) {} FTBufferGlyph::~FTBufferGlyph() {} const FTPoint& FTBufferGlyph::Render(const FTPoint& pen, int renderMode) { FTBufferGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLBufferGlyphImpl // FTBufferGlyphImpl::FTBufferGlyphImpl(FT_GlyphSlot glyph, FTBuffer *p) : FTGlyphImpl(glyph), has_bitmap(false), buffer(p) { err = FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL); if(err || glyph->format != ft_glyph_format_bitmap) { return; } bitmap = glyph->bitmap; pixels = new unsigned char[bitmap.pitch * bitmap.rows]; memcpy(pixels, bitmap.buffer, bitmap.pitch * bitmap.rows); if(bitmap.width && bitmap.rows) { has_bitmap = true; corner = FTPoint(glyph->bitmap_left, glyph->bitmap_top); } } FTBufferGlyphImpl::~FTBufferGlyphImpl() { delete[] pixels; } const FTPoint& FTBufferGlyphImpl::RenderImpl(const FTPoint& pen, int renderMode) { if(has_bitmap) { FTPoint pos(buffer->Pos() + pen + corner); int dx = (int)(pos.Xf() + 0.5f); int dy = buffer->Height() - (int)(pos.Yf() + 0.5f); unsigned char * dest = buffer->Pixels() + dx + dy * buffer->Width(); for(unsigned int y = 0; y < bitmap.rows; y++) { // FIXME: change the loop bounds instead of doing this test if(static_cast(y) + dy < 0 || static_cast(y) + dy >= buffer->Height()) continue; for(unsigned int x = 0; x < bitmap.width; x++) { if(static_cast(x) + dx < 0 || static_cast(x) + dx >= buffer->Width()) continue; unsigned char p = pixels[y * bitmap.pitch + x]; if(p) { dest[y * buffer->Width() + x] = p; } } } } return advance; } rgl/src/ext/ftgl/FTGlyph/FTBitmapGlyph.cpp0000644000176200001440000000640514531466703020072 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTBitmapGlyphImpl.h" // // FTGLBitmapGlyph // FTBitmapGlyph::FTBitmapGlyph(FT_GlyphSlot glyph) : FTGlyph(new FTBitmapGlyphImpl(glyph)) {} FTBitmapGlyph::~FTBitmapGlyph() {} const FTPoint& FTBitmapGlyph::Render(const FTPoint& pen, int renderMode) { FTBitmapGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLBitmapGlyphImpl // FTBitmapGlyphImpl::FTBitmapGlyphImpl(FT_GlyphSlot glyph) : FTGlyphImpl(glyph), destWidth(0), destHeight(0), data(0) { err = FT_Render_Glyph(glyph, FT_RENDER_MODE_MONO); if(err || ft_glyph_format_bitmap != glyph->format) { return; } FT_Bitmap bitmap = glyph->bitmap; unsigned int srcWidth = bitmap.width; unsigned int srcHeight = bitmap.rows; unsigned int srcPitch = bitmap.pitch; destWidth = srcWidth; destHeight = srcHeight; destPitch = srcPitch; if(destWidth && destHeight) { data = new unsigned char[destPitch * destHeight]; unsigned char* dest = data + ((destHeight - 1) * destPitch); unsigned char* src = bitmap.buffer; for(unsigned int y = 0; y < srcHeight; ++y) { memcpy(dest, src, srcPitch); dest -= destPitch; src += srcPitch; } } pos = FTPoint(glyph->bitmap_left, static_cast(srcHeight) - glyph->bitmap_top, 0.0); } FTBitmapGlyphImpl::~FTBitmapGlyphImpl() { delete [] data; } const FTPoint& FTBitmapGlyphImpl::RenderImpl(const FTPoint& pen, int renderMode) { if(data) { float dx, dy; dx = pen.Xf() + pos.Xf(); dy = pen.Yf() - pos.Yf(); glBitmap(0, 0, 0.0f, 0.0f, dx, dy, (const GLubyte*)0); glPixelStorei(GL_UNPACK_ROW_LENGTH, destPitch * 8); glBitmap(destWidth, destHeight, 0.0f, 0.0, 0.0, 0.0, (const GLubyte*)data); glBitmap(0, 0, 0.0f, 0.0f, -dx, -dy, (const GLubyte*)0); } return advance; } rgl/src/ext/ftgl/FTGlyph/FTExtrudeGlyph.cpp0000644000176200001440000001631314531466703020275 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTExtrudeGlyphImpl.h" #include "FTVectoriser.h" // // FTGLExtrudeGlyph // FTExtrudeGlyph::FTExtrudeGlyph(FT_GlyphSlot glyph, float depth, float frontOutset, float backOutset, bool useDisplayList) : FTGlyph(new FTExtrudeGlyphImpl(glyph, depth, frontOutset, backOutset, useDisplayList)) {} FTExtrudeGlyph::~FTExtrudeGlyph() {} const FTPoint& FTExtrudeGlyph::Render(const FTPoint& pen, int renderMode) { FTExtrudeGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLExtrudeGlyphImpl // FTExtrudeGlyphImpl::FTExtrudeGlyphImpl(FT_GlyphSlot glyph, float _depth, float _frontOutset, float _backOutset, bool useDisplayList) : FTGlyphImpl(glyph), vectoriser(0), glList(0) { bBox.SetDepth(-_depth); if(ft_glyph_format_outline != glyph->format) { err = 0x14; // Invalid_Outline return; } vectoriser = new FTVectoriser(glyph); if((vectoriser->ContourCount() < 1) || (vectoriser->PointCount() < 3)) { delete vectoriser; vectoriser = NULL; return; } hscale = glyph->face->size->metrics.x_ppem * 64; vscale = glyph->face->size->metrics.y_ppem * 64; depth = _depth; frontOutset = _frontOutset; backOutset = _backOutset; if(useDisplayList) { glList = glGenLists(3); /* Front face */ glNewList(glList + 0, GL_COMPILE); RenderFront(); glEndList(); /* Back face */ glNewList(glList + 1, GL_COMPILE); RenderBack(); glEndList(); /* Side face */ glNewList(glList + 2, GL_COMPILE); RenderSide(); glEndList(); delete vectoriser; vectoriser = NULL; } } FTExtrudeGlyphImpl::~FTExtrudeGlyphImpl() { if(glList) { glDeleteLists(glList, 3); } else if(vectoriser) { delete vectoriser; } } const FTPoint& FTExtrudeGlyphImpl::RenderImpl(const FTPoint& pen, int renderMode) { glTranslatef(pen.Xf(), pen.Yf(), pen.Zf()); if(glList) { if(renderMode & FTGL::RENDER_FRONT) glCallList(glList + 0); if(renderMode & FTGL::RENDER_BACK) glCallList(glList + 1); if(renderMode & FTGL::RENDER_SIDE) glCallList(glList + 2); } else if(vectoriser) { if(renderMode & FTGL::RENDER_FRONT) RenderFront(); if(renderMode & FTGL::RENDER_BACK) RenderBack(); if(renderMode & FTGL::RENDER_SIDE) RenderSide(); } glTranslatef(-pen.Xf(), -pen.Yf(), -pen.Zf()); return advance; } void FTExtrudeGlyphImpl::RenderFront() { vectoriser->MakeMesh(1.0, 1, frontOutset); glNormal3d(0.0, 0.0, 1.0); const FTMesh *mesh = vectoriser->GetMesh(); for(unsigned int j = 0; j < mesh->TesselationCount(); ++j) { const FTTesselation* subMesh = mesh->Tesselation(j); unsigned int polygonType = subMesh->PolygonType(); glBegin(polygonType); for(unsigned int i = 0; i < subMesh->PointCount(); ++i) { FTPoint pt = subMesh->Point(i); glTexCoord2f(pt.Xf() / hscale, pt.Yf() / vscale); glVertex3f(pt.Xf() / 64.0f, pt.Yf() / 64.0f, 0.0f); } glEnd(); } } void FTExtrudeGlyphImpl::RenderBack() { vectoriser->MakeMesh(-1.0, 2, backOutset); glNormal3d(0.0, 0.0, -1.0); const FTMesh *mesh = vectoriser->GetMesh(); for(unsigned int j = 0; j < mesh->TesselationCount(); ++j) { const FTTesselation* subMesh = mesh->Tesselation(j); unsigned int polygonType = subMesh->PolygonType(); glBegin(polygonType); for(unsigned int i = 0; i < subMesh->PointCount(); ++i) { FTPoint pt = subMesh->Point(i); glTexCoord2f(subMesh->Point(i).Xf() / hscale, subMesh->Point(i).Yf() / vscale); glVertex3f(subMesh->Point(i).Xf() / 64.0f, subMesh->Point(i).Yf() / 64.0f, -depth); } glEnd(); } } void FTExtrudeGlyphImpl::RenderSide() { int contourFlag = vectoriser->ContourFlag(); for(size_t c = 0; c < vectoriser->ContourCount(); ++c) { const FTContour* contour = vectoriser->Contour(c); size_t n = contour->PointCount(); if(n < 2) { continue; } glBegin(GL_QUAD_STRIP); for(size_t j = 0; j <= n; ++j) { size_t cur = (j == n) ? 0 : j; size_t next = (cur == n - 1) ? 0 : cur + 1; FTPoint frontPt = contour->FrontPoint(cur); FTPoint nextPt = contour->FrontPoint(next); FTPoint backPt = contour->BackPoint(cur); FTPoint normal = FTPoint(0.f, 0.f, 1.f) ^ (frontPt - nextPt); if(normal != FTPoint(0.0f, 0.0f, 0.0f)) { glNormal3dv(static_cast(normal.Normalise())); } glTexCoord2f(frontPt.Xf() / hscale, frontPt.Yf() / vscale); if(contourFlag & ft_outline_reverse_fill) { glVertex3f(backPt.Xf() / 64.0f, backPt.Yf() / 64.0f, 0.0f); glVertex3f(frontPt.Xf() / 64.0f, frontPt.Yf() / 64.0f, -depth); } else { glVertex3f(backPt.Xf() / 64.0f, backPt.Yf() / 64.0f, -depth); glVertex3f(frontPt.Xf() / 64.0f, frontPt.Yf() / 64.0f, 0.0f); } } glEnd(); } } rgl/src/ext/ftgl/FTGlyph/FTOutlineGlyph.cpp0000644000176200001440000000732614531466703020300 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTOutlineGlyphImpl.h" #include "FTVectoriser.h" // // FTGLOutlineGlyph // FTOutlineGlyph::FTOutlineGlyph(FT_GlyphSlot glyph, float outset, bool useDisplayList) : FTGlyph(new FTOutlineGlyphImpl(glyph, outset, useDisplayList)) {} FTOutlineGlyph::~FTOutlineGlyph() {} const FTPoint& FTOutlineGlyph::Render(const FTPoint& pen, int renderMode) { FTOutlineGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLOutlineGlyphImpl // FTOutlineGlyphImpl::FTOutlineGlyphImpl(FT_GlyphSlot glyph, float _outset, bool useDisplayList) : FTGlyphImpl(glyph), glList(0) { if(ft_glyph_format_outline != glyph->format) { err = 0x14; // Invalid_Outline return; } vectoriser = new FTVectoriser(glyph); if((vectoriser->ContourCount() < 1) || (vectoriser->PointCount() < 3)) { delete vectoriser; vectoriser = NULL; return; } outset = _outset; if(useDisplayList) { glList = glGenLists(1); glNewList(glList, GL_COMPILE); DoRender(); glEndList(); delete vectoriser; vectoriser = NULL; } } FTOutlineGlyphImpl::~FTOutlineGlyphImpl() { if(glList) { glDeleteLists(glList, 1); } else if(vectoriser) { delete vectoriser; } } const FTPoint& FTOutlineGlyphImpl::RenderImpl(const FTPoint& pen, int renderMode) { glTranslatef(pen.Xf(), pen.Yf(), pen.Zf()); if(glList) { glCallList(glList); } else if(vectoriser) { DoRender(); } glTranslatef(-pen.Xf(), -pen.Yf(), -pen.Zf()); return advance; } void FTOutlineGlyphImpl::DoRender() { for(unsigned int c = 0; c < vectoriser->ContourCount(); ++c) { const FTContour* contour = vectoriser->Contour(c); glBegin(GL_LINE_LOOP); for(unsigned int i = 0; i < contour->PointCount(); ++i) { FTPoint point = FTPoint(contour->Point(i).X() + contour->Outset(i).X() * outset, contour->Point(i).Y() + contour->Outset(i).Y() * outset, 0); glVertex2f(point.Xf() / 64.0f, point.Yf() / 64.0f); } glEnd(); } } rgl/src/ext/ftgl/FTGlyph/FTPolygonGlyph.cpp0000644000176200001440000000754414531466703020312 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTPolygonGlyphImpl.h" #include "FTVectoriser.h" // // FTGLPolyGlyph // FTPolygonGlyph::FTPolygonGlyph(FT_GlyphSlot glyph, float outset, bool useDisplayList) : FTGlyph(new FTPolygonGlyphImpl(glyph, outset, useDisplayList)) {} FTPolygonGlyph::~FTPolygonGlyph() {} const FTPoint& FTPolygonGlyph::Render(const FTPoint& pen, int renderMode) { FTPolygonGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLPolyGlyphImpl // FTPolygonGlyphImpl::FTPolygonGlyphImpl(FT_GlyphSlot glyph, float _outset, bool useDisplayList) : FTGlyphImpl(glyph), glList(0) { if(ft_glyph_format_outline != glyph->format) { err = 0x14; // Invalid_Outline return; } vectoriser = new FTVectoriser(glyph); if((vectoriser->ContourCount() < 1) || (vectoriser->PointCount() < 3)) { delete vectoriser; vectoriser = NULL; return; } hscale = glyph->face->size->metrics.x_ppem * 64; vscale = glyph->face->size->metrics.y_ppem * 64; outset = _outset; if(useDisplayList) { glList = glGenLists(1); glNewList(glList, GL_COMPILE); DoRender(); glEndList(); delete vectoriser; vectoriser = NULL; } } FTPolygonGlyphImpl::~FTPolygonGlyphImpl() { if(glList) { glDeleteLists(glList, 1); } else if(vectoriser) { delete vectoriser; } } const FTPoint& FTPolygonGlyphImpl::RenderImpl(const FTPoint& pen, int renderMode) { glTranslatef(pen.Xf(), pen.Yf(), pen.Zf()); if(glList) { glCallList(glList); } else if(vectoriser) { DoRender(); } glTranslatef(-pen.Xf(), -pen.Yf(), -pen.Zf()); return advance; } void FTPolygonGlyphImpl::DoRender() { vectoriser->MakeMesh(1.0, 1, outset); const FTMesh *mesh = vectoriser->GetMesh(); for(unsigned int t = 0; t < mesh->TesselationCount(); ++t) { const FTTesselation* subMesh = mesh->Tesselation(t); unsigned int polygonType = subMesh->PolygonType(); glBegin(polygonType); for(unsigned int i = 0; i < subMesh->PointCount(); ++i) { FTPoint point = subMesh->Point(i); glTexCoord2f(point.Xf() / hscale, point.Yf() / vscale); glVertex3f(point.Xf() / 64.0f, point.Yf() / 64.0f, 0.0f); } glEnd(); } } rgl/src/ext/ftgl/FTGlyph/FTPixmapGlyphImpl.h0000644000176200001440000000375514265301465020405 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTPixmapGlyphImpl__ #define __FTPixmapGlyphImpl__ #include "FTGlyphImpl.h" class FTPixmapGlyphImpl : public FTGlyphImpl { friend class FTPixmapGlyph; protected: FTPixmapGlyphImpl(FT_GlyphSlot glyph); virtual ~FTPixmapGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: /** * The width of the glyph 'image' */ int destWidth; /** * The height of the glyph 'image' */ int destHeight; /** * Vector from the pen position to the topleft corner of the pixmap */ FTPoint pos; /** * Pointer to the 'image' data */ unsigned char* data; }; #endif // __FTPixmapGlyphImpl__ rgl/src/ext/ftgl/FTGlyph/FTBufferGlyphImpl.h0000644000176200001440000000326214530125451020343 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTBufferGlyphImpl__ #define __FTBufferGlyphImpl__ #include "FTGlyphImpl.h" class FTBufferGlyphImpl : public FTGlyphImpl { friend class FTBufferGlyph; protected: FTBufferGlyphImpl(FT_GlyphSlot glyph, FTBuffer *p); virtual ~FTBufferGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: bool has_bitmap; FT_Bitmap bitmap; unsigned char *pixels; FTPoint corner; FTBuffer *buffer; }; #endif // __FTBufferGlyphImpl__ rgl/src/ext/ftgl/FTGlyph/FTPixmapGlyph.cpp0000644000176200001440000000676714265301465020124 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTPixmapGlyphImpl.h" // // FTGLPixmapGlyph // FTPixmapGlyph::FTPixmapGlyph(FT_GlyphSlot glyph) : FTGlyph(new FTPixmapGlyphImpl(glyph)) {} FTPixmapGlyph::~FTPixmapGlyph() {} const FTPoint& FTPixmapGlyph::Render(const FTPoint& pen, int renderMode) { FTPixmapGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLPixmapGlyphImpl // FTPixmapGlyphImpl::FTPixmapGlyphImpl(FT_GlyphSlot glyph) : FTGlyphImpl(glyph), destWidth(0), destHeight(0), data(0) { err = FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL); if(err || ft_glyph_format_bitmap != glyph->format) { return; } FT_Bitmap bitmap = glyph->bitmap; //check the pixel mode //ft_pixel_mode_grays int srcWidth = bitmap.width; int srcHeight = bitmap.rows; destWidth = srcWidth; destHeight = srcHeight; if(destWidth && destHeight) { data = new unsigned char[destWidth * destHeight * 2]; unsigned char* src = bitmap.buffer; unsigned char* dest = data + ((destHeight - 1) * destWidth * 2); size_t destStep = destWidth * 2 * 2; for(int y = 0; y < srcHeight; ++y) { for(int x = 0; x < srcWidth; ++x) { *dest++ = static_cast(255); *dest++ = *src++; } dest -= destStep; } destHeight = srcHeight; } pos.X(glyph->bitmap_left); pos.Y(srcHeight - glyph->bitmap_top); } FTPixmapGlyphImpl::~FTPixmapGlyphImpl() { delete [] data; } const FTPoint& FTPixmapGlyphImpl::RenderImpl(const FTPoint& pen, int renderMode) { if(data) { float dx, dy; dx = floor(pen.Xf() + pos.Xf()); dy = floor(pen.Yf() - pos.Yf()); glBitmap(0, 0, 0.0f, 0.0f, dx, dy, (const GLubyte*)0); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_ALIGNMENT, 2); glDrawPixels(destWidth, destHeight, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, (const GLvoid*)data); glBitmap(0, 0, 0.0f, 0.0f, -dx, -dy, (const GLubyte*)0); } return advance; } rgl/src/ext/ftgl/FTGlyph/FTOutlineGlyphImpl.h0000644000176200001440000000403014531466703020554 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTOutlineGlyphImpl__ #define __FTOutlineGlyphImpl__ #include "FTGlyphImpl.h" class FTVectoriser; class FTOutlineGlyphImpl : public FTGlyphImpl { friend class FTOutlineGlyph; protected: FTOutlineGlyphImpl(FT_GlyphSlot glyph, float outset, bool useDisplayList); virtual ~FTOutlineGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: /** * Private rendering method. */ void DoRender(); /** * Private rendering variables. */ FTVectoriser *vectoriser; /** * Private rendering variables. */ float outset; /** * OpenGL display list */ GLuint glList; }; #endif // __FTOutlineGlyphImpl__ rgl/src/ext/ftgl/FTGlyph/FTGlyphImpl.h0000644000176200001440000000354014265301465017216 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTGlyphImpl__ #define __FTGlyphImpl__ #include "FTGL/ftgl.h" class FTGlyphImpl { friend class FTGlyph; protected: FTGlyphImpl(FT_GlyphSlot glyph, bool useDisplayList = true); virtual ~FTGlyphImpl(); float Advance() const; const FTBBox& BBox() const; FT_Error Error() const; /** * The advance distance for this glyph */ FTPoint advance; /** * The bounding box of this glyph. */ FTBBox bBox; /** * Current error code. Zero means no error. */ FT_Error err; }; #endif // __FTGlyphImpl__ rgl/src/ext/ftgl/FTGlyph/FTPolygonGlyphImpl.h0000644000176200001440000000377214531466703020600 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTPolygonGlyphImpl__ #define __FTPolygonGlyphImpl__ #include "FTGlyphImpl.h" class FTVectoriser; class FTPolygonGlyphImpl : public FTGlyphImpl { friend class FTPolygonGlyph; public: FTPolygonGlyphImpl(FT_GlyphSlot glyph, float outset, bool useDisplayList); virtual ~FTPolygonGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: /** * Private rendering method. */ void DoRender(); /** * Private rendering variables. */ unsigned int hscale, vscale; FTVectoriser *vectoriser; float outset; /** * OpenGL display list */ GLuint glList; }; #endif // __FTPolygonGlyphImpl__ rgl/src/ext/ftgl/FTGlyph/FTBitmapGlyphImpl.h0000644000176200001440000000414114531466703020354 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTBitmapGlyphImpl__ #define __FTBitmapGlyphImpl__ #include "FTGlyphImpl.h" class FTBitmapGlyphImpl : public FTGlyphImpl { friend class FTBitmapGlyph; protected: FTBitmapGlyphImpl(FT_GlyphSlot glyph); virtual ~FTBitmapGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: /** * The width of the glyph 'image' */ unsigned int destWidth; /** * The height of the glyph 'image' */ unsigned int destHeight; /** * The pitch of the glyph 'image' */ unsigned int destPitch; /** * Vector from the pen position to the topleft corner of the bitmap */ FTPoint pos; /** * Pointer to the 'image' data */ unsigned char* data; }; #endif // __FTBitmapGlyphImpl__ rgl/src/ext/ftgl/FTGlyph/FTExtrudeGlyphImpl.h0000644000176200001440000000420114531466703020555 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTExtrudeGlyphImpl__ #define __FTExtrudeGlyphImpl__ #include "FTGlyphImpl.h" class FTVectoriser; class FTExtrudeGlyphImpl : public FTGlyphImpl { friend class FTExtrudeGlyph; protected: FTExtrudeGlyphImpl(FT_GlyphSlot glyph, float depth, float frontOutset, float backOutset, bool useDisplayList); virtual ~FTExtrudeGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: /** * Private rendering methods. */ void RenderFront(); void RenderBack(); void RenderSide(); /** * Private rendering variables. */ unsigned int hscale, vscale; float depth; float frontOutset, backOutset; FTVectoriser *vectoriser; /** * OpenGL display list */ GLuint glList; }; #endif // __FTExtrudeGlyphImpl__ rgl/src/ext/ftgl/FTGlyph/FTTextureGlyphImpl.h0000644000176200001440000000537714531466703020614 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTTextureGlyphImpl__ #define __FTTextureGlyphImpl__ #include "FTGlyphImpl.h" class FTTextureGlyphImpl : public FTGlyphImpl { friend class FTTextureGlyph; friend class FTTextureFontImpl; protected: FTTextureGlyphImpl(FT_GlyphSlot glyph, int id, int xOffset, int yOffset, int width, int height); virtual ~FTTextureGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: /** * Reset the currently active texture to zero to get into a known * state before drawing a string. This is to get round possible * threading issues. */ static void ResetActiveTexture() { activeTextureID = 0; } /** * The width of the glyph 'image' */ int destWidth; /** * The height of the glyph 'image' */ int destHeight; /** * Vector from the pen position to the topleft corner of the pixmap */ FTPoint corner; /** * The texture co-ords of this glyph within the texture. */ FTPoint uv[2]; /** * The texture index that this glyph is contained in. */ int glTextureID; /** * The texture index of the currently active texture * * We keep track of the currently active texture to try to reduce the * number of texture bind operations. */ static GLint activeTextureID; }; #endif // __FTTextureGlyphImpl__ rgl/src/ext/ftgl/FTContour.cpp0000644000176200001440000001625314531466703015770 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Éric Beets * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTContour.h" #include static const unsigned int BEZIER_STEPS = 5; void FTContour::AddPoint(FTPoint point) { if(pointList.empty() || (point != pointList[pointList.size() - 1] && point != pointList[0])) { pointList.push_back(point); } } void FTContour::AddOutsetPoint(FTPoint point) { outsetPointList.push_back(point); } void FTContour::AddFrontPoint(FTPoint point) { frontPointList.push_back(point); } void FTContour::AddBackPoint(FTPoint point) { backPointList.push_back(point); } void FTContour::evaluateQuadraticCurve(FTPoint A, FTPoint B, FTPoint C) { for(unsigned int i = 1; i < BEZIER_STEPS; i++) { float t = static_cast(i) / BEZIER_STEPS; FTPoint U = (1.0f - t) * A + t * B; FTPoint V = (1.0f - t) * B + t * C; AddPoint((1.0f - t) * U + t * V); } } void FTContour::evaluateCubicCurve(FTPoint A, FTPoint B, FTPoint C, FTPoint D) { for(unsigned int i = 0; i < BEZIER_STEPS; i++) { float t = static_cast(i) / BEZIER_STEPS; FTPoint U = (1.0f - t) * A + t * B; FTPoint V = (1.0f - t) * B + t * C; FTPoint W = (1.0f - t) * C + t * D; FTPoint M = (1.0f - t) * U + t * V; FTPoint N = (1.0f - t) * V + t * W; AddPoint((1.0f - t) * M + t * N); } } // This function is a bit tricky. Given a path ABC, it returns the // coordinates of the outset point facing B on the left at a distance // of 64.0. // M // - - - - - - X // ^ / ' // | 64.0 / ' // X---->-----X ==> X--v-------X ' // A B \ A B \ .>' // \ \<' 64.0 // \ \ . // \ \ . // C X C X // FTPoint FTContour::ComputeOutsetPoint(FTPoint A, FTPoint B, FTPoint C) { /* Build the rotation matrix from 'ba' vector */ FTPoint ba = (A - B).Normalise(); FTPoint bc = C - B; /* Rotate bc to the left */ FTPoint tmp(bc.X() * -ba.X() + bc.Y() * -ba.Y(), bc.X() * ba.Y() + bc.Y() * -ba.X()); /* Compute the vector bisecting 'abc' */ FTGL_DOUBLE norm = sqrt(tmp.X() * tmp.X() + tmp.Y() * tmp.Y()); FTGL_DOUBLE dist = 64.0 * sqrt((norm - tmp.X()) / (norm + tmp.X())); tmp.X(tmp.Y() < 0.0 ? dist : -dist); tmp.Y(64.0); /* Rotate the new bc to the right */ return FTPoint(tmp.X() * -ba.X() + tmp.Y() * ba.Y(), tmp.X() * -ba.Y() + tmp.Y() * -ba.X()); } void FTContour::SetParity(int parity) { size_t size = PointCount(); FTPoint vOutset; if(((parity & 1) && clockwise) || (!(parity & 1) && !clockwise)) { // Contour orientation is wrong! We must reverse all points. // FIXME: could it be worth writing FTVector::reverse() for this? for(size_t i = 0; i < size / 2; i++) { FTPoint tmp = pointList[i]; pointList[i] = pointList[size - 1 - i]; pointList[size - 1 -i] = tmp; } clockwise = !clockwise; } for(size_t i = 0; i < size; i++) { size_t prev, cur, next; prev = (i + size - 1) % size; cur = i; next = (i + size + 1) % size; vOutset = ComputeOutsetPoint(Point(prev), Point(cur), Point(next)); AddOutsetPoint(vOutset); } } FTContour::FTContour(FT_Vector* contour, char* tags, unsigned int n) { FTPoint prev, cur(contour[(n - 1) % n]), next(contour[0]); FTPoint a, b = next - cur; double olddir, dir = atan2((next - cur).Y(), (next - cur).X()); double angle = 0.0; // See http://freetype.sourceforge.net/freetype2/docs/glyphs/glyphs-6.html // for a full description of FreeType tags. for(unsigned int i = 0; i < n; i++) { prev = cur; cur = next; next = FTPoint(contour[(i + 1) % n]); olddir = dir; dir = atan2((next - cur).Y(), (next - cur).X()); // Compute our path's new direction. double t = dir - olddir; if(t < -M_PI) t += 2 * M_PI; if(t > M_PI) t -= 2 * M_PI; angle += t; // Only process point tags we know. if(n < 2 || FT_CURVE_TAG(tags[i]) == FT_Curve_Tag_On) { AddPoint(cur); } else if(FT_CURVE_TAG(tags[i]) == FT_Curve_Tag_Conic) { FTPoint prev2 = prev, next2 = next; // Previous point is either the real previous point (an "on" // point), or the midpoint between the current one and the // previous "conic off" point. if(FT_CURVE_TAG(tags[(i - 1 + n) % n]) == FT_Curve_Tag_Conic) { prev2 = (cur + prev) * 0.5; AddPoint(prev2); } // Next point is either the real next point or the midpoint. if(FT_CURVE_TAG(tags[(i + 1) % n]) == FT_Curve_Tag_Conic) { next2 = (cur + next) * 0.5; } evaluateQuadraticCurve(prev2, cur, next2); } else if(FT_CURVE_TAG(tags[i]) == FT_Curve_Tag_Cubic && FT_CURVE_TAG(tags[(i + 1) % n]) == FT_Curve_Tag_Cubic) { evaluateCubicCurve(prev, cur, next, FTPoint(contour[(i + 2) % n])); } } // If final angle is positive (+2PI), it's an anti-clockwise contour, // otherwise (-2PI) it's clockwise. clockwise = (angle < 0.0); } void FTContour::buildFrontOutset(float outset) { for(size_t i = 0; i < PointCount(); ++i) { AddFrontPoint(Point(i) + Outset(i) * outset); } } void FTContour::buildBackOutset(float outset) { for(size_t i = 0; i < PointCount(); ++i) { AddBackPoint(Point(i) + Outset(i) * outset); } } rgl/src/ext/ftgl/FTUnicode.h0000644000176200001440000001776714555455305015407 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2008 Daniel Remenak * * Portions derived from ConvertUTF.c Copyright (C) 2001-2004 Unicode, Inc * Unicode, Inc. hereby grants the right to freely use the information * supplied in this file in the creation of products supporting the * Unicode Standard, and to make copies of this file in any form * for internal or external distribution as long as this notice * remains attached. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTUnicode__ #define __FTUnicode__ /** * Provides a way to easily walk multibyte unicode strings in the various * Unicode encodings (UTF-8, UTF-16, UTF-32, UCS-2, and UCS-4). Encodings * with elements larger than one byte must already be in the correct endian * order for the current architecture. */ template class FTUnicodeStringItr { public: /** * Constructor. Also reads the first character and stores it. * * @param string The buffer to iterate. No copy is made. */ FTUnicodeStringItr(const T* string) : curPos(string), nextPos(string) { (*this)++; }; /** * Pre-increment operator. Reads the next unicode character and sets * the state appropriately. * Note - not protected against overruns. */ FTUnicodeStringItr& operator++() { curPos = nextPos; // unicode handling switch (sizeof(T)) { case 1: // UTF-8 // get this character readUTF8(); break; case 2: // UTF-16 readUTF16(); break; case 4: // UTF-32 // fall through default: // error condition really, but give it a shot anyway curChar = *nextPos++; } return *this; } /** * Post-increment operator. Reads the next character and sets * the state appropriately. * Note - not protected against overruns. */ FTUnicodeStringItr operator++(int) { FTUnicodeStringItr temp = *this; ++*this; return temp; } /** * Equality operator. Two FTUnicodeStringItrs are considered equal * if they have the same current buffer and buffer position. */ bool operator==(const FTUnicodeStringItr& right) const { if (curPos == right.getBufferFromHere()) return true; return false; } /** * Dereference operator. * * @return The unicode codepoint of the character currently pointed * to by the FTUnicodeStringItr. */ unsigned int operator*() const { return curChar; } /** * Buffer-fetching getter. You can use this to retreive the buffer * starting at the currently-iterated character for functions which * require a Unicode string as input. */ const T* getBufferFromHere() const { return curPos; } private: /** * Helper function for reading a single UTF8 character from the string. * Updates internal state appropriately. */ void readUTF8(); /** * Helper function for reading a single UTF16 character from the string. * Updates internal state appropriately. */ void readUTF16(); /** * The buffer position of the first element in the current character. */ const T* curPos; /** * The character stored at the current buffer position (prefetched on * increment, so there's no penalty for dereferencing more than once). */ unsigned int curChar; /** * The buffer position of the first element in the next character. */ const T* nextPos; // unicode magic numbers static const char utf8bytes[256]; static const unsigned long offsetsFromUTF8[6]; static const unsigned long highSurrogateStart; static const unsigned long highSurrogateEnd; static const unsigned long lowSurrogateStart; static const unsigned long lowSurrogateEnd; static const unsigned long highSurrogateShift; static const unsigned long lowSurrogateBase; }; /* The first character in a UTF8 sequence indicates how many bytes * to read (among other things) */ template const char FTUnicodeStringItr::utf8bytes[256] = { 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, 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, 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, 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, 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, 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, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,5,5,5,5,6,6,6,6 }; /* Magic values subtracted from a buffer value during UTF8 conversion. * This table contains as many values as there might be trailing bytes * in a UTF-8 sequence. */ template const unsigned long FTUnicodeStringItr::offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; // get a UTF8 character; leave the tracking pointer at the start of the // next character // not protected against invalid UTF8 template inline void FTUnicodeStringItr::readUTF8() { unsigned int ch = 0; unsigned int extraBytesToRead = utf8bytes[(unsigned char)(*nextPos)]; // falls through switch (extraBytesToRead) { case 6: ch += *nextPos++; ch <<= 6; /* remember, illegal UTF-8 */ case 5: ch += *nextPos++; ch <<= 6; /* remember, illegal UTF-8 */ case 4: ch += *nextPos++; ch <<= 6; case 3: ch += *nextPos++; ch <<= 6; case 2: ch += *nextPos++; ch <<= 6; case 1: ch += *nextPos++; } ch -= offsetsFromUTF8[extraBytesToRead-1]; curChar = ch; } // Magic numbers for UTF-16 conversions template const unsigned long FTUnicodeStringItr::highSurrogateStart = 0xD800; template const unsigned long FTUnicodeStringItr::highSurrogateEnd = 0xDBFF; template const unsigned long FTUnicodeStringItr::lowSurrogateStart = 0xDC00; template const unsigned long FTUnicodeStringItr::lowSurrogateEnd = 0xDFFF; template const unsigned long FTUnicodeStringItr::highSurrogateShift = 10; template const unsigned long FTUnicodeStringItr::lowSurrogateBase = 0x0010000UL; template inline void FTUnicodeStringItr::readUTF16() { unsigned int ch = *nextPos++; // if we have the first half of the surrogate pair if (ch >= highSurrogateStart && ch <= highSurrogateEnd) { unsigned int ch2 = *curPos; // complete the surrogate pair if (ch2 >= lowSurrogateStart && ch2 <= lowSurrogateEnd) { ch = static_cast(((ch - highSurrogateStart) << highSurrogateShift) + (ch2 - lowSurrogateStart) + lowSurrogateBase); ++nextPos; } } curChar = ch; } #endif rgl/src/ext/ftgl/FTBuffer.cpp0000644000176200001440000000324214265301465015537 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTGL/ftgl.h" FTBuffer::FTBuffer() : width(0), height(0), pixels(0), pos(FTPoint()) { } FTBuffer::~FTBuffer() { if(pixels) { delete[] pixels; } } void FTBuffer::Size(int w, int h) { if(w == width && h == height) { return; } if(w * h != width * height) { if(pixels) { delete[] pixels; } pixels = new unsigned char[w * h]; } memset(pixels, 0, w * h); width = w; height = h; } rgl/src/ext/ftgl/FTVectoriser.cpp0000644000176200001440000002106414531466703016460 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTInternals.h" #include "FTVectoriser.h" #ifndef CALLBACK #define CALLBACK #endif #if defined __APPLE_CC__ && __APPLE_CC__ < 5465 typedef GLvoid (*GLUTesselatorFunction) (...); #elif defined WIN32 && !defined __CYGWIN__ typedef GLvoid (CALLBACK *GLUTesselatorFunction) (); #else typedef GLvoid (*GLUTesselatorFunction) (); #endif void CALLBACK ftglError(GLenum errCode, FTMesh* mesh) { mesh->Error(errCode); } void CALLBACK ftglVertex(void* data, FTMesh* mesh) { FTGL_DOUBLE* vertex = static_cast(data); mesh->AddPoint(vertex[0], vertex[1], vertex[2]); } void CALLBACK ftglCombine(FTGL_DOUBLE coords[3], void* vertex_data[4], GLfloat weight[4], void** outData, FTMesh* mesh) { const FTGL_DOUBLE* vertex = static_cast(coords); *outData = const_cast(mesh->Combine(vertex[0], vertex[1], vertex[2])); } void CALLBACK ftglBegin(GLenum type, FTMesh* mesh) { mesh->Begin(type); } void CALLBACK ftglEnd(FTMesh* mesh) { mesh->End(); } FTMesh::FTMesh() : currentTesselation(0), err(0) { tesselationList.reserve(16); } FTMesh::~FTMesh() { for(size_t t = 0; t < tesselationList.size(); ++t) { delete tesselationList[t]; } tesselationList.clear(); } void FTMesh::AddPoint(const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z) { currentTesselation->AddPoint(x, y, z); } const FTGL_DOUBLE* FTMesh::Combine(const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z) { tempPointList.push_back(FTPoint(x, y,z)); return static_cast(tempPointList.back()); } void FTMesh::Begin(GLenum meshType) { currentTesselation = new FTTesselation(meshType); } void FTMesh::End() { tesselationList.push_back(currentTesselation); } const FTTesselation* const FTMesh::Tesselation(size_t index) const { return (index < tesselationList.size()) ? tesselationList[index] : NULL; } FTVectoriser::FTVectoriser(const FT_GlyphSlot glyph) : contourList(0), mesh(0), ftContourCount(0), contourFlag(0) { if(glyph) { outline = glyph->outline; ftContourCount = outline.n_contours; contourList = 0; contourFlag = outline.flags; ProcessContours(); } } FTVectoriser::~FTVectoriser() { for(size_t c = 0; c < ContourCount(); ++c) { delete contourList[c]; } delete [] contourList; delete mesh; } void FTVectoriser::ProcessContours() { short contourLength = 0; short startIndex = 0; short endIndex = 0; contourList = new FTContour*[ftContourCount]; for(int i = 0; i < ftContourCount; ++i) { FT_Vector* pointList = &outline.points[startIndex]; char* tagList = &outline.tags[startIndex]; endIndex = outline.contours[i]; contourLength = (endIndex - startIndex) + 1; FTContour* contour = new FTContour(pointList, tagList, contourLength); contourList[i] = contour; startIndex = endIndex + 1; } // Compute each contour's parity. FIXME: see if FT_Outline_Get_Orientation // can do it for us. for(int i = 0; i < ftContourCount; i++) { FTContour *c1 = contourList[i]; // 1. Find the leftmost point. FTPoint leftmost(65536.0, 0.0); for(size_t n = 0; n < c1->PointCount(); n++) { FTPoint p = c1->Point(n); if(p.X() < leftmost.X()) { leftmost = p; } } // 2. Count how many other contours we cross when going further to // the left. int parity = 0; for(int j = 0; j < ftContourCount; j++) { if(j == i) { continue; } FTContour *c2 = contourList[j]; for(size_t n = 0; n < c2->PointCount(); n++) { FTPoint p1 = c2->Point(n); FTPoint p2 = c2->Point((n + 1) % c2->PointCount()); /* FIXME: combinations of >= > <= and < do not seem stable */ if((p1.Y() < leftmost.Y() && p2.Y() < leftmost.Y()) || (p1.Y() >= leftmost.Y() && p2.Y() >= leftmost.Y()) || (p1.X() > leftmost.X() && p2.X() > leftmost.X())) { continue; } else if(p1.X() < leftmost.X() && p2.X() < leftmost.X()) { parity++; } else { FTPoint a = p1 - leftmost; FTPoint b = p2 - leftmost; if(b.X() * a.Y() > b.Y() * a.X()) { parity++; } } } } // 3. Make sure the glyph has the proper parity. c1->SetParity(parity); } } size_t FTVectoriser::PointCount() { size_t s = 0; for(size_t c = 0; c < ContourCount(); ++c) { s += contourList[c]->PointCount(); } return s; } const FTContour* const FTVectoriser::Contour(size_t index) const { return (index < ContourCount()) ? contourList[index] : NULL; } void FTVectoriser::MakeMesh(FTGL_DOUBLE zNormal, int outsetType, float outsetSize) { if(mesh) { delete mesh; } mesh = new FTMesh; GLUtesselator* tobj = gluNewTess(); gluTessCallback(tobj, GLU_TESS_BEGIN_DATA, (GLUTesselatorFunction)ftglBegin); gluTessCallback(tobj, GLU_TESS_VERTEX_DATA, (GLUTesselatorFunction)ftglVertex); gluTessCallback(tobj, GLU_TESS_COMBINE_DATA, (GLUTesselatorFunction)ftglCombine); gluTessCallback(tobj, GLU_TESS_END_DATA, (GLUTesselatorFunction)ftglEnd); gluTessCallback(tobj, GLU_TESS_ERROR_DATA, (GLUTesselatorFunction)ftglError); if(contourFlag & ft_outline_even_odd_fill) // ft_outline_reverse_fill { gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); } else { gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO); } gluTessProperty(tobj, GLU_TESS_TOLERANCE, 0); gluTessNormal(tobj, 0.0f, 0.0f, zNormal); gluTessBeginPolygon(tobj, mesh); for(size_t c = 0; c < ContourCount(); ++c) { /* Build the */ switch(outsetType) { case 1 : contourList[c]->buildFrontOutset(outsetSize); break; case 2 : contourList[c]->buildBackOutset(outsetSize); break; } const FTContour* contour = contourList[c]; gluTessBeginContour(tobj); for(size_t p = 0; p < contour->PointCount(); ++p) { const FTGL_DOUBLE* d; switch(outsetType) { case 1: d = contour->FrontPoint(p); break; case 2: d = contour->BackPoint(p); break; case 0: default: d = contour->Point(p); break; } // XXX: gluTessVertex doesn't modify the data but does not // specify "const" in its prototype, so we cannot cast to // a const type. gluTessVertex(tobj, (GLdouble *)d, (GLvoid *)d); } gluTessEndContour(tobj); } gluTessEndPolygon(tobj); gluDeleteTess(tobj); } rgl/src/ext/ftgl/FTFont/0000755000176200001440000000000014531466703014532 5ustar liggesusersrgl/src/ext/ftgl/FTFont/FTPolygonFont.cpp0000644000176200001440000000471714531466703017757 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTPolygonFontImpl.h" // // FTPolygonFont // FTPolygonFont::FTPolygonFont(char const *fontFilePath) : FTFont(new FTPolygonFontImpl(this, fontFilePath)) {} FTPolygonFont::FTPolygonFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTPolygonFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTPolygonFont::~FTPolygonFont() {} FTGlyph* FTPolygonFont::MakeGlyph(FT_GlyphSlot ftGlyph) { FTPolygonFontImpl *myimpl = dynamic_cast(impl); if(!myimpl) { return NULL; } return new FTPolygonGlyph(ftGlyph, myimpl->outset, myimpl->useDisplayLists); } // // FTPolygonFontImpl // FTPolygonFontImpl::FTPolygonFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath), outset(0.0f) { load_flags = FT_LOAD_NO_HINTING; } FTPolygonFontImpl::FTPolygonFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes), outset(0.0f) { load_flags = FT_LOAD_NO_HINTING; } rgl/src/ext/ftgl/FTFont/FTBufferFontImpl.h0000644000176200001440000000541214265301465020016 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTBufferFontImpl__ #define __FTBufferFontImpl__ #include "FTFontImpl.h" class FTGlyph; class FTBuffer; class FTBufferFontImpl : public FTFontImpl { friend class FTBufferFont; protected: FTBufferFontImpl(FTFont *ftFont, const char* fontFilePath); FTBufferFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); virtual ~FTBufferFontImpl(); virtual FTPoint Render(const char *s, const int len, FTPoint position, FTPoint spacing, int renderMode); virtual FTPoint Render(const wchar_t *s, const int len, FTPoint position, FTPoint spacing, int renderMode); virtual bool FaceSize(const unsigned int size, const unsigned int res); private: /** * Create an FTBufferGlyph object for the base class. */ FTGlyph* MakeGlyphImpl(FT_GlyphSlot ftGlyph); /* Internal generic Render() implementation */ template inline FTPoint RenderI(const T *s, const int len, FTPoint position, FTPoint spacing, int mode); /* Pixel buffer */ FTBuffer *buffer; static const int BUFFER_CACHE_SIZE = 16; /* Texture IDs */ GLuint idCache[BUFFER_CACHE_SIZE]; void *stringCache[BUFFER_CACHE_SIZE]; FTBBox bboxCache[BUFFER_CACHE_SIZE]; FTPoint advanceCache[BUFFER_CACHE_SIZE]; int lastString; }; #endif // __FTBufferFontImpl__ rgl/src/ext/ftgl/FTFont/FTTextureFontImpl.h0000644000176200001440000001100514530124704020232 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTTextureFontImpl__ #define __FTTextureFontImpl__ #include "FTFontImpl.h" #include "FTVector.h" class FTTextureGlyph; class FTTextureFontImpl : public FTFontImpl { friend class FTTextureFont; protected: FTTextureFontImpl(FTFont *ftFont, const char* fontFilePath); FTTextureFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); virtual ~FTTextureFontImpl(); /** * Set the char size for the current face. * * @param size the face size in points (1/72 inch) * @param res the resolution of the target device. * @return true if size was set correctly */ virtual bool FaceSize(const unsigned int size, const unsigned int res = 72); virtual FTPoint Render(const char *s, const int len, FTPoint position, FTPoint spacing, int renderMode); virtual FTPoint Render(const wchar_t *s, const int len, FTPoint position, FTPoint spacing, int renderMode); private: /** * Create an FTTextureGlyph object for the base class. */ FTGlyph* MakeGlyphImpl(FT_GlyphSlot ftGlyph); /** * Get the size of a block of memory required to layout the glyphs * * Calculates a width and height based on the glyph sizes and the * number of glyphs. It over estimates. */ inline void CalculateTextureSize(); /** * Creates a 'blank' OpenGL texture object. * * The format is GL_ALPHA and the params are * GL_TEXTURE_WRAP_S = GL_CLAMP * GL_TEXTURE_WRAP_T = GL_CLAMP * GL_TEXTURE_MAG_FILTER = GL_LINEAR * GL_TEXTURE_MIN_FILTER = GL_LINEAR * Note that mipmapping is NOT used */ inline GLuint CreateTexture(); /** * The maximum texture dimension on this OpenGL implemetation */ GLsizei maximumGLTextureSize; /** * The minimum texture width required to hold the glyphs */ GLsizei textureWidth; /** * The minimum texture height required to hold the glyphs */ GLsizei textureHeight; /** *An array of texture ids */ FTVector textureIDList; /** * The max height for glyphs in the current font */ int glyphHeight; /** * The max width for glyphs in the current font */ int glyphWidth; /** * A value to be added to the height and width to ensure that * glyphs don't overlap in the texture */ unsigned int padding; /** * */ unsigned int numGlyphs; /** */ unsigned int remGlyphs; /** */ int xOffset; /** */ int yOffset; /* Internal generic Render() implementation */ template inline FTPoint RenderI(const T *s, const int len, FTPoint position, FTPoint spacing, int mode); }; #endif // __FTTextureFontImpl__ rgl/src/ext/ftgl/FTFont/FTBufferFont.cpp0000644000176200001440000002265114265301465017533 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTBufferFontImpl.h" // // FTBufferFont // FTBufferFont::FTBufferFont(char const *fontFilePath) : FTFont(new FTBufferFontImpl(this, fontFilePath)) {} FTBufferFont::FTBufferFont(unsigned char const *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTBufferFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTBufferFont::~FTBufferFont() {} FTGlyph* FTBufferFont::MakeGlyph(FT_GlyphSlot ftGlyph) { FTBufferFontImpl *myimpl = dynamic_cast(impl); if(!myimpl) { return NULL; } return myimpl->MakeGlyphImpl(ftGlyph); } // // FTBufferFontImpl // FTBufferFontImpl::FTBufferFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath), buffer(new FTBuffer()) { load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; glGenTextures(BUFFER_CACHE_SIZE, idCache); for(int i = 0; i < BUFFER_CACHE_SIZE; i++) { stringCache[i] = NULL; glBindTexture(GL_TEXTURE_2D, idCache[i]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } lastString = 0; } FTBufferFontImpl::FTBufferFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes), buffer(new FTBuffer()) { load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; glGenTextures(BUFFER_CACHE_SIZE, idCache); for(int i = 0; i < BUFFER_CACHE_SIZE; i++) { stringCache[i] = NULL; glBindTexture(GL_TEXTURE_2D, idCache[i]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } lastString = 0; } FTBufferFontImpl::~FTBufferFontImpl() { glDeleteTextures(BUFFER_CACHE_SIZE, idCache); for(int i = 0; i < BUFFER_CACHE_SIZE; i++) { if(stringCache[i]) { free(stringCache[i]); } } delete buffer; } FTGlyph* FTBufferFontImpl::MakeGlyphImpl(FT_GlyphSlot ftGlyph) { return new FTBufferGlyph(ftGlyph, buffer); } bool FTBufferFontImpl::FaceSize(const unsigned int size, const unsigned int res) { for(int i = 0; i < BUFFER_CACHE_SIZE; i++) { if(stringCache[i]) { free(stringCache[i]); stringCache[i] = NULL; } } return FTFontImpl::FaceSize(size, res); } static inline GLuint NextPowerOf2(GLuint in) { in -= 1; in |= in >> 16; in |= in >> 8; in |= in >> 4; in |= in >> 2; in |= in >> 1; return in + 1; } inline int StringCompare(void const *a, char const *b, int len) { return len < 0 ? strcmp((char const *)a, b) : strncmp((char const *)a, b, len); } inline int StringCompare(void const *a, wchar_t const *b, int len) { return len < 0 ? wcscmp((wchar_t const *)a, b) : wcsncmp((wchar_t const *)a, b, len); } inline char *StringCopy(char const *s, int len) { if(len < 0) { return strdup(s); } else { #ifdef HAVE_STRNDUP return strndup(s, len); #else char *s2 = (char*)malloc(len + 1); memcpy(s2, s, len); s2[len] = 0; return s2; #endif } } inline wchar_t *StringCopy(wchar_t const *s, int len) { if(len < 0) { #if defined HAVE_WCSDUP return wcsdup(s); #else len = (int)wcslen(s); #endif } wchar_t *s2 = (wchar_t *)malloc((len + 1) * sizeof(wchar_t)); memcpy(s2, s, len * sizeof(wchar_t)); s2[len] = 0; return s2; } template inline FTPoint FTBufferFontImpl::RenderI(const T* string, const int len, FTPoint position, FTPoint spacing, int renderMode) { const float padding = 3.0f; int width, height, texWidth, texHeight; int cacheIndex = -1; bool inCache = false; // Protect blending functions, GL_BLEND and GL_TEXTURE_2D glPushAttrib(GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT); // Protect glPixelStorei() calls glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); glEnable(GL_BLEND); glEnable(GL_TEXTURE_2D); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE // Search whether the string is already in a texture we uploaded for(int n = 0; n < BUFFER_CACHE_SIZE; n++) { int i = (lastString + n + BUFFER_CACHE_SIZE) % BUFFER_CACHE_SIZE; if(stringCache[i] && !StringCompare(stringCache[i], string, len)) { cacheIndex = i; inCache = true; break; } } // If the string was not found, we need to put it in the cache and compute // its new bounding box. if(!inCache) { // FIXME: this cache is not very efficient. We should first expire // strings that are not used very often. cacheIndex = lastString; lastString = (lastString + 1) % BUFFER_CACHE_SIZE; if(stringCache[cacheIndex]) { free(stringCache[cacheIndex]); } // FIXME: only the first N bytes are copied; we want the first N chars. stringCache[cacheIndex] = StringCopy(string, len); bboxCache[cacheIndex] = BBox(string, len, FTPoint(), spacing); } FTBBox bbox = bboxCache[cacheIndex]; width = static_cast(bbox.Upper().X() - bbox.Lower().X() + padding + padding + 0.5); height = static_cast(bbox.Upper().Y() - bbox.Lower().Y() + padding + padding + 0.5); texWidth = NextPowerOf2(width); texHeight = NextPowerOf2(height); glBindTexture(GL_TEXTURE_2D, idCache[cacheIndex]); // If the string was not found, we need to render the text in a new // texture buffer, then upload it to the OpenGL layer. if(!inCache) { buffer->Size(texWidth, texHeight); buffer->Pos(FTPoint(padding, padding) - bbox.Lower()); advanceCache[cacheIndex] = FTFontImpl::Render(string, len, FTPoint(), spacing, renderMode); glBindTexture(GL_TEXTURE_2D, idCache[cacheIndex]); glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); /* TODO: use glTexSubImage2D later? */ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texWidth, texHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, (GLvoid *)buffer->Pixels()); buffer->Size(0, 0); } FTPoint low = position + bbox.Lower(); FTPoint up = position + bbox.Upper(); glBegin(GL_QUADS); glNormal3f(0.0f, 0.0f, 1.0f); glTexCoord2f(padding / texWidth, (texHeight - height + padding) / texHeight); glVertex2f(low.Xf(), up.Yf()); glTexCoord2f(padding / texWidth, (texHeight - padding) / texHeight); glVertex2f(low.Xf(), low.Yf()); glTexCoord2f((width - padding) / texWidth, (texHeight - padding) / texHeight); glVertex2f(up.Xf(), low.Yf()); glTexCoord2f((width - padding) / texWidth, (texHeight - height + padding) / texHeight); glVertex2f(up.Xf(), up.Yf()); glEnd(); glPopClientAttrib(); glPopAttrib(); return position + advanceCache[cacheIndex]; } FTPoint FTBufferFontImpl::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } FTPoint FTBufferFontImpl::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } rgl/src/ext/ftgl/FTFont/FTBitmapFont.cpp0000644000176200001440000000577714531466703017553 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTBitmapFontImpl.h" // // FTBitmapFont // FTBitmapFont::FTBitmapFont(char const *fontFilePath) : FTFont(new FTBitmapFontImpl(this, fontFilePath)) {} FTBitmapFont::FTBitmapFont(unsigned char const *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTBitmapFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTBitmapFont::~FTBitmapFont() {} FTGlyph* FTBitmapFont::MakeGlyph(FT_GlyphSlot ftGlyph) { return new FTBitmapGlyph(ftGlyph); } // // FTBitmapFontImpl // template inline FTPoint FTBitmapFontImpl::RenderI(const T* string, const int len, FTPoint position, FTPoint spacing, int renderMode) { // Protect GL_BLEND glPushAttrib(GL_COLOR_BUFFER_BIT); // Protect glPixelStorei() calls (also in FTBitmapGlyphImpl::RenderImpl) glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glDisable(GL_BLEND); FTPoint tmp = FTFontImpl::Render(string, len, position, spacing, renderMode); glPopClientAttrib(); glPopAttrib(); return tmp; } FTPoint FTBitmapFontImpl::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } FTPoint FTBitmapFontImpl::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } rgl/src/ext/ftgl/FTFont/FTOutlineFont.cpp0000644000176200001440000000733214531466703017743 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTOutlineFontImpl.h" // // FTOutlineFont // FTOutlineFont::FTOutlineFont(char const *fontFilePath) : FTFont(new FTOutlineFontImpl(this, fontFilePath)) {} FTOutlineFont::FTOutlineFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTOutlineFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTOutlineFont::~FTOutlineFont() {} FTGlyph* FTOutlineFont::MakeGlyph(FT_GlyphSlot ftGlyph) { FTOutlineFontImpl *myimpl = dynamic_cast(impl); if(!myimpl) { return NULL; } return new FTOutlineGlyph(ftGlyph, myimpl->outset, myimpl->useDisplayLists); } // // FTOutlineFontImpl // FTOutlineFontImpl::FTOutlineFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath), outset(0.0f) { load_flags = FT_LOAD_NO_HINTING; } FTOutlineFontImpl::FTOutlineFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes), outset(0.0f) { load_flags = FT_LOAD_NO_HINTING; } template inline FTPoint FTOutlineFontImpl::RenderI(const T* string, const int len, FTPoint position, FTPoint spacing, int renderMode) { // Protect GL_TEXTURE_2D, glHint(), GL_LINE_SMOOTH and blending functions glPushAttrib(GL_ENABLE_BIT | GL_HINT_BIT | GL_LINE_BIT | GL_COLOR_BUFFER_BIT); glDisable(GL_TEXTURE_2D); glEnable(GL_LINE_SMOOTH); glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE FTPoint tmp = FTFontImpl::Render(string, len, position, spacing, renderMode); glPopAttrib(); return tmp; } FTPoint FTOutlineFontImpl::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } FTPoint FTOutlineFontImpl::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } rgl/src/ext/ftgl/FTFont/FTPixmapFont.cpp0000644000176200001440000000770714367500106017561 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTPixmapFontImpl.h" // // FTPixmapFont // FTPixmapFont::FTPixmapFont(char const *fontFilePath) : FTFont(new FTPixmapFontImpl(this, fontFilePath)) {} FTPixmapFont::FTPixmapFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTPixmapFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTPixmapFont::~FTPixmapFont() {} FTGlyph* FTPixmapFont::MakeGlyph(FT_GlyphSlot ftGlyph) { return new FTPixmapGlyph(ftGlyph); } // // FTPixmapFontImpl // FTPixmapFontImpl::FTPixmapFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath) { load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; } FTPixmapFontImpl::FTPixmapFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes) { load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; } template inline FTPoint FTPixmapFontImpl::RenderI(const T* string, const int len, FTPoint position, FTPoint spacing, int renderMode) { // Protect GL_TEXTURE_2D and GL_BLEND, glPixelTransferf(), and blending // functions. glPushAttrib(GL_ENABLE_BIT | GL_PIXEL_MODE_BIT | GL_COLOR_BUFFER_BIT | GL_POLYGON_BIT); // Protect glPixelStorei() calls (made by FTPixmapGlyphImpl::RenderImpl). glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); // Needed on OSX glPolygonMode(GL_FRONT, GL_FILL); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_TEXTURE_2D); GLfloat ftglColour[4]; glGetFloatv(GL_CURRENT_RASTER_COLOR, ftglColour); glPixelTransferf(GL_RED_SCALE, ftglColour[0]); glPixelTransferf(GL_GREEN_SCALE, ftglColour[1]); glPixelTransferf(GL_BLUE_SCALE, ftglColour[2]); glPixelTransferf(GL_ALPHA_SCALE, ftglColour[3]); FTPoint tmp = FTFontImpl::Render(string, len, position, spacing, renderMode); glPopClientAttrib(); glPopAttrib(); return tmp; } FTPoint FTPixmapFontImpl::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } FTPoint FTPixmapFontImpl::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } rgl/src/ext/ftgl/FTFont/FTBitmapFontImpl.h0000644000176200001440000000447614530124502020020 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTBitmapFontImpl__ #define __FTBitmapFontImpl__ #include "FTFontImpl.h" class FTGlyph; class FTBitmapFontImpl : public FTFontImpl { friend class FTBitmapFont; protected: FTBitmapFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath) {}; FTBitmapFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes) {}; virtual FTPoint Render(const char *s, const int len, FTPoint position, FTPoint spacing, int renderMode); virtual FTPoint Render(const wchar_t *s, const int len, FTPoint position, FTPoint spacing, int renderMode); private: /* Internal generic Render() implementation */ template inline FTPoint RenderI(const T *s, const int len, FTPoint position, FTPoint spacing, int mode); }; #endif // __FTBitmapFontImpl__ rgl/src/ext/ftgl/FTFont/FTTextureFont.cpp0000644000176200001440000001644714531466703017773 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include #include // For memset #include "FTGL/ftgl.h" #include "FTInternals.h" #include "../FTGlyph/FTTextureGlyphImpl.h" #include "./FTTextureFontImpl.h" // // FTTextureFont // FTTextureFont::FTTextureFont(char const *fontFilePath) : FTFont(new FTTextureFontImpl(this, fontFilePath)) {} FTTextureFont::FTTextureFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTTextureFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTTextureFont::~FTTextureFont() {} FTGlyph* FTTextureFont::MakeGlyph(FT_GlyphSlot ftGlyph) { FTTextureFontImpl *myimpl = dynamic_cast(impl); if(!myimpl) { return NULL; } return myimpl->MakeGlyphImpl(ftGlyph); } // // FTTextureFontImpl // static inline GLuint NextPowerOf2(GLuint in) { in -= 1; in |= in >> 16; in |= in >> 8; in |= in >> 4; in |= in >> 2; in |= in >> 1; return in + 1; } FTTextureFontImpl::FTTextureFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath), maximumGLTextureSize(0), textureWidth(0), textureHeight(0), glyphHeight(0), glyphWidth(0), padding(3), xOffset(0), yOffset(0) { load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; remGlyphs = numGlyphs = face.GlyphCount(); } FTTextureFontImpl::FTTextureFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes), maximumGLTextureSize(0), textureWidth(0), textureHeight(0), glyphHeight(0), glyphWidth(0), padding(3), xOffset(0), yOffset(0) { load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; remGlyphs = numGlyphs = face.GlyphCount(); } FTTextureFontImpl::~FTTextureFontImpl() { if(textureIDList.size()) { glDeleteTextures((GLsizei)textureIDList.size(), (const GLuint*)&textureIDList[0]); } } FTGlyph* FTTextureFontImpl::MakeGlyphImpl(FT_GlyphSlot ftGlyph) { glyphHeight = static_cast(charSize.Height() + 0.5); glyphWidth = static_cast(charSize.Width() + 0.5); if(glyphHeight < 1) glyphHeight = 1; if(glyphWidth < 1) glyphWidth = 1; if(textureIDList.empty()) { textureIDList.push_back(CreateTexture()); xOffset = yOffset = padding; } if(xOffset > (textureWidth - glyphWidth)) { xOffset = padding; yOffset += glyphHeight; if(yOffset > (textureHeight - glyphHeight)) { textureIDList.push_back(CreateTexture()); yOffset = padding; } } FTTextureGlyph* tempGlyph = new FTTextureGlyph(ftGlyph, textureIDList[textureIDList.size() - 1], xOffset, yOffset, textureWidth, textureHeight); xOffset += static_cast(tempGlyph->BBox().Upper().X() - tempGlyph->BBox().Lower().X() + padding + 0.5); --remGlyphs; return tempGlyph; } void FTTextureFontImpl::CalculateTextureSize() { if(!maximumGLTextureSize) { maximumGLTextureSize = 1024; glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint*)&maximumGLTextureSize); assert(maximumGLTextureSize); // If you hit this then you have an invalid OpenGL context. } textureWidth = NextPowerOf2((remGlyphs * glyphWidth) + (padding * 2)); textureWidth = textureWidth > maximumGLTextureSize ? maximumGLTextureSize : textureWidth; int h = static_cast((textureWidth - (padding * 2)) / glyphWidth + 0.5); textureHeight = NextPowerOf2(((numGlyphs / h) + 1) * glyphHeight); textureHeight = textureHeight > maximumGLTextureSize ? maximumGLTextureSize : textureHeight; } GLuint FTTextureFontImpl::CreateTexture() { CalculateTextureSize(); int totalMemory = textureWidth * textureHeight; unsigned char* textureMemory = new unsigned char[totalMemory]; memset(textureMemory, 0, totalMemory); GLuint textID; glGenTextures(1, (GLuint*)&textID); glBindTexture(GL_TEXTURE_2D, textID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, textureWidth, textureHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, textureMemory); delete [] textureMemory; return textID; } bool FTTextureFontImpl::FaceSize(const unsigned int size, const unsigned int res) { if(!textureIDList.empty()) { glDeleteTextures((GLsizei)textureIDList.size(), (const GLuint*)&textureIDList[0]); textureIDList.clear(); remGlyphs = numGlyphs = face.GlyphCount(); } return FTFontImpl::FaceSize(size, res); } template inline FTPoint FTTextureFontImpl::RenderI(const T* string, const int len, FTPoint position, FTPoint spacing, int renderMode) { // Protect GL_TEXTURE_2D, GL_BLEND and blending functions glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE glEnable(GL_TEXTURE_2D); FTTextureGlyphImpl::ResetActiveTexture(); FTPoint tmp = FTFontImpl::Render(string, len, position, spacing, renderMode); glPopAttrib(); return tmp; } FTPoint FTTextureFontImpl::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } FTPoint FTTextureFontImpl::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } rgl/src/ext/ftgl/FTFont/FTExtrudeFontImpl.h0000644000176200001440000000510514530124574020223 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTExtrudeFontImpl__ #define __FTExtrudeFontImpl__ #include "FTFontImpl.h" class FTGlyph; class FTExtrudeFontImpl : public FTFontImpl { friend class FTExtrudeFont; protected: FTExtrudeFontImpl(FTFont *ftFont, const char* fontFilePath); FTExtrudeFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Set the extrusion distance for the font. * * @param d The extrusion distance. */ virtual void Depth(float d) { depth = d; } /** * Set the outset distance for the font. Only implemented by * FTOutlineFont, FTPolygonFont and FTExtrudeFont * * @param o The outset distance. */ virtual void Outset(float o) { front = back = o; } /** * Set the outset distance for the font. Only implemented by * FTExtrudeFont * * @param f The front outset distance. * @param b The back outset distance. */ virtual void Outset(float f, float b) { front = f; back = b; } private: /** * The extrusion distance for the font. */ float depth; /** * The outset distance (front and back) for the font. */ float front, back; }; #endif // __FTExtrudeFontImpl__ rgl/src/ext/ftgl/FTFont/FTFontImpl.h0000644000176200001440000001135314265301465016665 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTFontImpl__ #define __FTFontImpl__ #include "FTGL/ftgl.h" #include "FTFace.h" class FTGlyphContainer; class FTGlyph; class FTFontImpl { friend class FTFont; protected: FTFontImpl(FTFont *ftFont, char const *fontFilePath); FTFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); virtual ~FTFontImpl(); virtual bool Attach(const char* fontFilePath); virtual bool Attach(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); virtual void GlyphLoadFlags(FT_Int flags); virtual bool CharMap(FT_Encoding encoding); virtual unsigned int CharMapCount() const; virtual FT_Encoding* CharMapList(); virtual void UseDisplayList(bool useList); virtual float Ascender() const; virtual float Descender() const; virtual float LineHeight() const; virtual bool FaceSize(const unsigned int size, const unsigned int res); virtual unsigned int FaceSize() const; virtual void Depth(float depth); virtual void Outset(float outset); virtual void Outset(float front, float back); virtual FTBBox BBox(const char *s, const int len, FTPoint, FTPoint); virtual FTBBox BBox(const wchar_t *s, const int len, FTPoint, FTPoint); virtual float Advance(const char *s, const int len, FTPoint); virtual float Advance(const wchar_t *s, const int len, FTPoint); virtual FTPoint Render(const char *s, const int len, FTPoint, FTPoint, int); virtual FTPoint Render(const wchar_t *s, const int len, FTPoint, FTPoint, int); /** * Current face object */ FTFace face; /** * Current size object */ FTSize charSize; /** * Flag to enable or disable the use of Display Lists inside FTGL * true turns ON display lists. * false turns OFF display lists. */ bool useDisplayLists; /** * The default glyph loading flags. */ FT_Int load_flags; /** * Current error code. Zero means no error. */ FT_Error err; private: /** * A link back to the interface of which we are the implementation. */ FTFont *intf; /** * Check that the glyph at chr exist. If not load it. * * @param chr character index * @return true if the glyph can be created. */ bool CheckGlyph(const unsigned int chr); /** * An object that holds a list of glyphs */ FTGlyphContainer* glyphList; /** * Current pen or cursor position; */ FTPoint pen; /* Internal generic BBox() implementation */ template inline FTBBox BBoxI(const T *s, const int len, FTPoint position, FTPoint spacing); /* Internal generic Advance() implementation */ template inline float AdvanceI(const T *s, const int len, FTPoint spacing); /* Internal generic Render() implementation */ template inline FTPoint RenderI(const T *s, const int len, FTPoint position, FTPoint spacing, int mode); }; #endif // __FTFontImpl__ rgl/src/ext/ftgl/FTFont/FTOutlineFontImpl.h0000644000176200001440000000506014530124664020222 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTOutlineFontImpl__ #define __FTOutlineFontImpl__ #include "FTFontImpl.h" class FTGlyph; class FTOutlineFontImpl : public FTFontImpl { friend class FTOutlineFont; protected: FTOutlineFontImpl(FTFont *ftFont, const char* fontFilePath); FTOutlineFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Set the outset distance for the font. Only implemented by * FTOutlineFont, FTPolygonFont and FTExtrudeFont * * @param outset The outset distance. */ virtual void Outset(float o) { outset = o; } virtual FTPoint Render(const char *s, const int len, FTPoint position, FTPoint spacing, int renderMode); virtual FTPoint Render(const wchar_t *s, const int len, FTPoint position, FTPoint spacing, int renderMode); private: /** * The outset distance for the font. */ float outset; /* Internal generic Render() implementation */ template inline FTPoint RenderI(const T *s, const int len, FTPoint position, FTPoint spacing, int mode); }; #endif // __FTOutlineFontImpl__ rgl/src/ext/ftgl/FTFont/FTExtrudeFont.cpp0000644000176200001440000000503314531466703017740 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTExtrudeFontImpl.h" // // FTExtrudeFont // FTExtrudeFont::FTExtrudeFont(char const *fontFilePath) : FTFont(new FTExtrudeFontImpl(this, fontFilePath)) {} FTExtrudeFont::FTExtrudeFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTExtrudeFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTExtrudeFont::~FTExtrudeFont() {} FTGlyph* FTExtrudeFont::MakeGlyph(FT_GlyphSlot ftGlyph) { FTExtrudeFontImpl *myimpl = dynamic_cast(impl); if(!myimpl) { return NULL; } return new FTExtrudeGlyph(ftGlyph, myimpl->depth, myimpl->front, myimpl->back, myimpl->useDisplayLists); } // // FTExtrudeFontImpl // FTExtrudeFontImpl::FTExtrudeFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath), depth(0.0f), front(0.0f), back(0.0f) { load_flags = FT_LOAD_NO_HINTING; } FTExtrudeFontImpl::FTExtrudeFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes), depth(0.0f), front(0.0f), back(0.0f) { load_flags = FT_LOAD_NO_HINTING; } rgl/src/ext/ftgl/FTFont/FTFont.cpp0000644000176200001440000002601714265301465016401 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTInternals.h" #include "FTUnicode.h" #include "FTFontImpl.h" #include "FTBitmapFontImpl.h" #include "FTExtrudeFontImpl.h" #include "FTOutlineFontImpl.h" #include "FTPixmapFontImpl.h" #include "FTPolygonFontImpl.h" #include "FTTextureFontImpl.h" #include "FTGlyphContainer.h" #include "FTFace.h" // // FTFont // FTFont::FTFont(char const *fontFilePath) { impl = new FTFontImpl(this, fontFilePath); } FTFont::FTFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) { impl = new FTFontImpl(this, pBufferBytes, bufferSizeInBytes); } FTFont::FTFont(FTFontImpl *pImpl) { impl = pImpl; } FTFont::~FTFont() { delete impl; } bool FTFont::Attach(const char* fontFilePath) { return impl->Attach(fontFilePath); } bool FTFont::Attach(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) { return impl->Attach(pBufferBytes, bufferSizeInBytes); } bool FTFont::FaceSize(const unsigned int size, const unsigned int res) { return impl->FaceSize(size, res); } unsigned int FTFont::FaceSize() const { return impl->FaceSize(); } void FTFont::Depth(float depth) { return impl->Depth(depth); } void FTFont::Outset(float outset) { return impl->Outset(outset); } void FTFont::Outset(float front, float back) { return impl->Outset(front, back); } void FTFont::GlyphLoadFlags(FT_Int flags) { return impl->GlyphLoadFlags(flags); } bool FTFont::CharMap(FT_Encoding encoding) { return impl->CharMap(encoding); } unsigned int FTFont::CharMapCount() const { return impl->CharMapCount(); } FT_Encoding* FTFont::CharMapList() { return impl->CharMapList(); } void FTFont::UseDisplayList(bool useList) { return impl->UseDisplayList(useList); } float FTFont::Ascender() const { return impl->Ascender(); } float FTFont::Descender() const { return impl->Descender(); } float FTFont::LineHeight() const { return impl->LineHeight(); } FTPoint FTFont::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return impl->Render(string, len, position, spacing, renderMode); } FTPoint FTFont::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return impl->Render(string, len, position, spacing, renderMode); } float FTFont::Advance(const char * string, const int len, FTPoint spacing) { return impl->Advance(string, len, spacing); } float FTFont::Advance(const wchar_t * string, const int len, FTPoint spacing) { return impl->Advance(string, len, spacing); } FTBBox FTFont::BBox(const char *string, const int len, FTPoint position, FTPoint spacing) { return impl->BBox(string, len, position, spacing); } FTBBox FTFont::BBox(const wchar_t *string, const int len, FTPoint position, FTPoint spacing) { return impl->BBox(string, len, position, spacing); } FT_Error FTFont::Error() const { return impl->err; } // // FTFontImpl // FTFontImpl::FTFontImpl(FTFont *ftFont, char const *fontFilePath) : face(fontFilePath), useDisplayLists(true), load_flags(FT_LOAD_DEFAULT), intf(ftFont), glyphList(0) { err = face.Error(); if(err == 0) { glyphList = new FTGlyphContainer(&face); } } FTFontImpl::FTFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : face(pBufferBytes, bufferSizeInBytes), useDisplayLists(true), load_flags(FT_LOAD_DEFAULT), intf(ftFont), glyphList(0) { err = face.Error(); if(err == 0) { glyphList = new FTGlyphContainer(&face); } } FTFontImpl::~FTFontImpl() { if(glyphList) { delete glyphList; } } bool FTFontImpl::Attach(const char* fontFilePath) { if(!face.Attach(fontFilePath)) { err = face.Error(); return false; } err = 0; return true; } bool FTFontImpl::Attach(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) { if(!face.Attach(pBufferBytes, bufferSizeInBytes)) { err = face.Error(); return false; } err = 0; return true; } bool FTFontImpl::FaceSize(const unsigned int size, const unsigned int res) { if(glyphList != NULL) { delete glyphList; glyphList = NULL; } charSize = face.Size(size, res); err = face.Error(); if(err != 0) { return false; } glyphList = new FTGlyphContainer(&face); return true; } unsigned int FTFontImpl::FaceSize() const { return charSize.CharSize(); } void FTFontImpl::Depth(float depth) { ; } void FTFontImpl::Outset(float outset) { ; } void FTFontImpl::Outset(float front, float back) { ; } void FTFontImpl::GlyphLoadFlags(FT_Int flags) { load_flags = flags; } bool FTFontImpl::CharMap(FT_Encoding encoding) { bool result = glyphList->CharMap(encoding); err = glyphList->Error(); return result; } unsigned int FTFontImpl::CharMapCount() const { return face.CharMapCount(); } FT_Encoding* FTFontImpl::CharMapList() { return face.CharMapList(); } void FTFontImpl::UseDisplayList(bool useList) { useDisplayLists = useList; } float FTFontImpl::Ascender() const { return charSize.Ascender(); } float FTFontImpl::Descender() const { return charSize.Descender(); } float FTFontImpl::LineHeight() const { return charSize.Height(); } template inline FTBBox FTFontImpl::BBoxI(const T* string, const int len, FTPoint position, FTPoint spacing) { FTBBox totalBBox; /* Only compute the bounds if string is non-empty. */ if(string && ('\0' != string[0])) { // for multibyte - we can't rely on sizeof(T) == character FTUnicodeStringItr ustr(string); unsigned int thisChar = *ustr++; unsigned int nextChar = *ustr; if(CheckGlyph(thisChar)) { totalBBox = glyphList->BBox(thisChar); totalBBox += position; position += FTPoint(glyphList->Advance(thisChar, nextChar), 0.0); } /* Expand totalBox by each glyph in string */ for(int i = 1; (len < 0 && *ustr) || (len >= 0 && i < len); i++) { thisChar = *ustr++; nextChar = *ustr; if(CheckGlyph(thisChar)) { position += spacing; FTBBox tempBBox = glyphList->BBox(thisChar); tempBBox += position; totalBBox |= tempBBox; position += FTPoint(glyphList->Advance(thisChar, nextChar), 0.0); } } } return totalBBox; } FTBBox FTFontImpl::BBox(const char *string, const int len, FTPoint position, FTPoint spacing) { /* The chars need to be unsigned because they are cast to int later */ return BBoxI((const unsigned char *)string, len, position, spacing); } FTBBox FTFontImpl::BBox(const wchar_t *string, const int len, FTPoint position, FTPoint spacing) { return BBoxI(string, len, position, spacing); } template inline float FTFontImpl::AdvanceI(const T* string, const int len, FTPoint spacing) { float advance = 0.0f; FTUnicodeStringItr ustr(string); for(int i = 0; (len < 0 && *ustr) || (len >= 0 && i < len); i++) { unsigned int thisChar = *ustr++; unsigned int nextChar = *ustr; if(CheckGlyph(thisChar)) { advance += glyphList->Advance(thisChar, nextChar); } if(nextChar) { advance += spacing.Xf(); } } return advance; } float FTFontImpl::Advance(const char* string, const int len, FTPoint spacing) { /* The chars need to be unsigned because they are cast to int later */ return AdvanceI((const unsigned char *)string, len, spacing); } float FTFontImpl::Advance(const wchar_t* string, const int len, FTPoint spacing) { return AdvanceI(string, len, spacing); } template inline FTPoint FTFontImpl::RenderI(const T* string, const int len, FTPoint position, FTPoint spacing, int renderMode) { // for multibyte - we can't rely on sizeof(T) == character FTUnicodeStringItr ustr(string); for(int i = 0; (len < 0 && *ustr) || (len >= 0 && i < len); i++) { unsigned int thisChar = *ustr++; unsigned int nextChar = *ustr; if(CheckGlyph(thisChar)) { position += glyphList->Render(thisChar, nextChar, position, renderMode); } if(nextChar) { position += spacing; } } return position; } FTPoint FTFontImpl::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI((const unsigned char *)string, len, position, spacing, renderMode); } FTPoint FTFontImpl::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } bool FTFontImpl::CheckGlyph(const unsigned int characterCode) { if(glyphList->Glyph(characterCode)) { return true; } unsigned int glyphIndex = glyphList->FontIndex(characterCode); FT_GlyphSlot ftSlot = face.Glyph(glyphIndex, load_flags); if(!ftSlot) { err = face.Error(); return false; } FTGlyph* tempGlyph = intf->MakeGlyph(ftSlot); if(!tempGlyph) { if(0 == err) { err = 0x13; } return false; } glyphList->Add(tempGlyph, characterCode); return true; } rgl/src/ext/ftgl/FTFont/FTPixmapFontImpl.h0000644000176200001440000000430714265301465020045 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTPixmapFontImpl__ #define __FTPixmapFontImpl__ #include "FTFontImpl.h" class FTGlyph; class FTPixmapFontImpl : public FTFontImpl { friend class FTPixmapFont; protected: FTPixmapFontImpl(FTFont *ftFont, const char* fontFilePath); FTPixmapFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); virtual FTPoint Render(const char *s, const int len, FTPoint position, FTPoint spacing, int renderMode); virtual FTPoint Render(const wchar_t *s, const int len, FTPoint position, FTPoint spacing, int renderMode); private: /* Internal generic Render() implementation */ template inline FTPoint RenderI(const T *s, const int len, FTPoint position, FTPoint spacing, int mode); }; #endif // __FTPixmapFontImpl__ rgl/src/ext/ftgl/FTFont/FTPolygonFontImpl.h0000644000176200001440000000400214530124674020226 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTPolygonFontImpl__ #define __FTPolygonFontImpl__ #include "FTFontImpl.h" class FTGlyph; class FTPolygonFontImpl : public FTFontImpl { friend class FTPolygonFont; protected: FTPolygonFontImpl(FTFont *ftFont, const char* fontFilePath); FTPolygonFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Set the outset distance for the font. Only implemented by * FTOutlineFont, FTPolygonFont and FTExtrudeFont * * @param depth The outset distance. */ virtual void Outset(float o) { outset = o; } private: /** * The outset distance (front and back) for the font. */ float outset; }; #endif // __FTPolygonFontImpl__ rgl/src/ext/ftgl/FTFont/FTFontGlue.cpp0000644000176200001440000001701014531466703017212 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTInternals.h" static const FTPoint static_ftpoint; static const FTBBox static_ftbbox; FTGL_BEGIN_C_DECLS #define C_TOR(cname, cargs, cxxname, cxxarg, cxxtype) \ FTGLfont* cname cargs \ { \ cxxname *f = new cxxname cxxarg; \ if(f->Error()) \ { \ delete f; \ return NULL; \ } \ FTGLfont *ftgl = (FTGLfont *)malloc(sizeof(FTGLfont)); \ ftgl->ptr = f; \ ftgl->type = cxxtype; \ return ftgl; \ } // FTBitmapFont::FTBitmapFont(); C_TOR(ftglCreateBitmapFont, (const char *fontname), FTBitmapFont, (fontname), FONT_BITMAP); // FTBufferFont::FTBufferFont(); C_TOR(ftglCreateBufferFont, (const char *fontname), FTBufferFont, (fontname), FONT_BUFFER); // FTExtrudeFont::FTExtrudeFont(); C_TOR(ftglCreateExtrudeFont, (const char *fontname), FTExtrudeFont, (fontname), FONT_EXTRUDE); // FTOutlineFont::FTOutlineFont(); C_TOR(ftglCreateOutlineFont, (const char *fontname), FTOutlineFont, (fontname), FONT_OUTLINE); // FTPixmapFont::FTPixmapFont(); C_TOR(ftglCreatePixmapFont, (const char *fontname), FTPixmapFont, (fontname), FONT_PIXMAP); // FTPolygonFont::FTPolygonFont(); C_TOR(ftglCreatePolygonFont, (const char *fontname), FTPolygonFont, (fontname), FONT_POLYGON); // FTTextureFont::FTTextureFont(); C_TOR(ftglCreateTextureFont, (const char *fontname), FTTextureFont, (fontname), FONT_TEXTURE); // FTCustomFont::FTCustomFont(); class FTCustomFont : public FTFont { public: FTCustomFont(char const *fontFilePath, void *p, FTGLglyph * (*makeglyph) (FT_GlyphSlot, void *)) : FTFont(fontFilePath), data(p), makeglyphCallback(makeglyph) {} ~FTCustomFont() {} FTGlyph* MakeGlyph(FT_GlyphSlot slot) { FTGLglyph *g = makeglyphCallback(slot, data); FTGlyph *glyph = g->ptr; // XXX: we no longer need g, and no one will free it for us. Not // very elegant, and we need to make sure no one else will try to // use it. free(g); return glyph; } private: void *data; FTGLglyph *(*makeglyphCallback) (FT_GlyphSlot, void *); }; C_TOR(ftglCreateCustomFont, (char const *fontFilePath, void *data, FTGLglyph * (*makeglyphCallback) (FT_GlyphSlot, void *)), FTCustomFont, (fontFilePath, data, makeglyphCallback), FONT_CUSTOM); #define C_FUN(cret, cname, cargs, cxxerr, cxxname, cxxarg) \ cret cname cargs \ { \ if(!f || !f->ptr) \ { \ fprintf(stderr, "FTGL warning: NULL pointer in %s\n", #cname); \ cxxerr; \ } \ return f->ptr->cxxname cxxarg; \ } // FTFont::~FTFont(); void ftglDestroyFont(FTGLfont *f) { if(!f || !f->ptr) { fprintf(stderr, "FTGL warning: NULL pointer in %s\n", __FUNCTION__); return; } delete f->ptr; free(f); } // bool FTFont::Attach(const char* fontFilePath); C_FUN(int, ftglAttachFile, (FTGLfont *f, const char* path), return 0, Attach, (path)); // bool FTFont::Attach(const unsigned char *pBufferBytes, // size_t bufferSizeInBytes); C_FUN(int, ftglAttachData, (FTGLfont *f, const unsigned char *p, size_t s), return 0, Attach, (p, s)); // void FTFont::GlyphLoadFlags(FT_Int flags); C_FUN(void, ftglSetFontGlyphLoadFlags, (FTGLfont *f, FT_Int flags), return, GlyphLoadFlags, (flags)); // bool FTFont::CharMap(FT_Encoding encoding); C_FUN(int, ftglSetFontCharMap, (FTGLfont *f, FT_Encoding enc), return 0, CharMap, (enc)); // unsigned int FTFont::CharMapCount(); C_FUN(unsigned int, ftglGetFontCharMapCount, (FTGLfont *f), return 0, CharMapCount, ()); // FT_Encoding* FTFont::CharMapList(); C_FUN(FT_Encoding *, ftglGetFontCharMapList, (FTGLfont* f), return NULL, CharMapList, ()); // virtual bool FTFont::FaceSize(const unsigned int size, // const unsigned int res = 72); C_FUN(int, ftglSetFontFaceSize, (FTGLfont *f, unsigned int s, unsigned int r), return 0, FaceSize, (s, r > 0 ? r : 72)); // unsigned int FTFont::FaceSize() const; // XXX: need to call FaceSize() as FTFont::FaceSize() because of FTGLTexture C_FUN(unsigned int, ftglGetFontFaceSize, (FTGLfont *f), return 0, FTFont::FaceSize, ()); // virtual void FTFont::Depth(float depth); C_FUN(void, ftglSetFontDepth, (FTGLfont *f, float d), return, Depth, (d)); // virtual void FTFont::Outset(float front, float back); C_FUN(void, ftglSetFontOutset, (FTGLfont *f, float front, float back), return, FTFont::Outset, (front, back)); // void FTFont::UseDisplayList(bool useList); C_FUN(void, ftglSetFontDisplayList, (FTGLfont *f, int l), return, UseDisplayList, (l != 0)); // float FTFont::Ascender() const; C_FUN(float, ftglGetFontAscender, (FTGLfont *f), return 0.f, Ascender, ()); // float FTFont::Descender() const; C_FUN(float, ftglGetFontDescender, (FTGLfont *f), return 0.f, Descender, ()); // float FTFont::LineHeight() const; C_FUN(float, ftglGetFontLineHeight, (FTGLfont *f), return 0.f, LineHeight, ()); // void FTFont::BBox(const char* string, float& llx, float& lly, float& llz, // float& urx, float& ury, float& urz); extern "C++" { C_FUN(static FTBBox, _ftglGetFontBBox, (FTGLfont *f, char const *s, int len), return static_ftbbox, BBox, (s, len)); } void ftglGetFontBBox(FTGLfont *f, const char* s, int len, float c[6]) { FTBBox ret = _ftglGetFontBBox(f, s, len); FTPoint lower = ret.Lower(), upper = ret.Upper(); c[0] = lower.Xf(); c[1] = lower.Yf(); c[2] = lower.Zf(); c[3] = upper.Xf(); c[4] = upper.Yf(); c[5] = upper.Zf(); } // float FTFont::Advance(const char* string); C_FUN(float, ftglGetFontAdvance, (FTGLfont *f, char const *s), return 0.0, Advance, (s)); // virtual void Render(const char* string, int renderMode); extern "C++" { C_FUN(static FTPoint, _ftglRenderFont, (FTGLfont *f, char const *s, int len, FTPoint pos, FTPoint spacing, int mode), return static_ftpoint, Render, (s, len, pos, spacing, mode)); } void ftglRenderFont(FTGLfont *f, const char *s, int mode) { _ftglRenderFont(f, s, -1, FTPoint(), FTPoint(), mode); } // FT_Error FTFont::Error() const; C_FUN(FT_Error, ftglGetFontError, (FTGLfont *f), return -1, Error, ()); FTGL_END_C_DECLS rgl/src/ext/ftgl/FTSize.h0000644000176200001440000001126714265301465014713 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTSize__ #define __FTSize__ #include #include FT_FREETYPE_H #include "FTGL/ftgl.h" /** * FTSize class provides an abstraction layer for the Freetype Size. * * @see "Freetype 2 Documentation" * */ class FTSize { public: /** * Default Constructor */ FTSize(); /** * Destructor */ virtual ~FTSize(); /** * Sets the char size for the current face. * * This doesn't guarantee that the size was set correctly. Clients * should check errors. If an error does occur the size object isn't modified. * * @param face Parent face for this size object * @param point_size the face size in points (1/72 inch) * @param x_resolution the horizontal resolution of the target device. * @param y_resolution the vertical resolution of the target device. * @return true if the size has been set. Clients should check Error() for more information if this function returns false() */ bool CharSize(FT_Face* face, unsigned int point_size, unsigned int x_resolution, unsigned int y_resolution); /** * get the char size for the current face. * * @return The char size in points */ unsigned int CharSize() const; /** * Gets the global ascender height for the face in pixels. * * @return Ascender height */ float Ascender() const; /** * Gets the global descender height for the face in pixels. * * @return Ascender height */ float Descender() const; /** * Gets the global face height for the face. * * If the face is scalable this returns the height of the global * bounding box which ensures that any glyph will be less than or * equal to this height. If the font isn't scalable there is no * guarantee that glyphs will not be taller than this value. * * @return height in pixels. */ float Height() const; /** * Gets the global face width for the face. * * If the face is scalable this returns the width of the global * bounding box which ensures that any glyph will be less than or * equal to this width. If the font isn't scalable this value is * the max_advance for the face. * * @return width in pixels. */ float Width() const; /** * Gets the underline position for the face. * * @return underline position in pixels */ float Underline() const; /** * Queries for errors. * * @return The current error code. */ FT_Error Error() const { return err; } private: /** * The current Freetype face that this FTSize object relates to. */ FT_Face* ftFace; /** * The Freetype size. */ FT_Size ftSize; /** * The size in points. */ unsigned int size; /** * The horizontal resolution. */ unsigned int xResolution; /** * The vertical resolution. */ unsigned int yResolution; /** * Current error code. Zero means no error. */ FT_Error err; }; #endif // __FTSize__ rgl/src/ext/ftgl/FTCharmap.cpp0000644000176200001440000000536114555455305015712 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTFace.h" #include "FTCharmap.h" FTCharmap::FTCharmap(FTFace* face) : ftFace(*(face->Face())), err(0) { if(!ftFace->charmap) { if(!ftFace->num_charmaps) { // This face doesn't even have one charmap! err = 0x96; // Invalid_CharMap_Format return; } err = FT_Set_Charmap(ftFace, ftFace->charmaps[0]); } ftEncoding = ftFace->charmap->encoding; for(unsigned int i = 0; i < FTCharmap::MAX_PRECOMPUTED; i++) { charIndexCache[i] = FT_Get_Char_Index(ftFace, i); } } FTCharmap::~FTCharmap() { charMap.clear(); } bool FTCharmap::CharMap(FT_Encoding encoding) { if(ftEncoding == encoding) { err = 0; return true; } err = FT_Select_Charmap(ftFace, encoding); if(!err) { ftEncoding = encoding; charMap.clear(); } return !err; } unsigned int FTCharmap::GlyphListIndex(const unsigned int characterCode) { return static_cast(charMap.find(static_cast(characterCode))); } unsigned int FTCharmap::FontIndex(const unsigned int characterCode) { if(characterCode < FTCharmap::MAX_PRECOMPUTED) { return charIndexCache[characterCode]; } return FT_Get_Char_Index(ftFace, characterCode); } void FTCharmap::InsertIndex(const unsigned int characterCode, const size_t containerIndex) { charMap.insert(characterCode, static_cast(containerIndex)); } rgl/src/ext/ftgl/FTList.h0000644000176200001440000000630214265301465014706 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTList__ #define __FTList__ #include "FTGL/ftgl.h" /** * Provides a non-STL alternative to the STL list */ template class FTList { public: typedef FT_LIST_ITEM_TYPE value_type; typedef value_type& reference; typedef const value_type& const_reference; typedef size_t size_type; /** * Constructor */ FTList() : listSize(0), tail(0) { tail = NULL; head = new Node; } /** * Destructor */ ~FTList() { Node* next; for(Node *walk = head; walk; walk = next) { next = walk->next; delete walk; } } /** * Get the number of items in the list */ size_type size() const { return listSize; } /** * Add an item to the end of the list */ void push_back(const value_type& item) { Node* node = new Node(item); if(head->next == NULL) { head->next = node; } if(tail) { tail->next = node; } tail = node; ++listSize; } /** * Get the item at the front of the list */ reference front() const { return head->next->payload; } /** * Get the item at the end of the list */ reference back() const { return tail->payload; } private: struct Node { Node() : next(NULL) {} Node(const value_type& item) : next(NULL) { payload = item; } Node* next; value_type payload; }; size_type listSize; Node* head; Node* tail; }; #endif // __FTList__ rgl/src/ext/ftgl/FTGlyphContainer.h0000644000176200001440000001151514265301465016723 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTGlyphContainer__ #define __FTGlyphContainer__ #include #include FT_FREETYPE_H #include FT_GLYPH_H #include "FTGL/ftgl.h" #include "FTVector.h" class FTFace; class FTGlyph; class FTCharmap; /** * FTGlyphContainer holds the post processed FTGlyph objects. * * @see FTGlyph */ class FTGlyphContainer { typedef FTVector GlyphVector; public: /** * Constructor * * @param face The Freetype face */ FTGlyphContainer(FTFace* face); /** * Destructor */ ~FTGlyphContainer(); /** * Sets the character map for the face. * * @param encoding the Freetype encoding symbol. See above. * @return true if charmap was valid * and set correctly */ bool CharMap(FT_Encoding encoding); /** * Get the font index of the input character. * * @param characterCode The character code of the requested glyph in the * current encoding eg apple roman. * @return The font index for the character. */ unsigned int FontIndex(const unsigned int characterCode) const; /** * Adds a glyph to this glyph list. * * @param glyph The FTGlyph to be inserted into the container * @param characterCode The char code of the glyph NOT the glyph index. */ void Add(FTGlyph* glyph, const unsigned int characterCode); /** * Get a glyph from the glyph list * * @param characterCode The char code of the glyph NOT the glyph index * @return An FTGlyph or null is it hasn't been * loaded. */ const FTGlyph* const Glyph(const unsigned int characterCode) const; /** * Get the bounding box for a character. * @param characterCode The char code of the glyph NOT the glyph index */ FTBBox BBox(const unsigned int characterCode) const; /** * Returns the kerned advance width for a glyph. * * @param characterCode glyph index of the character * @param nextCharacterCode the next glyph in a string * @return advance width */ float Advance(const unsigned int characterCode, const unsigned int nextCharacterCode); /** * Renders a character * @param characterCode the glyph to be Rendered * @param nextCharacterCode the next glyph in the string. Used for kerning. * @param penPosition the position to Render the glyph * @param renderMode Render mode to display * @return The distance to advance the pen position after Rendering */ FTPoint Render(const unsigned int characterCode, const unsigned int nextCharacterCode, FTPoint penPosition, int renderMode); /** * Queries the Font for errors. * * @return The current error code. */ FT_Error Error() const { return err; } private: /** * The FTGL face */ FTFace* face; /** * The Character Map object associated with the current face */ FTCharmap* charMap; /** * A structure to hold the glyphs */ GlyphVector glyphs; /** * Current error code. Zero means no error. */ FT_Error err; }; #endif // __FTGlyphContainer__ rgl/src/ext/ftgl/FTContour.h0000644000176200001440000001431514531466703015432 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTContour__ #define __FTContour__ #include "FTGL/ftgl.h" #include "FTVector.h" /** * FTContour class is a container of points that describe a vector font * outline. It is used as a container for the output of the bezier curve * evaluator in FTVectoriser. * * @see FTOutlineGlyph * @see FTPolygonGlyph * @see FTPoint */ class FTContour { public: /** * Constructor * * @param contour * @param pointTags * @param numberOfPoints */ FTContour(FT_Vector* contour, char* pointTags, unsigned int numberOfPoints); /** * Destructor */ ~FTContour() { pointList.clear(); outsetPointList.clear(); frontPointList.clear(); backPointList.clear(); } /** * Return a point at index. * * @param index of the point in the curve. * @return const point reference */ const FTPoint& Point(size_t index) const { return pointList[index]; } /** * Return a point at index. * * @param index of the point in the outset curve. * @return const point reference */ const FTPoint& Outset(size_t index) const { return outsetPointList[index]; } /** * Return a point at index of the front outset contour. * * @param index of the point in the curve. * @return const point reference */ const FTPoint& FrontPoint(size_t index) const { if(frontPointList.size() == 0) return Point(index); return frontPointList[index]; } /** * Return a point at index of the back outset contour. * * @param index of the point in the curve. * @return const point reference */ const FTPoint& BackPoint(size_t index) const { if(backPointList.size() == 0) return Point(index); return backPointList[index]; } /** * How many points define this contour * * @return the number of points in this contour */ size_t PointCount() const { return pointList.size(); } /** * Make sure the glyph has the proper parity and create the front/back * outset contour. * * @param parity The contour's parity within the glyph. */ void SetParity(int parity); // FIXME: this should probably go away. void buildFrontOutset(float outset); void buildBackOutset(float outset); private: /** * Add a point to this contour. This function tests for duplicate * points. * * @param point The point to be added to the contour. */ inline void AddPoint(FTPoint point); /** * Add a point to this contour. This function tests for duplicate * points. * * @param point The point to be added to the contour. */ inline void AddOutsetPoint(FTPoint point); /* * Add a point to this outset contour. This function tests for duplicate * points. * * @param point The point to be added to the contour outset. */ inline void AddFrontPoint(FTPoint point); inline void AddBackPoint(FTPoint point); /** * De Casteljau (bezier) algorithm contributed by Jed Soane * Evaluates a quadratic or conic (second degree) curve */ inline void evaluateQuadraticCurve(FTPoint, FTPoint, FTPoint); /** * De Casteljau (bezier) algorithm contributed by Jed Soane * Evaluates a cubic (third degree) curve */ inline void evaluateCubicCurve(FTPoint, FTPoint, FTPoint, FTPoint); /** * Compute the vector norm */ inline FTGL_DOUBLE NormVector(const FTPoint &v); /** * Compute a rotation matrix from a vector */ inline void RotationMatrix(const FTPoint &a, const FTPoint &b, FTGL_DOUBLE *matRot, FTGL_DOUBLE *invRot); /** * Matrix and vector multiplication */ inline void MultMatrixVect(FTGL_DOUBLE *mat, FTPoint &v); /** * Compute the vector bisecting from a vector 'v' and a distance 'd' */ inline void ComputeBisec(FTPoint &v); /** * Compute the outset point coordinates */ inline FTPoint ComputeOutsetPoint(FTPoint a, FTPoint b, FTPoint c); /** * The list of points in this contour */ typedef FTVector PointVector; PointVector pointList; PointVector outsetPointList; PointVector frontPointList; PointVector backPointList; /** * Is this contour clockwise or anti-clockwise? */ bool clockwise; }; #endif // __FTContour__ rgl/src/ext/ftgl/FTGL/0000755000176200001440000000000014530125205014112 5ustar liggesusersrgl/src/ext/ftgl/FTGL/ftgl.h0000644000176200001440000001017714530125205015225 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ #define __ftgl__ /* We need the Freetype headers */ #include #include FT_FREETYPE_H #include FT_GLYPH_H #include FT_OUTLINE_H /* Floating point types used by the library */ typedef double FTGL_DOUBLE; typedef float FTGL_FLOAT; /* Macros used to declare C-linkage types and symbols */ #ifdef __cplusplus # define FTGL_BEGIN_C_DECLS extern "C" { namespace FTGL { # define FTGL_END_C_DECLS } } #else # define FTGL_BEGIN_C_DECLS # define FTGL_END_C_DECLS #endif #ifdef __cplusplus namespace FTGL { typedef enum { RENDER_FRONT = 0x0001, RENDER_BACK = 0x0002, RENDER_SIDE = 0x0004, RENDER_ALL = 0xffff } RenderMode; typedef enum { ALIGN_LEFT = 0, ALIGN_CENTER = 1, ALIGN_RIGHT = 2, ALIGN_JUSTIFY = 3 } TextAlignment; } #else # define FTGL_RENDER_FRONT 0x0001 # define FTGL_RENDER_BACK 0x0002 # define FTGL_RENDER_SIDE 0x0004 # define FTGL_RENDER_ALL 0xffff # define FTGL_ALIGN_LEFT 0 # define FTGL_ALIGN_CENTER 1 # define FTGL_ALIGN_RIGHT 2 # define FTGL_ALIGN_JUSTIFY 3 #endif // Compiler-specific conditional compilation #ifdef _MSC_VER // MS Visual C++ // Disable various warning. // 4786: template name too long #pragma warning(disable : 4251) #pragma warning(disable : 4275) #pragma warning(disable : 4786) // The following definitions control how symbols are exported. // If the target is a static library ensure that FTGL_LIBRARY_STATIC // is defined. If building a dynamic library (ie DLL) ensure the // FTGL_LIBRARY macro is defined, as it will mark symbols for // export. If compiling a project to _use_ the _dynamic_ library // version of the library, no definition is required. #ifdef FTGL_LIBRARY_STATIC // static lib - no special export required # define FTGL_EXPORT #elif FTGL_LIBRARY // dynamic lib - must export/import symbols appropriately. # define FTGL_EXPORT __declspec(dllexport) #else # define FTGL_EXPORT __declspec(dllimport) #endif #else // Compiler that is not MS Visual C++. // Ensure that the export symbol is defined (and blank) #define FTGL_EXPORT #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif // __ftgl__ rgl/src/ext/ftgl/FTGL/FTBufferGlyph.h0000644000176200001440000000426214530125205016736 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning Please use instead of . # include #endif #ifndef __FTBufferGlyph__ #define __FTBufferGlyph__ #ifdef __cplusplus /** * FTBufferGlyph is a specialisation of FTGlyph for memory buffer rendering. */ class FTGL_EXPORT FTBufferGlyph : public FTGlyph { public: /** * Constructor * * @param glyph The Freetype glyph to be processed * @param buffer An FTBuffer object in which to render the glyph. */ FTBufferGlyph(FT_GlyphSlot glyph, FTBuffer *buffer); /** * Destructor */ virtual ~FTBufferGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #endif //__cplusplus #endif // __FTBufferGlyph__ rgl/src/ext/ftgl/FTGL/FTPixmapGlyph.h0000644000176200001440000000472614530125205016770 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTPixmapGlyph__ #define __FTPixmapGlyph__ #ifdef __cplusplus /** * FTPixmapGlyph is a specialisation of FTGlyph for creating pixmaps. */ class FTGL_EXPORT FTPixmapGlyph : public FTGlyph { public: /** * Constructor * * @param glyph The Freetype glyph to be processed */ FTPixmapGlyph(FT_GlyphSlot glyph); /** * Destructor */ virtual ~FTPixmapGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialisation of FTGLglyph for creating pixmaps. * * @param glyph The Freetype glyph to be processed * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreatePixmapGlyph(FT_GlyphSlot glyph); FTGL_END_C_DECLS #endif // __FTPixmapGlyph__ rgl/src/ext/ftgl/FTGL/FTOutlineGlyph.h0000644000176200001440000000635114530125205017145 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTOutlineGlyph__ #define __FTOutlineGlyph__ #ifdef __cplusplus /** * FTOutlineGlyph is a specialisation of FTGlyph for creating outlines. */ class FTGL_EXPORT FTOutlineGlyph : public FTGlyph { public: /** * Constructor. Sets the Error to Invalid_Outline if the glyphs isn't * an outline. * * @param glyph The Freetype glyph to be processed * @param outset outset distance * @param useDisplayList Enable or disable the use of Display Lists * for this glyph * true turns ON display lists. * false turns OFF display lists. */ FTOutlineGlyph(FT_GlyphSlot glyph, float outset, bool useDisplayList); /** * Destructor */ virtual ~FTOutlineGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialisation of FTGLglyph for creating outlines. * * @param glyph The Freetype glyph to be processed * @param outset outset contour size * @param useDisplayList Enable or disable the use of Display Lists * for this glyph * true turns ON display lists. * false turns OFF display lists. * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreateOutlineGlyph(FT_GlyphSlot glyph, float outset, int useDisplayList); FTGL_END_C_DECLS #endif // __FTOutlineGlyph__ rgl/src/ext/ftgl/FTGL/FTGLPolygonFont.h0000644000176200001440000000614414530125205017223 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTPolygonFont__ #define __FTPolygonFont__ #ifdef __cplusplus /** * FTPolygonFont is a specialisation of the FTFont class for handling * tesselated Polygon Mesh fonts * * @see FTFont */ class FTGL_EXPORT FTPolygonFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTPolygonFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTPolygonFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ ~FTPolygonFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #define FTGLPolygonFont FTPolygonFont #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling tesselated polygon * mesh fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont */ FTGL_EXPORT FTGLfont *ftglCreatePolygonFont(const char *file); FTGL_END_C_DECLS #endif // __FTPolygonFont__ rgl/src/ext/ftgl/FTGL/FTGLOutlineFont.h0000644000176200001440000000611514530125205017211 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTOutlineFont__ #define __FTOutlineFont__ #ifdef __cplusplus /** * FTOutlineFont is a specialisation of the FTFont class for handling * Vector Outline fonts * * @see FTFont */ class FTGL_EXPORT FTOutlineFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTOutlineFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTOutlineFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ ~FTOutlineFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #define FTGLOutlineFont FTOutlineFont #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling vector outline fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont */ FTGL_EXPORT FTGLfont *ftglCreateOutlineFont(const char *file); FTGL_END_C_DECLS #endif // __FTOutlineFont__ rgl/src/ext/ftgl/FTGL/FTBufferFont.h0000644000176200001440000000563414530125205016565 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning Please use instead of . # include #endif #ifndef __FTBufferFont__ #define __FTBufferFont__ #ifdef __cplusplus /** * FTBufferFont is a specialisation of the FTFont class for handling * memory buffer fonts. * * @see FTFont */ class FTGL_EXPORT FTBufferFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTBufferFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTBufferFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ ~FTBufferFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling memory buffer fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont */ FTGL_EXPORT FTGLfont *ftglCreateBufferFont(const char *file); FTGL_END_C_DECLS #endif // __FTBufferFont__ rgl/src/ext/ftgl/FTGL/FTBuffer.h0000644000176200001440000000637314530125205015737 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning Please use instead of . # include #endif #ifndef __FTBuffer__ #define __FTBuffer__ #ifdef __cplusplus /** * FTBuffer is a helper class for pixel buffers. * * It provides the interface between FTBufferFont and FTBufferGlyph to * optimise rendering operations. * * @see FTBufferGlyph * @see FTBufferFont */ class FTGL_EXPORT FTBuffer { public: /** * Default constructor. */ FTBuffer(); /** * Destructor */ ~FTBuffer(); /** * Get the pen's position in the buffer. * * @return The pen's position as an FTPoint object. */ inline FTPoint Pos() const { return pos; } /** * Set the pen's position in the buffer. * * @param arg An FTPoint object with the desired pen's position. */ inline void Pos(FTPoint arg) { pos = arg; } /** * Set the buffer's size. * * @param w The buffer's desired width, in pixels. * @param h The buffer's desired height, in pixels. */ void Size(int w, int h); /** * Get the buffer's width. * * @return The buffer's width, in pixels. */ inline int Width() const { return width; } /** * Get the buffer's height. * * @return The buffer's height, in pixels. */ inline int Height() const { return height; } /** * Get the buffer's direct pixel buffer. * * @return A read-write pointer to the buffer's pixels. */ inline unsigned char *Pixels() const { return pixels; } private: /** * Buffer's width and height. */ int width, height; /** * Buffer's pixel buffer. */ unsigned char *pixels; /** * Buffer's internal pen position. */ FTPoint pos; }; #endif //__cplusplus #endif // __FTBuffer__ rgl/src/ext/ftgl/FTGL/FTGlyph.h0000644000176200001440000001414114530125205015601 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTGlyph__ #define __FTGlyph__ #ifdef __cplusplus class FTGlyphImpl; /** * FTGlyph is the base class for FTGL glyphs. * * It provides the interface between Freetype glyphs and their openGL * renderable counterparts. This is an abstract class and derived classes * must implement the Render function. * * @see FTBBox * @see FTPoint */ class FTGL_EXPORT FTGlyph { protected: /** * Create a glyph. * * @param glyph The Freetype glyph to be processed */ FTGlyph(FT_GlyphSlot glyph); private: /** * Internal FTGL FTGlyph constructor. For private use only. * * @param pImpl Internal implementation object. Will be destroyed * upon FTGlyph deletion. */ FTGlyph(FTGlyphImpl *pImpl); /* Allow our internal subclasses to access the private constructor */ friend class FTBitmapGlyph; friend class FTBufferGlyph; friend class FTExtrudeGlyph; friend class FTOutlineGlyph; friend class FTPixmapGlyph; friend class FTPolygonGlyph; friend class FTTextureGlyph; public: /** * Destructor */ virtual ~FTGlyph(); /** * Renders this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode) = 0; /** * Return the advance width for this glyph. * * @return advance width. */ virtual float Advance() const; /** * Return the bounding box for this glyph. * * @return bounding box. */ virtual const FTBBox& BBox() const; /** * Queries for errors. * * @return The current error code. */ virtual FT_Error Error() const; private: /** * Internal FTGL FTGlyph implementation object. For private use only. */ FTGlyphImpl *impl; }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * FTGLglyph is the base class for FTGL glyphs. * * It provides the interface between Freetype glyphs and their openGL * renderable counterparts. This is an abstract class and derived classes * must implement the ftglRenderGlyph() function. */ struct _FTGLGlyph; typedef struct _FTGLglyph FTGLglyph; /** * Create a custom FTGL glyph object. * FIXME: maybe get rid of "base" and have advanceCallback etc. functions * * @param base The base FTGLglyph* to subclass. * @param data A pointer to private data that will be passed to callbacks. * @param renderCallback A rendering callback function. * @param destroyCallback A callback function to be called upon destruction. * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreateCustomGlyph(FTGLglyph *base, void *data, void (*renderCallback) (FTGLglyph *, void *, FTGL_DOUBLE, FTGL_DOUBLE, int, FTGL_DOUBLE *, FTGL_DOUBLE *), void (*destroyCallback) (FTGLglyph *, void *)); /** * Destroy an FTGL glyph object. * * @param glyph An FTGLglyph* object. */ FTGL_EXPORT void ftglDestroyGlyph(FTGLglyph *glyph); /** * Render a glyph at the current pen position and compute the corresponding * advance. * * @param glyph An FTGLglyph* object. * @param penx The current pen's X position. * @param peny The current pen's Y position. * @param renderMode Render mode to display * @param advancex A pointer to an FTGL_DOUBLE where to write the advance's X * component. * @param advancey A pointer to an FTGL_DOUBLE where to write the advance's Y * component. */ FTGL_EXPORT void ftglRenderGlyph(FTGLglyph *glyph, FTGL_DOUBLE penx, FTGL_DOUBLE peny, int renderMode, FTGL_DOUBLE *advancex, FTGL_DOUBLE *advancey); /** * Return the advance for a glyph. * * @param glyph An FTGLglyph* object. * @return The advance's X component. */ FTGL_EXPORT float ftglGetGlyphAdvance(FTGLglyph *glyph); /** * Return the bounding box for a glyph. * * @param glyph An FTGLglyph* object. * @param bounds An array of 6 float values where the bounding box's lower * left near and upper right far 3D coordinates will be stored. */ FTGL_EXPORT void ftglGetGlyphBBox(FTGLglyph *glyph, float bounds[6]); /** * Query a glyph for errors. * * @param glyph An FTGLglyph* object. * @return The current error code. */ FTGL_EXPORT FT_Error ftglGetGlyphError(FTGLglyph* glyph); FTGL_END_C_DECLS #endif // __FTGlyph__ rgl/src/ext/ftgl/FTGL/FTPoint.h0000644000176200001440000001702414530125205015612 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTPoint__ #define __FTPoint__ #ifdef __cplusplus /** * FTPoint class is a basic 3-dimensional point or vector. */ class FTGL_EXPORT FTPoint { public: /** * Default constructor. Point is set to zero. */ inline FTPoint() { values[0] = 0; values[1] = 0; values[2] = 0; } /** * Constructor. Z coordinate is set to zero if unspecified. * * @param x First component * @param y Second component * @param z Third component */ inline FTPoint(const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z = 0) { values[0] = x; values[1] = y; values[2] = z; } /** * Constructor. This converts an FT_Vector to an FTPoint * * @param ft_vector A freetype vector */ inline FTPoint(const FT_Vector& ft_vector) { values[0] = ft_vector.x; values[1] = ft_vector.y; values[2] = 0; } /** * Normalise a point's coordinates. If the coordinates are zero, * the point is left untouched. * * @return A vector of norm one. */ FTPoint Normalise(); /** * Operator += In Place Addition. * * @param point * @return this plus point. */ inline FTPoint& operator += (const FTPoint& point) { values[0] += point.values[0]; values[1] += point.values[1]; values[2] += point.values[2]; return *this; } /** * Operator + * * @param point * @return this plus point. */ inline FTPoint operator + (const FTPoint& point) const { FTPoint temp; temp.values[0] = values[0] + point.values[0]; temp.values[1] = values[1] + point.values[1]; temp.values[2] = values[2] + point.values[2]; return temp; } /** * Operator -= In Place Substraction. * * @param point * @return this minus point. */ inline FTPoint& operator -= (const FTPoint& point) { values[0] -= point.values[0]; values[1] -= point.values[1]; values[2] -= point.values[2]; return *this; } /** * Operator - * * @param point * @return this minus point. */ inline FTPoint operator - (const FTPoint& point) const { FTPoint temp; temp.values[0] = values[0] - point.values[0]; temp.values[1] = values[1] - point.values[1]; temp.values[2] = values[2] - point.values[2]; return temp; } /** * Operator * Scalar multiplication * * @param multiplier * @return this multiplied by multiplier. */ inline FTPoint operator * (double multiplier) const { FTPoint temp; temp.values[0] = values[0] * multiplier; temp.values[1] = values[1] * multiplier; temp.values[2] = values[2] * multiplier; return temp; } /** * Operator * Scalar multiplication * * @param point * @param multiplier * @return multiplier multiplied by point. */ inline friend FTPoint operator * (double multiplier, FTPoint& point) { return point * multiplier; } /** * Operator * Scalar product * * @param a First vector. * @param b Second vector. * @return a.b scalar product. */ inline friend double operator * (FTPoint &a, FTPoint& b) { return a.values[0] * b.values[0] + a.values[1] * b.values[1] + a.values[2] * b.values[2]; } /** * Operator ^ Vector product * * @param point Second point * @return this vector point. */ inline FTPoint operator ^ (const FTPoint& point) { FTPoint temp; temp.values[0] = values[1] * point.values[2] - values[2] * point.values[1]; temp.values[1] = values[2] * point.values[0] - values[0] * point.values[2]; temp.values[2] = values[0] * point.values[1] - values[1] * point.values[0]; return temp; } /** * Operator == Tests for equality * * @param a * @param b * @return true if a & b are equal */ friend bool operator == (const FTPoint &a, const FTPoint &b); /** * Operator != Tests for non equality * * @param a * @param b * @return true if a & b are not equal */ friend bool operator != (const FTPoint &a, const FTPoint &b); /** * Cast to FTGL_DOUBLE* */ inline operator const FTGL_DOUBLE*() const { return values; } /** * Setters */ inline void X(FTGL_DOUBLE x) { values[0] = x; }; inline void Y(FTGL_DOUBLE y) { values[1] = y; }; inline void Z(FTGL_DOUBLE z) { values[2] = z; }; /** * Getters */ inline FTGL_DOUBLE X() const { return values[0]; }; inline FTGL_DOUBLE Y() const { return values[1]; }; inline FTGL_DOUBLE Z() const { return values[2]; }; inline FTGL_FLOAT Xf() const { return static_cast(values[0]); }; inline FTGL_FLOAT Yf() const { return static_cast(values[1]); }; inline FTGL_FLOAT Zf() const { return static_cast(values[2]); }; private: /** * The point data */ FTGL_DOUBLE values[3]; }; #endif //__cplusplus #endif // __FTPoint__ rgl/src/ext/ftgl/FTGL/FTGLTextureFont.h0000644000176200001440000000612614530125205017234 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTTextureFont__ #define __FTTextureFont__ #ifdef __cplusplus /** * FTTextureFont is a specialisation of the FTFont class for handling * Texture mapped fonts * * @see FTFont */ class FTGL_EXPORT FTTextureFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTTextureFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTTextureFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ virtual ~FTTextureFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #define FTGLTextureFont FTTextureFont #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling texture-mapped fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont */ FTGL_EXPORT FTGLfont *ftglCreateTextureFont(const char *file); FTGL_END_C_DECLS #endif // __FTTextureFont__ rgl/src/ext/ftgl/FTGL/FTBBox.h0000644000176200001440000001177714530125205015364 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTBBox__ #define __FTBBox__ #ifdef __cplusplus /** * FTBBox is a convenience class for handling bounding boxes. */ class FTGL_EXPORT FTBBox { public: /** * Default constructor. Bounding box is set to zero. */ FTBBox() : lower(0.0f, 0.0f, 0.0f), upper(0.0f, 0.0f, 0.0f) {} /** * Constructor. */ FTBBox(float lx, float ly, float lz, float ux, float uy, float uz) : lower(lx, ly, lz), upper(ux, uy, uz) {} /** * Constructor. */ FTBBox(FTPoint l, FTPoint u) : lower(l), upper(u) {} /** * Constructor. Extracts a bounding box from a freetype glyph. Uses * the control box for the glyph. FT_Glyph_Get_CBox() * * @param glyph A freetype glyph */ FTBBox(FT_GlyphSlot glyph) : lower(0.0f, 0.0f, 0.0f), upper(0.0f, 0.0f, 0.0f) { FT_BBox bbox; FT_Outline_Get_CBox(&(glyph->outline), &bbox); lower.X(static_cast(bbox.xMin) / 64.0f); lower.Y(static_cast(bbox.yMin) / 64.0f); lower.Z(0.0f); upper.X(static_cast(bbox.xMax) / 64.0f); upper.Y(static_cast(bbox.yMax) / 64.0f); upper.Z(0.0f); } /** * Destructor */ ~FTBBox() {} /** * Mark the bounds invalid by setting all lower dimensions greater * than the upper dimensions. */ void Invalidate() { lower = FTPoint(1.0f, 1.0f, 1.0f); upper = FTPoint(-1.0f, -1.0f, -1.0f); } /** * Determines if this bounding box is valid. * * @return True if all lower values are <= the corresponding * upper values. */ bool IsValid() { return lower.X() <= upper.X() && lower.Y() <= upper.Y() && lower.Z() <= upper.Z(); } /** * Move the Bounding Box by a vector. * * @param vector The vector to move the bbox in 3D space. */ FTBBox& operator += (const FTPoint vector) { lower += vector; upper += vector; return *this; } /** * Combine two bounding boxes. The result is the smallest bounding * box containing the two original boxes. * * @param bbox The bounding box to merge with the second one. */ FTBBox& operator |= (const FTBBox& bbox) { if(bbox.lower.X() < lower.X()) lower.X(bbox.lower.X()); if(bbox.lower.Y() < lower.Y()) lower.Y(bbox.lower.Y()); if(bbox.lower.Z() < lower.Z()) lower.Z(bbox.lower.Z()); if(bbox.upper.X() > upper.X()) upper.X(bbox.upper.X()); if(bbox.upper.Y() > upper.Y()) upper.Y(bbox.upper.Y()); if(bbox.upper.Z() > upper.Z()) upper.Z(bbox.upper.Z()); return *this; } void SetDepth(float depth) { if(depth > 0) upper.Z(lower.Z() + depth); else lower.Z(upper.Z() + depth); } inline FTPoint const Upper() const { return upper; } inline FTPoint const Lower() const { return lower; } private: /** * The bounds of the box */ FTPoint lower, upper; }; #endif //__cplusplus #endif // __FTBBox__ rgl/src/ext/ftgl/FTGL/FTExtrdGlyph.h0000644000176200001440000000727514530125205016622 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTExtrudeGlyph__ #define __FTExtrudeGlyph__ #ifdef __cplusplus /** * FTExtrudeGlyph is a specialisation of FTGlyph for creating tessellated * extruded polygon glyphs. */ class FTGL_EXPORT FTExtrudeGlyph : public FTGlyph { public: /** * Constructor. Sets the Error to Invalid_Outline if the glyph isn't * an outline. * * @param glyph The Freetype glyph to be processed * @param depth The distance along the z axis to extrude the glyph * @param frontOutset outset contour size * @param backOutset outset contour size * @param useDisplayList Enable or disable the use of Display Lists * for this glyph * true turns ON display lists. * false turns OFF display lists. */ FTExtrudeGlyph(FT_GlyphSlot glyph, float depth, float frontOutset, float backOutset, bool useDisplayList); /** * Destructor */ virtual ~FTExtrudeGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #define FTExtrdGlyph FTExtrudeGlyph #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialisation of FTGLglyph for creating tessellated * extruded polygon glyphs. * * @param glyph The Freetype glyph to be processed * @param depth The distance along the z axis to extrude the glyph * @param frontOutset outset contour size * @param backOutset outset contour size * @param useDisplayList Enable or disable the use of Display Lists * for this glyph * true turns ON display lists. * false turns OFF display lists. * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreateExtrudeGlyph(FT_GlyphSlot glyph, float depth, float frontOutset, float backOutset, int useDisplayList); FTGL_END_C_DECLS #endif // __FTExtrudeGlyph__ rgl/src/ext/ftgl/FTGL/FTGLBitmapFont.h0000644000176200001440000000606314530125205017010 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTBitmapFont__ #define __FTBitmapFont__ #ifdef __cplusplus /** * FTBitmapFont is a specialisation of the FTFont class for handling * Bitmap fonts * * @see FTFont */ class FTGL_EXPORT FTBitmapFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTBitmapFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTBitmapFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ ~FTBitmapFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #define FTGLBitmapFont FTBitmapFont #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling bitmap fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont */ FTGL_EXPORT FTGLfont *ftglCreateBitmapFont(const char *file); FTGL_END_C_DECLS #endif // __FTBitmapFont__ rgl/src/ext/ftgl/FTGL/FTTextureGlyph.h0000644000176200001440000000677714530125205017202 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTTextureGlyph__ #define __FTTextureGlyph__ #ifdef __cplusplus /** * FTTextureGlyph is a specialisation of FTGlyph for creating texture * glyphs. */ class FTGL_EXPORT FTTextureGlyph : public FTGlyph { public: /** * Constructor * * @param glyph The Freetype glyph to be processed * @param id The id of the texture that this glyph will be * drawn in * @param xOffset The x offset into the parent texture to draw * this glyph * @param yOffset The y offset into the parent texture to draw * this glyph * @param width The width of the parent texture * @param height The height (number of rows) of the parent texture */ FTTextureGlyph(FT_GlyphSlot glyph, int id, int xOffset, int yOffset, int width, int height); /** * Destructor */ virtual ~FTTextureGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialisation of FTGLglyph for creating pixmaps. * * @param glyph The Freetype glyph to be processed. * @param id The id of the texture that this glyph will be drawn in. * @param xOffset The x offset into the parent texture to draw this glyph. * @param yOffset The y offset into the parent texture to draw this glyph. * @param width The width of the parent texture. * @param height The height (number of rows) of the parent texture. * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreateTextureGlyph(FT_GlyphSlot glyph, int id, int xOffset, int yOffset, int width, int height); FTGL_END_C_DECLS #endif // __FTTextureGlyph__ rgl/src/ext/ftgl/FTGL/FTBitmapGlyph.h0000644000176200001440000000472514530125205016745 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTBitmapGlyph__ #define __FTBitmapGlyph__ #ifdef __cplusplus /** * FTBitmapGlyph is a specialisation of FTGlyph for creating bitmaps. */ class FTGL_EXPORT FTBitmapGlyph : public FTGlyph { public: /** * Constructor * * @param glyph The Freetype glyph to be processed */ FTBitmapGlyph(FT_GlyphSlot glyph); /** * Destructor */ virtual ~FTBitmapGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialisation of FTGLglyph for creating bitmaps. * * @param glyph The Freetype glyph to be processed * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreateBitmapGlyph(FT_GlyphSlot glyph); FTGL_END_C_DECLS #endif // __FTBitmapGlyph__ rgl/src/ext/ftgl/FTGL/FTLayout.h0000644000176200001440000001454514530125205016003 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTLayout__ #define __FTLayout__ #ifdef __cplusplus class FTLayoutImpl; /** * FTLayout is the interface for layout managers that render text. * * Specific layout manager classes are derived from this class. This class * is abstract and deriving classes must implement the protected * Render methods to render formatted text and * BBox methods to determine the bounding box of output text. * * @see FTFont * @see FTBBox */ class FTGL_EXPORT FTLayout { protected: FTLayout(); private: /** * Internal FTGL FTLayout constructor. For private use only. * * @param pImpl Internal implementation object. Will be destroyed * upon FTLayout deletion. */ FTLayout(FTLayoutImpl *pImpl); /* Allow our internal subclasses to access the private constructor */ friend class FTSimpleLayout; public: /** * Destructor */ virtual ~FTLayout(); /** * Get the bounding box for a formatted string. * * @param string A char string. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @return The corresponding bounding box. */ virtual FTBBox BBox(const char* string, const int len = -1, FTPoint position = FTPoint()) = 0; /** * Get the bounding box for a formatted string. * * @param string A wchar_t string. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @return The corresponding bounding box. */ virtual FTBBox BBox(const wchar_t* string, const int len = -1, FTPoint position = FTPoint()) = 0; /** * Render a string of characters. * * @param string 'C' style string to be output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param renderMode Render mode to display (optional) */ virtual void Render(const char *string, const int len = -1, FTPoint position = FTPoint(), int renderMode = FTGL::RENDER_ALL) = 0; /** * Render a string of characters. * * @param string wchar_t string to be output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param renderMode Render mode to display (optional) */ virtual void Render(const wchar_t *string, const int len = -1, FTPoint position = FTPoint(), int renderMode = FTGL::RENDER_ALL) = 0; /** * Queries the Layout for errors. * * @return The current error code. */ virtual FT_Error Error() const; private: /** * Internal FTGL FTLayout implementation object. For private use only. */ FTLayoutImpl *impl; }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * FTGLlayout is the interface for layout managers that render text. */ struct _FTGLlayout; typedef struct _FTGLlayout FTGLlayout; /** * Destroy an FTGL layout object. * * @param layout An FTGLlayout* object. */ FTGL_EXPORT void ftglDestroyLayout(FTGLlayout* layout); /** * Get the bounding box for a string. * * @param layout An FTGLlayout* object. * @param string A char buffer * @param bounds An array of 6 float values where the bounding box's lower * left near and upper right far 3D coordinates will be stored. */ FTGL_EXPORT void ftglGetLayoutBBox(FTGLlayout *layout, const char* string, float bounds[6]); /** * Render a string of characters. * * @param layout An FTGLlayout* object. * @param string Char string to be output. * @param mode Render mode to display. */ FTGL_EXPORT void ftglRenderLayout(FTGLlayout *layout, const char *string, int mode); /** * Query a layout for errors. * * @param layout An FTGLlayout* object. * @return The current error code. */ FTGL_EXPORT FT_Error ftglGetLayoutError(FTGLlayout* layout); FTGL_END_C_DECLS #endif /* __FTLayout__ */ rgl/src/ext/ftgl/FTGL/FTPolyGlyph.h0000644000176200001440000000651114530125205016447 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTPolygonGlyph__ #define __FTPolygonGlyph__ #ifdef __cplusplus /** * FTPolygonGlyph is a specialisation of FTGlyph for creating tessellated * polygon glyphs. */ class FTGL_EXPORT FTPolygonGlyph : public FTGlyph { public: /** * Constructor. Sets the Error to Invalid_Outline if the glyphs * isn't an outline. * * @param glyph The Freetype glyph to be processed * @param outset The outset distance * @param useDisplayList Enable or disable the use of Display Lists * for this glyph * true turns ON display lists. * false turns OFF display lists. */ FTPolygonGlyph(FT_GlyphSlot glyph, float outset, bool useDisplayList); /** * Destructor */ virtual ~FTPolygonGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #define FTPolyGlyph FTPolygonGlyph #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialisation of FTGLglyph for creating tessellated * polygon glyphs. * * @param glyph The Freetype glyph to be processed * @param outset outset contour size * @param useDisplayList Enable or disable the use of Display Lists * for this glyph * true turns ON display lists. * false turns OFF display lists. * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreatePolygonGlyph(FT_GlyphSlot glyph, float outset, int useDisplayList); FTGL_END_C_DECLS #endif // __FTPolygonGlyph__ rgl/src/ext/ftgl/FTGL/FTFont.h0000644000176200001440000004730314530125205015432 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTFont__ #define __FTFont__ #ifdef __cplusplus class FTFontImpl; /** * FTFont is the public interface for the FTGL library. * * Specific font classes are derived from this class. It uses the helper * classes FTFace and FTSize to access the Freetype library. This class * is abstract and deriving classes must implement the protected * MakeGlyph function to create glyphs of the * appropriate type. * * It is good practice after using these functions to test the error * code returned. FT_Error Error(). Check the freetype file * fterrdef.h for error definitions. * * @see FTFace * @see FTSize */ class FTGL_EXPORT FTFont { protected: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTFont(char const *fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); private: /* Allow our internal subclasses to access the private constructor */ friend class FTBitmapFont; friend class FTBufferFont; friend class FTExtrudeFont; friend class FTOutlineFont; friend class FTPixmapFont; friend class FTPolygonFont; friend class FTTextureFont; /** * Internal FTGL FTFont constructor. For private use only. * * @param pImpl Internal implementation object. Will be destroyed * upon FTFont deletion. */ FTFont(FTFontImpl *pImpl); public: virtual ~FTFont(); /** * Attach auxilliary file to font e.g font metrics. * * Note: not all font formats implement this function. * * @param fontFilePath auxilliary font file path. * @return true if file has been attached * successfully. */ virtual bool Attach(const char* fontFilePath); /** * Attach auxilliary data to font e.g font metrics, from memory. * * Note: not all font formats implement this function. * * @param pBufferBytes the in-memory buffer. * @param bufferSizeInBytes the length of the buffer in bytes. * @return true if file has been attached * successfully. */ virtual bool Attach(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Set the glyph loading flags. By default, fonts use the most * sensible flags when loading a font's glyph using FT_Load_Glyph(). * This function allows to override the default flags. * * @param flags The glyph loading flags. */ virtual void GlyphLoadFlags(FT_Int flags); /** * Set the character map for the face. * * @param encoding Freetype enumerate for char map code. * @return true if charmap was valid and * set correctly. */ virtual bool CharMap(FT_Encoding encoding); /** * Get the number of character maps in this face. * * @return character map count. */ virtual unsigned int CharMapCount() const; /** * Get a list of character maps in this face. * * @return pointer to the first encoding. */ virtual FT_Encoding* CharMapList(); /** * Set the char size for the current face. * * @param size the face size in points (1/72 inch) * @param res the resolution of the target device. * @return true if size was set correctly */ virtual bool FaceSize(const unsigned int size, const unsigned int res = 72); /** * Get the current face size in points (1/72 inch). * * @return face size */ virtual unsigned int FaceSize() const; /** * Set the extrusion distance for the font. Only implemented by * FTExtrudeFont * * @param depth The extrusion distance. */ virtual void Depth(float depth); /** * Set the outset distance for the font. Only implemented by * FTOutlineFont, FTPolygonFont and FTExtrudeFont * * @param outset The outset distance. */ virtual void Outset(float outset); /** * Set the front and back outset distances for the font. Only * implemented by FTExtrudeFont * * @param front The front outset distance. * @param back The back outset distance. */ virtual void Outset(float front, float back); /** * Enable or disable the use of Display Lists inside FTGL * * @param useList true turns ON display lists. * false turns OFF display lists. */ virtual void UseDisplayList(bool useList); /** * Get the global ascender height for the face. * * @return Ascender height */ virtual float Ascender() const; /** * Gets the global descender height for the face. * * @return Descender height */ virtual float Descender() const; /** * Gets the line spacing for the font. * * @return Line height */ virtual float LineHeight() const; /** * Get the bounding box for a string. * * @param string A char buffer. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param spacing A displacement vector to add after each character * has been checked (optional). * @return The corresponding bounding box. */ virtual FTBBox BBox(const char *string, const int len = -1, FTPoint position = FTPoint(), FTPoint spacing = FTPoint()); /** * Get the bounding box for a string (deprecated). * * @param string A char buffer. * @param llx Lower left near x coordinate. * @param lly Lower left near y coordinate. * @param llz Lower left near z coordinate. * @param urx Upper right far x coordinate. * @param ury Upper right far y coordinate. * @param urz Upper right far z coordinate. */ void BBox(const char* string, float& llx, float& lly, float& llz, float& urx, float& ury, float& urz) { FTBBox b = BBox(string); llx = b.Lower().Xf(); lly = b.Lower().Yf(); llz = b.Lower().Zf(); urx = b.Upper().Xf(); ury = b.Upper().Yf(); urz = b.Upper().Zf(); } /** * Get the bounding box for a string. * * @param string A wchar_t buffer. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param spacing A displacement vector to add after each character * has been checked (optional). * @return The corresponding bounding box. */ virtual FTBBox BBox(const wchar_t *string, const int len = -1, FTPoint position = FTPoint(), FTPoint spacing = FTPoint()); /** * Get the bounding box for a string (deprecated). * * @param string A wchar_t buffer. * @param llx Lower left near x coordinate. * @param lly Lower left near y coordinate. * @param llz Lower left near z coordinate. * @param urx Upper right far x coordinate. * @param ury Upper right far y coordinate. * @param urz Upper right far z coordinate. */ void BBox(const wchar_t* string, float& llx, float& lly, float& llz, float& urx, float& ury, float& urz) { FTBBox b = BBox(string); llx = b.Lower().Xf(); lly = b.Lower().Yf(); llz = b.Lower().Zf(); urx = b.Upper().Xf(); ury = b.Upper().Yf(); urz = b.Upper().Zf(); } /** * Get the advance for a string. * * @param string 'C' style string to be checked. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param spacing A displacement vector to add after each character * has been checked (optional). * @return The string's advance width. */ virtual float Advance(const char* string, const int len = -1, FTPoint spacing = FTPoint()); /** * Get the advance for a string. * * @param string A wchar_t string * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param spacing A displacement vector to add after each character * has been checked (optional). * @return The string's advance width. */ virtual float Advance(const wchar_t* string, const int len = -1, FTPoint spacing = FTPoint()); /** * Render a string of characters. * * @param string 'C' style string to be output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param spacing A displacement vector to add after each character * has been displayed (optional). * @param renderMode Render mode to use for display (optional). * @return The new pen position after the last character was output. */ virtual FTPoint Render(const char* string, const int len = -1, FTPoint position = FTPoint(), FTPoint spacing = FTPoint(), int renderMode = FTGL::RENDER_ALL); /** * Render a string of characters * * @param string wchar_t string to be output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param spacing A displacement vector to add after each character * has been displayed (optional). * @param renderMode Render mode to use for display (optional). * @return The new pen position after the last character was output. */ virtual FTPoint Render(const wchar_t *string, const int len = -1, FTPoint position = FTPoint(), FTPoint spacing = FTPoint(), int renderMode = FTGL::RENDER_ALL); /** * Queries the Font for errors. * * @return The current error code. */ virtual FT_Error Error() const; protected: /* Allow impl to access MakeGlyph */ friend class FTFontImpl; /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot) = 0; private: /** * Internal FTGL FTFont implementation object. For private use only. */ FTFontImpl *impl; }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * FTGLfont is the public interface for the FTGL library. * * It is good practice after using these functions to test the error * code returned. FT_Error Error(). Check the freetype file * fterrdef.h for error definitions. */ struct _FTGLFont; typedef struct _FTGLfont FTGLfont; /** * Create a custom FTGL font object. * * @param fontFilePath The font file name. * @param data A pointer to private data that will be passed to callbacks. * @param makeglyphCallback A glyph-making callback function. * @return An FTGLfont* object. */ FTGL_EXPORT FTGLfont *ftglCreateCustomFont(char const *fontFilePath, void *data, FTGLglyph * (*makeglyphCallback) (FT_GlyphSlot, void *)); /** * Destroy an FTGL font object. * * @param font An FTGLfont* object. */ FTGL_EXPORT void ftglDestroyFont(FTGLfont* font); /** * Attach auxilliary file to font e.g. font metrics. * * Note: not all font formats implement this function. * * @param font An FTGLfont* object. * @param path Auxilliary font file path. * @return 1 if file has been attached successfully. */ FTGL_EXPORT int ftglAttachFile(FTGLfont* font, const char* path); /** * Attach auxilliary data to font, e.g. font metrics, from memory. * * Note: not all font formats implement this function. * * @param font An FTGLfont* object. * @param data The in-memory buffer. * @param size The length of the buffer in bytes. * @return 1 if file has been attached successfully. */ FTGL_EXPORT int ftglAttachData(FTGLfont* font, const unsigned char * data, size_t size); /** * Set the character map for the face. * * @param font An FTGLfont* object. * @param encoding Freetype enumerate for char map code. * @return 1 if charmap was valid and set correctly. */ FTGL_EXPORT int ftglSetFontCharMap(FTGLfont* font, FT_Encoding encoding); /** * Get the number of character maps in this face. * * @param font An FTGLfont* object. * @return character map count. */ FTGL_EXPORT unsigned int ftglGetFontCharMapCount(FTGLfont* font); /** * Get a list of character maps in this face. * * @param font An FTGLfont* object. * @return pointer to the first encoding. */ FTGL_EXPORT FT_Encoding* ftglGetFontCharMapList(FTGLfont* font); /** * Set the char size for the current face. * * @param font An FTGLfont* object. * @param size The face size in points (1/72 inch). * @param res The resolution of the target device, or 0 to use the default * value of 72. * @return 1 if size was set correctly. */ FTGL_EXPORT int ftglSetFontFaceSize(FTGLfont* font, unsigned int size, unsigned int res); /** * Get the current face size in points (1/72 inch). * * @param font An FTGLfont* object. * @return face size */ FTGL_EXPORT unsigned int ftglGetFontFaceSize(FTGLfont* font); /** * Set the extrusion distance for the font. Only implemented by * FTExtrudeFont. * * @param font An FTGLfont* object. * @param depth The extrusion distance. */ FTGL_EXPORT void ftglSetFontDepth(FTGLfont* font, float depth); /** * Set the outset distance for the font. Only FTOutlineFont, FTPolygonFont * and FTExtrudeFont implement front outset. Only FTExtrudeFont implements * back outset. * * @param font An FTGLfont* object. * @param front The front outset distance. * @param back The back outset distance. */ FTGL_EXPORT void ftglSetFontOutset(FTGLfont* font, float front, float back); /** * Enable or disable the use of Display Lists inside FTGL. * * @param font An FTGLfont* object. * @param useList 1 turns ON display lists. * 0 turns OFF display lists. */ FTGL_EXPORT void ftglSetFontDisplayList(FTGLfont* font, int useList); /** * Get the global ascender height for the face. * * @param font An FTGLfont* object. * @return Ascender height */ FTGL_EXPORT float ftglGetFontAscender(FTGLfont* font); /** * Gets the global descender height for the face. * * @param font An FTGLfont* object. * @return Descender height */ FTGL_EXPORT float ftglGetFontDescender(FTGLfont* font); /** * Gets the line spacing for the font. * * @param font An FTGLfont* object. * @return Line height */ FTGL_EXPORT float ftglGetFontLineHeight(FTGLfont* font); /** * Get the bounding box for a string. * * @param font An FTGLfont* object. * @param string A char buffer * @param len The length of the string. If < 0 then all characters will be * checked until a null character is encountered (optional). * @param bounds An array of 6 float values where the bounding box's lower * left near and upper right far 3D coordinates will be stored. */ FTGL_EXPORT void ftglGetFontBBox(FTGLfont* font, const char *string, int len, float bounds[6]); /** * Get the advance width for a string. * * @param font An FTGLfont* object. * @param string A char string. * @return Advance width */ FTGL_EXPORT float ftglGetFontAdvance(FTGLfont* font, const char *string); /** * Render a string of characters. * * @param font An FTGLfont* object. * @param string Char string to be output. * @param mode Render mode to display. */ FTGL_EXPORT void ftglRenderFont(FTGLfont* font, const char *string, int mode); /** * Query a font for errors. * * @param font An FTGLfont* object. * @return The current error code. */ FTGL_EXPORT FT_Error ftglGetFontError(FTGLfont* font); FTGL_END_C_DECLS #endif // __FTFont__ rgl/src/ext/ftgl/FTGL/FTGLExtrdFont.h0000644000176200001440000000617714530125205016670 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTExtrudeFont__ #define __FTExtrudeFont__ #ifdef __cplusplus /** * FTExtrudeFont is a specialisation of the FTFont class for handling * extruded Polygon fonts * * @see FTFont * @see FTPolygonFont */ class FTGL_EXPORT FTExtrudeFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTExtrudeFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTExtrudeFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ ~FTExtrudeFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #define FTGLExtrdFont FTExtrudeFont #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling extruded poygon fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont * @see ftglCreatePolygonFont */ FTGL_EXPORT FTGLfont *ftglCreateExtrudeFont(const char *file); FTGL_END_C_DECLS #endif // __FTExtrudeFont__ rgl/src/ext/ftgl/FTGL/FTGLPixmapFont.h0000644000176200001440000000611614530125205017031 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTPixmapFont__ #define __FTPixmapFont__ #ifdef __cplusplus /** * FTPixmapFont is a specialisation of the FTFont class for handling * Pixmap (Grey Scale) fonts * * @see FTFont */ class FTGL_EXPORT FTPixmapFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTPixmapFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTPixmapFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ ~FTPixmapFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #define FTGLPixmapFont FTPixmapFont #endif // __cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling pixmap (grey scale) fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont */ FTGL_EXPORT FTGLfont *ftglCreatePixmapFont(const char *file); FTGL_END_C_DECLS #endif // __FTPixmapFont__ rgl/src/ext/ftgl/FTGL/FTSimpleLayout.h0000644000176200001440000001472014530125205017150 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTSimpleLayout__ #define __FTSimpleLayout__ #ifdef __cplusplus class FTFont; /** * FTSimpleLayout is a specialisation of FTLayout for simple text boxes. * * This class has basic support for text wrapping, left, right and centered * alignment, and text justification. * * @see FTLayout */ class FTGL_EXPORT FTSimpleLayout : public FTLayout { public: /** * Initializes line spacing to 1.0, alignment to * ALIGN_LEFT and wrap to 100.0 */ FTSimpleLayout(); /** * Destructor */ ~FTSimpleLayout(); /** * Get the bounding box for a formatted string. * * @param string A char string. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @return The corresponding bounding box. */ virtual FTBBox BBox(const char* string, const int len = -1, FTPoint position = FTPoint()); /** * Get the bounding box for a formatted string. * * @param string A wchar_t string. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @return The corresponding bounding box. */ virtual FTBBox BBox(const wchar_t* string, const int len = -1, FTPoint position = FTPoint()); /** * Render a string of characters. * * @param string 'C' style string to be output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param renderMode Render mode to display (optional) */ virtual void Render(const char *string, const int len = -1, FTPoint position = FTPoint(), int renderMode = FTGL::RENDER_ALL); /** * Render a string of characters. * * @param string wchar_t string to be output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param renderMode Render mode to display (optional) */ virtual void Render(const wchar_t *string, const int len = -1, FTPoint position = FTPoint(), int renderMode = FTGL::RENDER_ALL); /** * Set the font to use for rendering the text. * * @param fontInit A pointer to the new font. The font is * referenced by this but will not be * disposed of when this is deleted. */ void SetFont(FTFont *fontInit); /** * @return The current font. */ FTFont *GetFont(); /** * The maximum line length for formatting text. * * @param LineLength The new line length. */ void SetLineLength(const float LineLength); /** * @return The current line length. */ float GetLineLength() const; /** * The text alignment mode used to distribute * space within a line or rendered text. * * @param Alignment The new alignment mode. */ void SetAlignment(const FTGL::TextAlignment Alignment); /** * @return The text alignment mode. */ FTGL::TextAlignment GetAlignment() const; /** * Sets the line height. * * @param LineSpacing The height of each line of text expressed as * a percentage of the current fonts line height. */ void SetLineSpacing(const float LineSpacing); /** * @return The line spacing. */ float GetLineSpacing() const; }; #endif //__cplusplus FTGL_BEGIN_C_DECLS FTGL_EXPORT FTGLlayout *ftglCreateSimpleLayout(void); FTGL_EXPORT void ftglSetLayoutFont(FTGLlayout *, FTGLfont*); FTGL_EXPORT FTGLfont *ftglGetLayoutFont(FTGLlayout *); FTGL_EXPORT void ftglSetLayoutLineLength(FTGLlayout *, const float); FTGL_EXPORT float ftglGetLayoutLineLength(FTGLlayout *); FTGL_EXPORT void ftglSetLayoutAlignment(FTGLlayout *, const int); FTGL_EXPORT int ftglGetLayoutAlignement(FTGLlayout *); FTGL_EXPORT void ftglSetLayoutLineSpacing(FTGLlayout *, const float); FTGL_EXPORT float ftglGetLayoutLineSpacing(FTGLlayout *); FTGL_END_C_DECLS #endif /* __FTSimpleLayout__ */ rgl/src/ext/ftgl/FTCharToGlyphIndexMap.h0000644000176200001440000001147614555455305017622 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTCharToGlyphIndexMap__ #define __FTCharToGlyphIndexMap__ #include #include "FTGL/ftgl.h" /** * Provides a non-STL alternative to the STL map * which maps character codes to glyph indices inside FTCharmap. * * Implementation: * - NumberOfBuckets buckets are considered. * - Each bucket has BucketSize entries. * - When the glyph index for the character code C has to be stored, the * bucket this character belongs to is found using 'C div BucketSize'. * If this bucket has not been allocated yet, do it now. * The entry in the bucked is found using 'C mod BucketSize'. * If it is set to IndexNotFound, then the glyph entry has not been set. * - Try to mimic the calls made to the STL map API. * * Caveats: * - The glyph index is now a signed long instead of unsigned long, so * the special value IndexNotFound (= -1) can be used to specify that the * glyph index has not been stored yet. */ class FTCharToGlyphIndexMap { public: typedef unsigned long CharacterCode; typedef signed long GlyphIndex; enum { NumberOfBuckets = 256, BucketSize = 256, IndexNotFound = -1 }; FTCharToGlyphIndexMap() { this->Indices = 0; } virtual ~FTCharToGlyphIndexMap() { if(this->Indices) { // Free all buckets this->clear(); // Free main structure delete [] this->Indices; this->Indices = 0; } } void clear() { if(this->Indices) { for(int i = 0; i < FTCharToGlyphIndexMap::NumberOfBuckets; i++) { if(this->Indices[i]) { delete [] this->Indices[i]; this->Indices[i] = 0; } } } } const GlyphIndex find(CharacterCode c) { if(!this->Indices) { return 0; } // Find position of char code in buckets div_t pos = div(static_cast(c), FTCharToGlyphIndexMap::BucketSize); if(!this->Indices[pos.quot]) { return 0; } const FTCharToGlyphIndexMap::GlyphIndex *ptr = &this->Indices[pos.quot][pos.rem]; if(*ptr == FTCharToGlyphIndexMap::IndexNotFound) { return 0; } return *ptr; } void insert(CharacterCode c, GlyphIndex g) { if(!this->Indices) { this->Indices = new GlyphIndex* [FTCharToGlyphIndexMap::NumberOfBuckets]; for(int i = 0; i < FTCharToGlyphIndexMap::NumberOfBuckets; i++) { this->Indices[i] = 0; } } // Find position of char code in buckets div_t pos = div(static_cast(c), FTCharToGlyphIndexMap::BucketSize); // Allocate bucket if does not exist yet if(!this->Indices[pos.quot]) { this->Indices[pos.quot] = new GlyphIndex [FTCharToGlyphIndexMap::BucketSize]; for(int i = 0; i < FTCharToGlyphIndexMap::BucketSize; i++) { this->Indices[pos.quot][i] = FTCharToGlyphIndexMap::IndexNotFound; } } this->Indices[pos.quot][pos.rem] = g; } private: GlyphIndex** Indices; }; #endif // __FTCharToGlyphIndexMap__ rgl/src/ext/ftgl/FTCharmap.h0000644000176200001440000001220314265301465015343 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTCharmap__ #define __FTCharmap__ #include #include FT_FREETYPE_H #include FT_GLYPH_H #include "FTGL/ftgl.h" #include "FTCharToGlyphIndexMap.h" /** * FTCharmap takes care of specifying the encoding for a font and mapping * character codes to glyph indices. * * It doesn't preprocess all indices, only on an as needed basis. This may * seem like a performance penalty but it is quicker than using the 'raw' * freetype calls and will save significant amounts of memory when dealing * with unicode encoding * * @see "Freetype 2 Documentation" * */ class FTFace; class FTCharmap { public: /** * Constructor */ FTCharmap(FTFace* face); /** * Destructor */ virtual ~FTCharmap(); /** * Queries for the current character map code. * * @return The current character map code. */ FT_Encoding Encoding() const { return ftEncoding; } /** * Sets the character map for the face. If an error occurs the object is not modified. * Valid encodings as at Freetype 2.0.4 * ft_encoding_none * ft_encoding_symbol * ft_encoding_unicode * ft_encoding_latin_2 * ft_encoding_sjis * ft_encoding_gb2312 * ft_encoding_big5 * ft_encoding_wansung * ft_encoding_johab * ft_encoding_adobe_standard * ft_encoding_adobe_expert * ft_encoding_adobe_custom * ft_encoding_apple_roman * * @param encoding the Freetype encoding symbol. See above. * @return true if charmap was valid and set * correctly. */ bool CharMap(FT_Encoding encoding); /** * Get the FTGlyphContainer index of the input character. * * @param characterCode The character code of the requested glyph in * the current encoding eg apple roman. * @return The FTGlyphContainer index for the character or zero * if it wasn't found */ unsigned int GlyphListIndex(const unsigned int characterCode); /** * Get the font glyph index of the input character. * * @param characterCode The character code of the requested glyph in * the current encoding eg apple roman. * @return The glyph index for the character. */ unsigned int FontIndex(const unsigned int characterCode); /** * Set the FTGlyphContainer index of the character code. * * @param characterCode The character code of the requested glyph in * the current encoding eg apple roman. * @param containerIndex The index into the FTGlyphContainer of the * character code. */ void InsertIndex(const unsigned int characterCode, const size_t containerIndex); /** * Queries for errors. * * @return The current error code. Zero means no error. */ FT_Error Error() const { return err; } private: /** * Current character map code. */ FT_Encoding ftEncoding; /** * The current Freetype face. */ const FT_Face ftFace; /** * A structure that maps glyph indices to character codes * * < character code, face glyph index> */ typedef FTCharToGlyphIndexMap CharacterMap; CharacterMap charMap; /** * Precomputed font indices. */ static const unsigned int MAX_PRECOMPUTED = 128; unsigned int charIndexCache[MAX_PRECOMPUTED]; /** * Current error code. */ FT_Error err; }; #endif // __FTCharmap__ rgl/src/ext/ftgl/FTInternals.h0000644000176200001440000000644714555455305015751 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTINTERNALS_H__ #define __FTINTERNALS_H__ #include "FTGL/ftgl.h" #include #include // Fixes for deprecated identifiers in 2.1.5 #ifndef FT_OPEN_MEMORY #define FT_OPEN_MEMORY (FT_Open_Flags)1 #endif #ifndef FT_RENDER_MODE_MONO #define FT_RENDER_MODE_MONO ft_render_mode_mono #endif #ifndef FT_RENDER_MODE_NORMAL #define FT_RENDER_MODE_NORMAL ft_render_mode_normal #endif #ifdef WIN32 // Under windows avoid including is overrated. // Sure, it can be avoided and "name space pollution" can be // avoided, but why? It really doesn't make that much difference // these days. #define WIN32_LEAN_AND_MEAN #include #ifndef __gl_h_ #include #include #endif #else // Non windows platforms - don't require nonsense as seen above :-) #ifndef __gl_h_ #ifdef SDL_main #include "SDL_opengl.h" #elif __APPLE_CC__ #define GL_SILENCE_DEPRECATION #include #include #else #include #include #endif #endif // Required for compatibility with glext.h style function definitions of // OpenGL extensions, such as in src/osg/Point.cpp. #ifndef APIENTRY #define APIENTRY #endif #endif FTGL_BEGIN_C_DECLS typedef enum { GLYPH_CUSTOM, GLYPH_BITMAP, GLYPH_BUFFER, GLYPH_PIXMAP, GLYPH_OUTLINE, GLYPH_POLYGON, GLYPH_EXTRUDE, GLYPH_TEXTURE } GlyphType; struct _FTGLglyph { FTGlyph *ptr; FTGL::GlyphType type; }; typedef enum { FONT_CUSTOM, FONT_BITMAP, FONT_BUFFER, FONT_PIXMAP, FONT_OUTLINE, FONT_POLYGON, FONT_EXTRUDE, FONT_TEXTURE } FontType; struct _FTGLfont { FTFont *ptr; FTGL::FontType type; }; typedef enum { LAYOUT_SIMPLE } LayoutType; struct _FTGLlayout { FTLayout *ptr; FTGLfont *font; FTGL::LayoutType type; }; FTGL_END_C_DECLS #endif //__FTINTERNALS_H__ rgl/src/ext/ftgl/FTVectoriser.h0000644000176200001440000001722714531466703016133 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTVectoriser__ #define __FTVectoriser__ #include "FTGL/ftgl.h" #include "FTContour.h" #include "FTList.h" #include "FTVector.h" #ifndef CALLBACK #define CALLBACK #endif /** * FTTesselation captures points that are output by OpenGL's gluTesselator. */ class FTTesselation { public: /** * Default constructor */ FTTesselation(GLenum m) : meshType(m) { pointList.reserve(128); } /** * Destructor */ ~FTTesselation() { pointList.clear(); } /** * Add a point to the mesh. */ void AddPoint(const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z) { pointList.push_back(FTPoint(x, y, z)); } /** * The number of points in this mesh */ size_t PointCount() const { return pointList.size(); } /** * */ const FTPoint& Point(unsigned int index) const { return pointList[index]; } /** * Return the OpenGL polygon type. */ GLenum PolygonType() const { return meshType; } private: /** * Points generated by gluTesselator. */ typedef FTVector PointVector; PointVector pointList; /** * OpenGL primitive type from gluTesselator. */ GLenum meshType; }; /** * FTMesh is a container of FTTesselation's that make up a polygon glyph */ class FTMesh { typedef FTVector TesselationVector; typedef FTList PointList; public: /** * Default constructor */ FTMesh(); /** * Destructor */ ~FTMesh(); /** * Add a point to the mesh */ void AddPoint(const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z); /** * Create a combine point for the gluTesselator */ const FTGL_DOUBLE* Combine(const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z); /** * Begin a new polygon */ void Begin(GLenum meshType); /** * End a polygon */ void End(); /** * Record a gluTesselation error */ void Error(GLenum e) { err = e; } /** * The number of tesselations in the mesh */ size_t TesselationCount() const { return tesselationList.size(); } /** * Get a tesselation by index */ const FTTesselation* const Tesselation(size_t index) const; /** * Return the temporary point list. For testing only. */ const PointList& TempPointList() const { return tempPointList; } /** * Get the GL ERROR returned by the glu tesselator */ GLenum Error() const { return err; } private: /** * The current sub mesh that we are constructing. */ FTTesselation* currentTesselation; /** * Holds each sub mesh that comprises this glyph. */ TesselationVector tesselationList; /** * Holds extra points created by gluTesselator. See ftglCombine. */ PointList tempPointList; /** * GL ERROR returned by the glu tesselator */ GLenum err; }; const FTGL_DOUBLE FTGL_FRONT_FACING = 1.0; const FTGL_DOUBLE FTGL_BACK_FACING = -1.0; /** * FTVectoriser class is a helper class that converts font outlines into * point data. * * @see FTExtrudeGlyph * @see FTOutlineGlyph * @see FTPolygonGlyph * @see FTContour * @see FTPoint * */ class FTVectoriser { public: /** * Constructor * * @param glyph The freetype glyph to be processed */ FTVectoriser(const FT_GlyphSlot glyph); /** * Destructor */ virtual ~FTVectoriser(); /** * Build an FTMesh from the vector outline data. * * @param zNormal The direction of the z axis of the normal * for this mesh * FIXME: change the following for a constant * @param outsetType Specify the outset type contour * 0 : Original * 1 : Front * 2 : Back * @param outsetSize Specify the outset size contour */ void MakeMesh(FTGL_DOUBLE zNormal = FTGL_FRONT_FACING, int outsetType = 0, float outsetSize = 0.0f); /** * Get the current mesh. */ const FTMesh* const GetMesh() const { return mesh; } /** * Get the total count of points in this outline * * @return the number of points */ size_t PointCount(); /** * Get the count of contours in this outline * * @return the number of contours */ size_t ContourCount() const { return ftContourCount; } /** * Return a contour at index * * @return the number of contours */ const FTContour* const Contour(size_t index) const; /** * Get the number of points in a specific contour in this outline * * @param c The contour index * @return the number of points in contour[c] */ size_t ContourSize(int c) const { return contourList[c]->PointCount(); } /** * Get the flag for the tesselation rule for this outline * * @return The contour flag */ int ContourFlag() const { return contourFlag; } private: /** * Process the freetype outline data into contours of points * * @param front front outset distance * @param back back outset distance */ void ProcessContours(); /** * The list of contours in the glyph */ FTContour** contourList; /** * A Mesh for tesselations */ FTMesh* mesh; /** * The number of contours reported by Freetype */ short ftContourCount; /** * A flag indicating the tesselation rule for the glyph */ int contourFlag; /** * A Freetype outline */ FT_Outline outline; }; #endif // __FTVectoriser__ rgl/src/ext/ftgl/FTLayout/0000755000176200001440000000000014531466703015101 5ustar liggesusersrgl/src/ext/ftgl/FTLayout/FTLayoutGlue.cpp0000644000176200001440000001255114531466703020135 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTInternals.h" static const FTBBox static_ftbbox; FTGL_BEGIN_C_DECLS #define C_TOR(cname, cargs, cxxname, cxxarg, cxxtype) \ FTGLlayout* cname cargs \ { \ cxxname *l = new cxxname cxxarg; \ if(l->Error()) \ { \ delete l; \ return NULL; \ } \ FTGLlayout *ftgl = (FTGLlayout *)malloc(sizeof(FTGLlayout)); \ ftgl->ptr = l; \ ftgl->type = cxxtype; \ return ftgl; \ } // FTSimpleLayout::FTSimpleLayout(); C_TOR(ftglCreateSimpleLayout, (), FTSimpleLayout, (), LAYOUT_SIMPLE); #define C_FUN(cret, cname, cargs, cxxerr, cxxname, cxxarg) \ cret cname cargs \ { \ if(!l || !l->ptr) \ { \ fprintf(stderr, "FTGL warning: NULL pointer in %s\n", #cname); \ cxxerr; \ } \ return l->ptr->cxxname cxxarg; \ } // FTLayout::~FTLayout(); void ftglDestroyLayout(FTGLlayout *l) { if(!l || !l->ptr) { fprintf(stderr, "FTGL warning: NULL pointer in %s\n", __FUNCTION__); return; } delete l->ptr; free(l); } // virtual FTBBox FTLayout::BBox(const char* string) extern "C++" { C_FUN(static FTBBox, _ftgGetlLayoutBBox, (FTGLlayout *l, const char *s), return static_ftbbox, BBox, (s)); } void ftgGetlLayoutBBox(FTGLlayout *l, const char * s, float c[6]) { FTBBox ret = _ftgGetlLayoutBBox(l, s); FTPoint lower = ret.Lower(), upper = ret.Upper(); c[0] = lower.Xf(); c[1] = lower.Yf(); c[2] = lower.Zf(); c[3] = upper.Xf(); c[4] = upper.Yf(); c[5] = upper.Zf(); } // virtual void FTLayout::Render(const char* string, int renderMode); C_FUN(void, ftglRenderLayout, (FTGLlayout *l, const char *s, int r), return, Render, (s, r)); // FT_Error FTLayout::Error() const; C_FUN(FT_Error, ftglGetLayoutError, (FTGLlayout *l), return -1, Error, ()); // void FTSimpleLayout::SetFont(FTFont *fontInit) void ftglSetLayoutFont(FTGLlayout *l, FTGLfont *font) { if(!l || !l->ptr) { fprintf(stderr, "FTGL warning: NULL pointer in %s\n", __FUNCTION__); return; } if(l->type != FTGL::LAYOUT_SIMPLE) { fprintf(stderr, "FTGL warning: %s not implemented for %d\n", __FUNCTION__, l->type); } l->font = font; return dynamic_cast(l->ptr)->SetFont(font->ptr); } // FTFont *FTSimpleLayout::GetFont() FTGLfont *ftglGetLayoutFont(FTGLlayout *l) { if(!l || !l->ptr) { fprintf(stderr, "FTGL warning: NULL pointer in %s\n", __FUNCTION__); return NULL; } if(l->type != FTGL::LAYOUT_SIMPLE) { fprintf(stderr, "FTGL warning: %s not implemented for %d\n", __FUNCTION__, l->type); } return l->font; } #undef C_FUN #define C_FUN(cret, cname, cargs, cxxerr, cxxname, cxxarg) \ cret cname cargs \ { \ if(!l || !l->ptr) \ { \ fprintf(stderr, "FTGL warning: NULL pointer in %s\n", #cname); \ cxxerr; \ } \ if(l->type != FTGL::LAYOUT_SIMPLE) \ { \ fprintf(stderr, "FTGL warning: %s not implemented for %d\n", \ __FUNCTION__, l->type); \ cxxerr; \ } \ return dynamic_cast(l->ptr)->cxxname cxxarg; \ } // void FTSimpleLayout::SetLineLength(const float LineLength); C_FUN(void, ftglSetLayoutLineLength, (FTGLlayout *l, const float length), return, SetLineLength, (length)); // float FTSimpleLayout::GetLineLength() const C_FUN(float, ftglGetLayoutLineLength, (FTGLlayout *l), return 0.0f, GetLineLength, ()); // void FTSimpleLayout::SetAlignment(const TextAlignment Alignment) C_FUN(void, ftglSetLayoutAlignment, (FTGLlayout *l, const int a), return, SetAlignment, ((FTGL::TextAlignment)a)); // TextAlignment FTSimpleLayout::GetAlignment() const C_FUN(int, ftglGetLayoutAlignement, (FTGLlayout *l), return FTGL::ALIGN_LEFT, GetAlignment, ()); // void FTSimpleLayout::SetLineSpacing(const float LineSpacing) C_FUN(void, ftglSetLayoutLineSpacing, (FTGLlayout *l, const float f), return, SetLineSpacing, (f)); FTGL_END_C_DECLS rgl/src/ext/ftgl/FTLayout/FTSimpleLayout.cpp0000644000176200001440000003411414531466703020471 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include #include #include "FTInternals.h" #include "FTUnicode.h" #include "FTGlyphContainer.h" #include "FTSimpleLayoutImpl.h" // // FTSimpleLayout // FTSimpleLayout::FTSimpleLayout() : FTLayout(new FTSimpleLayoutImpl()) {} FTSimpleLayout::~FTSimpleLayout() {} FTBBox FTSimpleLayout::BBox(const char *string, const int len, FTPoint pos) { return dynamic_cast(impl)->BBox(string, len, pos); } FTBBox FTSimpleLayout::BBox(const wchar_t *string, const int len, FTPoint pos) { return dynamic_cast(impl)->BBox(string, len, pos); } void FTSimpleLayout::Render(const char *string, const int len, FTPoint pos, int renderMode) { return dynamic_cast(impl)->Render(string, len, pos, renderMode); } void FTSimpleLayout::Render(const wchar_t* string, const int len, FTPoint pos, int renderMode) { return dynamic_cast(impl)->Render(string, len, pos, renderMode); } void FTSimpleLayout::SetFont(FTFont *fontInit) { dynamic_cast(impl)->currentFont = fontInit; } FTFont *FTSimpleLayout::GetFont() { return dynamic_cast(impl)->currentFont; } void FTSimpleLayout::SetLineLength(const float LineLength) { dynamic_cast(impl)->lineLength = LineLength; } float FTSimpleLayout::GetLineLength() const { return dynamic_cast(impl)->lineLength; } void FTSimpleLayout::SetAlignment(const FTGL::TextAlignment Alignment) { dynamic_cast(impl)->alignment = Alignment; } FTGL::TextAlignment FTSimpleLayout::GetAlignment() const { return dynamic_cast(impl)->alignment; } void FTSimpleLayout::SetLineSpacing(const float LineSpacing) { dynamic_cast(impl)->lineSpacing = LineSpacing; } float FTSimpleLayout::GetLineSpacing() const { return dynamic_cast(impl)->lineSpacing; } // // FTSimpleLayoutImpl // FTSimpleLayoutImpl::FTSimpleLayoutImpl() { currentFont = NULL; lineLength = 100.0f; alignment = FTGL::ALIGN_LEFT; lineSpacing = 1.0f; } template inline FTBBox FTSimpleLayoutImpl::BBoxI(const T* string, const int len, FTPoint position) { FTBBox tmp; WrapText(string, len, position, 0, &tmp); return tmp; } FTBBox FTSimpleLayoutImpl::BBox(const char *string, const int len, FTPoint position) { return BBoxI(string, len, position); } FTBBox FTSimpleLayoutImpl::BBox(const wchar_t *string, const int len, FTPoint position) { return BBoxI(string, len, position); } template inline void FTSimpleLayoutImpl::RenderI(const T *string, const int len, FTPoint position, int renderMode) { pen = FTPoint(0.0f, 0.0f); WrapText(string, len, position, renderMode, NULL); } void FTSimpleLayoutImpl::Render(const char *string, const int len, FTPoint position, int renderMode) { RenderI(string, len, position, renderMode); } void FTSimpleLayoutImpl::Render(const wchar_t* string, const int len, FTPoint position, int renderMode) { RenderI(string, len, position, renderMode); } template inline void FTSimpleLayoutImpl::WrapTextI(const T *buf, const int len, FTPoint position, int renderMode, FTBBox *bounds) { FTUnicodeStringItr breakItr(buf); // points to the last break character FTUnicodeStringItr lineStart(buf); // points to the line start float nextStart = 0.0; // total width of the current line float breakWidth = 0.0; // width of the line up to the last word break float currentWidth = 0.0; // width of all characters on the current line float prevWidth; // width of all characters but the current glyph float wordLength = 0.0; // length of the block since the last break char int charCount = 0; // number of characters so far on the line int breakCharCount = 0; // number of characters before the breakItr float glyphWidth, advance; FTBBox glyphBounds; // Reset the pen position pen.Y(0); // If we have bounds mark them invalid if(bounds) { bounds->Invalidate(); } // Scan the input for all characters that need output FTUnicodeStringItr prevItr(buf); for (FTUnicodeStringItr itr(buf); *itr; prevItr = itr++, charCount++) { // Find the width of the current glyph glyphBounds = currentFont->BBox(itr.getBufferFromHere(), 1); glyphWidth = glyphBounds.Upper().Xf() - glyphBounds.Lower().Xf(); advance = currentFont->Advance(itr.getBufferFromHere(), 1); prevWidth = currentWidth; // Compute the width of all glyphs up to the end of buf[i] currentWidth = nextStart + glyphWidth; // Compute the position of the next glyph nextStart += advance; // See if the current character is a space, a break or a regular character if((currentWidth > lineLength) || (*itr == '\n')) { // A non whitespace character has exceeded the line length. Or a // newline character has forced a line break. Output the last // line and start a new line after the break character. // If we have not yet found a break, break on the last character if(breakItr == lineStart || (*itr == '\n')) { // Break on the previous character breakItr = prevItr; breakCharCount = charCount - 1; breakWidth = prevWidth; // None of the previous words will be carried to the next line wordLength = 0; // If the current character is a newline discard its advance if(*itr == '\n') advance = 0; } float remainingWidth = lineLength - breakWidth; // Render the current substring FTUnicodeStringItr breakChar = breakItr; // move past the break character and don't count it on the next line either ++breakChar; --charCount; // If the break character is a newline do not render it if(*breakChar == '\n') { ++breakChar; --charCount; } OutputWrapped(lineStart.getBufferFromHere(), breakCharCount, //breakItr.getBufferFromHere() - lineStart.getBufferFromHere(), position, renderMode, remainingWidth, bounds); // Store the start of the next line lineStart = breakChar; // TODO: Is Height() the right value here? pen -= FTPoint(0, currentFont->LineHeight() * lineSpacing); // The current width is the width since the last break nextStart = wordLength + advance; wordLength += advance; currentWidth = wordLength + advance; // Reset the safe break for the next line breakItr = lineStart; charCount -= breakCharCount; } else if(iswspace(*itr)) { // This is the last word break position wordLength = 0; breakItr = itr; breakCharCount = charCount; // Check to see if this is the first whitespace character in a run if(buf == itr.getBufferFromHere() || !iswspace(*prevItr)) { // Record the width of the start of the block breakWidth = currentWidth; } } else { wordLength += advance; } } float remainingWidth = lineLength - currentWidth; // Render any remaining text on the last line // Disable justification for the last row if(alignment == FTGL::ALIGN_JUSTIFY) { alignment = FTGL::ALIGN_LEFT; OutputWrapped(lineStart.getBufferFromHere(), -1, position, renderMode, remainingWidth, bounds); alignment = FTGL::ALIGN_JUSTIFY; } else { OutputWrapped(lineStart.getBufferFromHere(), -1, position, renderMode, remainingWidth, bounds); } } void FTSimpleLayoutImpl::WrapText(const char *buf, const int len, FTPoint position, int renderMode, FTBBox *bounds) { WrapTextI(buf, len, position, renderMode, bounds); } void FTSimpleLayoutImpl::WrapText(const wchar_t* buf, const int len, FTPoint position, int renderMode, FTBBox *bounds) { WrapTextI(buf, len, position, renderMode, bounds); } template inline void FTSimpleLayoutImpl::OutputWrappedI(const T *buf, const int len, FTPoint position, int renderMode, const float remaining, FTBBox *bounds) { float distributeWidth = 0.0; // Align the text according as specified by Alignment switch (alignment) { case FTGL::ALIGN_LEFT: pen.X(0); break; case FTGL::ALIGN_CENTER: pen.X(remaining / 2); break; case FTGL::ALIGN_RIGHT: pen.X(remaining); break; case FTGL::ALIGN_JUSTIFY: pen.X(0); distributeWidth = remaining; break; } // If we have bounds expand them by the line's bounds, otherwise render // the line. if(bounds) { FTBBox temp = currentFont->BBox(buf, len); // Add the extra space to the upper x dimension temp = FTBBox(temp.Lower() + pen, temp.Upper() + pen + FTPoint(distributeWidth, 0)); // See if this is the first area to be added to the bounds if(bounds->IsValid()) { *bounds |= temp; } else { *bounds = temp; } } else { RenderSpace(buf, len, position, renderMode, distributeWidth); } } void FTSimpleLayoutImpl::OutputWrapped(const char *buf, const int len, FTPoint position, int renderMode, const float remaining, FTBBox *bounds) { OutputWrappedI(buf, len, position, renderMode, remaining, bounds); } void FTSimpleLayoutImpl::OutputWrapped(const wchar_t *buf, const int len, FTPoint position, int renderMode, const float remaining, FTBBox *bounds) { OutputWrappedI(buf, len, position, renderMode, remaining, bounds); } template inline void FTSimpleLayoutImpl::RenderSpaceI(const T *string, const int len, FTPoint position, int renderMode, const float extraSpace) { float space = 0.0; // If there is space to distribute, count the number of spaces if(extraSpace > 0.0) { int numSpaces = 0; // Count the number of space blocks in the input FTUnicodeStringItr prevItr(string), itr(string); for(int i = 0; ((len < 0) && *itr) || ((len >= 0) && (i <= len)); ++i, prevItr = itr++) { // If this is the end of a space block, increment the counter if((i > 0) && !iswspace(*itr) && iswspace(*prevItr)) { numSpaces++; } } space = extraSpace/numSpaces; } // Output all characters of the string FTUnicodeStringItr prevItr(string), itr(string); for(int i = 0; ((len < 0) && *itr) || ((len >= 0) && (i <= len)); ++i, prevItr = itr++) { // If this is the end of a space block, distribute the extra space // inside it if((i > 0) && !iswspace(*itr) && iswspace(*prevItr)) { pen += FTPoint(space, 0); } pen = currentFont->Render(itr.getBufferFromHere(), 1, pen, FTPoint(), renderMode); } } void FTSimpleLayoutImpl::RenderSpace(const char *string, const int len, FTPoint position, int renderMode, const float extraSpace) { RenderSpaceI(string, len, position, renderMode, extraSpace); } void FTSimpleLayoutImpl::RenderSpace(const wchar_t *string, const int len, FTPoint position, int renderMode, const float extraSpace) { RenderSpaceI(string, len, position, renderMode, extraSpace); } rgl/src/ext/ftgl/FTLayout/FTLayoutImpl.h0000644000176200001440000000324114531466703017603 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTLayoutImpl__ #define __FTLayoutImpl__ #include "FTSize.h" #include "FTGlyphContainer.h" class FTLayoutImpl { friend class FTLayout; protected: FTLayoutImpl(); virtual ~FTLayoutImpl(); protected: /** * Current pen or cursor position; */ FTPoint pen; /** * Current error code. Zero means no error. */ FT_Error err; }; #endif // __FTLayoutImpl__ rgl/src/ext/ftgl/FTLayout/FTLayout.cpp0000644000176200001440000000325514531466703017321 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTGL/ftgl.h" #include "../FTFont/FTFontImpl.h" #include "./FTLayoutImpl.h" // // FTLayout // FTLayout::FTLayout() { impl = new FTLayoutImpl(); } FTLayout::FTLayout(FTLayoutImpl *pImpl) { impl = pImpl; } FTLayout::~FTLayout() { delete impl; } FT_Error FTLayout::Error() const { return impl->err; } // // FTLayoutImpl // FTLayoutImpl::FTLayoutImpl() : err(0) { ; } FTLayoutImpl::~FTLayoutImpl() { ; } rgl/src/ext/ftgl/FTLayout/FTSimpleLayoutImpl.h0000644000176200001440000002311314531466703020755 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTSimpleLayoutImpl__ #define __FTSimpleLayoutImpl__ #include "FTLayoutImpl.h" class FTFont; class FTSimpleLayoutImpl : public FTLayoutImpl { friend class FTSimpleLayout; protected: FTSimpleLayoutImpl(); virtual ~FTSimpleLayoutImpl() {}; virtual FTBBox BBox(const char* string, const int len, FTPoint position); virtual FTBBox BBox(const wchar_t* string, const int len, FTPoint position); virtual void Render(const char *string, const int len, FTPoint position, int renderMode); virtual void Render(const wchar_t *string, const int len, FTPoint position, int renderMode); /** * Render a string of characters and distribute extra space amongst * the whitespace regions of the string. * * @param string A buffer of wchar_t characters to output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered. * @param position TODO * @param renderMode Render mode to display * @param extraSpace The amount of extra space to distribute amongst * the characters. */ virtual void RenderSpace(const char *string, const int len, FTPoint position, int renderMode, const float extraSpace); /** * Render a string of characters and distribute extra space amongst * the whitespace regions of the string. * * @param string A buffer of wchar_t characters to output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered. * @param position TODO * @param renderMode Render mode to display * @param extraSpace The amount of extra space to distribute amongst * the characters. */ virtual void RenderSpace(const wchar_t *string, const int len, FTPoint position, int renderMode, const float extraSpace); private: /** * Either render a string of characters and wrap lines * longer than a threshold or compute the bounds * of a string of characters when wrapped. The functionality * of this method is exposed by the BBoxWrapped and * RenderWrapped methods. * * @param buf A char string to output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered. * @param position TODO * @param renderMode Render mode to display * @param bounds A pointer to a bounds object. If non null * the bounds of the text when laid out * will be stored in bounds. If null the * text will be rendered. */ virtual void WrapText(const char *buf, const int len, FTPoint position, int renderMode, FTBBox *bounds); /** * Either render a string of characters and wrap lines * longer than a threshold or compute the bounds * of a string of characters when wrapped. The functionality * of this method is exposed by the BBoxWrapped and * RenderWrapped methods. * * @param buf A wchar_t style string to output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered. * @param position TODO * @param renderMode Render mode to display * @param bounds A pointer to a bounds object. If non null * the bounds of the text when laid out * will be stored in bounds. If null the * text will be rendered. */ virtual void WrapText(const wchar_t *buf, const int len, FTPoint position, int renderMode, FTBBox *bounds); /** * A helper method used by WrapText to either output the text or * compute it's bounds. * * @param buf A pointer to an array of character data. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered. * @param position TODO * @param renderMode Render mode to display * @param RemainingWidth The amount of extra space left on the line. * @param bounds A pointer to a bounds object. If non null the * bounds will be initialized or expanded by the * bounds of the line. If null the text will be * rendered. If the bounds are invalid (lower > upper) * they will be initialized. Otherwise they * will be expanded. */ void OutputWrapped(const char *buf, const int len, FTPoint position, int renderMode, const float RemainingWidth, FTBBox *bounds); /** * A helper method used by WrapText to either output the text or * compute it's bounds. * * @param buf A pointer to an array of character data. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered. * @param position TODO * @param renderMode Render mode to display * @param RemainingWidth The amount of extra space left on the line. * @param bounds A pointer to a bounds object. If non null the * bounds will be initialized or expanded by the * bounds of the line. If null the text will be * rendered. If the bounds are invalid (lower > upper) * they will be initialized. Otherwise they * will be expanded. */ void OutputWrapped(const wchar_t *buf, const int len, FTPoint position, int renderMode, const float RemainingWidth, FTBBox *bounds); /** * The font to use for rendering the text. The font is * referenced by this but will not be disposed of when this * is deleted. */ FTFont *currentFont; /** * The maximum line length for formatting text. */ float lineLength; /** * The text alignment mode used to distribute * space within a line or rendered text. */ FTGL::TextAlignment alignment; /** * The height of each line of text expressed as * a percentage of the font's line height. */ float lineSpacing; /* Internal generic BBox() implementation */ template inline FTBBox BBoxI(const T* string, const int len, FTPoint position); /* Internal generic Render() implementation */ template inline void RenderI(const T* string, const int len, FTPoint position, int renderMode); /* Internal generic RenderSpace() implementation */ template inline void RenderSpaceI(const T* string, const int len, FTPoint position, int renderMode, const float extraSpace); /* Internal generic WrapText() implementation */ template void WrapTextI(const T* buf, const int len, FTPoint position, int renderMode, FTBBox *bounds); /* Internal generic OutputWrapped() implementation */ template void OutputWrappedI(const T* buf, const int len, FTPoint position, int renderMode, const float RemainingWidth, FTBBox *bounds); }; #endif // __FTSimpleLayoutImpl__ rgl/src/ext/ftgl/FTLibrary.cpp0000644000176200001440000000404414265301465015733 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "config.h" #include "FTLibrary.h" const FTLibrary& FTLibrary::Instance() { static FTLibrary ftlib; return ftlib; } FTLibrary::~FTLibrary() { if(library != 0) { FT_Done_FreeType(*library); delete library; library= 0; } // if(manager != 0) // { // FTC_Manager_Done(manager); // // delete manager; // manager= 0; // } } FTLibrary::FTLibrary() : library(0), err(0) { Initialise(); } bool FTLibrary::Initialise() { if(library != 0) return true; library = new FT_Library; err = FT_Init_FreeType(library); if(err) { delete library; library = 0; return false; } // FTC_Manager* manager; // // if(FTC_Manager_New(lib, 0, 0, 0, my_face_requester, 0, manager) // { // delete manager; // manager= 0; // return false; // } return true; } rgl/src/ext/ftgl/FTLibrary.h0000644000176200001440000000750114265301465015401 0ustar liggesusers/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef __FTLibrary__ #define __FTLibrary__ #include #include FT_FREETYPE_H //#include FT_CACHE_H #include "FTGL/ftgl.h" /** * FTLibrary class is the global accessor for the Freetype library. * * This class encapsulates the Freetype Library. This is a singleton class * and ensures that only one FT_Library is in existence at any one time. * All constructors are private therefore clients cannot create or * instantiate this class themselves and must access it's methods via the * static FTLibrary::Instance() function. * * Just because this class returns a valid FTLibrary object * doesn't mean that the Freetype Library has been successfully initialised. * Clients should check for errors. You can initialse the library AND check * for errors using the following code... * err = FTLibrary::Instance().Error(); * * @see "Freetype 2 Documentation" * */ class FTLibrary { public: /** * Global acces point to the single FTLibrary object. * * @return The global FTLibrary object. */ static const FTLibrary& Instance(); /** * Gets a pointer to the native Freetype library. * * @return A handle to a FreeType library instance. */ const FT_Library* const GetLibrary() const { return library; } /** * Queries the library for errors. * * @return The current error code. */ FT_Error Error() const { return err; } /** * Destructor * * Disposes of the Freetype library */ ~FTLibrary(); private: /** * Default constructors. * * Made private to stop clients creating there own FTLibrary * objects. */ FTLibrary(); FTLibrary(const FT_Library&){} FTLibrary& operator=(const FT_Library&) { return *this; } /** * Initialises the Freetype library * * Even though this function indicates success via the return value, * clients can't see this so must check the error codes. This function * is only ever called by the default c_stor * * @return true if the Freetype library was * successfully initialised, false * otherwise. */ bool Initialise(); /** * Freetype library handle. */ FT_Library* library; // FTC_Manager* manager; /** * Current error code. Zero means no error. */ FT_Error err; }; #endif // __FTLibrary__ rgl/src/ext/ftgl/config.h0000644000176200001440000000055115011677075015011 0ustar liggesusers/* Removed at request of CRAN */ /* In rgl, we don't run the FTGL configure script, and we don't have RTTI. It appears as though the configure script is not needed for the subset we use (except we need config.h, hence this file), and we can use static_casts in place of dynamic_casts, hence the define below. #define dynamic_cast static_cast */ rgl/src/SpriteSet.cpp0000644000176200001440000002564715011677075014302 0ustar liggesusers #include "SpriteSet.h" #include "Shape.h" #include "R.h" #include using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // SpriteSet // SpriteSet::SpriteSet(Material& in_material, int in_nvertex, double* in_vertex, int in_nsize, double* in_size, int in_ignoreExtent, int count, Shape** in_shapelist, int nshapelens, int* in_shapelens, double* in_userMatrix, bool in_fixedSize, bool in_rotating, Scene *in_scene, double* in_adj, int in_npos, int *in_pos, double in_offset) : Shape(in_material, in_ignoreExtent, SHAPE, true), vertex(in_nvertex, in_vertex), size(in_nsize, in_size), pos(in_npos, in_pos), offset(static_cast(in_offset)), fixedSize(in_fixedSize), rotating(in_rotating), scene(in_scene) { if (!count) material.colorPerVertex(false); else { blended = false; for (int i=0;igetObjID()); blended |= in_shapelist[i]->isBlended(); } if (nshapelens) { int first = 0; for (int i=0;i < nshapelens;i++) { shapefirst.push_back(first); shapelens.push_back(in_shapelens[i]); first += in_shapelens[i]; } } else { shapefirst.push_back(0); shapelens.push_back(count); } for (int i=0;i<16;i++) userMatrix[i] = *(in_userMatrix++); } for(int i=0;i(size.getRecycled(i)/1.414) ); if (!in_adj) adj = Vec3(0.5, 0.5, 0.5); else adj = Vec3(static_cast(in_adj[0]), static_cast(in_adj[1]), static_cast(in_adj[2])); } SpriteSet::~SpriteSet() { shapes.clear(); } int SpriteSet::getElementCount(void) { return vertex.size(); } Vertex SpriteSet::getPrimitiveCenter(int index) { return vertex.get(index); } /* These routines are for debugging static void printMatrix(const char* msg, double* m) { Rprintf("%s:\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n", msg, m[0], m[4], m[8], m[12], m[1], m[5], m[9], m[13], m[2], m[6], m[10], m[14], m[3], m[7], m[11], m[15]); } static void printMatrix(const char* msg, Matrix4x4 m) { double data[16]; m.getData(data); printMatrix(msg, data); } static void printMVMatrix(const char* msg) { double m[16] = {0}; #ifndef RGL_NO_OPENGL glGetDoublev(GL_MODELVIEW_MATRIX, m); #endif printMatrix(msg, m); } static void printPRMatrix(const char* msg) { double m[16] = {0}; #ifndef RGL_NO_OPENGL glGetDoublev(GL_PROJECTION_MATRIX, m); #endif printMatrix(msg, m); } */ void SpriteSet::drawBegin(RenderContext* renderContext) { #ifndef RGL_NO_OPENGL Shape::drawBegin(renderContext); m = Matrix4x4(renderContext->subscene->modelMatrix); if (fixedSize && !rotating) { p = Matrix4x4(renderContext->subscene->projMatrix); renderContext->subscene->projMatrix.setIdentity(); glMatrixMode(GL_MODELVIEW); } if (!shapes.size()) { doTex = (material.texture) ? true : false; glNormal3f(0.0f,0.0f,1.0f); material.beginUse(renderContext); } #endif } void SpriteSet::drawPrimitive(RenderContext* renderContext, int index) { #ifndef RGL_NO_OPENGL Vertex o; BBoxDeco* bboxdeco = 0; if (material.marginCoord >= 0) { Subscene* subscene = renderContext->subscene; bboxdeco = subscene->get_bboxdeco(); } if (bboxdeco) o = bboxdeco->marginVecToDataVec(vertex.get(index), renderContext, &material); else o = vertex.get(index); float s = size.getRecycled(index); if (o.missing() || ISNAN(s)) return; Vec3 v3; /* We need to modify the variable rather than the GPU's * copy, because some objects refer to it */ Matrix4x4 *modelMatrix = &renderContext->subscene->modelMatrix; if (fixedSize) { Subscene* subscene = renderContext->subscene; float winwidth = (float) subscene->pviewport.width; float winheight = (float) subscene->pviewport.height; // The magic number 27 is chosen so that plotmath3d matches text3d. float scalex = 27.0f/winwidth, scaley = 27.0f/winheight; if (!rotating) { v3 = p * (m * o); *modelMatrix = Matrix4x4::translationMatrix(v3.x, v3.y, v3.z)* Matrix4x4::scaleMatrix(scalex, scaley, (scalex + scaley)/2.0f); } else { UserViewpoint* userviewpoint = subscene->getUserViewpoint(); /* FIXME: The magic value below is supposed to approximate the non-rotating size. */ float zoom = userviewpoint->getZoom(), scale = zoom * sqrt(scalex * scaley) * 4.0f; *modelMatrix = m * Matrix4x4::translationMatrix(o.x, o.y, o.z)* Matrix4x4::scaleMatrix(scale, scale, scale); } } else { s = s * 0.5f; if (!rotating) { v3 = m * o; *modelMatrix = Matrix4x4::translationMatrix(v3.x, v3.y, v3.z); } else *modelMatrix = m * Matrix4x4::translationMatrix(o.x, o.y, o.z); } if (pos.size()) getAdj(index); if (shapes.size()) { Shape::drawEnd(renderContext); // The shape will call drawBegin/drawEnd *modelMatrix = (*modelMatrix)* Matrix4x4::scaleMatrix(2*s,2*s,2*s)* Matrix4x4::translationMatrix((1.0 - 2.0*adj.x), (1.0 - 2.0*adj.y), (1.0 - 2.0*adj.z))* Matrix4x4(userMatrix); /* Since we modified modelMatrix, we need to reload it */ renderContext->subscene->loadMatrices(); int j = index % shapefirst.size(); int first = shapefirst.at(j); for (int i = 0; i < shapelens.at(j) ; ++ i ) scene->get_shape(shapes.at(first + i))->draw(renderContext); Shape::drawBegin(renderContext); } else { material.useColor(index); /* Since we modified modelMatrix, we need to reload it */ renderContext->subscene->loadMatrices(); glBegin(GL_QUADS); if (doTex) glTexCoord2f(0.0f,0.0f); glVertex3f(s*(0.0f - 2.0f*adj.x), s*(0.0f - 2.0f*adj.y), s*(1.0f - 2.0f*adj.z)); if (doTex) glTexCoord2f(1.0f,0.0f); glVertex3f(s*(2.0f - 2.0f*adj.x), s*(0.0f - 2.0f*adj.y), s*(1.0f - 2.0f*adj.z)); if (doTex) glTexCoord2f(1.0f,1.0f); glVertex3f(s*(2.0f - 2.0f*adj.x), s*(2.0f - 2.0f*adj.y), s*(1.0f - 2.0f*adj.z)); if (doTex) glTexCoord2f(0.0f,1.0f); glVertex3f(s*(0.0f - 2.0f*adj.x), s*(2.0f - 2.0f*adj.y), s*(1.0f - 2.0f*adj.z)); glEnd(); } #endif } void SpriteSet::getAdj(int index) { int p = pos.get(index); switch(p) { case 0: case 1: case 3: case 5: case 6: adj.x = 0.5; break; case 2: adj.x = 1.0 + offset; break; case 4: adj.x = -offset; break; } switch(p) { case 0: case 2: case 4: case 5: case 6: adj.y = 0.5; break; case 1: adj.y = 1.0 + offset; break; case 3: adj.y = -offset; break; } switch(p) { case 0: case 1: case 2: case 3: case 4: adj.z = 0.5; break; case 5: adj.z = -offset; break; case 6: adj.z = 1.0 + offset; break; } } void SpriteSet::drawEnd(RenderContext* renderContext) { #ifndef RGL_NO_OPENGL if (fixedSize) { renderContext->subscene->projMatrix = Matrix4x4(p); } renderContext->subscene->modelMatrix = Matrix4x4(m); /* Restore the original GPU matrices */ renderContext->subscene->loadMatrices(); if (!shapes.size()) material.endUse(renderContext); Shape::drawEnd(renderContext); #endif } void SpriteSet::render(RenderContext* renderContext) { draw(renderContext); } int SpriteSet::getAttributeCount(SceneNode* subscene, AttribID attrib) { switch (attrib) { case VERTICES: return vertex.size(); case RADII: return size.size(); case IDS: case SHAPENUM: case TYPES: return static_cast(shapes.size()); case USERMATRIX: { if (!shapes.size()) return 0; else return 4; } case FLAGS: return 3; case ADJ: return 1; case POS: return pos.size(); } return Shape::getAttributeCount(subscene, attrib); } void SpriteSet::getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result) { int n = getAttributeCount(subscene, attrib); int ind = 0, res = 0; if (first + count < n) n = first + count; if (first < n) { switch(attrib) { case VERTICES: while (first < n) { Vertex v = vertex.get(first); *result++ = v.x; *result++ = v.y; *result++ = v.z; first++; } return; case RADII: while (first < n) *result++ = size.get(first++); return; case IDS: for (std::vector::iterator i = shapes.begin(); i != shapes.end() ; ++ i ) { if ( first <= ind && ind < n ) *result++ = *i; ind++; } return; case SHAPENUM: ind = 1; for (unsigned int i = 0; i < shapelens.size(); i++) { res++; for (int j = 0; j < shapelens.at(i); j++, ind++) { if (first < ind && ind <= n) *result++ = res; } } return; case USERMATRIX: while (first < n) { *result++ = userMatrix[4*first]; *result++ = userMatrix[4*first+1]; *result++ = userMatrix[4*first+2]; *result++ = userMatrix[4*first+3]; first++; } return; case FLAGS: if (first < 1) *result++ = (double) ignoreExtent; if (first < 2 && n > 1) *result++ = (double) fixedSize; if (n > 2) *result++ = (double) rotating; return; case ADJ: if (pos.size() > 0) { *result++ = offset; *result++ = NA_REAL; *result++ = NA_REAL; } else { *result++ = adj.x; *result++ = adj.y; *result++ = adj.z; } return; case POS: while (first < n) *result++ = pos.get(first++); return; } Shape::getAttribute(subscene, attrib, first, count, result); } } std::string SpriteSet::getTextAttribute(SceneNode* subscene, AttribID attrib, int index) { int n = getAttributeCount(subscene, attrib); if (index < n && attrib == TYPES) { return scene->get_shape(shapes[index])->getTypeName(); } else return Shape::getTextAttribute(subscene, attrib, index); } Shape* SpriteSet::get_shape(int id) { return scene->get_shape(id); } void SpriteSet::remove_shape(int id) { shapes.erase(std::remove(shapes.begin(), shapes.end(), id), shapes.end()); } rgl/src/Disposable.cpp0000644000176200001440000000170214265301465014424 0ustar liggesusers#include "Disposable.h" #include #include #include "assert.h" using namespace rgl; void Disposable::addDisposeListener(IDisposeListener* l) { assert( std::find( disposeListeners.begin(), disposeListeners.end(), l ) == disposeListeners.end() ); disposeListeners.push_back(l); } void Disposable::removeDisposeListener(IDisposeListener* l) { Container::iterator pos = std::find( disposeListeners.begin(), disposeListeners.end(), l ); assert( pos != disposeListeners.end() ); disposeListeners.erase(pos); } void Disposable::fireNotifyDisposed() { // copy the listeners to a queue, // so add/remove are stable during 'notifyDispose'. std::vector queue( disposeListeners.begin(), disposeListeners.end() ); for ( std::vector::iterator i = queue.begin() ; i != queue.end() ; ++ i ) (*i)->notifyDisposed(this); } void Disposable::dispose() { fireNotifyDisposed(); } rgl/src/SceneNode.h0000644000176200001440000000365515011677075013663 0ustar liggesusers#ifndef SCENENODE_H #define SCENENODE_H // // ABSTRACT BASE CLASS // SceneNode // #include #include "types.h" #include "geom.h" namespace rgl { /* enum TypeID { SHAPE=1, LIGHT, BBOXDECO, USERVIEWPOINT, BACKGROUND, SUBSCENE, MODELVIEWPOINT }; */ #define SHAPE 1 #define LIGHT 2 #define BBOXDECO 3 #define USERVIEWPOINT 4 #define BACKGROUND 6 // 5 was used for the material #define SUBSCENE 7 #define MODELVIEWPOINT 8 #define MAX_TYPE 8 typedef unsigned int TypeID; typedef int ObjID; /* Possible attributes to request */ #define VERTICES 1 #define NORMALS 2 #define COLORS 3 #define TEXCOORDS 4 #define SURFACEDIM 5 #define TEXTS 6 #define CEX 7 #define ADJ 8 #define RADII 9 #define CENTERS 10 #define IDS 11 #define USERMATRIX 12 #define TYPES 13 #define FLAGS 14 #define OFFSETS 15 #define FAMILY 16 #define FONT 17 #define POS 18 #define FOGSCALE 19 #define AXES 20 #define INDICES 21 #define SHAPENUM 22 typedef unsigned int AttribID; class SceneNode { public: inline const TypeID getTypeID() const { return typeID; } inline const ObjID getObjID() const { return objID; } virtual ~SceneNode() { }; static ObjID nextID; SceneNode *owner; /* don't delete this node while the owner is non-NULL */ /* Some nodes depend on the bbox, so we pass it to all */ virtual int getAttributeCount(SceneNode* subscene, AttribID attrib) { return 0; } virtual void getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result) { return; } virtual std::string getTextAttribute(SceneNode* subscene, AttribID attrib, int index) { return ""; } virtual std::string getTypeName() = 0; protected: SceneNode(const TypeID in_typeID) : typeID(in_typeID) { objID = nextID++; owner = NULL; }; private: const TypeID typeID; ObjID objID; }; /** * used in find_if searches, so can't be a method */ bool sameID(SceneNode* node, int id); } // namespace rgl #endif // SCENENODE_H rgl/src/callbacks.cpp0000644000176200001440000001765515011677075014277 0ustar liggesusers#include "rglview.h" #include "DeviceManager.h" #include "api.h" using namespace rgl; namespace rgl { extern DeviceManager* deviceManager; } /* These defines are not in the installed version of R */ #include "R.h" #include static void userControl(void *userData, int mouseX, int mouseY) { SEXP fn = (SEXP)userData; if (fn) { // Rprintf("userControl called with mouseX=%d userData=%p\n", mouseX, userData); Rf_eval(PROTECT(Rf_lang3(fn, PROTECT(Rf_ScalarInteger(mouseX)), PROTECT(Rf_ScalarInteger(mouseY)))), R_GlobalEnv); UNPROTECT(3); } } static void userControlEnd(void *userData) { SEXP fn = (SEXP)userData; if (fn) { Rf_eval(PROTECT(Rf_lang1(fn)), R_GlobalEnv); UNPROTECT(1); } } static void userCleanup(void **userData) { for (int i=0; i<3; i++) { if (userData[i]) { R_ReleaseObject((SEXP)userData[i]); userData[i] = 0; } } } static void userWheel(void *wheelData, int dir) { SEXP fn = (SEXP)wheelData; Rf_eval(PROTECT(Rf_lang2(fn, PROTECT(Rf_ScalarInteger(dir)))), R_GlobalEnv); UNPROTECT(2); } SEXP rgl::rgl_setMouseCallbacks(SEXP button, SEXP begin, SEXP update, SEXP end, SEXP dev, SEXP sub) { Device* device; if (deviceManager && (device = deviceManager->getDevice(Rf_asInteger(dev)))) { RGLView* rglview = device->getRGLView(); void* userData[3] = {0, 0, 0}; userControlPtr beginCallback, updateCallback; userControlEndPtr endCallback; userCleanupPtr cleanupCallback; int b = Rf_asInteger(button); if (b < 0 || b > 4) Rf_error("button must be 1=left, 2=right, 3=middle, 4=wheel, or 0 for no button"); Scene* scene = rglview->getScene(); Subscene* subscene = scene->getSubscene(Rf_asInteger(sub)); if (!subscene) Rf_error("subscene not found"); subscene->getMouseCallbacks(b, &beginCallback, &updateCallback, &endCallback, &cleanupCallback, (void**)&userData); if (Rf_isFunction(begin)) { beginCallback = &userControl; userData[0] = (void*)begin; R_PreserveObject(begin); } else if (begin == R_NilValue) beginCallback = 0; else Rf_error("callback must be a function"); if (Rf_isFunction(update)) { updateCallback = &userControl; userData[1] = (void*)update; R_PreserveObject(update); } else if (update == R_NilValue) updateCallback = 0; else Rf_error("callback must be a function"); if (Rf_isFunction(end)) { endCallback = &userControlEnd; userData[2] = (void*)end; R_PreserveObject(end); } else if (end == R_NilValue) endCallback = 0; else Rf_error("callback must be a function"); rglview->captureLost(); // Rprintf("setting mouse callbacks\n"); subscene->setMouseCallbacks(b, beginCallback, updateCallback, endCallback, &userCleanup, userData); if (b == bnNOBUTTON) rglview->windowImpl->watchMouse(subscene->getRootSubscene()->mouseNeedsWatching()); } else Rf_error("rgl device is not open"); return R_NilValue; } SEXP rgl::rgl_getMouseCallbacks(SEXP button, SEXP dev, SEXP sub) { Device* device; if (deviceManager && (device = deviceManager->getDevice(Rf_asInteger(dev)))) { RGLView* rglview = device->getRGLView(); void* userData[3] = {0, 0, 0}; userControlPtr beginCallback, updateCallback; userControlEndPtr endCallback; userCleanupPtr cleanupCallback; int b = Rf_asInteger(button); if (b < 0 || b > 4) Rf_error("button must be 1=left, 2=right, 3=middle, 4=wheel, or 0 for no button"); Scene* scene = rglview->getScene(); Subscene* subscene = scene->getSubscene(Rf_asInteger(sub)); if (!subscene) Rf_error("subscene not found"); subscene->getMouseCallbacks(b, &beginCallback, &updateCallback, &endCallback, &cleanupCallback, (void**)&userData); SEXP result; PROTECT(result = Rf_allocVector(VECSXP, 3)); if (beginCallback == &userControl) SET_VECTOR_ELT(result, 0, (SEXP)userData[0]); if (updateCallback == &userControl) SET_VECTOR_ELT(result, 1, (SEXP)userData[1]); if (endCallback == &userControlEnd) SET_VECTOR_ELT(result, 2, (SEXP)userData[2]); UNPROTECT(1); return result; } else Rf_error("rgl device is not open"); return R_NilValue; } SEXP rgl::rgl_setWheelCallback(SEXP rotate, SEXP dev, SEXP sub) { Device* device; if (deviceManager && (device = deviceManager->getDevice(Rf_asInteger(dev)))) { RGLView* rglview = device->getRGLView(); void* wheelData = 0; userWheelPtr wheelCallback; if (Rf_isFunction(rotate)) { wheelCallback = &userWheel; wheelData = (void*)rotate; R_PreserveObject(rotate); } else if (rotate == R_NilValue) wheelCallback = 0; else Rf_error("callback must be a function"); Scene* scene = rglview->getScene(); Subscene* subscene = scene->getSubscene(Rf_asInteger(sub)); if (!subscene) Rf_error("subscene not found"); subscene->setWheelCallback(wheelCallback, wheelData); } else Rf_error("rgl device is not open"); return R_NilValue; } SEXP rgl::rgl_getWheelCallback(SEXP dev, SEXP sub) { Device* device; SEXP result = R_NilValue; if (deviceManager && (device = deviceManager->getDevice(Rf_asInteger(dev)))) { RGLView* rglview = device->getRGLView(); void* wheelData = 0; userWheelPtr wheelCallback; Scene* scene = rglview->getScene(); Subscene* subscene = scene->getSubscene(Rf_asInteger(sub)); if (!subscene) Rf_error("subscene not found"); subscene->getWheelCallback(&wheelCallback, (void**)&wheelData); if (wheelCallback == &userWheel) result = (SEXP)wheelData; } else Rf_error("rgl device is not open"); return result; } static void userAxis(void *axisData, int axis, int edge[3]) { SEXP fn = (SEXP)axisData; char margin[4] = " "; int i, j = 1; margin[0] = static_cast('x' + axis); for (i = 0; i < 3 && j < 3; i++) { if (edge[i] == 1) margin[j++] = '+'; else if (edge[i] == -1) margin[j++] = '-'; } margin[j] = 0; // Rprintf("margin=%s\n", margin); Rf_eval(PROTECT(Rf_lang2(fn, PROTECT(Rf_ScalarString(Rf_mkChar(margin))))), R_GlobalEnv); UNPROTECT(2); } SEXP rgl::rgl_setAxisCallback(SEXP draw, SEXP dev, SEXP sub, SEXP axis) { Device* device; if (deviceManager && (device = deviceManager->getDevice(Rf_asInteger(dev)))) { RGLView* rglview = device->getRGLView(); void* axisData = 0; userAxisPtr axisCallback; if (Rf_isFunction(draw)) { axisCallback = &userAxis; axisData = (void*)draw; R_PreserveObject(draw); } else if (draw == R_NilValue) axisCallback = 0; else Rf_error("callback must be a function"); Scene* scene = rglview->getScene(); Subscene* subscene = scene->getSubscene(Rf_asInteger(sub)); if (!subscene) Rf_error("subscene not found"); BBoxDeco* bboxdeco = subscene->get_bboxdeco(); if (!bboxdeco) Rf_error("no bbox decoration"); int a = Rf_asInteger(axis); if (a < 0 || a > 2) Rf_error("axis must be 0=x, 1=y, or 2=z"); bboxdeco->setAxisCallback(axisCallback, axisData, a); rglview->update(); } else Rf_error("rgl device is not open"); return R_NilValue; } SEXP rgl::rgl_getAxisCallback(SEXP dev, SEXP sub, SEXP axis) { Device* device; SEXP result = R_NilValue; if (deviceManager && (device = deviceManager->getDevice(Rf_asInteger(dev)))) { RGLView* rglview = device->getRGLView(); void* axisData = 0; userAxisPtr axisCallback; Scene* scene = rglview->getScene(); Subscene* subscene = scene->getSubscene(Rf_asInteger(sub)); if (!subscene) Rf_error("subscene not found"); BBoxDeco* bboxdeco = subscene->get_bboxdeco(); if (!bboxdeco) Rf_error("bboxdeco not found"); bboxdeco->getAxisCallback(&axisCallback, (void**)&axisData, Rf_asInteger(axis)); if (axisCallback == &userAxis) result = (SEXP)axisData; } else Rf_error("rgl device is not open"); return result; } rgl/src/ftgl.cpp0000644000176200001440000000060114265301465013270 0ustar liggesusers #ifdef HAVE_FREETYPE #include "FTBuffer.cpp" #include "FTCharmap.cpp" #include "FTFace.cpp" #include "FTFont/FTFont.cpp" #include "FTFont/FTBufferFont.cpp" #include "FTFont/FTPixmapFont.cpp" #include "FTGlyphContainer.cpp" #include "FTGlyph/FTGlyph.cpp" #include "FTGlyph/FTPixmapGlyph.cpp" #include "FTGlyph/FTBufferGlyph.cpp" #include "FTLibrary.cpp" #include "FTSize.cpp" #endif rgl/src/ABCLineSet.cpp0000644000176200001440000000624515026570325014216 0ustar liggesusers#include #include "ABCLineSet.h" #include "R.h" using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // PlaneSet // ABCLineSet::ABCLineSet(Material& in_material, int in_nbase, double* in_base, int in_ndir, double* in_dir) : LineSet(in_material,true, false/* true */), nLines(std::max(in_nbase, in_ndir)), base(in_nbase, in_base), direction(in_ndir, in_dir) { /* We'll set up 1 segment per line. Each segment has 2 vertices, and each vertex gets 3 color components and 1 alpha component. */ ARRAY colors(6*nLines); ARRAY alphas(2*nLines); if (material.colors.getLength() > 1) { material.colors.recycle(nLines); for (int i=0; i vertices(6*nLines); for (int i=0; isubscene); invalidateDisplaylist(); LineSet::renderBegin(renderContext); } void ABCLineSet::updateSegments(SceneNode* subscene) { AABox sceneBBox = ((Subscene*)subscene)->getBoundingBox(); double bbox[2][3] = { {sceneBBox.vmin.x, sceneBBox.vmin.y, sceneBBox.vmin.z}, {sceneBBox.vmax.x, sceneBBox.vmax.y, sceneBBox.vmax.z} }; double x[2][3]; for (int elem = 0; elem < nLines; elem++) { Vertex bv = base.getRecycled(elem); double b[3] = { bv.x, bv.y, bv.z }; Vertex dv = direction.getRecycled(elem); double d[3] = { dv.x, dv.y, dv.z }; // Rprintf("bbox min=%f %f %f max=%f %f %f\n", bbox[0][0], bbox[0][1], bbox[0][2], // bbox[1][0], bbox[1][1], bbox[1][2]); double smin = R_NegInf, smax = R_PosInf; for (int i=0; i<3; i++) { // which coordinate if (d[i] != 0) { double s[2]; for (int j=0; j<2; j++) // which limit s[j] = (bbox[j][i] - b[i])/d[i]; smin = std::max(smin, std::min(s[0], s[1])); smax = std::min(smax, std::max(s[0], s[1])); } } if (smin <= smax) { for (int k=0; k<3; k++) { x[0][k] = b[k] + smin*d[k]; x[1][k] = b[k] + smax*d[k]; } setVertex(2*elem + 0, x[0]); setVertex(2*elem + 1, x[1]); } else { double missing[3] = {NA_REAL, NA_REAL, NA_REAL}; setVertex(2*elem + 0, missing); setVertex(2*elem + 1, missing); } } } void ABCLineSet::getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result) { updateSegments(subscene); LineSet::getAttribute(subscene, attrib, first, count, result); } rgl/src/SphereMesh.cpp0000644000176200001440000000726414771520323014411 0ustar liggesusers#include "SphereMesh.h" #include "subscene.h" #include "opengl.h" #include using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // SphereMesh // SphereMesh::SphereMesh() : center( Vertex(0.0f,0.0f,0.0f) ), radius( 1.0f ), philow(-90.0f ), phihigh( 90.0f ), segments( 16 ), sections( 16 ), type( GLOBE ), genNormal(false), genTexCoord(false) { } void SphereMesh::setGlobe(int in_segments, int in_sections) { type = GLOBE; segments = in_segments; sections = in_sections; setupMesh(); } void SphereMesh::setTesselation(int level) { type = TESSELATION; } void SphereMesh::setupMesh() { // setup arrays nvertex = (sections+1) * (segments+1); vertexArray.alloc(nvertex); if (genNormal) normalArray.alloc(nvertex); if (genTexCoord) texCoordArray.alloc(nvertex); } void SphereMesh::setCenter(const Vertex& in_center) { center = in_center; } void SphereMesh::setRadius(float in_radius) { radius = in_radius; } void SphereMesh::update() { Vertex scale; scale.x = scale.y = scale.z = 1.0; update(scale); } void SphereMesh::update(const Vertex& scale) { int i = 0; for(int iy=0;iy<=sections;iy++) { Vertex p(0.0f,0.0f,radius); float fy = ((float)iy)/((float)sections); float phi = philow + fy * (phihigh - philow); p.rotateX( -phi ); for (int ix=0;ix<=segments;ix++,i++) { float fx = ((float)ix)/((float)segments); float theta = fx * 360.0f; Vertex q(p); q.rotateY( theta ); q.x /= scale.x; q.y /= scale.y; q.z /= scale.z; vertexArray[i] = center + q; if (genNormal) { q.x *= scale.x*scale.x; q.y *= scale.y*scale.y; q.z *= scale.z*scale.z; normalArray[i] = q; normalArray[i].normalize(); } if (genTexCoord) { texCoordArray[i].s = fx; texCoordArray[i].t = fy; } } } } void SphereMesh::draw(RenderContext* renderContext) { #ifndef RGL_NO_OPENGL vertexArray.beginUse(); if (genNormal) normalArray.beginUse(); if (genTexCoord) texCoordArray.beginUse(); for(int i=0; i #include "types.h" #include "subscene.h" namespace rgl { class Scene { public: Scene(); ~Scene(); // ---[ client services ]--------------------------------------------------- /** * remove all nodes of the given type. This is always recursive through subscenes. **/ bool clear(TypeID type); /** * add node to current subscene **/ bool add(SceneNode* node); /** * remove specified node of given type, or last-added if id==0 **/ bool pop(TypeID stackTypeID, int id); /** * hide specified node in all subscenes **/ void hide(int id); /** * get information about stacks */ int get_id_count(TypeID type); void get_ids(TypeID type, int* ids, char** types); /** * get a SceneNode by id */ SceneNode* get_scenenode(int id); SceneNode* get_scenenode(TypeID type, int id); /** * get information about particular shapes **/ Shape* get_shape(int id); /** * get information about particular lights **/ Light* get_light(int id); /** * get a background */ Background* get_background(int id); /** * get the bbox */ BBoxDeco* get_bboxdeco(int id); /** * get subscene */ Subscene* getSubscene(int id); /* get subscene by its id */ Subscene* whichSubscene(int id); /* get subscene holding this id */ Subscene* whichSubscene(int mouseX, int mouseY); /* get subscene by mouse coords */ /* coordinates are window-relative */ /** * set/get the current subscene **/ Subscene* setCurrentSubscene(Subscene* subscene); /* return previous one */ Subscene* getCurrentSubscene() const { return currentSubscene; } const Subscene* getRootSubscene() const { return &rootSubscene; } // ---[ grouping component ]----------------------------------------------- /** * obtain subscene's axis-aligned bounding box. **/ const AABox& getBoundingBox() const { return currentSubscene->getBoundingBox(); } // ---[ Renderable interface ]--------------------------------------------- /** * update matrices etc. */ void update(RenderContext* renderContext); /** * do OpenGL plotting */ void render(RenderContext* renderContext); // ---[ bindable component ]----------------------------------------------- /** * obtain bounded viewpoint **/ UserViewpoint* getUserViewpoint(); ModelViewpoint* getModelViewpoint(); /** * Get and set flag to ignore elements in bounding box **/ int getIgnoreExtent(void) const { return doIgnoreExtent; } void setIgnoreExtent(int in_ignoreExtent) { doIgnoreExtent = in_ignoreExtent; } /** * invalidate display lists so objects will be rendered again **/ void invalidateDisplaylists(); Subscene rootSubscene; private: // Whether objects created in this scene should affect the bounding box or not bool doIgnoreExtent; void setupLightModel(); // --- [ Subscenes ]------------------------------------------------------- Subscene* currentSubscene; // ---[ nodes ]----------------------------------------------------------- /** * list of scene nodes. The scene owns them, the subscenes display a subset. **/ std::vector nodes; void deleteAll(std::vector list); void removeReferences(SceneNode* node); }; } // namespace rgl #endif /* SCENE_H */ rgl/src/PointSet.cpp0000644000176200001440000000102414771520323014077 0ustar liggesusers#include "PrimitiveSet.h" using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // PointSet // PointSet::PointSet(Material& in_material, int in_nvertices, double* in_vertices, bool in_ignoreExtent, int in_nindices, int* in_indices, bool in_bboxChange) : PrimitiveSet(in_material, in_nvertices, in_vertices, GL_POINTS, 1, in_ignoreExtent, in_nindices, in_indices) { material.lit = false; if (material.point_antialias) blended = true; } rgl/src/TextSet.cpp0000644000176200001440000001063215011677075013744 0ustar liggesusers#include "TextSet.h" #include "glgui.h" #include "R.h" #include "BBoxDeco.h" #include "subscene.h" #ifdef HAVE_FREETYPE #include #endif using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // TextSet // // INTERNAL TEXTS STORAGE // texts are copied to a buffer without null byte // a separate length buffer holds string lengths in order // TextSet::TextSet(Material& in_material, int in_ntexts, char** in_texts, double *in_center, double in_adjx, double in_adjy, double in_adjz, int in_ignoreExtent, FontArray& in_fonts, int in_npos, const int* in_pos) : Shape(in_material, in_ignoreExtent), npos(in_npos) { int i; material.lit = false; material.colorPerVertex(false); adjx = in_adjx; adjy = in_adjy; adjz = in_adjz; // init vertex array vertexArray.alloc(in_ntexts); for (i = 0; i < in_ntexts; i++) { textArray.push_back(in_texts[i]); } fonts = in_fonts; #ifdef HAVE_FREETYPE blended = true; #endif for (i=0;ivalid(textArray[i].c_str())) Rf_error("text %d contains unsupported character", i+1); } pos = new int[npos]; for (i=0; i= 0) { Subscene* subscene = renderContext->subscene; bboxdeco = subscene->get_bboxdeco(); } GLFont* font; Vertex pt = vertexArray[index]; if (bboxdeco) pt = bboxdeco->marginVecToDataVec(pt, renderContext, &material); if (!pt.missing()) { GLboolean valid; material.useColor(index); glRasterPos3f( pt.x, pt.y, pt.z ); glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid); if (valid) { font = fonts[index % fonts.size()]; if (font) { std::string text = textArray[index]; font->draw( text.c_str(), static_cast(text.size()), adjx, adjy, adjz, pos[index % npos], *renderContext ); } } } #endif } void TextSet::drawEnd(RenderContext* renderContext) { #ifndef RGL_NO_OPENGL material.endUse(renderContext); Shape::drawEnd(renderContext); #endif } int TextSet::getAttributeCount(SceneNode* subscene, AttribID attrib) { switch (attrib) { case FAMILY: case FONT: case CEX: return static_cast(fonts.size()); case TEXTS: case VERTICES: return static_cast(textArray.size()); case ADJ: return 1; case POS: return pos[0] ? npos : 0; } return Shape::getAttributeCount(subscene, attrib); } void TextSet::getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result) { int n = getAttributeCount(subscene, attrib); if (first + count < n) n = first + count; if (first < n) { switch(attrib) { case VERTICES: while (first < n) { *result++ = vertexArray[first].x; *result++ = vertexArray[first].y; *result++ = vertexArray[first].z; first++; } return; case CEX: while (first < n) *result++ = fonts[first++]->cex; return; case FONT: while (first < n) *result++ = fonts[first++]->style; return; case ADJ: *result++ = adjx; *result++ = adjy; *result++ = adjz; return; case POS: while (first < n) *result++ = pos[first++]; return; } Shape::getAttribute(subscene, attrib, first, count, result); } } std::string TextSet::getTextAttribute(SceneNode* subscene, AttribID attrib, int index) { int n = getAttributeCount(subscene, attrib); if (index < n) { switch (attrib) { case TEXTS: return textArray[index]; case FAMILY: char* family = fonts[index]->family; return family; } } return Shape::getTextAttribute(subscene, attrib, index); } rgl/src/Viewpoint.cpp0000644000176200001440000001450714771520323014330 0ustar liggesusers#include "Viewpoint.h" #include "subscene.h" #include "opengl.h" #include "R.h" using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // UserViewpoint -- the viewer's portion of the viewpoint // ModelViewpoint -- the model's portion // // These were previously just one Viewpoint class, but subscenes mean they need to be split // UserViewpoint::UserViewpoint(float in_fov, float in_zoom) : SceneNode(USERVIEWPOINT), fov(in_fov), zoom(in_zoom), viewerInScene(false) { clearUserProjection(); } ModelViewpoint::ModelViewpoint(PolarCoord in_position, Vec3 in_scale, bool in_interactive) : SceneNode(MODELVIEWPOINT), interactive(in_interactive) { scale = in_scale; scaleChanged = true; setPosition(in_position); clearMouseMatrix(); } PolarCoord& ModelViewpoint::getPosition() { return position; } ModelViewpoint::ModelViewpoint(double* in_userMatrix, Vec3 in_scale, bool in_interactive) : SceneNode(MODELVIEWPOINT), position( PolarCoord(0.0f, 0.0f) ), interactive(in_interactive) { for (int i=0; i<16; i++) { userMatrix[i] = in_userMatrix[i]; } scale = in_scale; scaleChanged = true; clearMouseMatrix(); } void ModelViewpoint::setPosition(const PolarCoord& in_position) { Matrix4x4 M,N; M.setRotate(0, in_position.phi); N.setRotate(1, -in_position.theta); M = M * N; M.getData((double*)userMatrix); position = in_position; } void ModelViewpoint::clearMouseMatrix() { Matrix4x4 M; M.setIdentity(); M.getData((double*)mouseMatrix); } void UserViewpoint::clearUserProjection() { userProjection.setIdentity(); } void UserViewpoint::getUserProjection(double* dest) { userProjection.transpose(); userProjection.getData(dest); userProjection.transpose(); } void UserViewpoint::setUserProjection(double* src) { userProjection.loadData(src); userProjection.transpose(); } float UserViewpoint::getZoom() const { return zoom; } void UserViewpoint::setZoom(const float in_zoom) { zoom = in_zoom; } bool ModelViewpoint::isInteractive() const { return interactive; } void UserViewpoint::setFOV(const float in_fov) { fov = clamp(in_fov, 0.0, 179.0 ); } float UserViewpoint::getFOV() const { return fov; } void UserViewpoint::setupFrustum(RenderContext* rctx, const Sphere& viewSphere) { frustum.enclose(viewSphere.radius, fov, rctx->subscene->pviewport.width, rctx->subscene->pviewport.height); if (!viewerInScene) { eye.x = 0.; eye.y = 0.; eye.z = frustum.distance; } else { float oldnear = frustum.znear; frustum.znear -= -eye.z + frustum.distance; frustum.zfar -= -eye.z + frustum.distance; if (frustum.zfar < 0) frustum.zfar = 1; if (frustum.znear < frustum.zfar/100.f) // we lose log2(100) bits of depth resolution frustum.znear = frustum.zfar/100.f; float ratio = frustum.znear/oldnear; frustum.left = frustum.left*ratio + eye.x; frustum.right = frustum.right*ratio + eye.x; frustum.top = frustum.top*ratio + eye.y; frustum.bottom = frustum.bottom*ratio + eye.y; } // zoom frustum.left *= zoom; frustum.right *= zoom; frustum.bottom *= zoom; frustum.top *= zoom; } void UserViewpoint::setupProjMatrix(RenderContext* rctx, const Sphere& viewSphere) { setupFrustum(rctx, viewSphere); rctx->subscene->projMatrix.loadData(rctx->subscene->projMatrix*userProjection*frustum.getMatrix()); } Vertex UserViewpoint::getObserver() { return this->eye; } void UserViewpoint::setObserver(bool automatic, Vertex in_eye) { viewerInScene = !automatic; if (viewerInScene && !ISNAN(in_eye.x) &&!ISNAN(in_eye.y) && !ISNAN(in_eye.z)) this->eye = in_eye; } void UserViewpoint::setupViewer(RenderContext* rctx) { rctx->subscene->modelMatrix = rctx->subscene->modelMatrix * Matrix4x4::translationMatrix(-eye.x, -eye.y, -eye.z); } void ModelViewpoint::setupOrientation(RenderContext* rctx) const { rctx->subscene->modelMatrix = rctx->subscene->modelMatrix * mouseMatrix * userMatrix; } void ModelViewpoint::setupTransformation(RenderContext* rctx) { // modelview setupOrientation(rctx); rctx->subscene->modelMatrix = rctx->subscene->modelMatrix * Matrix4x4::scaleMatrix(scale.x, scale.y, scale.z); } void ModelViewpoint::updateMouseMatrix(Vec3 dragStart, Vec3 dragCurrent) { #ifndef RGL_NO_OPENGL Vec3 axis = dragStart.cross(dragCurrent); float angle = dragStart.angle(dragCurrent); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); if (axis.getLength() > 0) glRotatef((GLfloat)angle, (GLfloat)axis.x, (GLfloat)axis.y, (GLfloat)axis.z); glGetDoublev(GL_MODELVIEW_MATRIX,mouseMatrix); glPopMatrix(); #endif } void ModelViewpoint::updateMouseMatrix(PolarCoord newpos) { Matrix4x4 M,N; M.setRotate(0, newpos.phi); N.setRotate(1, -newpos.theta); M = M * N; M.getData((double*)mouseMatrix); } void ModelViewpoint::mouseOneAxis(Vertex dragStart,Vertex dragCurrent,Vertex axis) { #ifndef RGL_NO_OPENGL float angle = math::rad2deg(dragCurrent.x-dragStart.x); Matrix4x4 M((double *)userMatrix); Vec4 v = M * Vec4(axis.x, axis.y, axis.z); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glRotatef((GLfloat)angle, (GLfloat)v.x/v.w, (GLfloat)v.y/v.w, (GLfloat)v.z/v.w); glGetDoublev(GL_MODELVIEW_MATRIX,mouseMatrix); glPopMatrix(); #endif } void ModelViewpoint::mergeMouseMatrix() { Matrix4x4 M((double *)userMatrix), N((double *)mouseMatrix); M = N * M; M.getData((double *)userMatrix); N.setIdentity(); N.getData((double *)mouseMatrix); } void ModelViewpoint::getUserMatrix(double* dest) { for(int i=0; i<16;i++) dest[i] = userMatrix[i]; } void ModelViewpoint::setUserMatrix(double* src) { for(int i=0; i<16;i++) userMatrix[i] = src[i]; } void ModelViewpoint::getScale(double* dest) { dest[0] = scale.x; dest[1] = scale.y; dest[2] = scale.z; } void ModelViewpoint::setScale(double* src) { scale.x = static_cast(src[0]); scale.y = static_cast(src[1]); scale.z = static_cast(src[2]); scaleChanged = true; } void ModelViewpoint::getPosition(double* dest) { dest[0] = position.theta; dest[1] = position.phi; } void ModelViewpoint::setPosition(double* src) { position.theta = static_cast(src[0]); position.phi = static_cast(src[1]); } rgl/src/render.cpp0000644000176200001440000000704714771520323013624 0ustar liggesusers#include "render.h" #include "opengl.h" #include "R.h" using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // SECTION: MATERIAL // ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // // CLASS // VertexArray // VertexArray::VertexArray() { arrayptr = NULL; } VertexArray::~VertexArray() { if (arrayptr) delete[] arrayptr; } void VertexArray::alloc(int in_nvertex) { if (arrayptr) { delete[] arrayptr; arrayptr = NULL; } nvertex = in_nvertex; if (nvertex) arrayptr = new float [nvertex*3]; } void VertexArray::copy(int in_nvertex, double* vertices) { if (in_nvertex > nvertex) { Rf_warning("Only %d values copied", nvertex); in_nvertex = nvertex; } for(int i=0;i nvertex) { Rf_warning("Only %d values copied", nvertex); in_nvertex = nvertex; } for(int i=0;iopenDevice(*useNULL, *antialias) ); CHECKGLERROR; } // // FUNCTION // rgl::rgl_dev_close // void rgl::rgl_dev_close(int* successptr) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getCurrentDevice())) { device->close(); success = RGL_SUCCESS; CHECKGLERROR; } *successptr = success; } void rgl::rgl_dev_bringtotop(int* successptr, int* stay) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getCurrentDevice())) { device->bringToTop(*stay); success = RGL_SUCCESS; CHECKGLERROR; } *successptr = success; } // // FUNCTION // rgl::rgl_dev_getcurrent // // RETURNS // device id // SEXP rgl::rgl_dev_getcurrent(void) { SEXP result; if (deviceManager) { int id = deviceManager->getCurrent(); PROTECT(result = Rf_ScalarInteger(id)); if (id) { PROTECT(result = Rf_namesgets(result, Rf_ScalarString(Rf_mkChar(deviceManager->getDevice(id)->getDevtype())))); CHECKGLERROR; UNPROTECT(1); } UNPROTECT(1); return result; } return Rf_ScalarInteger(0); } // // FUNCTION // rgl::rgl_dev_list // // RETURNS // list of active device ids // SEXP rgl::rgl_dev_list(void) { SEXP result, names; if (deviceManager) { int n = deviceManager->getDeviceCount(); PROTECT(result = Rf_allocVector(INTSXP, n)); deviceManager->getDeviceIds(INTEGER(result), n); PROTECT(names = Rf_allocVector(STRSXP, n)); for (int i = 0; i < n; i++) { Device* device = deviceManager->getDevice(INTEGER(result)[i]); SET_STRING_ELT(names, i, Rf_mkChar(device->getDevtype())); } PROTECT(result = Rf_namesgets(result, names)); CHECKGLERROR; UNPROTECT(3); return result; } return Rf_allocVector(INTSXP, 0); } // // FUNCTION // rgl::rgl_dev_setcurrent // // PARAMETERS // idata // [0] device id // void rgl::rgl_dev_setcurrent(int* successptr, int* idata) { int id = idata[0]; bool silent = (bool) idata[1]; *successptr = as_success ( deviceManager && deviceManager->setCurrent(id, silent) ); CHECKGLERROR; } // // SCENE MANAGEMENT // static Material currentMaterial(Color(1.0f,1.0f,1.0f),Color(1.0f,0.0f,0.0f)); // // FUNCTION // rgl::rgl_clear ( successPtr, idata(type) ) // // PARAMETERS // idata // [0] count of types // [1], [2], ... TypeID 1, 2, ... // // void rgl::rgl_clear(int* successptr, int *idata) { int success = RGL_SUCCESS; Device* device; int num = idata[0]; if (deviceManager && (device = deviceManager->getAnyDevice())) { for (int i=1; success && i<=num; i++) { TypeID stackTypeID = (TypeID) idata[i]; success = as_success( device->clear( stackTypeID ) ); // viewpoint & material handled in R, background ignored } CHECKGLERROR; } *successptr = success; } // // FUNCTION // rgl::rgl_pop ( successPtr, idata ) // // PARAMETERS // idata // [0] stack TypeID // [1] id SceneNode identifier // // void rgl::rgl_pop(int* successptr, int* idata) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getCurrentDevice())) { TypeID stackTypeID = (TypeID) idata[0]; int id = idata[1]; success = as_success( device->pop( stackTypeID, id ) ); CHECKGLERROR; } *successptr = success; } // // FUNCTION // rgl::rgl_id_count // void rgl::rgl_id_count(int* type, int* count, int* subsceneID) { Device* device; *count = 0; if (deviceManager && (device = deviceManager->getCurrentDevice())) { RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); Subscene* subscene; if (!*subsceneID) { while (*type) { *count += scene->get_id_count((TypeID) *type); type++; } } else if ((subscene = scene->getSubscene(*subsceneID))) { while (*type) { *count += subscene->get_id_count((TypeID) *type, false); type++; } } CHECKGLERROR; } } // // FUNCTION // rgl::rgl_ids // void rgl::rgl_ids(int* type, int* ids, char** types, int* subsceneID) { Device* device; if (deviceManager && (device = deviceManager->getCurrentDevice())) { RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); Subscene* subscene; if (!*subsceneID) { while (*type) { int n = scene->get_id_count((TypeID) *type); if (n) { scene->get_ids((TypeID) *type, ids, types); ids += n; types += n; } type++; } } else if ((subscene = scene->getSubscene(*subsceneID))) { while (*type) { int n = subscene->get_id_count((TypeID) *type, false); subscene->get_ids((TypeID) *type, ids, types, false); ids += n; types += n; type++; } } CHECKGLERROR; } } // // FUNCTION // rgl::rgl_attrib_count // void rgl::rgl_attrib_count(int* id, int* attrib, int* count) { Device* device; if (deviceManager && (device = deviceManager->getCurrentDevice())) { RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); Subscene* subscene = scene->whichSubscene(*id); SceneNode* scenenode = scene->get_scenenode(*id); // getBoundingBox is called for the side effect of possibly calculating data_bbox. subscene->getBoundingBox(); if ( scenenode ) *count = scenenode->getAttributeCount(subscene, *attrib); else *count = 0; } } // // FUNCTION // rgl::rgl_attrib // void rgl::rgl_attrib(int* id, int* attrib, int* first, int* count, double* result) { Device* device; if (deviceManager && (device = deviceManager->getCurrentDevice())) { RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); Subscene* subscene = scene->whichSubscene(*id); SceneNode* scenenode = scene->get_scenenode(*id); if ( scenenode ) scenenode->getAttribute(subscene, *attrib, *first, *count, result); } } // // FUNCTION // rgl::rgl_text_attrib // void rgl::rgl_text_attrib(int* id, int* attrib, int* first, int* count, char** result) { Device* device; if (deviceManager && (device = deviceManager->getCurrentDevice())) { RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); Subscene* subscene = scene->whichSubscene(*id); SceneNode* scenenode = scene->get_scenenode(*id); if (scenenode) for (int i=0; i < *count; i++) { std::string s = scenenode->getTextAttribute(subscene, *attrib, i + *first); if (s.size()) { *result = R_alloc(s.size() + 1, 1); strncpy(*result, s.c_str(), s.size()); (*result)[s.size()] = '\0'; } result++; } } } // // FUNCTION // rgl::rgl_bg ( successPtr, idata ) // // PARAMETERS // idata // [0] bool environment sphere // [1] int fogtype // void rgl::rgl_bg(int* successptr, int* idata, double* fogScale) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { bool sphere = as_bool( idata[0] ); int fogtype = idata[1]; Background* bg = new Background(currentMaterial, sphere, fogtype, static_cast(fogScale[0])); success = as_success( device->add( bg ) ); SceneNode* quad = bg->getQuad(); if (quad) { int save_ignore = device->getIgnoreExtent(), save_redraw = device->getSkipRedraw(); device->setSkipRedraw(true); device->setIgnoreExtent(true); device->add( quad ); device->getScene()->hide(quad->getObjID()); device->setIgnoreExtent(save_ignore); device->setSkipRedraw(save_redraw); } CHECKGLERROR; } *successptr = success; } // // FUNCTION // rgl::rgl_light ( successPtr, idata, cdata, ddata ) // void rgl::rgl_light ( int* successptr, int* idata, double* ddata ) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { bool viewpoint_rel = as_bool( idata[0] ); bool finite_pos = as_bool( idata[10] ); Color ambient; Color diffuse; Color specular; ambient.set3iv ( &idata[1] ); diffuse.set3iv ( &idata[4] ); specular.set3iv( &idata[7] ); float theta = (float) ddata[0]; float phi = (float) ddata[1]; Vertex finposition = Vertex( static_cast(ddata[2]), static_cast(ddata[3]), static_cast(ddata[4]) ); success = as_success( device->add( new Light( PolarCoord(theta, phi), finposition, (bool) viewpoint_rel, (bool) finite_pos, ambient, diffuse, specular ) ) ); CHECKGLERROR; } *successptr = success; } void rgl::rgl_viewpoint(int* successptr, int* idata, double* ddata) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { float theta = static_cast( ddata[0] ); float phi = static_cast( ddata[1] ); float fov = static_cast( ddata[2] ); float zoom = static_cast( ddata[3] ); Vertex scale = Vertex( static_cast(ddata[4]), static_cast(ddata[5]), static_cast(ddata[6]) ); int interactive = idata[0]; int polar = idata[1]; int user = idata[2]; int model = idata[3]; if (model) { if (polar) success = as_success( device->add( new ModelViewpoint(PolarCoord(theta, phi), scale, interactive) ) ); else success = as_success( device->add( new ModelViewpoint(ddata + 7, scale, interactive) ) ); } else success = RGL_SUCCESS; if (user && success) success = as_success( device->add( new UserViewpoint(fov, zoom) ) ); CHECKGLERROR; } *successptr = success; } void rgl::rgl_getObserver(int* successptr, double* ddata) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); Subscene* subscene = scene->getCurrentSubscene(); getObserver(ddata, subscene); success = RGL_SUCCESS; } *successptr = success; } void rgl::rgl_setObserver(int* successptr, double* ddata) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); bool automatic = (bool)*successptr; Subscene* subscene = scene->getCurrentSubscene(); setObserver(automatic, ddata, rglview, subscene); } *successptr = success; } SEXP rgl::rgl_primitive(SEXP idata, SEXP vertex, SEXP normals, SEXP texcoords) { int success = RGL_FAIL, *idataptr = INTEGER(idata); double *vertexptr = REAL(vertex), *normalptr, *texcoordptr; Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { int type = idataptr[0]; int nvertex = idataptr[1]; int ignoreExtent = device->getIgnoreExtent() || currentMaterial.marginCoord >= 0; int useNormals = idataptr[2]; int useTexcoords = idataptr[3]; int nindices = idataptr[4]; int* indices = idataptr + 5; normalptr = useNormals ? REAL(normals) : NULL; texcoordptr = useTexcoords ? REAL(texcoords) : NULL; SceneNode* node; switch(type) { case 1: // RGL_POINTS: node = new PointSet( currentMaterial, nvertex, vertexptr, ignoreExtent, nindices, indices); break; case 2: // RGL_LINES: node = new LineSet( currentMaterial, nvertex, vertexptr, ignoreExtent, nindices, indices); break; case 3: // RGL_TRIANGLES: node = new TriangleSet( currentMaterial, nvertex, vertexptr, normalptr, texcoordptr, ignoreExtent, nindices, indices, useNormals, useTexcoords); break; case 4: // RGL_QUADS: node = new QuadSet( currentMaterial, nvertex, vertexptr, normalptr, texcoordptr, ignoreExtent, nindices, indices, useNormals, useTexcoords); break; case 5: // RGL_LINE_STRIP: node = new LineStripSet( currentMaterial, nvertex, vertexptr, ignoreExtent, nindices, indices); break; default: node = NULL; } if (node) { success = as_success( device->add( node ) ); if (!success) delete node; } CHECKGLERROR; } return Rf_ScalarInteger(success); } void rgl::rgl_surface(int* successptr, int* idata, double* x, double* z, double* y, double* normal_x, double* normal_z, double* normal_y, double* texture_s, double* texture_t, int* coords, int* orientation, int* flags) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { int nx = idata[0]; int nz = idata[1]; success = as_success( device->add( new Surface(currentMaterial, nx, nz, x, z, y, normal_x, normal_z, normal_y, texture_s, texture_t, coords, *orientation, flags, device->getIgnoreExtent() || currentMaterial.marginCoord >= 0) ) ); CHECKGLERROR; } *successptr = success; } void rgl::rgl_spheres(int* successptr, int* idata, double* vertex, double* radius, int* fastTransparency) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { int nvertex = idata[0]; int nradius = idata[1]; success = as_success( device->add( new SphereSet(currentMaterial, nvertex, vertex, nradius, radius, device->getIgnoreExtent() || currentMaterial.marginCoord >= 0, *fastTransparency != 0) ) ); CHECKGLERROR; } *successptr = success; } void rgl::rgl_planes(int* successptr, int* idata, double* normals, double* offsets) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { int nnormal = idata[0]; int noffset = idata[1]; success = as_success( device->add( new PlaneSet(currentMaterial, nnormal, normals, noffset, offsets) ) ); CHECKGLERROR; } *successptr = success; } void rgl::rgl_clipplanes(int* successptr, int* idata, double* normals, double* offsets) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { int nnormal = idata[0]; int noffset = idata[1]; success = as_success( device->add( new ClipPlaneSet(currentMaterial, nnormal, normals, noffset, offsets) ) ); CHECKGLERROR; } *successptr = success; } void rgl::rgl_abclines(int* successptr, int* idata, double* bases, double* directions) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { int nbases = idata[0]; int ndirs = idata[1]; success = as_success( device->add( new ABCLineSet(currentMaterial, nbases, bases, ndirs, directions) ) ); CHECKGLERROR; } *successptr = success; } void rgl::rgl_sprites(int* successptr, int* idata, double* vertex, double* radius, int* shapes, double* userMatrix, double* adj, int* pos, double* offset) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { int nvertex = idata[0]; int nradius = idata[1]; int nshapes = idata[2]; bool fixedSize = (bool)idata[3]; int npos = idata[4]; bool rotating = (bool)idata[5]; int nshapelens = idata[6]; int count = 0; Shape** shapelist; Scene* scene = NULL; int* shapelens = NULL; if (nshapes) { shapelist = (Shape**) R_alloc(nshapes, sizeof(Shape*)); RGLView* rglview = device->getRGLView(); scene = rglview->getScene(); while (nshapes) { int id = *(shapes++); nshapes--; Shape* shape = scene->get_shape(id); if (shape) { scene->hide(id); shapelist[count++] = shape; } else Rf_error("shape %d not found", id); } if (nshapelens) { shapelens = (int *)R_alloc(nshapelens, sizeof(int)); for (int i=0; i < nshapelens; i++) { shapelens[i] = idata[7 + i]; } } } else shapelist = NULL; success = as_success( device->add( new SpriteSet(currentMaterial, nvertex, vertex, nradius, radius, device->getIgnoreExtent() || currentMaterial.marginCoord >= 0, count, shapelist, nshapelens, shapelens, userMatrix, fixedSize, rotating, scene, adj, npos, pos, *offset) ) ); CHECKGLERROR; } *successptr = success; } void rgl::rgl_newsubscene(int* successptr, int* parentid, int* embedding, int* ignoreExtent) { int success = RGL_FAIL; Device* device; // Rprintf("rgl_newsubscene with %d %d %d %d\n", // embedding[0], embedding[1], embedding[2], embedding[3]); if (deviceManager && (device = deviceManager->getAnyDevice())) { RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); // Rprintf("getting parent %d\n", parentid[0]); Subscene* parent = scene->getSubscene(parentid[0]); if (parent) { Subscene* current = scene->getCurrentSubscene(); scene->setCurrentSubscene(parent); // Rprintf("Creating subscene\n"); Subscene* subscene = new Subscene( (Embedding)embedding[0], (Embedding)embedding[1], (Embedding)embedding[2], EMBED_REPLACE, *ignoreExtent != 0); if (subscene && scene->add(subscene)) { for (int i=0; i<5; i++) subscene->setMouseMode(i, parent->getMouseMode(i)); if (embedding[3] != EMBED_REPLACE) subscene->setEmbedding(3, (Embedding)embedding[3]); success = as_success( subscene->getObjID() ); } scene->setCurrentSubscene(current); } } *successptr = success; } void rgl::rgl_setsubscene(int* id) { Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); Subscene* subscene = scene->getSubscene(*id); if (subscene) { *id = scene->setCurrentSubscene(subscene)->getObjID(); } else *id = 0; } else *id = 0; } void rgl::rgl_getsubsceneid(int* id, int* dev) { Device* device; if (deviceManager && (device = deviceManager->getDevice(*dev))) { RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); const Subscene* subscene = (*id) == 1 ? scene->getCurrentSubscene() : scene->getRootSubscene(); *id = subscene->getObjID(); } else *id = 0; } void rgl::rgl_getsubsceneparent(int* id) { Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); Subscene* subscene = scene->getSubscene(*id); if (!subscene) { *id = NA_INTEGER; } else { subscene = subscene->getParent(); *id = subscene ? subscene->getObjID() : 0; } } else *id = NA_INTEGER; } void rgl::rgl_getsubscenechildcount(int* id, int* n) { Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); Subscene* subscene = scene->getSubscene(*id); *n = subscene ? static_cast(subscene->getChildCount()) : 0; } else *n = 0; } void rgl::rgl_getsubscenechildren(int* id, int* children) { Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); const Subscene* subscene = scene->getSubscene(*id); if (subscene) { for (size_t i = 0; i < subscene->getChildCount(); i++) { Subscene* child = subscene->getChild(static_cast(i)); children[i] = child ? child->getObjID() : 0; } } } } void rgl::rgl_addtosubscene(int* successptr, int* count, int* ids) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); Subscene* subscene = scene->getSubscene(*successptr); if (subscene) { for (int i=0; i < count[0]; i++) { SceneNode* node = scene->get_scenenode(ids[i]); if (node) { subscene->add(node); success = RGL_SUCCESS; } else Rf_warning("id %d not found in scene", ids[i]); } rglview->update(); } } *successptr = success; } void rgl::rgl_delfromsubscene(int* successptr, int* count, int* ids) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); Subscene* subscene = scene->getSubscene(*successptr); if (subscene) { for (int i=0; i < count[0]; i++) { SceneNode* node = scene->get_scenenode(ids[i]); if (node) switch (node->getTypeID()) { case SHAPE: subscene->hideShape( ids[i] ); success++; break; case LIGHT: subscene->hideLight( ids[i] ); success++; break; case BBOXDECO: subscene->hideBBoxDeco( ids[i] ); success++; break; case SUBSCENE: scene->setCurrentSubscene( subscene->hideSubscene( ids[i], scene->getCurrentSubscene() ) ); success++; break; case BACKGROUND: subscene->hideBackground( ids[i] ); success++; break; case USERVIEWPOINT: case MODELVIEWPOINT: subscene->hideViewpoint( ids[i] ); success++; break; default: Rf_warning("id %d is type %s; cannot hide", ids[i], node->getTypeName().c_str()); } else Rf_warning("id %d not found in scene", ids[i]); } rglview->update(); } } *successptr = success; } void rgl::rgl_gc(int* count, int* protect) { Device* device; int nprotect = *count; *count = 0; if (deviceManager && (device = deviceManager->getAnyDevice())) { RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); if (scene) { Subscene* root = (Subscene *)scene->getRootSubscene(); // need to discard const int rootid = root->getObjID(); for (TypeID i = 1; i < MAX_TYPE; i++) { int n = scene->get_id_count(i); if (n) { std::vector ids(n); std::vector types(n); scene->get_ids(i, &ids[0], &types[0]); // First, remove the protected ones by setting them to zero. bool anyunprot = false; for (int j = 0; j < n; j++) { bool prot = (rootid == ids[j]); for (int k = 0; k < nprotect && !prot; k++) prot = (ids[j] == protect[k]); if (prot) ids[j] = 0; else anyunprot = true; } if (!anyunprot) continue; // Now look for the others in subscenes int m = root->get_id_count(i, true); if (m) { std::vector ids2(m); std::vector types2(m); root->get_ids(i, &ids2[0], &types2[0], true); for (int j = 0; j < n; j++) { for (int k = 0; k < m && ids[j] != 0; k++) { if (ids[j] == ids2[k]) ids[j] = 0; } } } for (int j = 0; j < n; j++) { if (ids[j] != 0) { scene->pop(i, ids[j]); (*count)++; } } } } } } } void rgl::rgl_material(int *successptr, int* idata, char** cdata, double* ddata) { Material& mat = currentMaterial; int ncolor = idata[0]; mat.lit = (idata[1]) ? true : false; mat.smooth = (idata[2]) ? true : false; mat.front = (Material::PolygonMode) idata[3]; mat.back = (Material::PolygonMode) idata[4]; mat.fog = (idata[5]) ? true : false; mat.textype = (Texture::Type) idata[6]; mat.mipmap = (idata[7]) ? true : false; mat.minfilter = idata[8]; mat.magfilter = idata[9]; int nalpha = idata[10]; mat.ambient.set3iv( &idata[11] ); mat.specular.set3iv( &idata[14] ); mat.emission.set3iv( &idata[17] ); mat.envmap = (idata[20]) ? true : false; mat.point_antialias = (idata[21]) ? true : false; mat.line_antialias = (idata[22]) ? true : false; mat.depth_mask = (idata[23]) ? true : false; mat.depth_test = idata[24]; mat.marginCoord = idata[25]; mat.edge[0] = idata[26]; mat.edge[1] = idata[27]; mat.edge[2] = idata[28]; mat.floating = idata[29]; mat.blend[0] = idata[30]; mat.blend[1] = idata[31]; mat.texmode = (Texture::Mode) idata[32]; bool deleteFile = (idata[33]) ? true : false; int* colors = &idata[34]; char* pixmapfn = cdata[1]; mat.shininess = (float) ddata[0]; mat.size = (float) ddata[1]; mat.lwd = (float) ddata[2]; mat.polygon_offset_factor = (float) ddata[3]; mat.polygon_offset_units = (float) ddata[4]; mat.polygon_offset = ddata[3] != 0.0 || ddata[4] != 0.0; double* alpha = &ddata[5]; mat.alphablend = false; size_t len_tag = strlen(cdata[0]); if (len_tag) { char* in_tag = new char [len_tag + 1]; strncpy(in_tag, cdata[0], len_tag); in_tag[len_tag] = '\0'; mat.tag = std::string(in_tag); delete[] in_tag; } else mat.tag = std::string(); if ( strlen(pixmapfn) > 0 ) { mat.texture = new Texture(pixmapfn, mat.textype, mat.texmode, mat.mipmap, mat.minfilter, mat.magfilter, mat.envmap, deleteFile); if ( !mat.texture->isValid() ) { mat.texture->unref(); // delete mat.texture; mat.texture = NULL; } else mat.alphablend = mat.alphablend || mat.texture->hasAlpha(); } else mat.texture = NULL; mat.colors.set( ncolor, colors, nalpha, alpha); mat.alphablend = mat.alphablend || mat.colors.hasAlpha(); CHECKGLERROR; *successptr = RGL_SUCCESS; } void rgl::rgl_getcolorcount(int* count) { *count = currentMaterial.colors.getLength(); CHECKGLERROR; } void rgl::rgl_getmaterial(int *successptr, int *id, int* idata, char** cdata, double* ddata) { Material* mat = ¤tMaterial; unsigned int i,j; std::string filename; if (*id > 0) { Device* device; *successptr = RGL_FAIL; if (deviceManager && (device = deviceManager->getCurrentDevice())) { RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); Shape* shape = scene->get_shape(*id); if (shape) mat = shape->getMaterial(); /* success! successptr will be set below */ else { BBoxDeco* bboxdeco = scene->get_bboxdeco(*id); if (bboxdeco) mat = bboxdeco->getMaterial(); else { Background* background = scene->get_background(*id); if (background) mat = background->getMaterial(); else return; } } } else return; } idata[1] = mat->lit ? 1 : 0; idata[2] = mat->smooth ? 1 : 0; idata[3] = (int) mat->front; idata[4] = (int) mat->back; idata[5] = mat->fog ? 1 : 0; if (mat->texture) { mat->texture->getParameters( (Texture::Type*) (idata + 6), (Texture::Mode*) (idata + 33), (bool*) (idata + 7), (unsigned int*) (idata + 8), (unsigned int*) (idata + 9), &filename); } else { idata[6] = (int)mat->textype; idata[7] = mat->mipmap ? 1 : 0; idata[8] = mat->minfilter; idata[9] = mat->magfilter; } idata[11] = (int) mat->ambient.getRedub(); idata[12] = (int) mat->ambient.getGreenub(); idata[13] = (int) mat->ambient.getBlueub(); idata[14] = (int) mat->specular.getRedub(); idata[15] = (int) mat->specular.getGreenub(); idata[16] = (int) mat->specular.getBlueub(); idata[17] = (int) mat->emission.getRedub(); idata[18] = (int) mat->emission.getGreenub(); idata[19] = (int) mat->emission.getBlueub(); idata[20] = mat->envmap ? 1 : 0; idata[21] = mat->point_antialias ? 1 : 0; idata[22] = mat->line_antialias ? 1 : 0; idata[23] = mat->depth_mask ? 1 : 0; idata[24] = mat->depth_test; idata[25] = mat->isTransparent(); idata[26] = mat->marginCoord; idata[27] = mat->edge[0]; idata[28] = mat->edge[1]; idata[29] = mat->edge[2]; idata[30] = mat->floating; idata[31] = mat->blend[0]; idata[32] = mat->blend[1]; idata[33] = mat->texmode; for (i=0, j=34; (i < mat->colors.getLength()) && (i < (unsigned int)idata[0]); i++) { idata[j++] = (int) mat->colors.getColor(i).getRedub(); idata[j++] = (int) mat->colors.getColor(i).getGreenub(); idata[j++] = (int) mat->colors.getColor(i).getBlueub(); } idata[0] = i; ddata[0] = (double) mat->shininess; ddata[1] = (double) mat->size; ddata[2] = (double) mat->lwd; ddata[3] = (double) mat->polygon_offset_factor; ddata[4] = (double) mat->polygon_offset_units; if (mat->colors.hasAlpha()) { for (i=0, j=5; (i < mat->colors.getLength()) && (i < (unsigned int)idata[10]); i++) ddata[j++] = (double) mat->colors.getColor(i).getAlphaf(); idata[10] = i; } else idata[10] = 0; cdata[0] = copyStringToR(mat->tag); cdata[1] = copyStringToR(filename); CHECKGLERROR; *successptr = RGL_SUCCESS; } void rgl::rgl_texts(int* successptr, int* idata, double* adj, char** text, double* vertex, int* nfonts, char** family, int* style, double* cex, int* useFreeType, int* npos, int* pos) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { int ntext = idata[0]; FontArray fonts; device->getFonts(fonts, *nfonts, family, style, cex, (bool) *useFreeType); success = as_success( device->add( new TextSet(currentMaterial, ntext, text, vertex, adj[0], adj[1], adj[2], device->getIgnoreExtent() || currentMaterial.marginCoord >= 0, fonts, *npos, pos) ) ); CHECKGLERROR; } *successptr = success; } void rgl::rgl_bbox(int* successptr, int* idata, double* ddata, double* xat, char** xtext, double* yat, char** ytext, double* zat, char** ztext) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { int xticks = idata[0]; /* these are length of xat etc. */ int yticks = idata[1]; int zticks = idata[2]; int xlen = idata[3]; /* these are suggested tick counts */ int ylen = idata[4]; int zlen = idata[5]; int marklen_rel = idata[6]; int front = idata[7]; float xunit = (float) ddata[0]; float yunit = (float) ddata[1]; float zunit = (float) ddata[2]; float marklen = (float) ddata[3]; float expand = (float) ddata[4]; AxisInfo xaxis(xticks, xat, xtext, xlen, xunit); AxisInfo yaxis(yticks, yat, ytext, ylen, yunit); AxisInfo zaxis(zticks, zat, ztext, zlen, zunit); success = as_success( device->add( new BBoxDeco(currentMaterial, xaxis, yaxis, zaxis, marklen, (bool) marklen_rel, expand, (bool)front ) ) ); CHECKGLERROR; } *successptr = success; } void rgl::rgl_snapshot(int* successptr, int* idata, char** cdata) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getCurrentDevice())) { int format = idata[0]; char* filename = cdata[0]; success = as_success( device->snapshot( format, filename ) ); CHECKGLERROR; } *successptr = success; } void rgl::rgl_pixels(int* successptr, int* ll, int* size, int* component, double* result) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getCurrentDevice())) { success = as_success( device->pixels( ll, size, *component, result) ); CHECKGLERROR; } *successptr = success; } void rgl::rgl_selectstate(int* dev, int* sub, int* successptr, int* selectstate, double* locations) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getDevice(*dev))) { RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); Subscene* subscene = scene->getSubscene(*sub); selectstate[0] = (int)subscene->getSelectState(); double* mousePosition = subscene->getMousePosition(); locations[0] = *mousePosition; locations[1] = *(mousePosition+1); locations[2] = *(mousePosition+2); locations[3] = *(mousePosition+3); success = RGL_SUCCESS; CHECKGLERROR; } *successptr = success; } void rgl::rgl_setselectstate(int* dev, int* sub, int* successptr, int *idata) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getDevice(*dev))) { MouseSelectionID selectState = (MouseSelectionID) idata[0]; RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); Subscene* subscene = scene->getSubscene(*sub); subscene->setSelectState(selectState); success = RGL_SUCCESS; CHECKGLERROR; } *successptr = success; } void rgl::rgl_getEmbeddings(int* id, int* embeddings) { Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); Subscene* subscene = scene->getSubscene(*id); if (subscene) { embeddings[0] = subscene->getEmbedding(EM_VIEWPORT); embeddings[1] = subscene->getEmbedding(EM_PROJECTION); embeddings[2] = subscene->getEmbedding(EM_MODEL); embeddings[3] = subscene->getEmbedding(EM_MOUSEHANDLERS); } } } void rgl::rgl_setEmbeddings(int* id, int* embeddings) { Device* device; if (deviceManager && (device = deviceManager->getAnyDevice())) { RGLView* rglview = device->getRGLView(); Scene* scene = rglview->getScene(); Subscene* subscene = scene->getSubscene(*id); *id = RGL_FAIL; if (subscene) { if (!subscene->getParent() && // can't change the root (embeddings[0] != EMBED_REPLACE || embeddings[1] != EMBED_REPLACE || embeddings[2] != EMBED_REPLACE || embeddings[3] != EMBED_REPLACE)) return; subscene->setEmbedding(0, (Embedding)embeddings[0]); subscene->setEmbedding(1, (Embedding)embeddings[1]); subscene->setEmbedding(2, (Embedding)embeddings[2]); subscene->setEmbedding(3, (Embedding)embeddings[3]); rglview->update(); *id = RGL_SUCCESS; } } } void rgl::rgl_postscript(int* successptr, int* idata, char** cdata) { int success = RGL_FAIL; Device* device; if (deviceManager && (device = deviceManager->getCurrentDevice())) { int format = idata[0]; bool drawText = (bool)idata[1]; char* filename = cdata[0]; success = as_success( device->postscript( format, filename, drawText ) ); CHECKGLERROR; } *successptr = success; } void rgl::rgl_incrementID(int* n) { if (*n > 0) SceneNode::nextID += *n; *n = SceneNode::nextID; } rgl/src/Disposable.h0000644000176200001440000000237714265301465014102 0ustar liggesusers#ifndef RGL_DISPOSABLE_H #define RGL_DISPOSABLE_H #include namespace rgl { // forward declaration class Disposable; /** * Dispose Listener Interface. **/ struct IDisposeListener { virtual ~IDisposeListener() { } virtual void notifyDisposed(Disposable* disposing) = 0; }; /** * Disposable objects can be disposed autonomous while * they might be managed by a different Subject. * They allow for registering listeners that will be notified when * the object becomes disposed. **/ class Disposable { public: /** * register listener. It is not allowed to add the listener * if it is already registered. * * @arg l listener to be added to list **/ void addDisposeListener(IDisposeListener* l); /** * unregister listener. * @arg l listener to be removed **/ void removeDisposeListener(IDisposeListener* l); /** * dispose object. * Default implementatin will fire NotifyDisposed. **/ void dispose(); protected: /** * fires 'notifyDisposed' on all registered listeners. * It is save to call add/remove during 'notifyDisposed'. **/ void fireNotifyDisposed(); private: typedef std::vector Container; Container disposeListeners; }; } // namespace rgl #endif // RGL_DISPOSABLE_H rgl/src/x11gui.h0000644000176200001440000000314015011677075013123 0ustar liggesusers#ifndef X11_GUI_H #define X11_GUI_H // --------------------------------------------------------------------------- // C++ header file // This file is part of RGL // // --------------------------------------------------------------------------- #include #include #include #include "gui.h" namespace rgl { // --------------------------------------------------------------------------- class X11WindowImpl; enum { GUI_X11_ATOM_WM_DELETE = 0, GUI_X11_ATOM_LAST }; // --------------------------------------------------------------------------- class X11GUIFactory : public GUIFactory { public: X11GUIFactory (const char* displayname); virtual ~X11GUIFactory (); WindowImpl* createWindowImpl(Window* window, int antialias); inline bool isConnected() { return (xdisplay) ? true : false; } inline int getFD() { return ConnectionNumber(xdisplay); } void notifyDelete(::Window xwindowid); // implementation services: void processEvents(); void flushX(); // display specific: ::Display* xdisplay; ::Atom atoms[GUI_X11_ATOM_LAST]; // GLX specific int errorBase, eventBase; // Font specific XFontStruct* xfont; // Previous error handler XErrorHandler old_error_handler; void throw_error(const char* string); private: void connect(const char* displayname); void disconnect(); // administrative data: typedef std::map< XID , X11WindowImpl*> WindowMap; WindowMap windowMap; ::Window group_leader; }; // --------------------------------------------------------------------------- } // namespace rgl #endif // X11_GUI_H rgl/src/RenderContext.cpp0000644000176200001440000000026414265301465015125 0ustar liggesusers#include "RenderContext.h" #include using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // RenderContext // rgl/src/render.h0000644000176200001440000000230414771520323013260 0ustar liggesusers#ifndef RENDER_H #define RENDER_H #include "RenderContext.h" #include "types.h" namespace rgl { // // CLASS // VertexArray // /** * VertexArray **/ class VertexArray { public: VertexArray(); ~VertexArray(); void alloc(int in_nvertex); void copy(int in_nvertex, double* vertices); void copy(int in_nvertex, float* vertices); void duplicate(VertexArray source); void beginUse(); void endUse(); Vertex& operator[](int index); void setVertex(int index, double* v); void setVertex(int index, Vertex v); Vertex getNormal(int v1, int v2, int v3); int size() { return nvertex; } protected: int nvertex; float* arrayptr; }; inline Vertex& VertexArray::operator[](int index) { return (Vertex&) arrayptr[index*3]; } /** * NormalArray **/ class NormalArray : public VertexArray { public: void beginUse(); void endUse(); }; struct TexCoord { float s,t; }; /** * TexCoordArray **/ class TexCoordArray { public: TexCoordArray(); ~TexCoordArray(); void alloc(int in_nvertex); void beginUse(); void endUse(); TexCoord& operator[](int index); int size() { return nvertex; }; private: int nvertex; float* arrayptr; }; } // namespace rgl #endif // RENDER_H rgl/src/earcut.cpp0000644000176200001440000000315615011677075013632 0ustar liggesusers#include "R.h" #include #include #include "api.h" #include "earcut.h" // The number type to use for tessellation using Coord = double; // The index type. Defaults to uint32_t, but you can also pass uint16_t if you know that your // data won't have more than 65536 vertices. using N = uint32_t; // Create array using Point = std::array; SEXP rgl::rgl_earcut(SEXP x, SEXP y) { std::vector> polygon = {}; std::vector chain = {}; PROTECT(x = Rf_coerceVector(x, REALSXP)); PROTECT(y = Rf_coerceVector(y, REALSXP)); int n = Rf_length(x); if (n != Rf_length(y)) Rf_error("x and y must be the same length"); std::vector orig = {}; /* original index */ for (int i = 0; i < n; i++) { double xi = REAL(x)[i], yi = REAL(y)[i]; if (ISNAN(xi) || ISNAN(yi)) { if (chain.size() > 0) { /* Delete last point if it repeats the first one */ if (chain.front()[0] == chain.back()[0] && chain.front()[1] == chain.back()[1]) { chain.pop_back(); orig.pop_back(); Rf_warning("polygon vertices should not repeat"); } polygon.push_back(chain); chain.clear(); } } else { chain.push_back({xi, yi}); orig.push_back(i); } } if (chain.size() > 0) polygon.push_back(chain); std::vector indices = mapbox::earcut(polygon); SEXP value; PROTECT(value = Rf_allocVector(INTSXP, indices.size())); for (unsigned int i = 0; i < indices.size(); i++) INTEGER(value)[i] = orig[indices[i]]; UNPROTECT(3); return value; } rgl/src/platform.cpp0000644000176200001440000000612014555455305014167 0ustar liggesusers// C++ source // This file is part of RGL. // #include "platform.h" /* MacOSX */ #ifdef RGL_OSX #if __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_9 // pre-Mavericks code #else // Mavericks and later #include #include #include GLint gluUnProject(GLdouble winX, GLdouble winY, GLdouble winZ, const GLdouble * model, const GLdouble * proj, const GLint * view, GLdouble* objX, GLdouble* objY, GLdouble* objZ) { int glkview[] = {view[0], view[1], view[2], view[3]}; bool success; GLKVector3 result = GLKMathUnproject(GLKVector3Make(static_cast(winX), static_cast(winY), static_cast(winZ)), GLKMatrix4Make(static_cast(model[0]), static_cast(model[1]), static_cast(model[2]), static_cast(model[3]), static_cast(model[4]), static_cast(model[5]), static_cast(model[6]), static_cast(model[7]), static_cast(model[8]), static_cast(model[9]), static_cast(model[10]), static_cast(model[11]), static_cast(model[12]), static_cast(model[13]), static_cast(model[14]), static_cast(model[15])), GLKMatrix4Make(static_cast(proj[0]), static_cast(proj[1]), static_cast(proj[2]), static_cast(proj[3]), static_cast(proj[4]), static_cast(proj[5]), static_cast(proj[6]), static_cast(proj[7]), static_cast(proj[8]), static_cast(proj[9]), static_cast(proj[10]), static_cast(proj[11]), static_cast(proj[12]), static_cast(proj[13]), static_cast(proj[14]), static_cast(proj[15])), glkview, &success ); *objX = result.v[0]; *objY = result.v[1]; *objZ = result.v[2]; return success ? GLU_TRUE : GLU_FALSE; } const GLubyte * gluErrorString(GLenum error) { return (GLubyte*)"glu Error"; } #endif /* Mavericks */ #endif /* RGL_OSX */ rgl/src/fps.h0000644000176200001440000000055614555455305012607 0ustar liggesusers#ifndef RGL_FPS_H #define RGL_FPS_H // C++ header file // This file is part of RGL // #include "scene.h" namespace rgl { // // FPS COUNTER // class FPS { private: double lastTime; int framecnt; char buffer[12]; public: inline FPS() { }; void init(double t); void render(double t, RenderContext* ctx); }; } // namespace rgl #endif // RGL_FPS_H rgl/src/gui.cpp0000644000176200001440000002303315011677075013127 0ustar liggesusers// C++ source // This file is part of RGL. // // --------------------------------------------------------------------------- #include "gui.h" #include "lib.h" #include "R.h" using namespace rgl; // --------------------------------------------------------------------------- // WindowImpl common code // --------------------------------------------------------------------------- void WindowImpl::getFonts(FontArray& outfonts, int nfonts, char** family, int* style, double* cex, bool useFreeType) { GLFont* font; outfonts.resize(nfonts); for (int i = 0; i < nfonts; i++) { font = getFont(*(family++), *(style++), *(cex++), useFreeType); outfonts[i] = font; } } int WindowImpl::setSkipRedraw(int in_skipRedraw) { int result = 0; if (window) { result = window->getSkipRedraw(); window->setSkipRedraw(in_skipRedraw, 0); } return result; } // --------------------------------------------------------------------------- // View Implementation // --------------------------------------------------------------------------- View::View() : baseX(0) , baseY(0) , width(0) , height(0) , flags(0) , windowImpl(0) { } // --------------------------------------------------------------------------- View::View(int inBaseX, int inBaseY, int inWidth, int inHeight, int inFlags) : baseX(inBaseX) , baseY(inBaseY) , width(inWidth) , height(inHeight) , flags(inFlags) , windowImpl(0) { } // --------------------------------------------------------------------------- View::~View() { if ((windowImpl) && (flags & WINDOW_IMPL_OWNER)) { windowImpl->unbind(); windowImpl->destroy(); windowImpl = 0; } } // --------------------------------------------------------------------------- void View::setSize(int inWidth, int inHeight) { /* record the size in case the Impl doesn't do anything */ resize(inWidth, inHeight); if ((windowImpl) && (flags & WINDOW_IMPL_OWNER)) { int left, top, right, bottom; windowImpl->getWindowRect(&left, &top, &right, &bottom); windowImpl->setWindowRect(left, top, left+inWidth, top+inHeight); } } // --------------------------------------------------------------------------- void View::setLocation(int inBaseX, int inBaseY) { if ((windowImpl) && (flags & WINDOW_IMPL_OWNER)) { int left, top, right, bottom; windowImpl->getWindowRect(&left, &top, &right, &bottom); windowImpl->setWindowRect(inBaseX, inBaseY, inBaseX + left-right, inBaseY + bottom-top); } else relocate(inBaseX, inBaseY); } // --------------------------------------------------------------------------- void View::update(void) { if (windowImpl) windowImpl->update(); } // --------------------------------------------------------------------------- void View::setWindowImpl(WindowImpl* inWindowImpl) { windowImpl = inWindowImpl; } // --------------------------------------------------------------------------- void View::show(void) { } // --------------------------------------------------------------------------- void View::hide(void) { } // --------------------------------------------------------------------------- void View::paint(void) { } // --------------------------------------------------------------------------- void View::resize(int inWidth, int inHeight) { width = inWidth; height = inHeight; } // --------------------------------------------------------------------------- void View::relocate(int inBaseX, int inBaseY) { baseX = inBaseX; baseY = inBaseY; } // --------------------------------------------------------------------------- void View::keyPress(int code) { } // --------------------------------------------------------------------------- void View::keyRelease(int code) { } // --------------------------------------------------------------------------- void View::buttonPress(int button, int mouseX, int mouseY) { } // --------------------------------------------------------------------------- void View::buttonRelease(int button, int mouseX, int mouseY) { } // --------------------------------------------------------------------------- void View::mouseMove(int mouseX, int mouseY) { } // --------------------------------------------------------------------------- void View::wheelRotate(int direction, int mouseX, int mouseY) { } // --------------------------------------------------------------------------- void View::captureLost() { } // --------------------------------------------------------------------------- // Window Implementation // --------------------------------------------------------------------------- Window::Window(View* in_child, GUIFactory* factory, int antialias) : View(0,0,in_child->width, in_child->height,WINDOW_IMPL_OWNER) , child(in_child) , title("untitled") { skipRedraw = false; if (!factory){ return; } windowImpl = factory->createWindowImpl(this, antialias); if (!windowImpl) { return; } if (child) child->setWindowImpl(windowImpl); } // --------------------------------------------------------------------------- Window::~Window() { if (child) { delete child; } fireNotifyDisposed(); } // --------------------------------------------------------------------------- void Window::setWindowImpl(WindowImpl* impl) { View::setWindowImpl(impl); if (child) child->setWindowImpl(impl); } // --------------------------------------------------------------------------- void Window::setTitle(const char* in_title) { if (windowImpl) windowImpl->setTitle(in_title); } // --------------------------------------------------------------------------- void Window::update(void) { windowImpl->update(); } // --------------------------------------------------------------------------- void Window::setVisibility(bool state) { if (state) windowImpl->show(); else windowImpl->hide(); } // --------------------------------------------------------------------------- void Window::bringToTop(int stay) { windowImpl->bringToTop(stay); } // --------------------------------------------------------------------------- void Window::getWindowRect(int *in_left, int *in_top, int *in_width, int *in_height) { /* Set defaults in case the impl doesn't do anything */ *in_left = 0; *in_top = 0; *in_width = width; *in_height = height; windowImpl->getWindowRect(in_left, in_top, in_width, in_height); } // --------------------------------------------------------------------------- void Window::setWindowRect(int left, int top, int right, int bottom) { right = getMax(right, left + 1); bottom = getMax(bottom, top + 1); resize(right-left, bottom-top); // In case message never gets sent, e.g. Xvfb windowImpl->setWindowRect(left, top, right, bottom); } // --------------------------------------------------------------------------- int Window::getSkipRedraw(void) { return (int)skipRedraw; } // --------------------------------------------------------------------------- void Window::setSkipRedraw(int in_skipRedraw, int doUpdate) { skipRedraw = (bool)in_skipRedraw; if (!skipRedraw && doUpdate) update(); } // --------------------------------------------------------------------------- void Window::show(void) { if (child) child->show(); } // --------------------------------------------------------------------------- void Window::hide(void) { if (child) child->hide(); } // --------------------------------------------------------------------------- void Window::resize(int in_width, int in_height) { if (child) child->resize(in_width,in_height); } // --------------------------------------------------------------------------- void Window::paint(void) { if (child) child->paint(); } // --------------------------------------------------------------------------- void Window::notifyDestroy(void) { if (child) { delete child; child = NULL; } fireNotifyDisposed(); } // --------------------------------------------------------------------------- void Window::buttonPress(int button, int mouseX, int mouseY) { if (child) child->buttonPress(button, mouseX, mouseY); } // --------------------------------------------------------------------------- void Window::buttonRelease(int button, int mouseX, int mouseY) { if (child) child->buttonRelease(button, mouseX, mouseY); } // --------------------------------------------------------------------------- void Window::mouseMove(int mouseX, int mouseY) { if (child) child->mouseMove(mouseX, mouseY); } // --------------------------------------------------------------------------- void Window::keyPress(int code) { if (child) child->keyPress(code); } // --------------------------------------------------------------------------- void Window::wheelRotate(int dir, int mouseX, int mouseY) { if (child) child->wheelRotate(dir, mouseX, mouseY); } // --------------------------------------------------------------------------- void Window::on_close() { if (windowImpl) windowImpl->destroy(); } // --------------------------------------------------------------------------- void Window::getFonts(FontArray& outfonts, int nfonts, char** family, int* style, double* cex, bool useFreeType) { windowImpl->getFonts(outfonts, nfonts, family, style, cex, useFreeType); } // --------------------------------------------------------------------------- int WindowImpl::getAntialias() { #ifndef RGL_NO_OPENGL if (beginGL()) { int result; glGetIntegerv(GL_SAMPLES, &result); endGL(); CHECKGLERROR; return result; } #endif return 1; } int WindowImpl::getMaxClipPlanes() { #ifndef RGL_NO_OPENGL int result; glGetError(); glGetIntegerv(GL_MAX_CLIP_PLANES, &result); if (glGetError() == GL_NO_ERROR) return result; else #endif return 6; } rgl/src/device.cpp0000644000176200001440000001143615011677075013606 0ustar liggesusers// C++ source // This file is part of RGL. // // --------------------------------------------------------------------------- #include #include "Device.h" #include "lib.h" using namespace rgl; // --------------------------------------------------------------------------- Device::Device(int id, bool useNULL, int antialias) : id_(id) { scene = new Scene(); rglview = new RGLView(scene); window = new Window( rglview, getGUIFactory(useNULL), antialias ); if (window && !window->windowImpl) { delete window; window = NULL; } if (!window) { devtype = "none"; return; } devtype = GUIFactoryName(useNULL); window->addDisposeListener(this); } // --------------------------------------------------------------------------- Device::~Device() { delete scene; } // --------------------------------------------------------------------------- int Device::getID() { return id_; } // --------------------------------------------------------------------------- void Device::notifyDisposed(Disposable* disposable) { dispose(); } // --------------------------------------------------------------------------- void Device::setName(const char* string) { if (window) window->setTitle(string); } // --------------------------------------------------------------------------- void Device::update() { // window->update(); } // --------------------------------------------------------------------------- bool Device::open(void) { if (window) { window->setVisibility(true); return true; } else return false; } // --------------------------------------------------------------------------- void Device::close(void) { if (window) window->on_close(); } // --------------------------------------------------------------------------- void Device::bringToTop(int stay) { if (window) window->bringToTop(stay); } void Device::setWindowRect(int left, int top, int right, int bottom) { if (window) window->setWindowRect(left, top, right, bottom); } void Device::getWindowRect(int *left, int *top, int *right, int *bottom) { if (window) window->getWindowRect(left, top, right, bottom); } // --------------------------------------------------------------------------- int Device::getIgnoreExtent(void) { return scene->getIgnoreExtent(); } // --------------------------------------------------------------------------- void Device::setIgnoreExtent(int in_ignoreExtent) { scene->setIgnoreExtent(in_ignoreExtent); } // --------------------------------------------------------------------------- int Device::getSkipRedraw(void) { if (window) return window->getSkipRedraw(); else return 0; } // --------------------------------------------------------------------------- void Device::setSkipRedraw(int in_skipRedraw) { if (window) window->setSkipRedraw(in_skipRedraw); } // --------------------------------------------------------------------------- bool Device::clear(TypeID stackTypeID) { bool success; success = scene->clear(stackTypeID); rglview->update(); return success; } // --------------------------------------------------------------------------- int Device::add(SceneNode* node) { bool success; success = scene->add(node); rglview->update(); if (success) return node->getObjID(); else return 0; } // --------------------------------------------------------------------------- bool Device::pop(TypeID stackTypeID, int id) { bool success; bool inGL = rglview->windowImpl->beginGL(); // May need to set context for display lists. success = scene->pop(stackTypeID, id); if (inGL) { rglview->windowImpl->endGL(); } rglview->update(); return success; } // --------------------------------------------------------------------------- bool Device::snapshot(int format, const char* filename) { return rglview->snapshot( (PixmapFileFormatID) format, filename); } // --------------------------------------------------------------------------- bool Device::pixels(int* ll, int* size, int component, double* result) { return rglview->pixels( ll, size, component, result); } // --------------------------------------------------------------------------- RGLView* Device::getRGLView(void) { return rglview; } // --------------------------------------------------------------------------- bool Device::postscript(int format, const char* filename, bool drawText) { return rglview->postscript( format, filename, drawText); } // --------------------------------------------------------------------------- void Device::getFonts(FontArray& outfonts, int nfonts, char** family, int* style, double* cex, bool useFreeType) { if (window) window->getFonts(outfonts, nfonts, family, style, cex, useFreeType); } // --------------------------------------------------------------------------- const char * Device::getDevtype() { return devtype; } rgl/src/Color.h0000644000176200001440000000347114714647212013071 0ustar liggesusers#ifndef COLOR_H #define COLOR_H // // CLASS // Color // // IMPLEMENTATION // uses floats as the general format for single colors, clear colors, // lighting and material color properties // #include "types.h" namespace rgl { class Color { public: Color(); Color(float red, float green, float blue, float alpha=1.0f); Color(u8 red, u8 green, u8 blue, u8 alpha); Color(const char* string); float getRedf() const { return data[0]; } float getGreenf() const { return data[1]; } float getBluef() const { return data[2]; } float getAlphaf() const { return data[3]; } u8 getRedub() const { return (u8) (data[0]*255.0f); } u8 getGreenub()const { return (u8) (data[1]*255.0f); } u8 getBlueub() const { return (u8) (data[2]*255.0f); } u8 getAlphaub()const { return (u8) (data[3]*255.0f); } float* getFloatPtr() const { return (float*) data; } /// set by integer ptr void set3iv(int* color); void useClearColor() const; void useColor() const; float data[4]; }; // // CLASS // ColorArray // IMPLEMENTATION // uses unsigned bytes as internal format for mass color datas // carries alpha values // class ColorArray { public: ColorArray(); ColorArray( ColorArray& src ); ColorArray( Color& bg, Color& fg ); ~ColorArray(); // void set( int ncolor, RColor* rcolors, u8 alpha=255 ); void set( int ncolor, char** colors, int nalpha, double* alphas ); void set( int ncolor, int* colors, int nalpha, double* alphas ); void useColor( int index ) const; void useArray() const; unsigned int getLength() const; Color getColor( int index ) const; void recycle( unsigned int newsize ); bool hasAlpha() const; private: bool hint_alphablend; unsigned int ncolor; unsigned int nalpha; u8* arrayptr; friend class Material; }; } // namespace rgl #endif // COLOR_H rgl/src/win32gui.cpp0000644000176200001440000006122715011677075014021 0ustar liggesusers#include "config.h" #ifdef RGL_W32 // C++ source // This file is part of RGL. // #include "win32gui.h" #include "lib.h" #include "glgui.h" #include #include #include "assert.h" #include "R.h" #include #include namespace rgl { extern int gInitValue; extern HANDLE gHandle; extern SEXP rglNamespace; static WNDPROC gDefWindowProc; static HWND gMDIClientHandle = 0; static HWND gMDIFrameHandle = 0; // describe requirements static const PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd 1, // version number 0 | PFD_DRAW_TO_WINDOW // support window | PFD_SUPPORT_OPENGL // support OpenGL | PFD_GENERIC_FORMAT // generic format | PFD_DOUBLEBUFFER // double buffered , PFD_TYPE_RGBA, // RGBA type 16, // 16-bit color depth 0, 0, 0, 0, 0, 0, // color bits ignored 1, // alpha buffer 0, // shift bit ignored 0, // no accumulation buffer 0, 0, 0, 0, // accum bits ignored 16, // 16-bit z-buffer 0, // no stencil buffer 0, // no auxiliary buffer PFD_MAIN_PLANE, // main layer 0, // reserved 0, 0, 0 // layer masks ignored }; // --------------------------------------------------------------------------- // // translate keycode // // --------------------------------------------------------------------------- static int translate_key(int wParam) { if ( (wParam >= VK_F1) && (wParam <= VK_F12) ) { return ( GUI_KeyF1 + (wParam - VK_F1) ); } else { switch(wParam) { case VK_UP: return GUI_KeyUp; case VK_DOWN: return GUI_KeyDown; case VK_LEFT: return GUI_KeyLeft; case VK_RIGHT: return GUI_KeyRight; case VK_INSERT: return GUI_KeyInsert; case VK_ESCAPE: return GUI_KeyESC; default: return 0; } } } // --------------------------------------------------------------------------- class Win32WindowImpl : public WindowImpl { public: Win32WindowImpl(Window* in_window, int in_antialias); ~Win32WindowImpl(); void setTitle(const char* title); void setWindowRect(int left, int top, int right, int bottom); void getWindowRect(int *left, int *top, int *right, int *bottom); void show(); void hide(); int isTopmost(HWND handle); void bringToTop(int stay); void update(); void destroy(); void captureMouse(View* pView); void releaseMouse(); void watchMouse(bool withoutButton) {}; GLFont* getFont(const char* family, int style, double cex, bool useFreeType); private: LRESULT processMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); static bool registerClass(); static void unregisterClass(); static LRESULT CALLBACK delegateWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); static LRESULT CALLBACK windowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); static ATOM classAtom; HWND windowHandle; View* captureView; bool painting; // window is currently busy painting bool autoUpdate; // update/refresh automatically bool refreshMenu; // need to tell Windows to update the menu #if defined(WGL_ARB_pixel_format) && !defined(WGL_WGLEXT_PROTOTYPES) PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB; #endif friend class Win32GUIFactory; int antialias; public: bool beginGL(); void endGL(); void swap(); private: bool initGL(int antialias); void shutdownGL(); GLBitmapFont* initGLBitmapFont(u8 firstGlyph, u8 lastGlyph); HDC dcHandle; // temporary variable setup by lock HGLRC glrcHandle; }; } // namespace rgl using namespace rgl; // ---------------------------------------------------------------------------- // constructor // ---------------------------------------------------------------------------- Win32WindowImpl::Win32WindowImpl(Window* in_window, int in_antialias) : WindowImpl(in_window), antialias(in_antialias) { windowHandle = NULL; captureView = NULL; dcHandle = NULL; glrcHandle = NULL; painting = false; autoUpdate = false; refreshMenu = false; } Win32WindowImpl::~Win32WindowImpl() { beginGL(); for (unsigned int i=0; i < fonts.size(); i++) { delete fonts[i]; } endGL(); } void Win32WindowImpl::setTitle(const char* title) { SetWindowText(windowHandle, title); } void Win32WindowImpl::setWindowRect(int left, int top, int right, int bottom) { if (windowHandle) { RECT rect; rect.left = left; rect.top = top; rect.right = right; rect.bottom = bottom; // Specification gives the desired client coordinates; expand to include the frame AdjustWindowRectEx(&rect, GetWindowLong(windowHandle, GWL_STYLE), FALSE, GetWindowLong(windowHandle, GWL_EXSTYLE)); MoveWindow(windowHandle, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top, TRUE); } } void Win32WindowImpl::getWindowRect(int *left, int *top, int *right, int *bottom) { if (windowHandle) { RECT rect; GetClientRect(windowHandle, &rect); ClientToScreen(windowHandle, (LPPOINT)&rect.left); ClientToScreen(windowHandle, (LPPOINT)&rect.right); // Rect is now in screen coordinates; convert to parent client area coordinates // for MDI HWND parent = GetParent(windowHandle); if (parent) { ScreenToClient(parent, (LPPOINT)&rect.left); ScreenToClient(parent, (LPPOINT)&rect.right); } *left = rect.left; *top = rect.top; *right = rect.right; *bottom = rect.bottom; } } void Win32WindowImpl::show() { if (windowHandle) { // ShowWindow is required in SDI to show the window once // (otherwise to update takes place) ShowWindow(windowHandle, SW_SHOW); SetWindowPos( windowHandle ,HWND_TOP ,0,0,0,0 ,SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOACTIVATE|SWP_NOSIZE ); update(); } else printMessage("window not bound"); } void Win32WindowImpl::hide() { if (windowHandle) { ShowWindow(windowHandle, SW_HIDE); } } int Win32WindowImpl::isTopmost(HWND handle) { return GetWindowLong(handle, GWL_EXSTYLE) & WS_EX_TOPMOST; } void Win32WindowImpl::bringToTop(int stay) /* stay=0 for regular, 1 for topmost, 2 for toggle */ { if (windowHandle) { SetForegroundWindow(windowHandle); /* needed in Rterm */ BringWindowToTop(windowHandle); /* needed in Rgui --mdi */ if (stay == 2) stay = !isTopmost(windowHandle); if (stay) SetWindowPos( windowHandle , HWND_TOPMOST , 0, 0, 0, 0 , SWP_NOMOVE | SWP_NOSIZE ); else SetWindowPos(windowHandle , HWND_NOTOPMOST , 0, 0, 0, 0 , SWP_NOMOVE | SWP_NOSIZE ); } else printMessage("window not bound"); } void Win32WindowImpl::update() { InvalidateRect(windowHandle, NULL, false); SAVEGLERROR; UpdateWindow(windowHandle); SAVEGLERROR; } void Win32WindowImpl::destroy() { if (gHandle) SendMessage(gMDIClientHandle, WM_MDIDESTROY, (WPARAM) windowHandle, 0); else DestroyWindow(windowHandle); } bool Win32WindowImpl::beginGL() { dcHandle = GetDC(windowHandle); if (wglMakeCurrent( dcHandle, glrcHandle )) return true; else return false; } void Win32WindowImpl::endGL() { ReleaseDC(windowHandle, dcHandle); } void Win32WindowImpl::swap() { dcHandle = GetDC(windowHandle); SwapBuffers(dcHandle); ReleaseDC(windowHandle, dcHandle); } void Win32WindowImpl::captureMouse(View* inCaptureView) { captureView = inCaptureView; SetCapture(windowHandle); } void Win32WindowImpl::releaseMouse(void) { captureView = NULL; ReleaseCapture(); } bool Win32WindowImpl::initGL (int antialias) { bool success = false; // obtain a device context for the window dcHandle = GetDC(windowHandle); if (dcHandle) { int iPixelFormat; #ifdef WGL_ARB_pixel_format // Setup antialiasing if (antialias == -1) antialias = RGL_ANTIALIAS; if (antialias > 0) { float fAttributes[] = { 0, 0 }; int iAttributes[] = { WGL_DRAW_TO_WINDOW_ARB, GL_TRUE, WGL_SUPPORT_OPENGL_ARB, GL_TRUE, WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB, WGL_COLOR_BITS_ARB, 24, WGL_ALPHA_BITS_ARB, 8, WGL_DEPTH_BITS_ARB, 16, WGL_STENCIL_BITS_ARB, 0, WGL_DOUBLE_BUFFER_ARB, GL_TRUE, WGL_SAMPLE_BUFFERS_ARB, GL_TRUE, WGL_SAMPLES_ARB, antialias, 0, 0 }; UINT numFormats = 0; if (!wglChoosePixelFormatARB || !wglChoosePixelFormatARB(dcHandle, iAttributes, fAttributes, 1, &iPixelFormat, &numFormats) || numFormats < 1) { iPixelFormat = ChoosePixelFormat(dcHandle, &pfd); } } else #endif // get the device context's best, available pixel format match iPixelFormat = ChoosePixelFormat(dcHandle, &pfd); if (iPixelFormat != 0) { // make that match the device context's current pixel format SetPixelFormat(dcHandle, iPixelFormat, &pfd); // create GL context if ( ( glrcHandle = wglCreateContext( dcHandle ) ) ) { if (wglMakeCurrent(dcHandle, glrcHandle)) { int version = gladLoaderLoadGL(); if (version) success = true; else printMessage("gladLoadGL failed"); wglMakeCurrent(NULL, NULL); } else printMessage("wglMakeCurrent failed"); } else printMessage("wglCreateContext failed"); } else printMessage("iPixelFormat == 0!"); ReleaseDC(windowHandle,dcHandle); } return success; } void Win32WindowImpl::shutdownGL() { dcHandle = GetDC(windowHandle); wglMakeCurrent(NULL,NULL); ReleaseDC(windowHandle, dcHandle); wglDeleteContext(glrcHandle); } GLFont* Win32WindowImpl::getFont(const char* family, int style, double cex, bool useFreeType) { for (unsigned int i=0; i < fonts.size(); i++) { if (fonts[i]->cex == cex && fonts[i]->style == style && !strcmp(fonts[i]->family, family) && fonts[i]->useFreeType == useFreeType) return fonts[i]; } if (!useFreeType) { // Not found, so create it. This is based on code from graphapp gdraw.c if (strcmp(family, "NA") && beginGL()) { // User passes NA_character_ for default, looks like "NA" here SEXP Rfontname = VECTOR_ELT(PROTECT(Rf_eval(Rf_lang2(Rf_install("windowsFonts"), Rf_ScalarString(Rf_mkChar(family))), rglNamespace)), 0); if (Rf_isString(Rfontname)) { const char* fontname = CHAR(STRING_ELT(Rfontname, 0)); GLBitmapFont* font = new GLBitmapFont(family, style, cex, fontname); HFONT hf; LOGFONT lf; double size = 12*cex + 0.5; lf.lfHeight = -MulDiv(size, GetDeviceCaps(dcHandle, LOGPIXELSY), 72); lf.lfWidth = 0 ; lf.lfEscapement = lf.lfOrientation = 0; lf.lfWeight = FW_NORMAL; lf.lfItalic = lf.lfUnderline = lf.lfStrikeOut = 0; if ((! strcmp(fontname, "Symbol")) || (! strcmp(fontname, "Wingdings"))) lf.lfCharSet = SYMBOL_CHARSET; else lf.lfCharSet = DEFAULT_CHARSET; lf.lfClipPrecision = CLIP_DEFAULT_PRECIS; lf.lfQuality = DEFAULT_QUALITY; lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE; if ((strlen(fontname) > 1) && (fontname[0] == 'T') && (fontname[1] == 'T')) { const char *pf; lf.lfOutPrecision = OUT_TT_ONLY_PRECIS; for (pf = &fontname[2]; isspace(*pf) ; pf++); strncpy(lf.lfFaceName, pf, LF_FACESIZE-1); } else { lf.lfOutPrecision = OUT_DEFAULT_PRECIS; strncpy(lf.lfFaceName, fontname, LF_FACESIZE-1); } if (style == 2 || style == 4) lf.lfWeight = FW_BOLD; if (style == 3 || style == 4) lf.lfItalic = 1; if ((hf = CreateFontIndirect(&lf))) { SelectObject (dcHandle, hf ); font->nglyph = GL_BITMAP_FONT_LAST_GLYPH - GL_BITMAP_FONT_FIRST_GLYPH + 1; font->widths = new unsigned int [font->nglyph]; GLuint listBase = glGenLists(font->nglyph); font->firstGlyph = GL_BITMAP_FONT_FIRST_GLYPH; font->listBase = listBase - font->firstGlyph; GetCharWidth32( dcHandle, font->firstGlyph, GL_BITMAP_FONT_LAST_GLYPH, (LPINT) font->widths ); { TEXTMETRIC tm; GetTextMetrics( dcHandle, &tm); font->ascent = tm.tmAscent; } wglUseFontBitmaps(dcHandle, font->firstGlyph, font->nglyph, listBase); DeleteObject( hf ); endGL(); fonts.push_back(font); UNPROTECT(1); return font; } delete font; endGL(); } UNPROTECT(1); } } else { // useFreeType #ifdef HAVE_FREETYPE char fontname_absolute[MAX_PATH+1] = ""; int len=0; SEXP Rfontname = VECTOR_ELT(PROTECT(Rf_eval(Rf_lang2(Rf_install("rglFonts"), Rf_ScalarString(Rf_mkChar(family))), rglNamespace)), 0); if (Rf_isString(Rfontname) && Rf_length(Rfontname) >= style) { const char* fontname = CHAR(STRING_ELT(Rfontname, style-1)); if (!IS_ABSOLUTE_PATH(fontname)) { LPITEMIDLIST pidlFonts; assert(SUCCEEDED(SHGetSpecialFolderLocation(0, CSIDL_FONTS, &pidlFonts)) && SUCCEEDED(SHGetPathFromIDList(pidlFonts, fontname_absolute)) ); len = strlen(fontname_absolute); if (len && fontname_absolute[len-1] != '\\') { strcat(fontname_absolute, "\\"); len++; } } assert(len + strlen(fontname) <= MAX_PATH); strcat(fontname_absolute, fontname); GLFTFont* font=new GLFTFont(family, style, cex, fontname_absolute); if (font->font) { fonts.push_back(font); UNPROTECT(1); return font; } else { Rf_warning(font->errmsg); delete font; } } UNPROTECT(1); #endif } if (strcmp(family, fonts[0]->family)) Rf_warning("font family \"%s\" not found, using \"%s\"", family, fonts[0]->family); else if (style != fonts[0]->style) Rf_warning("\"%s\" family only supports font %d", fonts[0]->family, fonts[0]->style); else if (cex != fonts[0]->cex) Rf_warning("\"%s\" family only supports cex = %g", fonts[0]->family, fonts[0]->cex); else if (useFreeType) Rf_warning("FreeType font not available"); return fonts[0]; } GLBitmapFont* Win32WindowImpl::initGLBitmapFont(u8 firstGlyph, u8 lastGlyph) { GLBitmapFont* font = NULL; if (beginGL()) { font = new GLBitmapFont("bitmap", 1, 1, "System"); SelectObject (dcHandle, GetStockObject (SYSTEM_FONT) ); font->nglyph = lastGlyph-firstGlyph+1; font->widths = new unsigned int [font->nglyph]; GLuint listBase = glGenLists(font->nglyph); font->firstGlyph = firstGlyph; font->listBase = listBase - firstGlyph; GetCharWidth32( dcHandle, font->firstGlyph, lastGlyph, (LPINT) font->widths ); { TEXTMETRIC tm; GetTextMetrics( dcHandle, &tm); font->ascent = tm.tmAscent; } wglUseFontBitmaps(dcHandle, font->firstGlyph, font->nglyph, listBase); endGL(); } return font; } LRESULT Win32WindowImpl::processMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { LRESULT returnValue = 0; switch(message) { case WM_CREATE: windowHandle = hwnd; initGL(antialias); fonts[0] = initGLBitmapFont(GL_BITMAP_FONT_FIRST_GLYPH, GL_BITMAP_FONT_LAST_GLYPH); if (gHandle) { refreshMenu = true; } break; case WM_SHOWWINDOW: if ( ( (BOOL) wParam ) == TRUE ) { window->show(); autoUpdate = true; } else { window->hide(); autoUpdate = false; } break; case WM_PAINT: // Fixed now? don't put Rprintf calls in paint/render/draw methods, or you get a permanent loop! if (!painting) { painting = true; if (refreshMenu) { SendMessage(gMDIClientHandle, WM_MDIREFRESHMENU, 0, 0); DrawMenuBar(gMDIFrameHandle); refreshMenu = false; } if (!window->skipRedraw) { window->paint(); swap(); } painting = false; } ValidateRect(hwnd, NULL); break; case WM_SIZE: window->resize(LOWORD(lParam), HIWORD(lParam)); if (gHandle) return gDefWindowProc(hwnd,message,wParam,lParam); else break; case WM_CLOSE: window->on_close(); break; case WM_KEYDOWN: if (int keycode = translate_key(wParam) ) { window->keyPress(keycode); } else return -1; case WM_CHAR: window->keyPress( (int) ( (char) wParam ) ); break; case WM_LBUTTONDOWN: ( (captureView) ? captureView : window ) -> buttonPress(GUI_ButtonLeft, (short) LOWORD(lParam), (short) HIWORD(lParam) ); break; case WM_LBUTTONUP: ( (captureView) ? captureView : window ) -> buttonRelease(GUI_ButtonLeft, (short) LOWORD(lParam), (short) HIWORD(lParam)); break; case WM_RBUTTONDOWN: ( (captureView) ? captureView : window ) -> buttonPress(GUI_ButtonRight,(short) LOWORD(lParam), (short) HIWORD(lParam) ); break; case WM_RBUTTONUP: ( (captureView) ? captureView : window ) -> buttonRelease(GUI_ButtonRight,(short) LOWORD(lParam), (short) HIWORD(lParam) ); break; case WM_MBUTTONDOWN: ( (captureView) ? captureView : window ) -> buttonPress(GUI_ButtonMiddle, (short) LOWORD(lParam), (short) HIWORD(lParam) ); break; case WM_MBUTTONUP: ( (captureView) ? captureView : window ) -> buttonRelease(GUI_ButtonMiddle, (short) LOWORD(lParam), (short) HIWORD(lParam) ); break; #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) case WM_MOUSEWHEEL: { int dir = ( (short) HIWORD(wParam) > 0 ) ? GUI_WheelForward : GUI_WheelBackward; ( (captureView) ? captureView : window ) -> wheelRotate(dir, (short) LOWORD(lParam), (short) HIWORD(lParam) ); break; } #endif case WM_MOUSEMOVE: ( (captureView) ? captureView : window ) -> mouseMove( ( (short) LOWORD(lParam) ), ( (short) HIWORD(lParam) ) ); break; case WM_CAPTURECHANGED: if (captureView) { captureView->captureLost(); captureView = NULL; } break; case WM_DESTROY: shutdownGL(); #if defined (WIN64) || defined(_MSC_VER) SetWindowLongPtr(hwnd, GWLP_USERDATA, (long)NULL); #else SetWindowLong(hwnd, GWL_USERDATA, (LONG) NULL ); #endif if (window) window->notifyDestroy(); delete this; break; default: return gDefWindowProc(hwnd,message,wParam,lParam); } return returnValue; } // static LRESULT CALLBACK Win32WindowImpl::delegateWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { #if defined (WIN64) || defined(_MSC_VER) Win32WindowImpl* windowImpl = (Win32WindowImpl*) GetWindowLongPtr(hwnd, GWLP_USERDATA); #else Win32WindowImpl* windowImpl = (Win32WindowImpl*) GetWindowLong(hwnd, GWL_USERDATA); #endif return windowImpl->processMessage(hwnd, message, wParam, lParam); } // static LRESULT CALLBACK Win32WindowImpl::windowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { if (message == WM_CREATE) { Win32WindowImpl* windowImpl; LPCREATESTRUCT pCreateStruct = reinterpret_cast(lParam); if (gHandle) { LPMDICREATESTRUCT pMDICreateStruct = reinterpret_cast(pCreateStruct->lpCreateParams); windowImpl = reinterpret_cast( pMDICreateStruct->lParam ); } else { windowImpl = reinterpret_cast( pCreateStruct->lpCreateParams ); } if (windowImpl) { #if defined (WIN64) || defined(_MSC_VER) SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)windowImpl ); SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR) delegateWindowProc ); #else SetWindowLong(hwnd, GWL_USERDATA, (long) windowImpl ); SetWindowLong(hwnd, GWL_WNDPROC, (long) delegateWindowProc ); #endif return windowImpl->processMessage(hwnd, message, wParam, lParam); } } return gDefWindowProc(hwnd, message, wParam, lParam); } // static bool Win32WindowImpl::registerClass() { WNDCLASSEX wcex; ZeroMemory( &wcex, sizeof(WNDCLASSEX) ); wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wcex.lpfnWndProc = (WNDPROC) windowProc; wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.lpszClassName = "RGLDevice"; classAtom = RegisterClassEx(&wcex); return (classAtom) ? true : false; } // static void Win32WindowImpl::unregisterClass(void) { if (classAtom) UnregisterClass(MAKEINTATOM(classAtom), NULL ); } // static ATOM Win32WindowImpl::classAtom = (ATOM) NULL; // --------------------------------------------------------------------------- // // Win32GUIFactory class // // --------------------------------------------------------------------------- Win32GUIFactory::Win32GUIFactory() #if defined(WGL_ARB_pixel_format) && !defined(WGL_WGLEXT_PROTOTYPES) : wglChoosePixelFormatARB(NULL) #endif { if (gInitValue) { // we must be running in pre-2.6.0 R gHandle = reinterpret_cast(gInitValue); } if (gHandle) { // the handle is given for the console window, so that // client and frame windows can be derived HWND consoleHandle = reinterpret_cast(gHandle); gMDIClientHandle = GetParent(consoleHandle); gMDIFrameHandle = GetParent(gMDIClientHandle); gDefWindowProc = &DefMDIChildProc; } else gDefWindowProc = &DefWindowProc; if ( !Win32WindowImpl::registerClass() ) Rf_error("window class registration failed"); #if defined(WGL_ARB_pixel_format) && !defined(WGL_WGLEXT_PROTOTYPES) HANDLE saveHandle = gHandle; gHandle = NULL; /* call below fails for MDI windows */ // wglGetProcAddress needs to be called within valid GL context, we need to create dummy window here HWND windowHandle = CreateWindow(MAKEINTATOM(Win32WindowImpl::classAtom), "", WS_POPUP | WS_DISABLED, 0, 0, 10, 10, NULL, NULL, NULL, NULL); if (windowHandle) { HDC dcHandle = GetDC(windowHandle); if (dcHandle) { int iPixelFormat = ChoosePixelFormat(dcHandle, &pfd); if (iPixelFormat != 0) { SetPixelFormat(dcHandle, iPixelFormat, &pfd); HGLRC glrcHandle = wglCreateContext(dcHandle); if (glrcHandle) { wglMakeCurrent(dcHandle, glrcHandle); wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); wglMakeCurrent(NULL, NULL); wglDeleteContext(glrcHandle); } } ReleaseDC(windowHandle, dcHandle); } DestroyWindow(windowHandle); } gHandle = saveHandle; #endif } // --------------------------------------------------------------------------- Win32GUIFactory::~Win32GUIFactory() { Win32WindowImpl::unregisterClass(); } // --------------------------------------------------------------------------- WindowImpl* Win32GUIFactory::createWindowImpl(Window* in_window, int antialias) { Win32WindowImpl* impl = new Win32WindowImpl(in_window, antialias); #if defined(WGL_ARB_pixel_format) && !defined(WGL_WGLEXT_PROTOTYPES) impl->wglChoosePixelFormatARB = wglChoosePixelFormatARB; #endif RECT size; size.left = 0; size.right = in_window->width-1; size.top = 0; size.bottom = in_window->height-1; AdjustWindowRect( &size , WS_OVERLAPPEDWINDOW // WS_CAPTION|WS_SYSMENU|WS_THICKFRAME|WS_MINIMIZEBOX|WS_MAXIMIZEBOX , false // no menu ); HWND success = 0; if (gHandle) { success = CreateMDIWindow( MAKEINTATOM(Win32WindowImpl::classAtom) , in_window->title , MDIS_ALLCHILDSTYLES|WS_OVERLAPPEDWINDOW , CW_USEDEFAULT, 0 , size.right- size.left+1, size.bottom - size.top+1 , gMDIClientHandle, NULL // GetModuleHandle(NULL) , reinterpret_cast(impl) ); } else { success = CreateWindow( MAKEINTATOM(Win32WindowImpl::classAtom) , in_window->title , WS_OVERLAPPEDWINDOW , CW_USEDEFAULT, 0 , size.right- size.left+1, size.bottom - size.top+1 , NULL, NULL, NULL , reinterpret_cast(impl) ); } if (!success) Rf_error("window creation failed"); return impl; } // --------------------------------------------------------------------------- #endif // RGL_W32 rgl/src/R.cpp0000644000176200001440000000044114771520323012535 0ustar liggesusers#include #include "R.h" namespace rgl { using namespace rgl; char* copyStringToR(std::string s) { /* R has highjacked length() */ char* result; size_t len = s.size(); result = R_alloc(len + 1, 1); strncpy(result, s.c_str(), len); result[len] = '\0'; return result; } } rgl/src/assert.h0000644000176200001440000000162614771520323013310 0ustar liggesusers/* * assert.hpp * Based on assert.h from MinGW, which had the following notice: * This file has no copyright assigned and is placed in the Public Domain. * This file is a part of the mingw-runtime package. * No warranty is given; refer to the file DISCLAIMER within the package. * * Define the assert macro for debug output. * */ /* We should be able to include this file multiple times to allow the assert macro to be enabled/disabled for different parts of code. So don't add a header guard. */ #undef assert #ifdef __cplusplus extern "C" { #endif /* #ifdef NDEBUG * If not debugging, standard assert does nothing; ours always * does the same. #define assert(x) ((void)0) #else */ void rgl_assert (const char*, const char*, int); /* * Definition of the assert macro. */ #define assert(e) ((e) ? (void)0 : rgl_assert(#e, __FILE__, __LINE__)) #ifdef __cplusplus } #endif rgl/src/x11gui.cpp0000644000176200001440000005746515011677075013501 0ustar liggesusers#include "config.h" #ifdef RGL_X11 // --------------------------------------------------------------------------- // C++ source // This file is part of RGL. // // Uncomment for verbose output on stderr: // #define RGL_X11_DEBUG // --------------------------------------------------------------------------- #include "opengl.h" #include #include #include "x11gui.h" #include "lib.h" #include "R.h" #include namespace rgl { // --------------------------------------------------------------------------- extern SEXP rglNamespace; // --------------------------------------------------------------------------- class X11WindowImpl : public WindowImpl { public: X11WindowImpl(rgl::Window* in_window , X11GUIFactory* in_factory , ::Window in_xwindow , XVisualInfo* invisualinfo ); virtual ~X11WindowImpl(); void setTitle(const char* title); void setWindowRect(int left, int top, int right, int bottom); void getWindowRect(int *left, int *top, int *right, int *bottom); void show(); void hide(); void bringToTop(int stay); void update(); void destroy(); bool beginGL(); void endGL(); void swap(); void captureMouse(View* captureview); void releaseMouse(); void watchMouse(bool withoutButton); GLFont* getFont(const char* family, int style, double cex, bool useFreeType); private: void initGL(); GLBitmapFont* initGLFont(); void shutdownGL(); static int translate_key(KeySym keysym); void on_init(); void on_shutdown(); void on_paint(); void processEvent(XEvent& ev); X11GUIFactory* factory; ::Window xwindow; ::GLXContext glxctx; friend class X11GUIFactory; XVisualInfo* xvisualinfo; }; } // namespace rgl using namespace rgl; // --------------------------------------------------------------------------- // X11WindowImpl Implementation // --------------------------------------------------------------------------- X11WindowImpl::X11WindowImpl(Window* w, X11GUIFactory* f, ::Window in_xwindow, XVisualInfo* invisualinfo) : WindowImpl(w) , factory(f) , xwindow(in_xwindow) , xvisualinfo(invisualinfo) { on_init(); } // --------------------------------------------------------------------------- X11WindowImpl::~X11WindowImpl() { if (xwindow != 0) destroy(); // free XVisualInfo structure if (xvisualinfo) { XFree(xvisualinfo); xvisualinfo = 0; } } // --------------------------------------------------------------------------- void X11WindowImpl::setTitle(const char* title) { XStoreName(factory->xdisplay,xwindow,title); factory->flushX(); } // --------------------------------------------------------------------------- void X11WindowImpl::setWindowRect(int left, int top, int right, int bottom) { ::Window root, child, parent, *children; int x, y; unsigned int nchildren; XQueryTree(factory->xdisplay, xwindow, &root, &parent, &children, &nchildren); XTranslateCoordinates(factory->xdisplay, xwindow, parent, 0, 0, &x, &y, &child); // The weird calculation below (subtracting twice (x,y)) compensates for the diff // between coordinates of the rgl window within the parent window. // There's probably a smarter way to do this... XMoveWindow(factory->xdisplay, xwindow, left-2*x, top-2*y); XResizeWindow(factory->xdisplay, xwindow, right-left, bottom-top); factory->flushX(); } // --------------------------------------------------------------------------- void X11WindowImpl::getWindowRect(int *left, int *top, int *right, int *bottom) { ::Window root, child; int x, y; unsigned int width, height, border_width, depth; do { factory->flushX(); factory->processEvents(); } while (XEventsQueued(factory->xdisplay, QueuedAfterFlush)); XGetGeometry(factory->xdisplay, xwindow, &root, &x, &y, &width, &height, &border_width, &depth); XTranslateCoordinates(factory->xdisplay, xwindow, root, x, y, left, top, &child); XTranslateCoordinates(factory->xdisplay, xwindow, root, x+width, y+height, right, bottom, &child); } // --------------------------------------------------------------------------- static Bool IsMapNotify(Display* d, XEvent* ev, XPointer arg) { ::Window w = (::Window) arg; return ( (ev->xany.window == w) && (ev->type == MapNotify) ); } void X11WindowImpl::show() { XMapWindow(factory->xdisplay, xwindow); XEvent ev; XIfEvent(factory->xdisplay, &ev, IsMapNotify, (XPointer) xwindow ); factory->processEvents(); factory->flushX(); update(); } // --------------------------------------------------------------------------- void X11WindowImpl::hide() { XUnmapWindow(factory->xdisplay, xwindow); factory->flushX(); } // --------------------------------------------------------------------------- void X11WindowImpl::bringToTop(int stay) { XRaiseWindow(factory->xdisplay, xwindow); factory->processEvents(); factory->flushX(); } // --------------------------------------------------------------------------- void X11WindowImpl::on_paint() { if (window) { if (window->skipRedraw) return; window->paint(); SAVEGLERROR; } swap(); SAVEGLERROR; } // --------------------------------------------------------------------------- void X11WindowImpl::update() { on_paint(); SAVEGLERROR; } // --------------------------------------------------------------------------- void X11WindowImpl::destroy() { if (xwindow != 0) { on_shutdown(); if (factory->xdisplay) XDestroyWindow(factory->xdisplay, xwindow); factory->flushX(); factory->notifyDelete(xwindow); /* Why didn't this happen in the lines above, from the DestroyNotify event? */ xwindow = 0; if (window) window->notifyDestroy(); delete this; } } // --------------------------------------------------------------------------- bool X11WindowImpl::beginGL() { if ( glXMakeCurrent(factory->xdisplay, xwindow, glxctx) == False ) { printMessage("ERROR: can't bind glx context to window"); return false; } else return true; } // --------------------------------------------------------------------------- void X11WindowImpl::endGL() { } // --------------------------------------------------------------------------- void X11WindowImpl::swap() { glXSwapBuffers(factory->xdisplay, xwindow); } // --------------------------------------------------------------------------- void X11WindowImpl::captureMouse(View* captureview) { } // --------------------------------------------------------------------------- void X11WindowImpl::releaseMouse() { } // --------------------------------------------------------------------------- void X11WindowImpl::watchMouse(bool withoutButton) { unsigned long valuemask=CWEventMask; XSetWindowAttributes attrib; attrib.event_mask = (withoutButton ? PointerMotionMask : ButtonMotionMask) | PointerMotionHintMask | VisibilityChangeMask | ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask | KeyReleaseMask | ButtonReleaseMask; XChangeWindowAttributes(factory->xdisplay, xwindow, valuemask, &attrib); factory->flushX(); } // --------------------------------------------------------------------------- void X11WindowImpl::processEvent(XEvent& ev) { char keybuffer[8]; KeySym keysym; XComposeStatus compose; int keycode; ::Window root, child; int rootx, rooty, winx, winy; unsigned int mask; switch(ev.type) { case ButtonPress: switch(ev.xbutton.button) { case 1: if (window) window->buttonPress( GUI_ButtonLeft, ev.xbutton.x, ev.xbutton.y ); break; case 2: if (window) window->buttonPress( GUI_ButtonMiddle, ev.xbutton.x, ev.xbutton.y ); break; case 3: if (window) window->buttonPress( GUI_ButtonRight, ev.xbutton.x, ev.xbutton.y ); break; case 4: if (window) window->wheelRotate( GUI_WheelForward, ev.xbutton.x, ev.xbutton.y ); break; case 5: if (window) window->wheelRotate( GUI_WheelBackward, ev.xbutton.x, ev.xbutton.y ); break; } break; case ButtonRelease: switch(ev.xbutton.button) { case 1: if (window) window->buttonRelease( GUI_ButtonLeft, ev.xbutton.x, ev.xbutton.y ); break; case 2: if (window) window->buttonRelease( GUI_ButtonMiddle, ev.xbutton.x, ev.xbutton.y ); break; case 3: if (window) window->buttonRelease( GUI_ButtonRight, ev.xbutton.x, ev.xbutton.y ); break; } break; case KeyPress: XLookupString(&ev.xkey, keybuffer, sizeof(keybuffer), &keysym, &compose); keycode = translate_key(keysym); if (keycode) if (window) window->keyPress(keycode); break; case KeyRelease: XLookupString(&ev.xkey, keybuffer, sizeof(keybuffer), &keysym, &compose); keycode = translate_key(keysym); if (keycode) if (window) window->keyRelease(keycode); break; case MappingNotify: XRefreshKeyboardMapping(&ev.xmapping); break; case MotionNotify: if( XQueryPointer(factory->xdisplay, xwindow, &root, &child, &rootx, &rooty, &winx, &winy, &mask) == True ) if (window) window->mouseMove( winx, winy ); break; case Expose: if (ev.xexpose.count == 0) { if (window) { if (window->skipRedraw) break; window->paint(); } swap(); } break; case ConfigureNotify: if (window) window->resize( ev.xconfigure.width, ev.xconfigure.height ); break; case MapNotify: if (window) window->show(); break; case UnmapNotify: if (window) window->hide(); break; case ClientMessage: if ( ( (::Atom) ev.xclient.data.l[0] ) == factory->atoms[GUI_X11_ATOM_WM_DELETE]) if (window) window->on_close(); break; case DestroyNotify: factory->notifyDelete(xwindow); xwindow = 0; if (window) window->notifyDestroy(); delete this; break; } } // --------------------------------------------------------------------------- static int error_code; static X11GUIFactory *errorGuiFactory; static int X11SaveErr(Display *dsp, XErrorEvent *event) { if (errorGuiFactory->old_error_handler && dsp != errorGuiFactory->xdisplay) return errorGuiFactory->old_error_handler(dsp, event); error_code = event->error_code; return 0; } // --------------------------------------------------------------------------- void X11WindowImpl::initGL() { glxctx = glXCreateContext(factory->xdisplay, xvisualinfo, NULL, True); if (glxctx) { if (glXMakeCurrent(factory->xdisplay, xwindow, glxctx) == True) { int gl_version = gladLoadGL((GLADloadfunc)glXGetProcAddressARB); if (gl_version) { GLenum error_code; // Rprintf("loaded gl version %d.%d\n", GLAD_VERSION_MAJOR(gl_version), GLAD_VERSION_MINOR(gl_version)); /* clear old errors */ while ((error_code = glGetError())) { switch(error_code) { case GL_INVALID_ENUM: Rprintf("cleared GL_INVALID_ENUM\n"); break; case GL_INVALID_VALUE:Rprintf("cleared GL_INVALID_VALUE\n"); break; case GL_INVALID_OPERATION:Rprintf("cleared GL_INVALID_OPERATION\n"); break; case GL_STACK_OVERFLOW:Rprintf("cleared GL_STACK_OVERFLOW\n"); break; case GL_STACK_UNDERFLOW:Rprintf("cleared GL_STACK_UNDERFLOW\n"); break; default: Rprintf("cleared GL error %d\n", error_code); }; }; fonts[0] = initGLFont(); } else { Rprintf("Unable to load GL"); shutdownGL(); } glXMakeCurrent(factory->xdisplay, None, NULL); } } } // --------------------------------------------------------------------------- void X11WindowImpl::shutdownGL() { // destroy GL context if (glxctx) { glXMakeCurrent(factory->xdisplay, None, NULL); glXDestroyContext(factory->xdisplay, glxctx); glxctx = NULL; } } // --------------------------------------------------------------------------- GLFont* X11WindowImpl::getFont(const char* family, int style, double cex, bool useFreeType) { for (unsigned int i=0; i < fonts.size(); i++) { if (fonts[i] && fonts[i]->cex == cex && fonts[i]->style == style && !strcmp(fonts[i]->family, family) && fonts[i]->useFreeType == useFreeType) return fonts[i]; } if (useFreeType) { #ifdef HAVE_FREETYPE SEXP Rfontname = VECTOR_ELT(PROTECT(Rf_eval(PROTECT(Rf_lang2(PROTECT(Rf_install("rglFonts")), PROTECT(Rf_ScalarString(Rf_mkChar(family))))), rglNamespace)), 0); if (Rf_isString(Rfontname) && Rf_length(Rfontname) >= style) { const char* fontname = CHAR(STRING_ELT(Rfontname, style-1)); GLFTFont* font=new GLFTFont(family, style, cex, fontname); if (font->font) { fonts.push_back(font); UNPROTECT(4); return font; } else { Rf_warning("Error creating font: %s", font->errmsg); delete font; } } UNPROTECT(4); #else Rf_warning("FreeType not available"); #endif } if (strcmp(family, fonts.back()->family)) Rf_warning("font family \"%s\" not found, using \"%s\"", family, fonts.back()->family); else if (style != fonts.back()->style) Rf_warning("\"%s\" family only supports font %d", fonts.back()->family, fonts.back()->style); else if (cex != fonts.back()->cex) Rf_warning("\"%s\" family only supports cex = %g", fonts.back()->family, fonts.back()->cex); else if (useFreeType) Rf_warning("FreeType font not available"); if (useFreeType) return fonts.back(); else return fonts[0]; } GLBitmapFont* X11WindowImpl::initGLFont() { GLBitmapFont* font = NULL; if (factory->xfont && beginGL()) { font = new GLBitmapFont("bitmap", 1, 1, "fixed"); font->nglyph = GL_BITMAP_FONT_COUNT; font->firstGlyph = GL_BITMAP_FONT_FIRST_GLYPH; GLuint listBase = glGenLists(font->nglyph); font->listBase = listBase - font->firstGlyph; glXUseXFont(factory->xfont->fid, font->firstGlyph, font->nglyph, listBase); font->widths = new unsigned int[font->nglyph]; for(unsigned int i=0;inglyph;i++) font->widths[i] = 9; font->ascent = factory->xfont->ascent; endGL(); // Should this be added? } return font; } // --------------------------------------------------------------------------- void X11WindowImpl::on_init() { initGL(); } void X11WindowImpl::on_shutdown() { if (glxctx) for (unsigned int i=0; i < fonts.size(); i++) { if (fonts[i]) { delete fonts[i]; fonts[i] = NULL; } } shutdownGL(); } // --------------------------------------------------------------------------- // // FUNCTION // translate_key // // translates X11 KeySym keycode to GUI_Key code // // --------------------------------------------------------------------------- int X11WindowImpl::translate_key(KeySym keysym) { if ( (keysym >= XK_space) && (keysym <= XK_asciitilde) ) return (int) keysym; else if ((keysym >= XK_F1) && (keysym <= XK_F12)) return static_cast(GUI_KeyF1 + keysym - XK_F1); else { switch(keysym) { case XK_Return: return GUI_KeyReturn; case XK_Escape: return GUI_KeyESC; default: return 0; } } } // --------------------------------------------------------------------------- // X11GUIFactory Implementation // --------------------------------------------------------------------------- // throw error // --------------------------------------------------------------------------- void X11GUIFactory::throw_error(const char* string) { printMessage(string); disconnect(); } // --------------------------------------------------------------------------- X11GUIFactory::X11GUIFactory(const char* displayname) : xdisplay(0) , xfont(0) , old_error_handler(0) { // Open one display connection for all RGL X11 devices xdisplay = XOpenDisplay(displayname); if (xdisplay == 0) { throw_error("unable to open X11 display"); return; } /* XSynchronize(xdisplay, True); */ // Load System font xfont = XLoadQueryFont(xdisplay,"fixed"); if (!xfont) { // Try the first available xfont = XLoadQueryFont(xdisplay, "*"); if (!xfont) { throw_error("unable to load X11 font"); return; } } // Obtain display atoms static char* atom_names[GUI_X11_ATOM_LAST] = { const_cast("WM_DELETE_WINDOW") }; Status s = XInternAtoms(xdisplay, atom_names, sizeof(atom_names)/sizeof(char*), True, atoms); if (!s) printMessage("some atoms not available"); // Query glx extension if ( glXQueryExtension(xdisplay, &errorBase, &eventBase) == False ) { throw_error("GLX extension missing on server"); return; } ::Window rootwin = DefaultRootWindow(xdisplay); group_leader = XCreateSimpleWindow( /* never mapped or visible */ xdisplay, rootwin, 0, 0, 1, 1, 0, 0, 0); } // --------------------------------------------------------------------------- X11GUIFactory::~X11GUIFactory() { disconnect(); } // --------------------------------------------------------------------------- void X11GUIFactory::disconnect() { if (xdisplay) { // close invisible group leader XDestroyWindow(xdisplay, group_leader); // process pending XDestroyNotify events XSync(xdisplay, False); processEvents(); // free xfont if (xfont) { XUnloadFont(xdisplay, xfont->fid); xfont = 0; } // disconnect from X server XCloseDisplay(xdisplay); xdisplay = 0; if (old_error_handler) { XSetErrorHandler(old_error_handler); old_error_handler = 0; } } } // --------------------------------------------------------------------------- void X11GUIFactory::flushX() { if (xdisplay) XSync(xdisplay, False); glXWaitX(); } // --------------------------------------------------------------------------- void X11GUIFactory::processEvents() { for(;;) { int nevents = XEventsQueued(xdisplay, QueuedAfterReading); if (nevents == 0) return; while(nevents--) { XEvent ev; XNextEvent(xdisplay,&ev); X11WindowImpl* impl = windowMap[ev.xany.window]; if (impl) impl->processEvent(ev); #ifdef RGL_X11_DEBUG else fprintf(stderr,"unknown window id %lx(code %lx)\n" , static_cast(ev.xany.window) , static_cast(ev.type) ); #endif } } } // --------------------------------------------------------------------------- WindowImpl* X11GUIFactory::createWindowImpl(Window* window, int antialias) { X11WindowImpl* impl = NULL; XVisualInfo* xvisualinfo; // Choose GLX visual static int attribList[] = { GLX_RGBA, GLX_DOUBLEBUFFER, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1, GLX_ALPHA_SIZE, 0, GLX_DEPTH_SIZE, 1, None, None, // Space for optional AA settings None, None, None }; #ifdef GLX_SAMPLE_BUFFERS // Setup antialiasing if (antialias == -1) antialias = RGL_ANTIALIAS; if(antialias > 0) { attribList[12] = GLX_SAMPLE_BUFFERS; attribList[13] = 1; attribList[14] = GLX_SAMPLES; attribList[15] = antialias; } #endif /* These codes are only used in debugging, they are never displayed. */ #define RGL_ERROR_CODE (LastExtensionError + 1000) /* Catch protocol errors and convert to R errors */ error_code = 0; errorGuiFactory = this; if (old_error_handler) XSetErrorHandler(X11SaveErr); else old_error_handler = XSetErrorHandler(X11SaveErr); xvisualinfo = glXChooseVisual( xdisplay, DefaultScreen(xdisplay), attribList ); #ifdef GLX_SAMPLE_BUFFERS // Try to set up visual without MSAA if it failed if (xvisualinfo == 0 && antialias > 0 && !error_code) { attribList[12] = None; xvisualinfo = glXChooseVisual( xdisplay, DefaultScreen(xdisplay), attribList ); } #endif if (xvisualinfo == 0) { error_code = RGL_ERROR_CODE + 1; } // create X11 window // We don't want a border, but MacOSX Xvfb requires one. unsigned long valuemask=CWEventMask|CWColormap|CWBorderPixel; XSetWindowAttributes attrib; attrib.event_mask = PointerMotionMask | PointerMotionHintMask | VisibilityChangeMask | ExposureMask | StructureNotifyMask | ButtonPressMask | KeyPressMask | KeyReleaseMask | ButtonReleaseMask; ::Window xparent = 0; if (!error_code) { xparent = RootWindow(xdisplay, DefaultScreen(xdisplay)); if (!error_code && !xparent) error_code = RGL_ERROR_CODE + 2; } if (!error_code) { attrib.colormap = XCreateColormap(xdisplay, xparent, xvisualinfo->visual, AllocNone); if (!error_code && !attrib.colormap) error_code = RGL_ERROR_CODE + 3; } attrib.border_pixel = 0; ::Window xwindow = 0; if (!error_code) { if (window) window->resize(256, 256); // This may be changed by window manager xwindow = XCreateWindow( xdisplay, xparent, 0, 0, 256, 256, 0, xvisualinfo->depth, InputOutput, xvisualinfo->visual, valuemask, &attrib ); if (!error_code && !xwindow) error_code = RGL_ERROR_CODE + 4; } if (!error_code) XSync(xdisplay, False); /* set WM_CLASS on window */ if (!error_code) { XClassHint *classHint = XAllocClassHint(); if (!error_code) { if (classHint) { classHint->res_name = const_cast("rgl"); classHint->res_class = const_cast("R_x11"); XSetClassHint(xdisplay, xwindow, classHint); XFree(classHint); } else error_code = RGL_ERROR_CODE + 5; } } // set window manager protocols int n = 0; ::Atom proto_atoms[GUI_X11_ATOM_LAST]; if (atoms[GUI_X11_ATOM_WM_DELETE]) { proto_atoms[n] = atoms[GUI_X11_ATOM_WM_DELETE]; n++; } if (xwindow && n && !error_code) XSetWMProtocols(xdisplay,xwindow,proto_atoms,n); // Set group leader if (xwindow && !error_code) { ::XWMHints *hints; hints = XAllocWMHints(); if (hints) { hints->window_group = group_leader; hints->flags |= WindowGroupHint; XSetWMHints(xdisplay, xwindow, hints); XFree(hints); } } // create window implementation instance if (xwindow && !error_code) { impl = new X11WindowImpl(window, this, xwindow, xvisualinfo); if (!error_code && !impl) error_code = RGL_ERROR_CODE + 6; } else { impl = NULL; } // flush X requests flushX(); if (error_code) { switch (error_code) { case RGL_ERROR_CODE + 1: Rf_warning("no conforming visual"); break; case RGL_ERROR_CODE + 2: Rf_warning("no root window"); break; case RGL_ERROR_CODE + 3: Rf_warning("XCreateColormap failed"); break; case RGL_ERROR_CODE + 4: Rf_warning("XCreateWindow failed"); break; case RGL_ERROR_CODE + 5: Rf_warning("XAllocClassHint failed"); break; case RGL_ERROR_CODE + 6: Rf_warning("X11WindowImpl failed"); break; default: if (error_code > RGL_ERROR_CODE) Rf_warning("rgl error %d", error_code - RGL_ERROR_CODE); else { char error_text[1024]; XGetErrorText(xdisplay, error_code, error_text, sizeof(error_text)); Rf_warning("X11 error: %s",error_text); } } impl = NULL; } // register instance if (xwindow) windowMap[xwindow] = impl; return (WindowImpl*) impl; } // --------------------------------------------------------------------------- void X11GUIFactory::notifyDelete(::Window xwindowid) { #ifdef RGL_X11_DEBUG fprintf(stderr,"notifyDelete %lx\n", xwindowid); #endif // remove window from map windowMap.erase(xwindowid); } // --------------------------------------------------------------------------- #endif // RGL_X11_H rgl/src/win32gui.h0000644000176200001440000000132615011677075013460 0ustar liggesusers#ifndef RGL_W32_GUI_H #define RGL_W32_GUI_H // --------------------------------------------------------------------------- #include "gui.h" // --------------------------------------------------------------------------- #include namespace rgl { // --------------------------------------------------------------------------- class Win32GUIFactory : public GUIFactory { public: Win32GUIFactory(); virtual ~Win32GUIFactory(); WindowImpl* createWindowImpl(Window* window, int antialias); #ifndef WGL_WGLEXT_PROTOTYPES PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB; #endif }; // --------------------------------------------------------------------------- } // namespace rgl #endif // RGL_W32_GUI_H rgl/src/lib.h0000644000176200001440000000075014555455305012561 0ustar liggesusers#ifndef RGL_LIB_H #define RGL_LIB_H // --------------------------------------------------------------------------- namespace rgl { // --------------------------------------------------------------------------- bool init(bool onlyNULLDevice); const char * GUIFactoryName(bool useNULLDevice); void quit(); void printMessage(const char* string); double getTime(); // --------------------------------------------------------------------------- } // namespace rgl #endif // RGL_LIB_H rgl/src/ABCLineSet.h0000644000176200001440000000177714771520323013667 0ustar liggesusers#ifndef ABCLINESET_H #define ABCLINESET_H #include "scene.h" #include "geom.h" #include "Shape.h" #include "PrimitiveSet.h" #include namespace rgl { class ABCLineSet : public LineSet { private: /* Use parametrization (x,y,z) + s*(a,b,c) */ int nLines; ARRAY base; /* (x,y,z) */ ARRAY direction; /* (a,b,c) */ public: ABCLineSet(Material& in_material, int in_nbase, double* in_base, int in_ndir, double* in_dir); /** * tell type. **/ virtual std::string getTypeName() { return "abclines"; }; /** * overload to update segments first. */ virtual AABox& getBoundingBox(Subscene* subscene); /** * overload to update segments first. */ virtual void renderBegin(RenderContext* renderContext); /** * update mesh */ void updateSegments(SceneNode* subscene); /** * update then get attributes */ void getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result); }; } // namespace rgl #endif // PLANESET_H rgl/src/devicemanager.cpp0000644000176200001440000000767515011677075015153 0ustar liggesusers// C++ source // This file is part of RGL. // #include #include #include "DeviceManager.h" #include "types.h" #include "assert.h" #include "lib.h" using namespace rgl; DeviceManager::DeviceManager(bool in_useNULLDevice) : newID(1), devices(), current( devices.end() ), useNULLDevice(in_useNULLDevice) { } DeviceManager::~DeviceManager() { std::vector disposeList; { for( Container::const_iterator i = devices.begin(), end = devices.end() ; i!=end ; ++i ) { disposeList.push_back(*i); } } // disploseList. devices.begin(), devices.end() ); for (std::vector::iterator i = disposeList.begin(); i != disposeList.end() ; ++ i ) { // remove manager from listeners (*i)->removeDisposeListener(this); // close device (*i)->close(); } } bool DeviceManager::openDevice(bool useNULL, int antialias) { Device* pDevice = new Device(newID, useNULL, antialias); if ( pDevice->open() ) { ++newID; pDevice->addDisposeListener(this); devices.insert( devices.end(), pDevice ); setCurrent( pDevice->getID() ); return true; } else { delete pDevice; return false; } } Device* DeviceManager::getCurrentDevice() { if ( current != devices.end() ) return *current; else return NULL; } Device* DeviceManager::getAnyDevice() { Device* pDevice = getCurrentDevice(); if (pDevice == NULL) { if (openDevice(useNULLDevice, RGL_ANTIALIAS)) pDevice = getCurrentDevice(); } return pDevice; } Device* DeviceManager::getDevice(int id) { for (Container::iterator i = devices.begin() ; i != devices.end() ; ++i ) { if ( (*i)->getID() == id ) return *i; } return NULL; } bool DeviceManager::setCurrent(int id, bool silent) { char buffer[64]; Container::iterator i; for (i = devices.begin() ; i != devices.end() ; ++ i ) { if ( (*i)->getID() == id ) break; } if ( i != devices.end() ) { if ( !silent && current != devices.end() ) { snprintf(buffer, 64, "RGL device %d", (*current)->getID() ); (*current)->setName(buffer); } current = i; if ( !silent ) { snprintf(buffer, 64, "RGL device %d [Focus]", (*current)->getID() ); (*current)->setName(buffer); } return true; } else return false; } int DeviceManager::getCurrent() { if ( current != devices.end() ) return (*current)->getID(); else return 0; } int DeviceManager::getDeviceCount() { int result = 0; for (Container::iterator i = devices.begin(); i != devices.end() ; ++i, ++result); return result; } void DeviceManager::getDeviceIds(int *buffer, int bufsize) { int count = 0; for (Container::iterator i = devices.begin(); i != devices.end() && count < bufsize; ++i, ++count) { *(buffer++) = (*i)->getID(); } } /** * Device disposed handler **/ void DeviceManager::notifyDisposed(Disposable* disposed) { Container::iterator pos = std::find( devices.begin(), devices.end(), static_cast( disposed ) ); assert( pos != devices.end() ); if ( pos == current ) { if ( devices.size() == 1 ) current = devices.end(); else nextDevice(); } devices.erase(pos); } void DeviceManager::nextDevice() { if ( current != devices.end() ) { // cycle to next Iterator next = ++current; if ( next == devices.end() ) next = devices.begin(); setCurrent( (*next)->getID() ); } else { // ignore: no devices } } void DeviceManager::previousDevice() { if ( current != devices.end() ) { // cycle to previous Iterator prev = current; if (prev == devices.begin() ) prev = devices.end(); --prev; setCurrent( (*prev)->getID() ); } else { // ignore: no devices } } bool DeviceManager::createTestWindow() { bool result = false; Device* pDevice = new Device(newID, false, RGL_ANTIALIAS); if ( pDevice ) { if ( pDevice->hasWindow() ) result = true; pDevice->close(); delete pDevice; } return result; } rgl/src/pretty.h0000644000176200001440000000047114265301465013335 0ustar liggesusers#ifndef RGL_PRETTY_H #define RGL_PRETTY_H #ifdef __cplusplus extern "C" { #endif double R_pretty0(double *lo, double *up, int *ndiv, int min_n, double shrink_sml, double high_u_fact[], int eps_correction, int return_bounds); #ifdef __cplusplus } #endif #endif /* RGL_API_H */ rgl/src/build/0000755000176200001440000000000015026603601012723 5ustar liggesusersrgl/src/build/autoconf/0000755000176200001440000000000015011677075014553 5ustar liggesusersrgl/src/build/autoconf/install-sh0000755000176200001440000003610115011677075016560 0ustar liggesusers#!/bin/sh # install - install a program, script, or datafile scriptversion=2023-11-23.18; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. tab=' ' nl=' ' IFS=" $tab$nl" # Set DOITPROG to "echo" to test this script. doit=${DOITPROG-} doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_mkdir= # Desired mode of installed file. mode=0755 # Create dirs (including intermediate dirs) using mode 755. # This is like GNU 'install' as of coreutils 8.32 (2020). mkdir_umask=22 backupsuffix= chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -p pass -p to $cpprog. -s $stripprog installed files. -S SUFFIX attempt to back up existing files, with suffix SUFFIX. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG By default, rm is invoked with -f; when overridden with RMPROG, it's up to you to specify -f if you want it. If -S is not specified, no backups are attempted. Report bugs to . GNU Automake home page: . General help using GNU software: ." while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -p) cpprog="$cpprog -p";; -s) stripcmd=$stripprog;; -S) backupsuffix="$2" shift;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? # Don't chown directories that already exist. if test $dstdir_status = 0; then chowncmd="" fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dstbase=`basename "$src"` case $dst in */) dst=$dst$dstbase;; *) dst=$dst/$dstbase;; esac dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi case $dstdir in */) dstdirslash=$dstdir;; *) dstdirslash=$dstdir/;; esac obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false # The $RANDOM variable is not portable (e.g., dash). Use it # here however when possible just to lower collision chance. tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap ' ret=$? rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null exit $ret ' 0 # Because "mkdir -p" follows existing symlinks and we likely work # directly in world-writeable /tmp, make sure that the '$tmpdir' # directory is successfully created first before we actually test # 'mkdir -p'. if (umask $mkdir_umask && $mkdirprog $mkdir_mode "$tmpdir" && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. test_tmpdir="$tmpdir/a" ls_ld_tmpdir=`ls -ld "$test_tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi trap '' 0;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac oIFS=$IFS IFS=/ set -f set fnord $dstdir shift set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=${dstdirslash}_inst.$$_ rmtmp=${dstdirslash}_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && { test -z "$stripcmd" || { # Create $dsttmp read-write so that cp doesn't create it read-only, # which would cause strip to fail. if test -z "$doit"; then : >"$dsttmp" # No need to fork-exec 'touch'. else $doit touch "$dsttmp" fi } } && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # If $backupsuffix is set, and the file being installed # already exists, attempt a backup. Don't worry if it fails, # e.g., if mv doesn't support -f. if test -n "$backupsuffix" && test -f "$dst"; then $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null fi # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: rgl/src/build/autoconf/config.guess0000755000176200001440000014267615011677075017113 0ustar liggesusers#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2023 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2023-08-22' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.guess # # Please send patches to . # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system '$me' is run on. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try '$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi # Just in case it came from the environment. GUESS= # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, 'CC_FOR_BUILD' used to be named 'HOST_CC'. We still # use 'HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. tmp= # shellcheck disable=SC2172 trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 set_cc_for_build() { # prevent multiple calls if $tmp is already set test "$tmp" && return 0 : "${TMPDIR=/tmp}" # shellcheck disable=SC2039,SC3028 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } dummy=$tmp/dummy case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in ,,) echo "int x;" > "$dummy.c" for driver in cc gcc c89 c99 ; do if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then CC_FOR_BUILD=$driver break fi done if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac } # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case $UNAME_SYSTEM in Linux|GNU|GNU/*) LIBC=unknown set_cc_for_build cat <<-EOF > "$dummy.c" #if defined(__ANDROID__) LIBC=android #else #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #elif defined(__GLIBC__) LIBC=gnu #else #include /* First heuristic to detect musl libc. */ #ifdef __DEFINED_va_list LIBC=musl #endif #endif #endif EOF cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` eval "$cc_set_libc" # Second heuristic to detect musl libc. if [ "$LIBC" = unknown ] && command -v ldd >/dev/null && ldd --version 2>&1 | grep -q ^musl; then LIBC=musl fi # If the system lacks a compiler, then just pick glibc. # We could probably try harder. if [ "$LIBC" = unknown ]; then LIBC=gnu fi ;; esac # Note: order is significant - the case branches are not exclusive. case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ echo unknown)` case $UNAME_MACHINE_ARCH in aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine=${arch}${endian}-unknown ;; *) machine=$UNAME_MACHINE_ARCH-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. case $UNAME_MACHINE_ARCH in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # Determine ABI tags. case $UNAME_MACHINE_ARCH in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case $UNAME_VERSION in Debian*) release='-gnu' ;; *) release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. GUESS=$machine-${os}${release}${abi-} ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE ;; *:SecBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE ;; *:MidnightBSD:*:*) GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE ;; *:ekkoBSD:*:*) GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE ;; *:SolidBSD:*:*) GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE ;; *:OS108:*:*) GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE ;; macppc:MirBSD:*:*) GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE ;; *:MirBSD:*:*) GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE ;; *:Sortix:*:*) GUESS=$UNAME_MACHINE-unknown-sortix ;; *:Twizzler:*:*) GUESS=$UNAME_MACHINE-unknown-twizzler ;; *:Redox:*:*) GUESS=$UNAME_MACHINE-unknown-redox ;; mips:OSF1:*.*) GUESS=mips-dec-osf1 ;; alpha:OSF1:*:*) # Reset EXIT trap before exiting to avoid spurious non-zero exit code. trap '' 0 case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case $ALPHA_CPU_TYPE in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") UNAME_MACHINE=alpha ;; "EV5 (21164)") UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` GUESS=$UNAME_MACHINE-dec-osf$OSF_REL ;; Amiga*:UNIX_System_V:4.0:*) GUESS=m68k-unknown-sysv4 ;; *:[Aa]miga[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-amigaos ;; *:[Mm]orph[Oo][Ss]:*:*) GUESS=$UNAME_MACHINE-unknown-morphos ;; *:OS/390:*:*) GUESS=i370-ibm-openedition ;; *:z/VM:*:*) GUESS=s390-ibm-zvmoe ;; *:OS400:*:*) GUESS=powerpc-ibm-os400 ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) GUESS=arm-acorn-riscix$UNAME_RELEASE ;; arm*:riscos:*:*|arm*:RISCOS:*:*) GUESS=arm-unknown-riscos ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) GUESS=hppa1.1-hitachi-hiuxmpp ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. case `(/bin/universe) 2>/dev/null` in att) GUESS=pyramid-pyramid-sysv3 ;; *) GUESS=pyramid-pyramid-bsd ;; esac ;; NILE*:*:*:dcosx) GUESS=pyramid-pyramid-svr4 ;; DRS?6000:unix:4.0:6*) GUESS=sparc-icl-nx6 ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) GUESS=sparc-icl-nx7 ;; esac ;; s390x:SunOS:*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL ;; sun4H:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-hal-solaris2$SUN_REL ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris2$SUN_REL ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) GUESS=i386-pc-auroraux$UNAME_RELEASE ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=$SUN_ARCH-pc-solaris2$SUN_REL ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=sparc-sun-solaris3$SUN_REL ;; sun4*:SunOS:*:*) case `/usr/bin/arch -k` in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like '4.1.3-JL'. SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` GUESS=sparc-sun-sunos$SUN_REL ;; sun3*:SunOS:*:*) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 case `/bin/arch` in sun3) GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun4) GUESS=sparc-sun-sunos$UNAME_RELEASE ;; esac ;; aushp:SunOS:*:*) GUESS=sparc-auspex-sunos$UNAME_RELEASE ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) GUESS=m68k-atari-mint$UNAME_RELEASE ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) GUESS=m68k-milan-mint$UNAME_RELEASE ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) GUESS=m68k-hades-mint$UNAME_RELEASE ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) GUESS=m68k-unknown-mint$UNAME_RELEASE ;; m68k:machten:*:*) GUESS=m68k-apple-machten$UNAME_RELEASE ;; powerpc:machten:*:*) GUESS=powerpc-apple-machten$UNAME_RELEASE ;; RISC*:Mach:*:*) GUESS=mips-dec-mach_bsd4.3 ;; RISC*:ULTRIX:*:*) GUESS=mips-dec-ultrix$UNAME_RELEASE ;; VAX*:ULTRIX*:*:*) GUESS=vax-dec-ultrix$UNAME_RELEASE ;; 2020:CLIX:*:* | 2430:CLIX:*:*) GUESS=clipper-intergraph-clix$UNAME_RELEASE ;; mips:*:*:UMIPS | mips:*:*:RISCos) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } GUESS=mips-mips-riscos$UNAME_RELEASE ;; Motorola:PowerMAX_OS:*:*) GUESS=powerpc-motorola-powermax ;; Motorola:*:4.3:PL8-*) GUESS=powerpc-harris-powermax ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) GUESS=powerpc-harris-powermax ;; Night_Hawk:Power_UNIX:*:*) GUESS=powerpc-harris-powerunix ;; m88k:CX/UX:7*:*) GUESS=m88k-harris-cxux7 ;; m88k:*:4*:R4*) GUESS=m88k-motorola-sysv4 ;; m88k:*:3*:R3*) GUESS=m88k-motorola-sysv3 ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ test "$TARGET_BINARY_INTERFACE"x = x then GUESS=m88k-dg-dgux$UNAME_RELEASE else GUESS=m88k-dg-dguxbcs$UNAME_RELEASE fi else GUESS=i586-dg-dgux$UNAME_RELEASE fi ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) GUESS=m88k-dolphin-sysv3 ;; M88*:*:R3*:*) # Delta 88k system running SVR3 GUESS=m88k-motorola-sysv3 ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) GUESS=m88k-tektronix-sysv3 ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) GUESS=m68k-tektronix-bsd ;; *:IRIX*:*:*) IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` GUESS=mips-sgi-irix$IRIX_REL ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) GUESS=i386-ibm-aix ;; ia64:AIX:*:*) if test -x /usr/bin/oslevel ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then GUESS=$SYSTEM_NAME else GUESS=rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then GUESS=rs6000-ibm-aix3.2.4 else GUESS=rs6000-ibm-aix3.2 fi ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if test -x /usr/bin/lslpp ; then IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi GUESS=$IBM_ARCH-ibm-aix$IBM_REV ;; *:AIX:*:*) GUESS=rs6000-ibm-aix ;; ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) GUESS=romp-ibm-bsd4.4 ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) GUESS=rs6000-bull-bosx ;; DPX/2?00:B.O.S.:*:*) GUESS=m68k-bull-sysv3 ;; 9000/[34]??:4.3bsd:1.*:*) GUESS=m68k-hp-bsd ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) GUESS=m68k-hp-bsd4.4 ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` case $UNAME_MACHINE in 9000/31?) HP_ARCH=m68000 ;; 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if test -x /usr/bin/getconf; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case $sc_cpu_version in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case $sc_kernel_bits in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi if test "$HP_ARCH" = ""; then set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if test "$HP_ARCH" = hppa2.0w then set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH=hppa2.0w else HP_ARCH=hppa64 fi fi GUESS=$HP_ARCH-hp-hpux$HPUX_REV ;; ia64:HP-UX:*:*) HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` GUESS=ia64-hp-hpux$HPUX_REV ;; 3050*:HI-UX:*:*) set_cc_for_build sed 's/^ //' << EOF > "$dummy.c" #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } GUESS=unknown-hitachi-hiuxwe2 ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) GUESS=hppa1.1-hp-bsd ;; 9000/8??:4.3bsd:*:*) GUESS=hppa1.0-hp-bsd ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) GUESS=hppa1.0-hp-mpeix ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) GUESS=hppa1.1-hp-osf ;; hp8??:OSF1:*:*) GUESS=hppa1.0-hp-osf ;; i*86:OSF1:*:*) if test -x /usr/sbin/sysversion ; then GUESS=$UNAME_MACHINE-unknown-osf1mk else GUESS=$UNAME_MACHINE-unknown-osf1 fi ;; parisc*:Lites*:*:*) GUESS=hppa1.1-hp-lites ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) GUESS=c1-convex-bsd ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) GUESS=c34-convex-bsd ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) GUESS=c38-convex-bsd ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) GUESS=c4-convex-bsd ;; CRAY*Y-MP:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=ymp-cray-unicos$CRAY_REL ;; CRAY*[A-Z]90:*:*:*) echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=t90-cray-unicos$CRAY_REL ;; CRAY*T3E:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=alphaev5-cray-unicosmk$CRAY_REL ;; CRAY*SV1:*:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=sv1-cray-unicos$CRAY_REL ;; *:UNICOS/mp:*:*) CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` GUESS=craynv-cray-unicosmp$CRAY_REL ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE ;; sparc*:BSD/OS:*:*) GUESS=sparc-unknown-bsdi$UNAME_RELEASE ;; *:BSD/OS:*:*) GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE ;; arm:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` set_cc_for_build if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi else FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf fi ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in amd64) UNAME_PROCESSOR=x86_64 ;; i386) UNAME_PROCESSOR=i586 ;; esac FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL ;; i*:CYGWIN*:*) GUESS=$UNAME_MACHINE-pc-cygwin ;; *:MINGW64*:*) GUESS=$UNAME_MACHINE-pc-mingw64 ;; *:MINGW*:*) GUESS=$UNAME_MACHINE-pc-mingw32 ;; *:MSYS*:*) GUESS=$UNAME_MACHINE-pc-msys ;; i*:PW*:*) GUESS=$UNAME_MACHINE-pc-pw32 ;; *:SerenityOS:*:*) GUESS=$UNAME_MACHINE-pc-serenity ;; *:Interix*:*) case $UNAME_MACHINE in x86) GUESS=i586-pc-interix$UNAME_RELEASE ;; authenticamd | genuineintel | EM64T) GUESS=x86_64-unknown-interix$UNAME_RELEASE ;; IA64) GUESS=ia64-unknown-interix$UNAME_RELEASE ;; esac ;; i*:UWIN*:*) GUESS=$UNAME_MACHINE-pc-uwin ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) GUESS=x86_64-pc-cygwin ;; prep*:SunOS:5.*:*) SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` GUESS=powerpcle-unknown-solaris2$SUN_REL ;; *:GNU:*:*) # the GNU system GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL ;; *:GNU/*:*:*) # other systems with GNU libc and userland GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC ;; x86_64:[Mm]anagarm:*:*|i?86:[Mm]anagarm:*:*) GUESS="$UNAME_MACHINE-pc-managarm-mlibc" ;; *:[Mm]anagarm:*:*) GUESS="$UNAME_MACHINE-unknown-managarm-mlibc" ;; *:Minix:*:*) GUESS=$UNAME_MACHINE-unknown-minix ;; aarch64:Linux:*:*) set_cc_for_build CPU=$UNAME_MACHINE LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then ABI=64 sed 's/^ //' << EOF > "$dummy.c" #ifdef __ARM_EABI__ #ifdef __ARM_PCS_VFP ABI=eabihf #else ABI=eabi #endif #endif EOF cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` eval "$cc_set_abi" case $ABI in eabi | eabihf) CPU=armv8l; LIBCABI=$LIBC$ABI ;; esac fi GUESS=$CPU-unknown-linux-$LIBCABI ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; arm*:Linux:*:*) set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then GUESS=$UNAME_MACHINE-unknown-linux-$LIBC else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi else GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf fi fi ;; avr32*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; cris:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; crisv32:Linux:*:*) GUESS=$UNAME_MACHINE-axis-linux-$LIBC ;; e2k:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; frv:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; hexagon:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:Linux:*:*) GUESS=$UNAME_MACHINE-pc-linux-$LIBC ;; ia64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; k1om:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; kvx:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; kvx:cos:*:*) GUESS=$UNAME_MACHINE-unknown-cos ;; kvx:mbr:*:*) GUESS=$UNAME_MACHINE-unknown-mbr ;; loongarch32:Linux:*:* | loongarch64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m32r*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; m68*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; mips:Linux:*:* | mips64:Linux:*:*) set_cc_for_build IS_GLIBC=0 test x"${LIBC}" = xgnu && IS_GLIBC=1 sed 's/^ //' << EOF > "$dummy.c" #undef CPU #undef mips #undef mipsel #undef mips64 #undef mips64el #if ${IS_GLIBC} && defined(_ABI64) LIBCABI=gnuabi64 #else #if ${IS_GLIBC} && defined(_ABIN32) LIBCABI=gnuabin32 #else LIBCABI=${LIBC} #endif #endif #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa64r6 #else #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 CPU=mipsisa32r6 #else #if defined(__mips64) CPU=mips64 #else CPU=mips #endif #endif #endif #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) MIPS_ENDIAN=el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) MIPS_ENDIAN= #else MIPS_ENDIAN= #endif #endif EOF cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` eval "$cc_set_vars" test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; openrisc*:Linux:*:*) GUESS=or1k-unknown-linux-$LIBC ;; or32:Linux:*:* | or1k*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; padre:Linux:*:*) GUESS=sparc-unknown-linux-$LIBC ;; parisc64:Linux:*:* | hppa64:Linux:*:*) GUESS=hppa64-unknown-linux-$LIBC ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; *) GUESS=hppa-unknown-linux-$LIBC ;; esac ;; ppc64:Linux:*:*) GUESS=powerpc64-unknown-linux-$LIBC ;; ppc:Linux:*:*) GUESS=powerpc-unknown-linux-$LIBC ;; ppc64le:Linux:*:*) GUESS=powerpc64le-unknown-linux-$LIBC ;; ppcle:Linux:*:*) GUESS=powerpcle-unknown-linux-$LIBC ;; riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; s390:Linux:*:* | s390x:Linux:*:*) GUESS=$UNAME_MACHINE-ibm-linux-$LIBC ;; sh64*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sh*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; sparc:Linux:*:* | sparc64:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; tile*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; vax:Linux:*:*) GUESS=$UNAME_MACHINE-dec-linux-$LIBC ;; x86_64:Linux:*:*) set_cc_for_build CPU=$UNAME_MACHINE LIBCABI=$LIBC if test "$CC_FOR_BUILD" != no_compiler_found; then ABI=64 sed 's/^ //' << EOF > "$dummy.c" #ifdef __i386__ ABI=x86 #else #ifdef __ILP32__ ABI=x32 #endif #endif EOF cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` eval "$cc_set_abi" case $ABI in x86) CPU=i686 ;; x32) LIBCABI=${LIBC}x32 ;; esac fi GUESS=$CPU-pc-linux-$LIBCABI ;; xtensa*:Linux:*:*) GUESS=$UNAME_MACHINE-unknown-linux-$LIBC ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. GUESS=i386-sequent-sysv4 ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION ;; i*86:OS/2:*:*) # If we were able to find 'uname', then EMX Unix compatibility # is probably installed. GUESS=$UNAME_MACHINE-pc-os2-emx ;; i*86:XTS-300:*:STOP) GUESS=$UNAME_MACHINE-unknown-stop ;; i*86:atheos:*:*) GUESS=$UNAME_MACHINE-unknown-atheos ;; i*86:syllable:*:*) GUESS=$UNAME_MACHINE-pc-syllable ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) GUESS=i386-unknown-lynxos$UNAME_RELEASE ;; i*86:*DOS:*:*) GUESS=$UNAME_MACHINE-pc-msdosdjgpp ;; i*86:*:4.*:*) UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL fi ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL else GUESS=$UNAME_MACHINE-pc-sysv32 fi ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. GUESS=i586-pc-msdosdjgpp ;; Intel:Mach:3*:*) GUESS=i386-pc-mach3 ;; paragon:*:*:*) GUESS=i860-intel-osf1 ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 fi ;; mini*:CTIX:SYS*5:*) # "miniframe" GUESS=m68010-convergent-sysv ;; mc68k:UNIX:SYSTEM5:3.51m) GUESS=m68k-convergent-sysv ;; M680?0:D-NIX:5.3:*) GUESS=m68k-diab-dnix ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) GUESS=m68k-unknown-lynxos$UNAME_RELEASE ;; mc68030:UNIX_System_V:4.*:*) GUESS=m68k-atari-sysv4 ;; TSUNAMI:LynxOS:2.*:*) GUESS=sparc-unknown-lynxos$UNAME_RELEASE ;; rs6000:LynxOS:2.*:*) GUESS=rs6000-unknown-lynxos$UNAME_RELEASE ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) GUESS=powerpc-unknown-lynxos$UNAME_RELEASE ;; SM[BE]S:UNIX_SV:*:*) GUESS=mips-dde-sysv$UNAME_RELEASE ;; RM*:ReliantUNIX-*:*:*) GUESS=mips-sni-sysv4 ;; RM*:SINIX-*:*:*) GUESS=mips-sni-sysv4 ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` GUESS=$UNAME_MACHINE-sni-sysv4 else GUESS=ns32k-sni-sysv fi ;; PENTIUM:*:4.0*:*) # Unisys 'ClearPath HMP IX 4000' SVR4/MP effort # says GUESS=i586-unisys-sysv4 ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm GUESS=hppa1.1-stratus-sysv4 ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. GUESS=i860-stratus-sysv4 ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. GUESS=$UNAME_MACHINE-stratus-vos ;; *:VOS:*:*) # From Paul.Green@stratus.com. GUESS=hppa1.1-stratus-vos ;; mc68*:A/UX:*:*) GUESS=m68k-apple-aux$UNAME_RELEASE ;; news*:NEWS-OS:6*:*) GUESS=mips-sony-newsos6 ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if test -d /usr/nec; then GUESS=mips-nec-sysv$UNAME_RELEASE else GUESS=mips-unknown-sysv$UNAME_RELEASE fi ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. GUESS=powerpc-be-beos ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. GUESS=powerpc-apple-beos ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. GUESS=i586-pc-beos ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. GUESS=i586-pc-haiku ;; ppc:Haiku:*:*) # Haiku running on Apple PowerPC GUESS=powerpc-apple-haiku ;; *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) GUESS=$UNAME_MACHINE-unknown-haiku ;; SX-4:SUPER-UX:*:*) GUESS=sx4-nec-superux$UNAME_RELEASE ;; SX-5:SUPER-UX:*:*) GUESS=sx5-nec-superux$UNAME_RELEASE ;; SX-6:SUPER-UX:*:*) GUESS=sx6-nec-superux$UNAME_RELEASE ;; SX-7:SUPER-UX:*:*) GUESS=sx7-nec-superux$UNAME_RELEASE ;; SX-8:SUPER-UX:*:*) GUESS=sx8-nec-superux$UNAME_RELEASE ;; SX-8R:SUPER-UX:*:*) GUESS=sx8r-nec-superux$UNAME_RELEASE ;; SX-ACE:SUPER-UX:*:*) GUESS=sxace-nec-superux$UNAME_RELEASE ;; Power*:Rhapsody:*:*) GUESS=powerpc-apple-rhapsody$UNAME_RELEASE ;; *:Rhapsody:*:*) GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE ;; arm64:Darwin:*:*) GUESS=aarch64-apple-darwin$UNAME_RELEASE ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac if command -v xcode-select > /dev/null 2> /dev/null && \ ! xcode-select --print-path > /dev/null 2> /dev/null ; then # Avoid executing cc if there is no toolchain installed as # cc will be a stub that puts up a graphical alert # prompting the user to install developer tools. CC_FOR_BUILD=no_compiler_found else set_cc_for_build fi if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_PPC >/dev/null then UNAME_PROCESSOR=powerpc fi elif test "$UNAME_PROCESSOR" = i386 ; then # uname -m returns i386 or x86_64 UNAME_PROCESSOR=$UNAME_MACHINE fi GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE ;; *:QNX:*:4*) GUESS=i386-pc-qnx ;; NEO-*:NONSTOP_KERNEL:*:*) GUESS=neo-tandem-nsk$UNAME_RELEASE ;; NSE-*:NONSTOP_KERNEL:*:*) GUESS=nse-tandem-nsk$UNAME_RELEASE ;; NSR-*:NONSTOP_KERNEL:*:*) GUESS=nsr-tandem-nsk$UNAME_RELEASE ;; NSV-*:NONSTOP_KERNEL:*:*) GUESS=nsv-tandem-nsk$UNAME_RELEASE ;; NSX-*:NONSTOP_KERNEL:*:*) GUESS=nsx-tandem-nsk$UNAME_RELEASE ;; *:NonStop-UX:*:*) GUESS=mips-compaq-nonstopux ;; BS2000:POSIX*:*:*) GUESS=bs2000-siemens-sysv ;; DS/*:UNIX_System_V:*:*) GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "${cputype-}" = 386; then UNAME_MACHINE=i386 elif test "x${cputype-}" != x; then UNAME_MACHINE=$cputype fi GUESS=$UNAME_MACHINE-unknown-plan9 ;; *:TOPS-10:*:*) GUESS=pdp10-unknown-tops10 ;; *:TENEX:*:*) GUESS=pdp10-unknown-tenex ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) GUESS=pdp10-dec-tops20 ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) GUESS=pdp10-xkl-tops20 ;; *:TOPS-20:*:*) GUESS=pdp10-unknown-tops20 ;; *:ITS:*:*) GUESS=pdp10-unknown-its ;; SEI:*:*:SEIUX) GUESS=mips-sei-seiux$UNAME_RELEASE ;; *:DragonFly:*:*) DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case $UNAME_MACHINE in A*) GUESS=alpha-dec-vms ;; I*) GUESS=ia64-dec-vms ;; V*) GUESS=vax-dec-vms ;; esac ;; *:XENIX:*:SysV) GUESS=i386-pc-xenix ;; i*86:skyos:*:*) SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL ;; i*86:rdos:*:*) GUESS=$UNAME_MACHINE-pc-rdos ;; i*86:Fiwix:*:*) GUESS=$UNAME_MACHINE-pc-fiwix ;; *:AROS:*:*) GUESS=$UNAME_MACHINE-unknown-aros ;; x86_64:VMkernel:*:*) GUESS=$UNAME_MACHINE-unknown-esx ;; amd64:Isilon\ OneFS:*:*) GUESS=x86_64-unknown-onefs ;; *:Unleashed:*:*) GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE ;; esac # Do we have a guess based on uname results? if test "x$GUESS" != x; then echo "$GUESS" exit fi # No uname command or uname output not recognized. set_cc_for_build cat > "$dummy.c" < #include #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #include #if defined(_SIZE_T_) || defined(SIGLOST) #include #endif #endif #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) #if !defined (ultrix) #include #if defined (BSD) #if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); #else #if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); #else printf ("vax-dec-bsd\n"); exit (0); #endif #endif #else printf ("vax-dec-bsd\n"); exit (0); #endif #else #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname un; uname (&un); printf ("vax-dec-ultrix%s\n", un.release); exit (0); #else printf ("vax-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) #if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) #if defined(_SIZE_T_) || defined(SIGLOST) struct utsname *un; uname (&un); printf ("mips-dec-ultrix%s\n", un.release); exit (0); #else printf ("mips-dec-ultrix\n"); exit (0); #endif #endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } echo "$0: unable to guess system type" >&2 case $UNAME_MACHINE:$UNAME_SYSTEM in mips:Linux | mips64:Linux) # If we got here on MIPS GNU/Linux, output extra information. cat >&2 <&2 <&2 </dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = "$UNAME_MACHINE" UNAME_RELEASE = "$UNAME_RELEASE" UNAME_SYSTEM = "$UNAME_SYSTEM" UNAME_VERSION = "$UNAME_VERSION" EOF fi exit 1 # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: rgl/src/build/autoconf/config.sub0000755000176200001440000010720215011677075016540 0ustar liggesusers#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2023 Free Software Foundation, Inc. # shellcheck disable=SC2006,SC2268 # see below for rationale timestamp='2023-09-19' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # https://git.savannah.gnu.org/cgit/config.git/plain/config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. # The "shellcheck disable" line above the timestamp inhibits complaints # about features and limitations of the classic Bourne shell that were # superseded or lifted in POSIX. However, this script identifies a wide # variety of pre-POSIX systems that do not have POSIX shells at all, and # even some reasonably current systems (Solaris 10 as case-in-point) still # have a pre-POSIX /bin/sh. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2023 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try '$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. echo "$1" exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Split fields of configuration type # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read field1 field2 field3 field4 <&2 exit 1 ;; *-*-*-*) basic_machine=$field1-$field2 basic_os=$field3-$field4 ;; *-*-*) # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two # parts maybe_os=$field2-$field3 case $maybe_os in nto-qnx* | linux-* | uclinux-uclibc* \ | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ | storm-chaos* | os2-emx* | rtmk-nova* | managarm-* \ | windows-* ) basic_machine=$field1 basic_os=$maybe_os ;; android-linux) basic_machine=$field1-unknown basic_os=linux-android ;; *) basic_machine=$field1-$field2 basic_os=$field3 ;; esac ;; *-*) # A lone config we happen to match not fitting any pattern case $field1-$field2 in decstation-3100) basic_machine=mips-dec basic_os= ;; *-*) # Second component is usually, but not always the OS case $field2 in # Prevent following clause from handling this valid os sun*os*) basic_machine=$field1 basic_os=$field2 ;; zephyr*) basic_machine=$field1-unknown basic_os=$field2 ;; # Manufacturers dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ | unicom* | ibm* | next | hp | isi* | apollo | altos* \ | convergent* | ncr* | news | 32* | 3600* | 3100* \ | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ | ultra | tti* | harris | dolphin | highlevel | gould \ | cbm | ns | masscomp | apple | axis | knuth | cray \ | microblaze* | sim | cisco \ | oki | wec | wrs | winbond) basic_machine=$field1-$field2 basic_os= ;; *) basic_machine=$field1 basic_os=$field2 ;; esac ;; esac ;; *) # Convert single-component short-hands not valid as part of # multi-component configurations. case $field1 in 386bsd) basic_machine=i386-pc basic_os=bsd ;; a29khif) basic_machine=a29k-amd basic_os=udi ;; adobe68k) basic_machine=m68010-adobe basic_os=scout ;; alliant) basic_machine=fx80-alliant basic_os= ;; altos | altos3068) basic_machine=m68k-altos basic_os= ;; am29k) basic_machine=a29k-none basic_os=bsd ;; amdahl) basic_machine=580-amdahl basic_os=sysv ;; amiga) basic_machine=m68k-unknown basic_os= ;; amigaos | amigados) basic_machine=m68k-unknown basic_os=amigaos ;; amigaunix | amix) basic_machine=m68k-unknown basic_os=sysv4 ;; apollo68) basic_machine=m68k-apollo basic_os=sysv ;; apollo68bsd) basic_machine=m68k-apollo basic_os=bsd ;; aros) basic_machine=i386-pc basic_os=aros ;; aux) basic_machine=m68k-apple basic_os=aux ;; balance) basic_machine=ns32k-sequent basic_os=dynix ;; blackfin) basic_machine=bfin-unknown basic_os=linux ;; cegcc) basic_machine=arm-unknown basic_os=cegcc ;; convex-c1) basic_machine=c1-convex basic_os=bsd ;; convex-c2) basic_machine=c2-convex basic_os=bsd ;; convex-c32) basic_machine=c32-convex basic_os=bsd ;; convex-c34) basic_machine=c34-convex basic_os=bsd ;; convex-c38) basic_machine=c38-convex basic_os=bsd ;; cray) basic_machine=j90-cray basic_os=unicos ;; crds | unos) basic_machine=m68k-crds basic_os= ;; da30) basic_machine=m68k-da30 basic_os= ;; decstation | pmax | pmin | dec3100 | decstatn) basic_machine=mips-dec basic_os= ;; delta88) basic_machine=m88k-motorola basic_os=sysv3 ;; dicos) basic_machine=i686-pc basic_os=dicos ;; djgpp) basic_machine=i586-pc basic_os=msdosdjgpp ;; ebmon29k) basic_machine=a29k-amd basic_os=ebmon ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson basic_os=ose ;; gmicro) basic_machine=tron-gmicro basic_os=sysv ;; go32) basic_machine=i386-pc basic_os=go32 ;; h8300hms) basic_machine=h8300-hitachi basic_os=hms ;; h8300xray) basic_machine=h8300-hitachi basic_os=xray ;; h8500hms) basic_machine=h8500-hitachi basic_os=hms ;; harris) basic_machine=m88k-harris basic_os=sysv3 ;; hp300 | hp300hpux) basic_machine=m68k-hp basic_os=hpux ;; hp300bsd) basic_machine=m68k-hp basic_os=bsd ;; hppaosf) basic_machine=hppa1.1-hp basic_os=osf ;; hppro) basic_machine=hppa1.1-hp basic_os=proelf ;; i386mach) basic_machine=i386-mach basic_os=mach ;; isi68 | isi) basic_machine=m68k-isi basic_os=sysv ;; m68knommu) basic_machine=m68k-unknown basic_os=linux ;; magnum | m3230) basic_machine=mips-mips basic_os=sysv ;; merlin) basic_machine=ns32k-utek basic_os=sysv ;; mingw64) basic_machine=x86_64-pc basic_os=mingw64 ;; mingw32) basic_machine=i686-pc basic_os=mingw32 ;; mingw32ce) basic_machine=arm-unknown basic_os=mingw32ce ;; monitor) basic_machine=m68k-rom68k basic_os=coff ;; morphos) basic_machine=powerpc-unknown basic_os=morphos ;; moxiebox) basic_machine=moxie-unknown basic_os=moxiebox ;; msdos) basic_machine=i386-pc basic_os=msdos ;; msys) basic_machine=i686-pc basic_os=msys ;; mvs) basic_machine=i370-ibm basic_os=mvs ;; nacl) basic_machine=le32-unknown basic_os=nacl ;; ncr3000) basic_machine=i486-ncr basic_os=sysv4 ;; netbsd386) basic_machine=i386-pc basic_os=netbsd ;; netwinder) basic_machine=armv4l-rebel basic_os=linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony basic_os=newsos ;; news1000) basic_machine=m68030-sony basic_os=newsos ;; necv70) basic_machine=v70-nec basic_os=sysv ;; nh3000) basic_machine=m68k-harris basic_os=cxux ;; nh[45]000) basic_machine=m88k-harris basic_os=cxux ;; nindy960) basic_machine=i960-intel basic_os=nindy ;; mon960) basic_machine=i960-intel basic_os=mon960 ;; nonstopux) basic_machine=mips-compaq basic_os=nonstopux ;; os400) basic_machine=powerpc-ibm basic_os=os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson basic_os=ose ;; os68k) basic_machine=m68k-none basic_os=os68k ;; paragon) basic_machine=i860-intel basic_os=osf ;; parisc) basic_machine=hppa-unknown basic_os=linux ;; psp) basic_machine=mipsallegrexel-sony basic_os=psp ;; pw32) basic_machine=i586-unknown basic_os=pw32 ;; rdos | rdos64) basic_machine=x86_64-pc basic_os=rdos ;; rdos32) basic_machine=i386-pc basic_os=rdos ;; rom68k) basic_machine=m68k-rom68k basic_os=coff ;; sa29200) basic_machine=a29k-amd basic_os=udi ;; sei) basic_machine=mips-sei basic_os=seiux ;; sequent) basic_machine=i386-sequent basic_os= ;; sps7) basic_machine=m68k-bull basic_os=sysv2 ;; st2000) basic_machine=m68k-tandem basic_os= ;; stratus) basic_machine=i860-stratus basic_os=sysv4 ;; sun2) basic_machine=m68000-sun basic_os= ;; sun2os3) basic_machine=m68000-sun basic_os=sunos3 ;; sun2os4) basic_machine=m68000-sun basic_os=sunos4 ;; sun3) basic_machine=m68k-sun basic_os= ;; sun3os3) basic_machine=m68k-sun basic_os=sunos3 ;; sun3os4) basic_machine=m68k-sun basic_os=sunos4 ;; sun4) basic_machine=sparc-sun basic_os= ;; sun4os3) basic_machine=sparc-sun basic_os=sunos3 ;; sun4os4) basic_machine=sparc-sun basic_os=sunos4 ;; sun4sol2) basic_machine=sparc-sun basic_os=solaris2 ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun basic_os= ;; sv1) basic_machine=sv1-cray basic_os=unicos ;; symmetry) basic_machine=i386-sequent basic_os=dynix ;; t3e) basic_machine=alphaev5-cray basic_os=unicos ;; t90) basic_machine=t90-cray basic_os=unicos ;; toad1) basic_machine=pdp10-xkl basic_os=tops20 ;; tpf) basic_machine=s390x-ibm basic_os=tpf ;; udi29k) basic_machine=a29k-amd basic_os=udi ;; ultra3) basic_machine=a29k-nyu basic_os=sym1 ;; v810 | necv810) basic_machine=v810-nec basic_os=none ;; vaxv) basic_machine=vax-dec basic_os=sysv ;; vms) basic_machine=vax-dec basic_os=vms ;; vsta) basic_machine=i386-pc basic_os=vsta ;; vxworks960) basic_machine=i960-wrs basic_os=vxworks ;; vxworks68) basic_machine=m68k-wrs basic_os=vxworks ;; vxworks29k) basic_machine=a29k-wrs basic_os=vxworks ;; xbox) basic_machine=i686-pc basic_os=mingw32 ;; ymp) basic_machine=ymp-cray basic_os=unicos ;; *) basic_machine=$1 basic_os= ;; esac ;; esac # Decode 1-component or ad-hoc basic machines case $basic_machine in # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) cpu=hppa1.1 vendor=winbond ;; op50n) cpu=hppa1.1 vendor=oki ;; op60c) cpu=hppa1.1 vendor=oki ;; ibm*) cpu=i370 vendor=ibm ;; orion105) cpu=clipper vendor=highlevel ;; mac | mpw | mac-mpw) cpu=m68k vendor=apple ;; pmac | pmac-mpw) cpu=powerpc vendor=apple ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) cpu=m68000 vendor=att ;; 3b*) cpu=we32k vendor=att ;; bluegene*) cpu=powerpc vendor=ibm basic_os=cnk ;; decsystem10* | dec10*) cpu=pdp10 vendor=dec basic_os=tops10 ;; decsystem20* | dec20*) cpu=pdp10 vendor=dec basic_os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) cpu=m68k vendor=motorola ;; dpx2*) cpu=m68k vendor=bull basic_os=sysv3 ;; encore | umax | mmax) cpu=ns32k vendor=encore ;; elxsi) cpu=elxsi vendor=elxsi basic_os=${basic_os:-bsd} ;; fx2800) cpu=i860 vendor=alliant ;; genix) cpu=ns32k vendor=ns ;; h3050r* | hiux*) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) cpu=m68000 vendor=hp ;; hp9k3[2-9][0-9]) cpu=m68k vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) cpu=hppa1.1 vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) cpu=hppa1.1 vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) cpu=hppa1.0 vendor=hp ;; i*86v32) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv32 ;; i*86v4*) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv4 ;; i*86v) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=sysv ;; i*86sol2) cpu=`echo "$1" | sed -e 's/86.*/86/'` vendor=pc basic_os=solaris2 ;; j90 | j90-cray) cpu=j90 vendor=cray basic_os=${basic_os:-unicos} ;; iris | iris4d) cpu=mips vendor=sgi case $basic_os in irix*) ;; *) basic_os=irix4 ;; esac ;; miniframe) cpu=m68000 vendor=convergent ;; *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) cpu=m68k vendor=atari basic_os=mint ;; news-3600 | risc-news) cpu=mips vendor=sony basic_os=newsos ;; next | m*-next) cpu=m68k vendor=next case $basic_os in openstep*) ;; nextstep*) ;; ns2*) basic_os=nextstep2 ;; *) basic_os=nextstep3 ;; esac ;; np1) cpu=np1 vendor=gould ;; op50n-* | op60c-*) cpu=hppa1.1 vendor=oki basic_os=proelf ;; pa-hitachi) cpu=hppa1.1 vendor=hitachi basic_os=hiuxwe2 ;; pbd) cpu=sparc vendor=tti ;; pbb) cpu=m68k vendor=tti ;; pc532) cpu=ns32k vendor=pc532 ;; pn) cpu=pn vendor=gould ;; power) cpu=power vendor=ibm ;; ps2) cpu=i386 vendor=ibm ;; rm[46]00) cpu=mips vendor=siemens ;; rtpc | rtpc-*) cpu=romp vendor=ibm ;; sde) cpu=mipsisa32 vendor=sde basic_os=${basic_os:-elf} ;; simso-wrs) cpu=sparclite vendor=wrs basic_os=vxworks ;; tower | tower-32) cpu=m68k vendor=ncr ;; vpp*|vx|vx-*) cpu=f301 vendor=fujitsu ;; w65) cpu=w65 vendor=wdc ;; w89k-*) cpu=hppa1.1 vendor=winbond basic_os=proelf ;; none) cpu=none vendor=none ;; leon|leon[3-9]) cpu=sparc vendor=$basic_machine ;; leon-*|leon[3-9]-*) cpu=sparc vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read cpu vendor <&2 exit 1 ;; esac ;; esac # Here we canonicalize certain aliases for manufacturers. case $vendor in digital*) vendor=dec ;; commodore*) vendor=cbm ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if test x"$basic_os" != x then # First recognize some ad-hoc cases, or perhaps split kernel-os, or else just # set os. obj= case $basic_os in gnu/linux*) kernel=linux os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` ;; os2-emx) kernel=os2 os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` ;; nto-qnx*) kernel=nto os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` ;; *-*) # shellcheck disable=SC2162 saved_IFS=$IFS IFS="-" read kernel os <&2 fi ;; *) echo "Invalid configuration '$1': OS '$os' not recognized" 1>&2 exit 1 ;; esac case $obj in aout* | coff* | elf* | pe*) ;; '') # empty is fine ;; *) echo "Invalid configuration '$1': Machine code format '$obj' not recognized" 1>&2 exit 1 ;; esac # Here we handle the constraint that a (synthetic) cpu and os are # valid only in combination with each other and nowhere else. case $cpu-$os in # The "javascript-unknown-ghcjs" triple is used by GHC; we # accept it here in order to tolerate that, but reject any # variations. javascript-ghcjs) ;; javascript-* | *-ghcjs) echo "Invalid configuration '$1': cpu '$cpu' is not valid with os '$os$obj'" 1>&2 exit 1 ;; esac # As a final step for OS-related things, validate the OS-kernel combination # (given a valid OS), if there is a kernel. case $kernel-$os-$obj in linux-gnu*- | linux-dietlibc*- | linux-android*- | linux-newlib*- \ | linux-musl*- | linux-relibc*- | linux-uclibc*- | linux-mlibc*- ) ;; uclinux-uclibc*- ) ;; managarm-mlibc*- | managarm-kernel*- ) ;; windows*-msvc*-) ;; -dietlibc*- | -newlib*- | -musl*- | -relibc*- | -uclibc*- | -mlibc*- ) # These are just libc implementations, not actual OSes, and thus # require a kernel. echo "Invalid configuration '$1': libc '$os' needs explicit kernel." 1>&2 exit 1 ;; -kernel*- ) echo "Invalid configuration '$1': '$os' needs explicit kernel." 1>&2 exit 1 ;; *-kernel*- ) echo "Invalid configuration '$1': '$kernel' does not support '$os'." 1>&2 exit 1 ;; *-msvc*- ) echo "Invalid configuration '$1': '$os' needs 'windows'." 1>&2 exit 1 ;; kfreebsd*-gnu*- | kopensolaris*-gnu*-) ;; vxworks-simlinux- | vxworks-simwindows- | vxworks-spe-) ;; nto-qnx*-) ;; os2-emx-) ;; *-eabi*- | *-gnueabi*-) ;; none--*) # None (no kernel, i.e. freestanding / bare metal), # can be paired with an machine code file format ;; -*-) # Blank kernel with real OS is always fine. ;; --*) # Blank kernel and OS with real machine code file format is always fine. ;; *-*-*) echo "Invalid configuration '$1': Kernel '$kernel' not known to work with OS '$os'." 1>&2 exit 1 ;; esac # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. case $vendor in unknown) case $cpu-$os in *-riscix*) vendor=acorn ;; *-sunos*) vendor=sun ;; *-cnk* | *-aix*) vendor=ibm ;; *-beos*) vendor=be ;; *-hpux*) vendor=hp ;; *-mpeix*) vendor=hp ;; *-hiux*) vendor=hitachi ;; *-unos*) vendor=crds ;; *-dgux*) vendor=dg ;; *-luna*) vendor=omron ;; *-genix*) vendor=ns ;; *-clix*) vendor=intergraph ;; *-mvs* | *-opened*) vendor=ibm ;; *-os400*) vendor=ibm ;; s390-* | s390x-*) vendor=ibm ;; *-ptx*) vendor=sequent ;; *-tpf*) vendor=ibm ;; *-vxsim* | *-vxworks* | *-windiss*) vendor=wrs ;; *-aux*) vendor=apple ;; *-hms*) vendor=hitachi ;; *-mpw* | *-macos*) vendor=apple ;; *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) vendor=atari ;; *-vos*) vendor=stratus ;; esac ;; esac echo "$cpu-$vendor${kernel:+-$kernel}${os:+-$os}${obj:+-$obj}" exit # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: rgl/src/PrimitiveSet.h0000644000176200001440000001533214771520323014432 0ustar liggesusers#ifndef PRIMITIVE_SET_H #define PRIMITIVE_SET_H #include "Shape.h" #include "render.h" #include namespace rgl { // // ABSTRACT CLASS // PrimitiveSet // class PrimitiveSet : public Shape { public: /** * overloaded **/ virtual void draw(RenderContext* renderContext); /** * overloaded **/ virtual std::string getTypeName() { return "primitive"; } /** * overloaded **/ virtual int getElementCount(void) { return nprimitives; } int getAttributeCount(SceneNode* subscene, AttribID attrib); void getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result); /** * overloaded **/ virtual Vertex getPrimitiveCenter(int item) { return getCenter(item); } /** * begin sending primitives * interface **/ virtual void drawBegin(RenderContext* renderContext); /** * send primitive * interface **/ virtual void drawPrimitive(RenderContext* renderContext, int index); /** * end sending primitives * interface **/ virtual void drawEnd(RenderContext* renderContext); /** * set a vertex **/ const void setVertex(int index, double* v) { vertexArray.setVertex(index, v); } /** * setup all vertices **/ void initPrimitiveSet(int in_nvertices, double* in_vertices, int in_nindices = 0, int* in_indices = NULL); protected: /** * abstract class constructor **/ PrimitiveSet ( Material& in_material, int in_nvertices, double* vertex, int in_type, int in_nverticesperelement, bool in_ignoreExtent, int in_nindices, int* in_indices, bool in_bboxChange = false ); PrimitiveSet( Material& in_material, int in_type, int in_verticesperelement, bool in_ignoreExtent, bool in_bboxChange ); ~PrimitiveSet(); /** * get primitive center point **/ inline Vertex getCenter(int index) { Vertex accu; int begin = index*nverticesperelement; int end = begin+nverticesperelement; for (int i = begin ; i < end ; ++i ) { if (nindices) accu += vertexArray[indices[i]]; else accu += vertexArray[i]; } return accu * ( 1.0f / ( (float) nverticesperelement ) ); } // ---[ PRIMITIVE DRAW INTERFACE ]------------------------------------------ /** * send all elements * interface **/ virtual void drawAll(RenderContext* renderContext); void initPrimitiveSet ( int in_nvertices, double* vertex, int in_type, int in_nverticesperelement, bool in_ignoreExtent, bool in_bboxChange ); int type; int nverticesperelement; int nvertices; int nprimitives; VertexArray vertexArray, /* the vertices given by the user */ verticesTodraw; /* the margin vertices in data coords */ bool hasmissing; /* whether any vertices contain missing values */ int nindices; unsigned int* indices; }; // // ABSTRACT CLASS // FaceSet // class FaceSet : public PrimitiveSet { public: /** * overload **/ virtual void drawBegin(RenderContext* renderContext); /** * overload **/ virtual void drawEnd(RenderContext* renderContext); /** * overloaded **/ virtual std::string getTypeName() { return "faces"; }; int getAttributeCount(SceneNode* subscene, AttribID attrib); void getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result); protected: /** * Constructor **/ FaceSet( Material& in_material, int in_nvertex, double* in_vertex, double* in_normals, double* in_texcoords, int in_type, int in_nverticesperelement, bool in_ignoreExtent, int in_nindices, int* in_indices, int in_useNormals, int in_useTexcoords, bool in_bboxChange = false ); FaceSet( Material& in_material, int in_type, int in_verticesperelement, bool in_ignoreExtent, bool in_bboxChange = false ); /* (re-)set mesh */ void initFaceSet(int in_nvertex, double* in_vertex, double* in_normals, double* in_texcoords); /* set up normals */ void initNormals(double* in_normals); private: NormalArray normalArray, normalsToDraw; TexCoordArray texCoordArray; }; // // CLASS // PointSet // class PointSet : public PrimitiveSet { public: PointSet(Material& material, int nvertices, double* vertices, bool in_ignoreExtent, int nindices, int* indices, bool bboxChange=false ); /** * overloaded **/ virtual std::string getTypeName() { return "points"; }; }; // // CLASS // LineSet // class LineSet : public PrimitiveSet { public: LineSet(Material& material, int nvertices, double* vertices, bool in_ignoreExtent, int in_nindices, int* in_indices, bool in_bboxChange=false); LineSet(Material& in_material, bool in_ignoreExtent, bool in_bboxChange); /** * overloaded **/ virtual std::string getTypeName() { return "lines"; }; }; // // CLASS // TriangleSet // class TriangleSet : public FaceSet { public: TriangleSet(Material& in_material, int in_nvertex, double* in_vertex, double* in_normals, double* in_texcoords, bool in_ignoreExtent, int in_nindices, int* in_indices, int in_useNormals, int in_useTexcoords, bool in_bboxChange = false) : FaceSet(in_material,in_nvertex, in_vertex, in_normals, in_texcoords, GL_TRIANGLES, 3, in_ignoreExtent, in_nindices, in_indices, in_useNormals, in_useTexcoords, in_bboxChange) { } TriangleSet(Material& in_material, bool in_ignoreExtent, bool in_bboxChange) : FaceSet(in_material, GL_TRIANGLES, 3, in_ignoreExtent, in_bboxChange) { } /** * overloaded **/ virtual std::string getTypeName() { return "triangles"; }; }; // // CLASS // QuadSet // class QuadSet : public FaceSet { public: QuadSet(Material& in_material, int in_nvertex, double* in_vertex, double* in_normals, double* in_texcoords, bool in_ignoreExtent, int in_nindices, int* in_indices, int in_useNormals, int in_useTexcoords) : FaceSet(in_material,in_nvertex,in_vertex, in_normals, in_texcoords, GL_QUADS, 4, in_ignoreExtent, in_nindices, in_indices, in_useNormals, in_useTexcoords) { } /** * overloaded **/ virtual std::string getTypeName() { return "quads"; }; }; // // CLASS // LineStripSet // class LineStripSet : public PrimitiveSet { public: LineStripSet(Material& material, int in_nvertex, double* in_vertex, bool in_ignoreExtent, int in_nindices, int* in_indices, bool in_bboxChange = false); void drawPrimitive(RenderContext* renderContext, int index); /** * overloaded **/ virtual std::string getTypeName() { return "linestrip"; }; }; } // namespace rgl #endif // PRIMITIVE_SET_H rgl/src/PlaneSet.cpp0000644000176200001440000001445514771520323014061 0ustar liggesusers#include #include "PlaneSet.h" #include "Viewpoint.h" #include "R.h" using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // PlaneSet // PlaneSet::PlaneSet(Material& in_material, int in_nnormal, double* in_normal, int in_noffset, double* in_offset) : TriangleSet(in_material,true, false/* true */), nPlanes(std::max(in_nnormal, in_noffset)), normal(in_nnormal, in_normal), offset(in_noffset, in_offset) { /* We'll set up 4 triangles per plane, in case we need to render a hexagon. Each triangle has 3 vertices (so 12 for the plane), and each vertex gets 3 color components and 1 alpha component. */ ARRAY colors(36*nPlanes); ARRAY alphas(12*nPlanes); if (material.colors.getLength() > 1) { material.colors.recycle(nPlanes); for (int i=0; i vertices(36*nPlanes), normals(36*nPlanes); for (int i=0; isubscene); invalidateDisplaylist(); TriangleSet::renderBegin(renderContext); } void PlaneSet::updateTriangles(Subscene* subscene) { int perms[3][3] = { {0,0,1}, {1,2,2}, {2,1,0} }; AABox sceneBBox = subscene->getBoundingBox(); double bbox[2][3] = { {sceneBBox.vmin.x, sceneBBox.vmin.y, sceneBBox.vmin.z}, {sceneBBox.vmax.x, sceneBBox.vmax.y, sceneBBox.vmax.z} }; double x[12][3]; for (int elem = 0; elem < nPlanes; elem++) { Vertex Av = normal.getRecycled(elem); double A[3] = { Av.x, Av.y, Av.z }; double d = offset.getRecycled(elem); int nhits = 0; int face1[12], face2[12]; /* to identify which faces of the cube we're on */ /* Find intersection of bbox edges with plane. Problem: * there might be 3 edges all intersecting the plane * at the same place, i.e. a vertex of the bbox. Need * to fix this case. */ for (int i=0; i<3; i++) for (int j=0; j<2; j++) for (int k=0; k<2; k++) { int u=perms[0][i], v=perms[1][i], w=perms[2][i]; if (A[w] != 0.0) { double intersect = -(d + A[u]*bbox[j][u] + A[v]*bbox[k][v])/A[w]; if (bbox[0][w] <= intersect && intersect <= bbox[1][w]) { x[nhits][u] = bbox[j][u]; x[nhits][v] = bbox[k][v]; x[nhits][w] = intersect; /* Check for duplicate */ int dup = 0; for (int l=0; l < nhits; l++) { if (std::abs(x[l][0] - x[nhits][0]) <= 1.e-8*std::abs(x[l][0]) && std::abs(x[l][1] - x[nhits][1]) <= 1.e-8*std::abs(x[l][1]) && std::abs(x[l][2] - x[nhits][2]) <= 1.e-8*std::abs(x[l][2])) { dup = 1; break; } } if (!dup) { face1[nhits] = j + 2*u; face2[nhits] = k + 2*v; nhits++; } } } } if (nhits > 3) { /* Re-order the intersections so the triangles work */ for (int i=0; i i+1) { for (int j=0; j<3; j++) std::swap(x[i+1][j], x[which][j]); std::swap(face1[i+1], face1[which]); std::swap(face2[i+1], face2[which]); } } } if (nhits >= 3) { /* Put in order so that the normal points out the FRONT of the faces */ Vec3 v0(static_cast(x[0][0] - x[1][0]), static_cast(x[0][1] - x[1][1]), static_cast(x[0][2] - x[1][2])), v2(static_cast(x[2][0] - x[1][0]), static_cast(x[2][1] - x[1][1]), static_cast(x[2][2] - x[1][2])), vx = v0.cross(v2); bool reverse = vx*Av > 0; for (int i=0; i namespace rgl { class ClipPlaneSet : public Shape { private: /* Use parametrization ax + by + cz + d = 0 */ int nPlanes; GLenum firstPlane; ARRAY normal; /* (a,b,c) */ ARRAY offset; /* d */ public: ClipPlaneSet(Material& in_material, int in_nnormal, double* in_normal, int in_noffset, double* in_offset); // ~PlaneSet(); static int num_planes; // clip plane count for drawing; set to 0 initially, incremented // as each plane is added or drawn. /** * tell type. **/ virtual std::string getTypeName() { return "clipplanes"; }; virtual void renderBegin(RenderContext* renderContext); virtual void drawPrimitive(RenderContext* renderContext, int index); virtual int getElementCount(void) { return nPlanes; } virtual int getAttributeCount(SceneNode* subscene, AttribID attrib); virtual void getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result); void enable(bool show); // after it has been drawn, this enables it or disables it bool isClipPlane(void) { return true; } void intersectBBox(AABox& bbox); }; } // namespace rgl #endif // CLIPPLANE_H rgl/src/SphereMesh.h0000644000176200001440000000264014714647212014053 0ustar liggesusers#ifndef SPHERE_MESH_H #define SPHERE_MESH_H #include "render.h" namespace rgl { // // CLASS // SphereMesh // class SphereMesh { public: enum Type { GLOBE, TESSELATION }; SphereMesh(); inline void setGenNormal (bool in_genNormal) { genNormal = in_genNormal; } inline void setGenTexCoord (bool in_genTexCoord) { genTexCoord = in_genTexCoord; } void setGlobe (int segments, int sections); void setTesselation (int level); void setCenter (const Vertex& center); void setRadius (float radius); void update(); void update (const Vertex& scale); /* void beginDraw(RenderContext* renderContext); void drawSection(int section); void endDraw(RenderContext* renderContext); */ void draw(RenderContext* renderContext); void drawBegin(RenderContext* renderContext, bool endcap); void drawPrimitive(RenderContext* renderContext, int i); void drawEnd(RenderContext* renderContext); int getPrimitiveCount() { return segments*sections; } int getSegments() { return segments; } Vertex getPrimitiveCenter(int i); private: Vertex center; float radius; float philow; float phihigh; VertexArray vertexArray; NormalArray normalArray; TexCoordArray texCoordArray; int segments; int sections; int nvertex; Type type; bool genNormal; bool genTexCoord; void setupMesh(); }; } // namespace rgl #endif // SPHERE_MESH_H rgl/src/rglview.h0000644000176200001440000000447014714647212013472 0ustar liggesusers#ifndef RGLVIEW_H #define RGLVIEW_H // C++ header file // This file is part of RGL #include "scene.h" #include "gui.h" #include "fps.h" #include "pixmap.h" namespace rgl { class RGLView : public View { public: RGLView(Scene* scene); ~RGLView(); bool snapshot(PixmapFileFormatID formatID, const char* filename); bool pixels(int* ll, int* size, int component, double* result); bool postscript(int format, const char* filename, bool drawText); // event handler: void show(void); void hide(void); void paint(void); void resize(int width, int height); void buttonPress(int button, int mouseX, int mouseY); void buttonRelease(int button, int mouseX, int mouseY); void mouseMove(int mouseX, int mouseY); void wheelRotate(int dir, int mouseX, int mouseY); void captureLost(); void keyPress(int code); Scene* getScene(); void getUserMatrix(double* dest); void setUserMatrix(double* src); void getScale(double* dest); void setScale(double* src); const char* getFontFamily() const; void setFontFamily(const char *family); int getFontStyle() const; void setFontStyle(int style); double getFontCex() const; void setFontCex(double cex); bool getFontUseFreeType() const; void setFontUseFreeType(bool useFreeType); void setDefaultFont(const char *family, int style, double cex, bool useFreeType); const char* getFontname() const; int getActiveSubscene() {return activeSubscene;} /* NB: these functions do not maintain consistency with userMatrix */ void getPosition(double* dest); void setPosition(double* src); void setMouseListeners(Subscene* sub, unsigned int n, int* ids); protected: void setWindowImpl(WindowImpl* impl); private: // // DRAG USER-INPUT // int activeSubscene; // Translate from OS window-relative coordinates (relative to top left corner) to // OpenGL window relative (relative to bottom left corner) void translateCoords(int* mouseX, int* mouseY) const { *mouseY = height - *mouseY; } // // RENDER SYSTEM // // o LAYERS Scene* scene; FPS fps; // o CONTEXT RenderContext renderContext; bool autoUpdate; enum { FSHOWFPS = 1<<0, FAUTOUPDATE = 1<<1 }; int flags; }; } // namespace rgl #endif /* RGLVIEW_H */ rgl/src/Light.h0000644000176200001440000000177314771520323013061 0ustar liggesusers#ifndef LIGHT_H #define LIGHT_H #include "SceneNode.h" #include "rglmath.h" #include "Color.h" #include "RenderContext.h" #include "opengl.h" namespace rgl { // // CLASS // Light // class Light : public SceneNode { public: Light( PolarCoord in_position = PolarCoord(0.0,0.0) , Vertex in_finposition=Vertex(0.0f,0.0f,0.0f), bool in_viewpoint=true, bool in_posisfinite=false, Color ambient=Color(1.0f,1.0f,1.0f), Color diffuse=Color(1.0,1.0,1.0), Color specular=Color(1.0,1.0,1.0) ); void setup(RenderContext* renderContext); int getAttributeCount(SceneNode* subscene, AttribID attrib); void getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result); virtual std::string getTypeName() { return "light"; }; private: float position[4]; Vertex finposition; Color ambient; Color diffuse; Color specular; GLenum id; bool viewpoint; bool posisfinite; friend class Scene; friend class Subscene; }; } // namespace rgl #endif // LIGHT_H rgl/src/DeviceManager.h0000644000176200001440000000215115011677075014500 0ustar liggesusers#ifndef RGL_DEVICE_MANAGER_H #define RGL_DEVICE_MANAGER_H // C++ header file // This file is part of RGL // #include "Device.h" #include namespace rgl { /** * Manager component that is used as a front-end for multiple devices access * using an 'id' to set the current device. **/ class DeviceManager : protected IDisposeListener { public: DeviceManager(bool in_useNULLDevice); virtual ~DeviceManager(); bool openDevice(bool useNULL, int antialias); Device* getCurrentDevice(void); Device* getAnyDevice(void); Device* getDevice(int id); bool setCurrent(int id, bool silent = false); int getCurrent(); int getDeviceCount(); void getDeviceIds(int *buffer, int bufsize); bool createTestWindow(); protected: /** * Dispose Listener implementation **/ void notifyDisposed(Disposable*); private: void nextDevice(); void previousDevice(); typedef std::list Container; typedef Container::iterator Iterator; int newID; Container devices; Iterator current; bool useNULLDevice; }; } // namespace rgl #endif // DEVICE_MANAGER_H rgl/src/config.h0000644000176200001440000000116614771224114013252 0ustar liggesusers#ifndef RGL_CONFIG_H #define RGL_CONFIG_H #ifdef RGL_NO_OPENGL #undef RGL_OSX #undef RGL_X11 #undef RGL_W32 #else // --------------------------------------------------------------------------- // Platform detection // --------------------------------------------------------------------------- #if defined(__APPLE__) # define GL_SILENCE_DEPRECATION # define RGL_OSX 1 # define RGL_X11 1 #else # if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) # define RGL_W32 1 # else # define RGL_X11 1 # endif #endif // --------------------------------------------------------------------------- #endif #endif //RGL_CONFIG_H rgl/src/Light.cpp0000644000176200001440000000503514771520323013407 0ustar liggesusers#include "Light.h" using namespace rgl; ////////////////////////////////////////////////////////////////////////////// // // CLASS // Light // Light::Light( PolarCoord in_position, Vertex in_finposition, bool in_viewpoint, bool in_posisfinite, Color in_ambient, Color in_diffuse, Color in_specular ) : SceneNode(LIGHT), finposition(in_finposition), ambient(in_ambient), diffuse(in_diffuse), specular(in_specular), id(GL_FALSE), viewpoint(in_viewpoint), posisfinite(in_posisfinite) { if (posisfinite) { position[0] = finposition.x; position[1] = finposition.y; position[2] = finposition.z; position[3] = 1.0f; } else { Vertex v(0.0f, 0.0f, 1.0f); v.rotateX( -in_position.phi ); v.rotateY( in_position.theta ); position[0] = v.x; position[1] = v.y; position[2] = v.z; position[3] = 0.0f; } } void Light::setup(RenderContext* renderContext) { #ifndef RGL_NO_OPENGL glLightfv(id, GL_AMBIENT, ambient.data ); glLightfv(id, GL_DIFFUSE, diffuse.data ); glLightfv(id, GL_SPECULAR, specular.data ); glLightfv(id, GL_POSITION, position ); glLightf(id, GL_SPOT_EXPONENT, 0.0f); glLightf(id, GL_SPOT_CUTOFF, 180.0f); glLightf(id, GL_CONSTANT_ATTENUATION, 1.0f); glLightf(id, GL_LINEAR_ATTENUATION, 0.0f); glLightf(id, GL_QUADRATIC_ATTENUATION, 0.0f); glEnable(id); #endif } int Light::getAttributeCount(SceneNode* subscene, AttribID attrib) { switch (attrib) { case COLORS: return 3; case VERTICES: return 1; case FLAGS: return 2; } return 0; } void Light::getAttribute(SceneNode* subscene, AttribID attrib, int first, int count, double* result) { int n = getAttributeCount(subscene, attrib); if (first + count < n) n = first + count; if (first < n) { switch (attrib) { case COLORS: { while (first < n) { Color color; switch(first) { case 0: color = ambient; break; case 1: color = diffuse; break; case 2: color = specular;break; } *result++ = color.data[0]; *result++ = color.data[1]; *result++ = color.data[2]; *result++ = color.data[3]; first++; } return; } case VERTICES: { *result++ = position[0]; *result++ = position[1]; *result++ = position[2]; return; } case FLAGS: { if (first == 0) *result++ = (double) viewpoint; *result++ = (double) posisfinite; return; } } } } rgl/NAMESPACE0000644000176200001440000001560515012460301012254 0ustar liggesusersexport(.check3d, abclines3d, addNormals, addToSubscene3d, arc3d, arrow3d, as.mesh3d, as.rglscene, as.tmesh3d, as.triangles3d, asRow, asEuclidean, asEuclidean2, asHomogeneous, asHomogeneous2, aspect3d, axes3d, axis3d, box3d, bbox3d, bg3d, bgplot3d, Buffer, checkDeldir, clear3d, clearSubsceneList, clipplanes3d, clipMesh3d, clipObj3d, close3d, compare_proxy.mesh3d, contourLines3d, cube3d, cuboctahedron3d, cur3d, currentSubscene3d, cylinder3d, decorate3d, deform.mesh3d, delFromSubscene3d, divide.mesh3d, dodecahedron3d, dot3d, drape3d, ellipse3d, expect_known_scene, extrude3d, facing3d, figWidth, figHeight, filledContour3d, gc3d, getBoundary3d, getr3dDefaults, getShaders, getWidgetId, gltfTypes, GramSchmidt, grid3d, highlevel, hook_rgl, hook_webgl, hover3d, icosahedron3d, identify3d, identityMatrix, ids3d, in_pkgdown, in_pkgdown_example, layout3d, legend3d, light3d, lines3d, lowlevel, makeDependency, material3d, mergeVertices, mesh3d, mfrow3d, movie3d, mtext3d, newSubscene3d, next3d, normalize.mesh3d, observer3d, octahedron3d, oh3d, open3d, par3d, par3dinterp, par3dinterpControl, particles3d, pch3d, persp3d, planes3d, play3d, plot3d, plotmath3d, points3d, polygon3d, pop3d, projectDown, qmesh3d, quads3d, readOBJ, readSTL, rgl.abclines, rgl.bbox, rgl.bg, rgl.bringtotop, rgl.clear, rgl.getAxisCallback, rgl.getMouseCallbacks, rgl.getWheelCallback, rgl.close, rgl.cur, rgl.ids, rgl.init, rgl.light, rgl.lines, rgl.linestrips, rgl.clipplanes, rgl.material, rgl.material.names, rgl.material.readonly, rgl.par3d.names, rgl.par3d.readonly, rgl.open, rgl.pixels, rgl.planes, rgl.points, rgl.pop, rgl.postscript, rgl.primitive, rgl.projection, rgl.quads, rgl.quit, rgl.Sweave, rgl.Sweave.off, rgl.select, rgl.select3d, rgl.set, rgl.snapshot, rgl.spheres, rgl.sprites, rgl.surface, rgl.texts, rgl.triangles, rgl.user2window, rgl.attrib, rgl.attrib.count, rgl.attrib.info, rgl.dev.list, rgl.incrementID, rgl.useNULL, rgl.viewpoint, rgl.window2user, rglExtrafonts, rglFonts, rglId, rglMouse, rglShared, rglToLattice, rglToBase, r3dDefaults, rotate3d, rotationMatrix, scale3d, scaleMatrix, scene3d, segments3d, select3d, selectionFunction3d, selectpoints3d, rgl.setAxisCallback, rgl.setMouseCallbacks, rgl.setWheelCallback, safe.dev.off, set3d, setAxisCallbacks, setGraphicsDelay, setupKnitr, setUserCallbacks, setUserShaders, shade3d, shadow3d, shapelist3d, shinyGetPar3d, shinySetPar3d, shinyResetBrush, show2d, snapshot3d, spheres3d, spin3d, sprites3d, subdivision3d, subsceneInfo, subsceneList, Sweave.snapshot, surface3d, tagged3d, terrain3d, tetrahedron3d, text3d, texts3d, textureSource, thigmophobe3d, title3d, tkpar3dsave, tkspinControl, tkspin3d, toggleWidget, triangulate, tmesh3d, transform3d, translate3d, translationMatrix, triangles3d, turn3d, useSubscene3d, view3d, wire3d, writeASY, writeOBJ, writePLY, writeSTL, writeWebGL) S3method(dot3d, shapelist3d) S3method(wire3d, shapelist3d) S3method(shade3d, shapelist3d) S3method(translate3d, shapelist3d) S3method(rotate3d, shapelist3d) S3method(scale3d, shapelist3d) S3method(addNormals, shapelist3d) S3method(dot3d, mesh3d) S3method(translate3d, mesh3d) S3method(rotate3d, mesh3d) S3method(scale3d, mesh3d) S3method(merge, mesh3d) S3method(wire3d, mesh3d) S3method(shade3d, mesh3d) S3method(subdivision3d, mesh3d) S3method(addNormals, mesh3d) S3method(plot3d, mesh3d) S3method(all.equal, mesh3d) S3method(all.equal, rglscene) S3method(as.mesh3d, deldir) S3method(as.mesh3d, tri) S3method(as.mesh3d, triSht) S3method(as.mesh3d, ashape3d) S3method(as.mesh3d, rglId) S3method(as.mesh3d, rglobject) S3method(as.mesh3d, rglsubscene) S3method(as.mesh3d, rglscene) S3method(as.mesh3d, mesh3d) S3method(as.mesh3d, default) S3method(as.tmesh3d, mesh3d) S3method(as.tmesh3d, default) S3method(as.triangles3d, mesh3d) S3method(as.triangles3d, rglId) S3method(translate3d, default) S3method(rotate3d, default) S3method(scale3d, default) S3method(ellipse3d, default) S3method(ellipse3d, lm) S3method(ellipse3d, glm) S3method(ellipse3d, nls) S3method(plot3d, default) S3method(persp3d, default) S3method(persp3d, "function") S3method(persp3d, deldir) S3method(persp3d, tri) S3method(persp3d, triSht) S3method(persp3d, ashape3d) S3method(persp3d, formula) S3method(plot3d, rglscene) S3method(plot3d, rglobject) S3method(plot3d, rglbboxdeco) S3method(plot3d, rglbackground) S3method(plot3d, rglsubscene) S3method(plot3d, rglWebGL) S3method(plot3d, "function") S3method(plot3d, deldir) S3method(plot3d, tri) S3method(plot3d, triSht) S3method(plot3d, ashape3d) S3method(plot3d, formula) S3method(plot3d, lm) S3method(print, rglscene) S3method(print, rglobject) S3method(print, rglsubscene) S3method(print, rglId) S3method(print, rglOpen3d) S3method(print, mesh3d) S3method(print, shapelist3d) S3method(print, rglMouseSelection) S3method(print, rglshaders) S3method(knit_print, rglId) S3method(knit_print, rglOpen3d) S3method(summary, rglscene) S3method(summary, rglsubscene) S3method(drape3d, default) S3method(drape3d, mesh3d) S3method(contourLines3d, rglId) S3method(contourLines3d, mesh3d) S3method(filledContour3d, rglId) S3method(filledContour3d, mesh3d) S3method(sew, rglRecordedplot) S3method(is_low_change, rglRecordedplot) if(.Platform$OS.type == "windows") { importFrom(utils, getWindowsHandle) } importFrom(graphics, legend, par, plot, plot.new, polygon, strwidth, strheight) importFrom(grDevices, as.raster, col2rgb, colorRamp, dev.cur, dev.list, dev.new, dev.off, dev.prev, dev.set, png, postscript, rgb, xy.coords, xyz.coords) importFrom(stats, approxfun, get_all_vars, model.frame, qchisq, qf, splinefun, terms, var) importFrom(tools, file_ext) importFrom(utils, capture.output, count.fields, file_test, flush.console, packageVersion, read.table, head, tail) importFrom(R6, R6Class) # These were in rglwidget export(rglwidget, renderRglwidget, rglwidgetOutput, playwidget, renderPlaywidget, playwidgetOutput, subsetControl, propertyControl, clipplaneControl, ageControl, vertexControl, elementId2Prefix, registerSceneChange, sceneChange, "%>%") importFrom(htmlwidgets, createWidget, prependContent, saveWidget, shinyRenderWidget, shinyWidgetOutput, sizingPolicy) importFrom(htmltools, css, HTML, htmlDependency, htmlPreserve, img, includeScript, tags, tagAppendAttributes, tagHasAttribute, tagList, browsable, resolveDependencies) importFrom(jsonlite, toJSON, base64_dec) importFrom(knitr, asis_output, fig_path, hook_plot_custom, include_graphics, is_low_change, knit_hooks, knit_meta_add, knit_print, opts_current, opts_hooks, opts_knit, pandoc_to, sew) importFrom(magrittr, "%>%") importFrom(stats, coef, predict, residuals) importFrom(base64enc, base64encode) rgl/NEWS.md0000644000176200001440000024701615026603462012152 0ustar liggesusers# rgl 1.3.24 * The `shapelist3d()` function did not handle material names properly (issue #462). * The `markdown` package no longer supports `rgl`, so the change in `rgl` 1.3.1 to use it has been reverted. This means Pandoc is once again necessary to build the vignettes. * Links from help pages to vignettes have been repaired and added, using new `\HTMLVignette{}{}{}` and `\HTMLVignetteCRAN{}{}{}{}` macros. * To support those macros, two environment variables are used. `VignetteRdPath` (default `"../html/"`) should be the lead-in of the URL for the HTML version of an Rd help file referenced from a vignette, and `RdVignettePath` (default `"../doc/"`) should be the lead-in of the URL for a vignette referenced from an Rd file. * `abclines3d()` did not handle multiple colors properly, sometimes causing a crash (issue #476). * The `COPYING.GL2PS` file containing the license for the code used in `rgl.postscript()` has been moved so that it will be installed at the top level of the package. # rgl 1.3.18 * Internal code changes to satisfy `R CMD check` requirements. * Some memory leaks reported in issue #451 have been fixed. * The OpenGL "glad" loader has been updated to version 2.0.8. * A number of implicit type conversions have been made explicit to avoid compiler warnings. # rgl 1.3.17 ## Bug fix * The previous fix for `rgl.init()` introduced a new possible segfault for users who had DISPLAY unset or set to a non-existent server. # rgl 1.3.16 ## Bug fixes * `triangulate()` now uses the `earcut` library from https://github.com/mapbox/earcut.hpp, which should be faster and more reliable than the previous R implementation. * In cases where the X11 server did not provide sufficient support, `rgl.init()` could sometimes segfault. That has been fixed, and warning messages have been made more informative. # rgl 1.3.14 ## Minor changes * `rgl.incrementID()` has been added. * An example using log axes has been added to the help page for `axes3d()`. ## Bug fixes * `clear3d("all")`, calling `bg3d()` on the root subscene, and some cases of `pop3d()` involving the background could create a leak of a background object (issue #439). For back compatibility of saved results, these cases still increment the object ID number, but don't actually create a new object. * `rglwidget()` displays didn't support objects with `smooth = FALSE`. # rgl 1.3.12 ## Minor changes * `readSTL()` can now read (some) ASCII format STL files. * The configure script has had minor changes, and autoconf support files have been updated. * `uname` is no longer used during startup (PR #435 submitted by Jonathon Love). ## Bug fixes * Background plots did not always appear (issue #421). * Changing the background resulted in an additional background object instead of replacing the current one. * Colors weren't handled correctly by `writePLY()` (issue #425). * `bbox3d()` objects ignored the `xlen`, `ylen` and `zlen` settings when rendered using `rglwidget()` (issue #415). * In certain cases, the `WebGL` vignette started with the mouse mode set to "selecting". * The `rglwidget()` function gets a new argument `fastTransparency` which makes WebGL mimic the `rgl` device when drawing transparent objects. The default value is `TRUE` unless option `rgl.fastTransparency` is set to `FALSE`. * `writeSTL()` now writes `endsolid`, which is required by some apps. # rgl 1.3.1 ## Major changes * `sprites3d()` now supports plotting different 3D symbols at each location (issue #406). ## Minor changes * ARIA support now declares `rgl` scenes with `role = "img"`. * The vignettes in this package now use `markdown::html_format`, so they no longer require Pandoc (though Pandoc-using output formats like `html_document` will still be supported). * Christophe Geuzaine's GL2PS library (used by `rgl.postscript()`) updated to version 1.4.2, and blending (transparency) has been enabled in formats that support it. * The `Makevars.ucrt` file has been changed for compatibility with an upcoming change to Windows Rtools. (Pull request #412 submitted by Tomas Kalibera). ## Bug fixes * The ARIA support caused `htmlwidgets::saveWidget()` to fail when run in a Shiny session. * `text3d()` and `mtext3d()` did not pass the `cex` argument to `plotmath3d()` (pull request #384). * `polygon3d()` failed when given exactly 3 points (issue #388). * `snapshot3d()` failed on Windows with some versions of `webshot2` (issue #391). * Fixed issues caused by misuse of `dev.off()` using new function `safe.dev.off()`. * Fixed issue with `warning()` call reported by CRAN. * Smooth shapes were not rendered correctly by `rglwidget()`. This was especially noticeable for spheres with `fov = 0`, but was present in other cases as well (issue #401). * `textype = "alpha"` was not rendered correctly by `rglwidget()` (issue #408). * `setUserCallbacks()` and related functions failed when the `subscene` argument was anything other than the root subscene. # rgl 1.2.1 ## Major changes * Support for non-PNG textures has been added. Currently supported: JPEG files and any other object for which `grDevices::as.raster()` works, e.g. matrices. (Fixes issue #196.) ## Minor changes * Support for "alt" text has been added to `rglwidget()`. Full support in R Markdown or `knitr` requires a `knitr` update to version 1.42.12 or newer. * Some of the tests have been relaxed slightly so they shouldn't trigger errors on the M1Mac test platform. * Internally, the C++ code has dropped the use of the internally defined `String` type, settling on `std::string` instead. * `subdivision3d()`, `clipMesh3d()` and related functions now (optionally) record the original faces associated with each new one in a `mesh$tags` addition to the output. ## Bug fixes * The `Makevars.win` file was being produced incorrectly on older Windows versions. * `rgl.window2user()` did not work correctly when multiple panes were showing. This caused `arrow3d()` to fail in some panes (issue #354). * `selectpoints3d()` had a typo which was revealed by warnings in recent R versions. * `getShaders()` was broken in 1.1.3. * `arc3d()` can now handle "arcs" that are straight lines along a radius (issue #357). * Spheres did not show textures correctly (issue #360). * `hover3d()` failed to display default labels in R (issue #362). * `shade3d()` didn't handle meshes with a mix of triangles and quads properly when `meshColor == "faces"`. * `subdivision3d()` and related functions now handle colors properly. * `addNormals()` sometimes gave `NaN` values due to rounding error (issue #372). * `arc3d()` sometimes missed plotting the last segment of the arc (issue #369). * `R_NO_REMAP` has been defined and header includes have been rearranged to prevent conflict between R internals and C++17 library. (Thanks to Prof. B. D. Ripley and G. Csardi for suggested fixes.) # rgl 1.1.3 ## Major changes * A new function `hover3d()` has been added to display "hover hints": labels next to points when the mouse passes near them. * A new material property `"texmode"` has been added to control how textures are applied. The default is `"modulate"`, consistent with previous versions. If set to `"replace"`, the texture is displayed without any lighting effects or dependence on the original color of the surface. * Many of the demos have been moved to a new vignette called `demos`. * `rgl` now uses the `glad` loader which will eventually allow access to newer OpenGL functions in systems that support them. ## Minor changes * The `texenvmap = TRUE` material property is now supported in WebGL. * The method of including shader source code has changed to work around a limitation in Jupyter. * The default C++ standard is now accepted, rather than requiring C++11. On R versions prior to R 4.2.0 C++11 is still requested. ## Bug fixes * The `as.mesh3d.rglId()` and `as.triangles3d.rglId()` methods and the `selectpoints3d()`, `writeOBJ()`, `writePLY()` and `writeSTL()` functions did not handle indices in the objects they were processing (issue #293). * Transparent planes were not always drawn properly in WebGL (issue #300). * `view3d()` now returns a `lowlevel()` result so that it will be handled properly in WebGL vignettes with auto printing. * If `transform3d()` or `rotate3d()` changed the orientation of a `mesh3d` object with normals, the normals ended up with the wrong sign. (Reported by Stephane Laurent.) * `scene3d()` (and hence `rglwidget()`) did not save the normals for unlit objects. When the objects were also indexed, this prevented proper calculation of front and back. This is fixed, and a warning is issued if normals are not provided when needed. * It was possible to call `glVersion` before OpenGL was initialized; this resulted in a segfault with the new `glad` loader, and may have been the cause of some older crashes as well. This has been fixed. * `readOBJ()` did not handle comments properly. * Sprites consisting only of line segments (as used for example by `pch3d()`) caused rendering to fail in `rglwidget()` (issue #316). * Headers have been cleaned up to fix problems identified by Rtools43. # rgl 1.0.1 ## Major changes * The long promised deprecations of the `rgl.*` functions have happened. Now deprecated: `rgl.abclines`, `rgl.bbox`, `rgl.bg`, `rgl.clear`, `rgl.clipplanes`, `rgl.close`, `rgl.light`, `rgl.lines`, `rgl.linestrips`, `rgl.material`, `rgl.open`, `rgl.planes`, `rgl.points`, `rgl.quads`, `rgl.select3d`, `rgl.set`, `rgl.setAxisCallback`, `rgl.sprites`, `rgl.surface`, `rgl.texts`, `rgl.triangles`, and `rgl.viewpoint`. * A vignette "Deprecating the `rgl.*` interface" has been added. * Also deprecated: `elementId2Prefix`, `writeWebGL` ## Minor changes * Since `rgl.material` is deprecated and no longer contains the list of material types in its argument list, `rgl.material.names` and `rgl.material.readonly` have been added. * Similarly, `rgl.par3d.names` and `rgl.par3d.readonly` contain lists of properties that may be set or queried in `par3d()`. * The flexibility improvements for `surface3d()` in 0.111.6 were incomplete. * Argument `flip` has been added to `surface3d()` to allow front and back to be switched. # rgl 0.111.6 ## Minor changes * Added a panning example to the help page for `setUserCallbacks()`. * Replaced all calls to `sprintf` from C/C++ code with calls to `snprintf`. * `surface3d` and `rgl.surface` are now more flexible, allowing any of the 3 coordinates to be a vector or matrix as long as at least one is a matrix. * `material3d` can now specify an `id` to query properties for individual objects. * Since `rgl.material` is soon to be deprecated and no longer contain the list of material types in its argument list, `rgl.material.names` and `rgl.material.readonly` have been added. * Similarly, `rgl.par3d.names` and `rgl.par3d.readonly` contain lists of properties that may be set or queried in `par3d()`. * Made some examples conditional on interactive use to save time on CRAN. ## Bug fixes * Default mouse modes used when a window is opened by an `rgl.*` call (which is not recommended!) now match the defaults in `rgl::r3dDefaults`. * Missing values could cause `surface3d()` to segfault. * The C source code for `gl2psGetFileFormat` missed declaring a prototype. # rgl 0.110.2 ## Major changes * Material property `"blend"` has been added, to allow various kinds of blending for semi-transparent objects (issue #245). ## Minor changes * The `Buffer` object now handles reading of sparse accessors. * Low level drawing of primitives has been made more memory efficient. This is only likely to make a noticeable change with very large objects, where R was running out of memory because of unnecessary duplication. (Related to issue #260.) * Recycling of x, y and z vectors in several functions is more consistent. * The `polygon3d()` function now chooses coordinates automatically, as `triangulate()` does (PR #262.) * The `mtext3d()` and related functions such as `title3d()` now accept language objects other than expressions, as `plotmath3d()` always has (issue #273). ## Bug fixes * The bounding box could be calculated incorrectly if data all had large values (issue #250). * Shiny displays failed to load the shaders (issue #249). * `transform3d()` failed due to missing argument (issue #253). * `readOBJ()` is now more flexible in what kinds of separators it will accept. (issue #258). * Failure to initialize could cause a segfault. * On non-macOS platforms, gray-scale textures failed to display, with a message about an invalid enumerant. * The third coordinate for `adj` that was added in 0.108.3 was not rendered properly in `rglwidget()` displays of text. This sometimes caused text to disappear when it was near the far limit of the display (issue #269). * The X11 error fix in 0.109.6 could result in R freezing in `Rcmdr`. * Low level drawing functions are now more consistent about returning an invisible `NULL` if asked to plot zero items, rather than raising an error or crashing (issue #274). * Calling `axis3d()` with no ticks or labels no longer triggers an error, it now silently returns `NULL`. # rgl 0.109.6 ## Minor changes * `rglwidget()` displays now act on "pointer" events, not just "mouse" events, so they should be more usable on touch screens and tablets (PR #240). ## Bug fixes * Plotting `scene3d()` objects didn't handle suppressed axes properly, drawing the default axis instead (issue #241). * On some systems using X11, `rgl` would segfault when the "fixed" font was not found. * X11 errors could cause R to abort. # rgl 0.109.2 ## Major changes * Changes to support glTF animation: - Handling of `embedding = "modify"` for the model matrix has changed. Now the centering step is only done for `embedding = "replace"`. In addition, various bugs have been fixed. - If a subscene has no lights defined, the lights from the parent are used. - `plot.rglscene()` now ends with the root subscene as current. It also allows specification of `open3d()` parameters in a list. - The `MATn` types in `Buffer` are returned as arrays with dim `c(n, n, count)`. - The `plot3d.rglscene` method now passes `...` to `open3d()`. - The `setUserShaders()` function now allows arrays of 4x4 matrices as "uniforms", and allows additional textures to be specified. * `sprites3d()` now has the option of `rotating = TRUE`, to allow 3D sprites to rotate with the scene. * Added `getShaders()` function to get shaders used in WebGL. * Now detects if `rgl` is running within `reprex::reprex()` and if so arranges that a screenshot will be included in the output. * Added default shaders to be used in `rglwidget()`, rather than constructing them on the fly. This incompatibly affects the use of lights and clipping planes with user shaders: their data is now stored in arrays rather than multiple numbered variables. ## Minor changes * Now that `pkgdown` 2.0.0 has been released, a number of internal workarounds to support the development version have been removed. * Added `as.mesh3d()` methods for `"rglsubscene"` and `"rglscene"`. * `open3d()` now handles `useNULL` and `silent` arguments passed in `params`. * Controls passed to `playwidget()` may now include a component specifying HTML dependencies. * Added `rglwidgetClass.readAccessor()` method to let other code use the buffering. * Changed the internal organization of bounding box calculations. * All functions that produce meshes now accept material properties. Newly modified to do so using the `...` argument: `cylinder3d()`, and `getBoundary3d()`. * Updated the system requirements and installation instructions. * Solid bounding box decorations now try harder to display 3 faces (issue #206). * Now that `webshot2` is on CRAN, instructions for installing it from Github have been removed. * Sometimes `webshot2` snapshots are very slow, so the default for the `webshot` argument to `snapshot3d()` now depends on the `RGL_USE_WEBSHOT` environment variable, using `TRUE` if it is unset. (Reported by Prof. B. D. Ripley.) * If the Chrome browser is not found, `snapshot3d(webshot = TRUE)` now issues a warning and reverts to using `rgl.snapshot()`. * Buffers now use "normalized integers" to store color or texture coordinate values that lie between 0 and 1 when it saves some space. * At the request of CRAN, the `akima` package is no longer suggested. ## Bug fixes * `as.mesh3d.rglobject()` didn't handle objects with indices properly. * In WebGL, the front vs back calculation sometimes got the wrong result (issue #164). * `pop3d(tag = x)` did not always find the objects with `tag == x` if they were not in the current subscene. * The default values for `front` and `back` in `rgl.material` and `material3d` are now `"filled"`, as documented in some places. * The `fog` setting wasn't handled properly by `bg3d()`. * Numerous cases of partial argument matching were fixed (suggestion of Henrik Bengtsson in issue #170.) * Argument `col` is accepted as a synonym for `color` in `material3d()` and `rgl.material()`. * `planes3d()` objects were not displayed consistently in `rgl` windows and WebGL displays, because the bounding boxes were not computed consistently (issue #169). * Some initialization wasn't done properly in Shiny apps, so they failed after a redraw (issue #173). * Buffers are now optional, as they don't work with Shiny scene changes (also issue #173). * The NULL device would sometimes miscalculate the bounding box. * `selectpoints3d(closest = TRUE)` selected too many points when multiple objects were in the scene. * Clearing nested subscenes could cause a segfault and crash. * In `knitr` and `rmarkdown`, blank plots could be shown when `par3d(skipRedraw=TRUE)` was set (issue #188). * Objects drawn with `sprites3d()` weren't lit correctly in WebGL (issue #189). * Objects with textures were sometimes drawn more than once, both before the texture loaded and after. This was most noticeable for objects with user textures. * Axis mode `"pretty"` got lost when scenes were redrawn. * Tick labels were sometimes lost in WebGL displays and `snapshot3d()` results (issue #197). * The new material properties from 0.107.10 and 0.108.3 were not handled properly by `plotmath3d()`. * `rglMouse()` did not set the default value of the drop-down selector properly (issue #213). * `merge.mesh3d()`, used by `filledContour3d()`, didn't handle colors properly (issue #212). * `bg3d(sphere = TRUE)` has been fixed (issue #207). * Textures were not appearing on spheres, and front-back differences weren't being rendered (issue #217). * When "knitting" within RStudio under R 4.2.0 on Windows, `rgl` scenes didn't appear (reported by Dieter Menne.) A workaround has been added. * In `rglwidget()`, axis labels were not always displayed, and did not move with solid bounding box decorations properly (issue #206). * On some systems, `lines3d()` using both missing values and transparency did not draw properly (issue #234, originally reported by Gaspar Jekely). * The `rglShared()` example failed when `crosstalk` was uninstalled. # rgl 0.108.3.2 ## Bug fixes * Changes introduced in 0.100.50 lacked checks; these caused segfaults in Windows with R 4.2.0 and RStudio (issue #208). * A typo caused problems loading fonts on some systems. # rgl 0.108.3 ## Major changes * Added `getBoundary3d()` function to extract the boundary edges of a mesh. * Added material property `tag`, a string associated with each object. The value is reported by `ids3d(tags = TRUE)` and may be used to select objects in most functions that use ids, but otherwise is largely ignored by `rgl`. The `tagged3d()` function returns information on tags. * Primitive types (points, lines, segments, triangles, quads) can now accept an `indices` parameter, similar to the indices in `mesh3d` objects. * Added `Buffer` object, based on glTF design, for holding binary data for `rglwidget()`. ## Minor changes * Allowed for a third coordinate in `text3d()`'s `adj` parameter. * Added support for `adj`, `pos` and `offset` to `sprites3d()`. * Added support for `pos` values of `0` (at specified location), `5` (in front of it), and `6` (behind it) in `text3d()`, `sprites3d()` and `plotmath3d()`. * `crosstalk` is now a Suggested package, rather than a required one. * The `Makevars.ucrt` file has been modified with contributions from Tomas Kalibera to work with his `winutf8` build of R. * `bgplot3d()` no longer pauses for each page when running examples. * `deldir` version 1.0-2 is incompatible with `rgl`. Added the `checkDeldir()` function to avoid running it. * `shade3d()` treated texture coordinates like colors, and duplicated the first one for the whole face when `meshColor = "faces"` was chosen. Instead, they are now treated like vertex coordinates. (Reported by Michael Sumner in issue #145). * Corrected the documentation and made the implementations of `asHomogeneous()`, `asEuclidean()` etc. more consistent. * An `as.rglscene()` generic has been added, though no methods are defined in this package. * `downlit` 0.4.0 has been released with support for `rgl`, so instructions for installing the devel version have been removed. ## Bug fixes * Fixed rendering of text as sprites3d() objects. * Added `--static` flag to configure script for FreeType installation. (Suggestion of Simon Urbanek and Prof. Brian Ripley.) * `shade3d()`, `wire3d()` and `dots3d()` overrode `"front"` and `"back"` material settings in mesh objects. * `rglwidget()` handling of bounding box decorations had several bugs. * `rgl` could not find routines in the DLL on some Windows installs (Issue 148.) * Some cases where allocations were not protected have been fixed. # rgl 0.107.10 ## Major changes * Added `expect_known_scene()` function to work with `testthat`. * Added some `testthat` tests. * Prepend a 5th entry to `par3d("mouseMode")`, corresponding to actions to take when no button is pressed. * Allowed any of the mouse modes to be applied to the mouse wheel. * Added the `setUserCallbacks()` function to allow user-specified mouse callbacks in WebGL code. * Added Javascript code for support of movable axis labels in `bboxdeco` objects. * Most drawing functions can now draw in the margins using new material properties `margin` and `floating`, with objects that move as the bounding box changes. See `?mtext3d` for details. * The `mtext3d()` argument order has changed. * Added the `setAxisCallbacks()` function to allow user-specified axis drawing routines. * Exposed (and generalized) the `as.tmesh3d()` function. ## Minor changes * The `shiny` and `manipulateWidget` packages have been changed from imports that are always loaded to suggested packages that will only be loaded if needed. This will reduce the "footprint" of `rgl` for users who don't use them. * The NULL device can now specify `par3d("useFreeType")` and the result is saved. * Code to work with pre-1.33 versions of `knitr` has now been removed. * Added documentation of Javascript to web page. * The handling of the `RGL_DEBUGGING` environment variable has changed: now it must look like `TRUE` to trigger Javascript debugging mode. * Argument `webshot = TRUE` has been added to `movie3d` (issue #113). * The assert() macro is now always defined. * In Windows, the `WM_PAINT` handler should be more tolerant of code called while painting. * `as.mesh3d.default()` can create segments. (Contributed by Michael Sumner.) * `compare_proxy.mesh3d()` has been modified to be compatible with both current and upcoming versions of `waldo`. ## Bug fixes * The bug workaround in 0.105.22 for issue #27 triggered a bug in RStudio, resulting in two RStudio processes showing up when `rgl` was loaded. The workaround is now skipped when RStudio is detected. Use `options(startQuartz = TRUE)` in RStudio before loading `rgl` to run it, or `options(startQuartz = FALSE)` to suppress it. * In some cases, snapshots in `rmarkdown` documents were produced at the wrong size. * Controls failed to modify sphere colors (e.g. as in `example(playwidget)`, issue #102) # rgl 0.106.8 ## Bug fixes * Some of the changes related to avoiding `testthat` errors in other files accidentally introduced a new error in coloring meshes in `rgl`: now fixed. * `readOBJ()` was broken by the 0.106.x changes. * `merge.mesh3d()` failed for meshes containing points or segments. # rgl 0.106.6 ## Major changes * Changes for `pkgdown` compatibility have been added. See `vignette("pkgdown")`. * Added `drape3d()`, to "drape" objects across a mesh. (Contributed by George Helffrich.) * Added `shadow3d()` to project one mesh onto another. * Added `facing3d()` to subset a mesh to parts facing in a particular direction. * Meshes may now include points and line segments as well as triangles and quads. The arguments to `as.mesh3d.default()` have changed accordingly, and a new function `mesh3d()` has been added. * Reformatted the `inst/NEWS` file so it is visible here. * Added `asHomogeneous2()` and `asEuclidean2()` to work directly with `3 x n` and `4 x n` matrices. * Added `rglExtrafonts()` to load additional fonts for use with FreeType rendering. Requires the `extrafont` package. ## Minor changes * The help pages have been edited to continue to de-emphasize `rgl.*` functions. * Changes have been made for compatibility with the experimental Windows-UTF8 build of R. * Allowed infinite values for strip limits in `filledContour3d()`. * Setting material property `point_antialias = TRUE` now gives round points in `rglwidget()` displays. * The reuse argument in `rglwidget()` is no longer used. * Sphere initialization in WebGL displays is now done entirely in Javascript. * Set "window_group" in X11 so `rgl` windows are grouped, based on code by Ivan Krylov. * `filledContour3d()` now accepts levels in decreasing order. * `mergeVertices()` and `as.mesh3d.rglId()` have been improved. * `r3dDefaults$useFreeType` is now set to `FALSE` on Windows, so that system fonts will be used by default. * Text `family = "symbol"` has never really worked, and is no longer recommended. * Added `compare_proxy` method in case a recent `testthat` is being used. ## Bug fixes * The width and height of an `rglwidget()` once again adapt to the viewer window in RStudio (issue #74). # rgl 0.105.22 ## Minor changes * Add `Biarch` to `DESCRIPTION` so both architectures are built on Windows. ## Bug fixes * Fixed error in new args to `snapshot3d()` (reported by Tony Hirst: https://github.com/dmurdoch/rgl/issues/21 .) * Improved test for presence of WebGL (suggested by Git Demont, https://github.com/dmurdoch/rgl/issues/31 ). * On macOS an interaction between `rgl` and the `quartz()` device caused a segfault (see issue #27). Added workaround. (reported by Rich Heiberger, https://github.com/dmurdoch/rgl/issues/27). * Fixed a bug affecting fat (`lwd > 1`) line segments in `rglwidget()`. * A bug in the `Makevars` files caused builds using a parallel make to fail. * A bug in conversion of displays to WebGL prevented planes from displaying properly. * In `rglwidget()`, background images could cause other parts of the display to disappear. # rgl 0.105.13 ## Major changes * Inclusion in `knitr` documents will now be simplified in versions of `knitr` that incorporate its PR#1892. * Added `webshot` argument to `snapshot3d()`, to use the `webshot2` package (currently only available from Github; see `?snapshot3d` for details) to produce snapshots even on headless systems. * Moved development home from R-forge to Github. ## Minor changes * Windows builds now download Freetype from `rwinlib` during the build. (Contributed by Jeroen Ooms.) * `shinySetPar3d()` now accepts a list, as returned in `input$par3d` by `shinyGetPar3d()`, as input. (Suggestion of Yohann Demont.) * The default color scheme for `filledContour3d()` changed in R versions previous to 3.6.0, as `hcl.colors()` didn't exist in those versions. (Reported by Daniel Baston.) * Testing shows that with the above change, `rgl` will now work in R versions from 3.3.0 up. * `snapshot3d()` now defaults to writing to a temporary file instead of failing if no filename is given. * Both `snapshot3d()` and `rgl.snapshot()` now return the output filename invisibly. * `rglwidget()` no longer tries to include both a snapshot and a WebGL scene: it can only do one or the other. * Now builds the non-OpenGL DLL and puts it in `inst/useNULL`, so `options(rgl.useNULL=TRUE)` before loading `rgl` will cause it to not use X11 at all. * Made the startup code more resilient in case X11 isn't working. * Set up a `drat` repository to hold the unreleased `webshot2` package. ## Bug fixes * Some bugs in `thigmophobe3d()`, `mergeVertices()` and `as.mesh3d.default()` have been fixed. # rgl 0.104.16 ## Minor changes * Added `--disable-opengl` configure option to run entirely without OpenGL (to support Apple M1 machines without GLX, and others which don't have X11 or OpenGL devel files installed). * Added explicit typecasts to suppress compile warnings. * Restored some of the Windows configuration from pre-0.101.2 to allow use on older R versions. * Dropped use of `mathjaxr`, which caused issues on Debian. * Experimental support for handling mouse selection in Shiny added, along with `"shinyMouse"` demo. * The result of `open3d()` now has class `"rglOpen3d"`, and `knitr` will use this during auto-plotting. ## Bug fixes * Fixed bug in `rglwidget()` that caused it to fail to display text if too many strings were in the same object. (Reported by Yohann Demont.) * Fixed some small bugs, found by `lintr`. * Fixed bugs in Shiny support, and moved Shiny demo code into single files in demo directory. * Fixed bugs in `addNormals.mesh3d()` method, added `angleWeighted` argument, defaulting to `TRUE`. * Fixed bugs in `rglwidget()` displays of transparent spheres. # rgl 0.103.5 ## Major changes * Added `clipObj3d()`, `contourLines3d()` and `filledContour3d()` functions. * Modified `clipMesh3d()` function to make it more consistent with the above three functions. The main incompatibility with the version in 0.100.26 is that only vertex coordinates are now passed to the clipping function. ## Minor changes * Add `merge()` method for `"mesh3d"` objects, and use it in `filledContour3d()`. * More deprecation of older `writeWebGL()` style controls. * Add extra `knitr` hooks, so support for `rgl` should be very similar to support for standard graphics output. * Major rewrite of the WebGL code so that transparency is handled better in `rglwidget()`. It has also been split into multiple files which are joined with "minification" on installation. * Added utility function `makeDependency()` to support Javascript library in source. * WebGL code now supports fog in scenes. The default `r3dDefaults` now sets `material$fog` to `TRUE`, and `bg$fog` to `"none"`. (In `rgl`, fog must be set *both* in the background and in the object to display.) The formula used in WebGL is slightly different than in the internal R display.) * `getr3dDefaults()` now has two optional arguments to specify what to retrieve, e.g. `getr3dDefaults("material", "color")` to retrieve `r3dDefaults$material$color`, with NULL if either part is missing. * Added `fogScale` parameter to `bg3d()` and `rgl.bg()` to allow increased or decreased fog. * Added `fastTransparency` parameter to `spheres3d()` and `rgl.spheres()`, to allow them to be drawn more quickly when transparency is used. * `"mesh3d"` methods for `shade3d()`, `wire3d()`, and `dots3d()` have been rewritten to share code, allowing meshes to have different front and back material properties. * New functions `cur3d()`, `set3d()`, `close3d()` and `ids3d()` have been added. Generally, users should use these rather than `rgl.cur()`, `rgl.set()`, `rgl.close()` and `rgl.ids()`. * `snapshot3d()` now has optional width and height parameters for the saved snapshot. * the cursor now reflects the mouse mode in `rglwidget()` displays. * Texture coordinates in mesh objects now act the same as colors with respect to the `meshColor` variable. * Touch events are now supported in WebGL. * Added `"snapshot"` `knitr` option to use when autoprinting. * Added defaults to `snapshot3d(width = NULL, height = NULL)`. * Added `as.mesh3d.rglobject()` method. * Added `clip_to_density` argument to `plot3d.lm()` method. * The build files have been updated to work with Rtools40 on Windows. * `rglwidget()` now saves a copy of the original scene, so it can be reconstructed or modified later. ## Bug fixes * Fixed some memory leaks found by `valgrind`, and problems seen on systems with no functional Asymptote or Pandoc. * A bug in the initial color of a mesh object has been fixed. * A bug in translating mouse coordinates (reported on StackOverflow by Richard Morey) when an `rgl` widget is included in a `Gitbook` has been fixed. * Modified `writeASY()` for compatibility with Asymptote 2.65. (Reported by Pavel Stříž.) * `pop3d()` has been modified slightly so that it no longer opens a new window if none is already present * added `setGraphicsDelay()` function to work around bug in macOS Catalina XQuartz. * Made various improvements to reduce notes and warnings during install, including suppressing deprecated OpenGL warnings on macOS. * Some declarations in WebGL made assumptions that were not valid on mobile devices. * The `"depth_mask"` material property was being ignored in `rglwidget()`. * `rgl.snapshot()` and `rgl.postscript()` could crash if a zero length filename was passed to them. # rgl 0.100.54 ## Minor changes * Changed `rgl.attrib(id, "normals")` so the normals will be returned whether or not the object is lit. (Suggestion of Tyler Morgan-Wall) * The labels used in `rglwidget()` are now independent of `set.seed()`, using code borrowed from Shiny for our own private RNG. * `getr3dDefaults()` now gets values from `rgl::r3dDefaults` if they are not present in the user's `r3dDefaults` list. * `bgplot3d()` now uses the background colour from argument `bg.color` (defaulting to the background color from `getr3dDefaults()`) rather than always choosing white. * The maintainer email address has been changed to murdoch.duncan@gmail.com. ## Bug fixes * Fixed bug in `plot3d.rglscene()` that caused restored subscenes to ignore the mouse. * `next3d()` no longer messes up when a user changes active subscenes. * If a sufficient version of Pandoc is not found, the vignettes will still run, but won't execute any `rgl` code. # rgl 0.100.50 ## Minor changes * Added `?rgl.init` help topic to describe initialization issues. * Added sanity check to setting of `par3d("windowRect")`. ## Bug fixes * Rewrote the initialization code to deal with problems related to indirect GLX and `Xvfb`. # rgl 0.100.47 ## Minor changes * `demo(stereo)` now uses `plot.raster()` rather than `image()`. * Added a section on textures to the main vignette. * The configure script has been updated. * The functions in the `tkrgl` package have been moved into `rgl`. * Demo tests are suppressed when run with the `rgl` null device. * The `anaglyph()` function in the `"stereo"` demo now prints information about failed pixel reads. * Included textures have been compressed (and in some cases repaired). * The tests of the demos have been moved to `inst/slowTests` so that running them is optional (and the CRAN checks will go faster). ## Bug fixes * Fixed a bug in `readOBJ()` that affected reading texture coordinates. * `rgl.pixels()`, `rgl.snapshot()` and `snapshot3d()` now read from the back buffer, which should increase reliability. * Fixed bug when setting `windowRect`: `viewport` was not always updated. * Fixed bug in handling mouse wheel events: they were not directed to the correct subscene. * Fixed bug in configure script for systems with `pkg-config` but no freetype2. * Fixed bug that caused `bg3d()` and `bgplot3d()` to wipe out fog setting. * Fixed `writeASY()` to work with a more recent version of Asymptote. Use `ver244 = TRUE` for the older version. * `plot3d(..., type = "s", add = TRUE)` chose a bad default radius for the spheres -- possibly even zero. * `planes3d()` could fail to draw the plane if it intersected a vertex of the bounding box of the scene. * In Shiny, controllers like `rglMouse()` did not automatically link to an `rglwidget()`. # rgl 0.100.30 ## Minor changes * Added `meshColor` as an argument to `tmesh3d()`, `qmesh3d()` and `dot3d()`; changed default to no longer give warning if `meshColor` is not specified. * Added `all.equal()` method for `"mesh3d"` objects, so that changes caused by the above are ignored. * Added `tri_to_keep` argument to `as.mesh3d.ashape3d()` for compatibility with conflicting method from `nat` package version 1.8.11. * Removed deprecated C++ functions `std::bind2nd` and `std::ptr_fun` as requested by CRAN. Other changes to remove compile warnings also made. # rgl 0.100.26 ## Major changes * added `clipMesh3d()` to allow smooth clipping of mesh objects * Made `plot3d.lm()` method handle a larger variety of models, by allowing for curved surfaces. * Added `as.mesh3d.default()` method to convert triangles or quads to a `"mesh3d"` object. * Added `as.triangles3d()` generic with methods to convert `"mesh3d"` objects into matrices representing triangles. * Added `as.triangles3d.rglId()` and `as.mesh3d.rglId()` methods to convert displayed objects to usable data. ## Minor changes * `open3d()` now signals an error if unnamed parameters are used * `toggleWidget()` now makes it easier to initialize the scene with some objects hidden. ## Bug fixes * Fixed the startup code so that systems that don't provide `uname` still work. (Suggestion of Settra Khemri.) # rgl 0.100.24 ## Bug fixes * Fix `thigmophobe3d()` to try to keep up with changes in `plotrix::thigmophobe()`. * Stop `rgl.postscript()` from writing files to current directory # rgl 0.100.19 ## Bug fixes * Fix some bugs detected by `valgrind` # rgl 0.100.18 ## Major changes * Added `shinyGetPar3d()` and `shinySetPar3d()` functions for Shiny interaction. * Added `thigmophobe3d()` function to place labels away from other points using `plotrix::thigmophobe()`. * Added `arc3d()` function to draw spherical arcs. * Added `"polygon_offset"` material property, to allow lines to be drawn on surfaces. * Added `plot3d()`, `persp3d()` and `as.mesh3d()` methods for `"triSht"` and `"tri"` classes (produced by `interp` and `tripack` packages.) * `plot3d()` methods for objects of class `"formula"` and `"lm"` and a `persp3d()` method for objects of class `"formula"` have been added. (A bug in the implementation of `as.mesh3d.deldir()` was found and fixed during the latter addition.) * `as.mesh3d()`, `plot3d()` and `persp3d()` methods for `"ashape3d"` objects from the `alphashape3d` package have been added. * The mouse mode (trackball, zoom, etc.) can now be applied separately to each individual subscene in a scene. (By default the mode is inherited from the root subscene.) * Added `par3d("userProjection")`, to allow the user to supply a change to the projection after all other display calculations have been done. * Added `par3d("activeSubscene")`, to allow mouse callback functions to determine which subscene was clicked. ## Minor changes * Added check for `"highp"` support to fragment shader in `rglwidget()`. * Updated `text3d()` and related functions: dropped deprecated argument `justify`, added `pos` and `offset` like base graphics `text()`. * Improved support of `"mesh3d"` objects: added print methods, added `meshColor` argument to `wire3d()` and `shade3d()` to control how colors are interpreted, added `"rgl.meshColorWarning"` option to control warnings about these changes. * The `plot3d.mesh3d()` method now has the same default for `aspect` as the default method. * `pch3d()` now allows separate `color` and `bg` specifications for each point. In addition, the default for the `"lit"` material property is now `FALSE`, so by default filled symbols will match the requested colour regardless of lighting. * Minor fix ups to the vignettes. * Now uses the `manipulateWidget::combineWidgets` function when putting multiple objects into a pipe. * Now accepts fixed CSS units in width and height for `rglwidget()`. * `playwidget()` is no longer an S3 generic function. * The configure code to detect freetype has been updated to use `pkg-config` (code contributed by Dirk Eddelbuettel.) * If a `playwidget()` has been initialized but it can't find the `rglwidget()` that it is controlling (likely due to a typo somewhere), it now throws an alert message. ## Bug fixes * Fixed texture bug introduced in fix in 0.99.16. * The `persp3d.deldir()` method didn't display labels properly. * When the X11 initialization failed, `rgl` messed up the S3 methods system. (Reported by Gregory Jefferis.) * Probably due to a compiler change, `rgl.bbox()` was returning 0/1 instead of the id of the axes. * `pch3d()` was failing in `rglwidget()` for some shapes. (Reported by Luca Scrucca.) * `par3d(mouseMode = "none")` was not implemented properly, so appeared to be a no-op. * Selection functions did not work well with subscenes. * Deleting an object that has been added as a 3D sprite caused `rgl` to crash. * A number of memory bugs found by `rchk` have been fixed. * Textures specified in global material list (e.g. by being used in `rgl.*` functions) were not handled properly. (Reported by Ty Tuff.) # rgl 0.99.9 ## Major changes * Added support for communication with other widgets using the `crosstalk` package. See `?rglShared` and `vignette("WebGL")` for details. * Added the `rglMouse()` function to allow the mouse mode to be changed in a WebGL display. ## Minor changes * Christophe Geuzaine's GL2PS library (used by `rgl.postscript()`) updated to version 1.4.0. * The Pandoc system requirement has been updated to 1.14, as 1.13.1 is no longer sufficient. ## Bug fixes * Fixed a bug causing the `rglwidget()` to fail to work in a `flexdashboard()` display. * Fixed a bug in Shiny interaction * Changed WebGL text rendering to avoid overloading browser. * Sphere rendering within R sometimes showed strange artifacts. # rgl 0.98.22 ## Minor changes * Record context (`ioslides`, `shiny`, etc.) in scene when `rglwidget()` is called. * Allow more than 16 scenes in `html_document`, `ioslides_presentation` and `slidy_presentation`. * `useSubscene3d()` now returns the id of the previously active subscene, to make temporary changes more convenient. * `renderRglwidget()` and `renderPlaywidget()` now have an optional argument `outputArgs` for use in dynamic R Markdown documents. * `rglwidget()` now warns if an object has too many vertices. * added an approximation to "polar" mouse controls to WebGL display. * the `"centers"` attribute now refers to the individual facets of spheres, rather than the whole sphere. Use `"vertices"` for that. * Tried to give a more helpful startup error message on macOS. * Added documentation to `rglwidgetClass` in Javascript. * `vertexSetter()` can now set plane parameters. * Modified `platform.cpp` so it works with `__STRICT_ANSI__` defined. * As many browsers have dropped support for setting line width in WebGL scenes, this has been redone in `rglwidget()` code using a vertex shader. Line endings and joins are rounded, not squared as in OpenGL. * The 65535 vertex limit has been removed (at least in browsers that support big indices). * The requirement that colors being controlled by an `ageControl()` or `vertexControl()` be duplicated in the original has been removed. ## Bug fixes * The rendering order is changed: now all opaque objects are drawn first, then all transparent objects. Previously this ordering was only done within subscenes, leading to rendering errors when transparent objects in one subscene were drawn before opaque objects in another. * transparent spheres sometimes showed rendering artifacts because they were not drawn from back to front. (Reported by Atte Tenkanen; original fix improved so nested spheres should now work. WebGL display could still be improved.) * `par3dinterp()` did not always choose the best direction for interpolation of the `userMatrix`. * The `toggleWidget()` function didn't work properly in Shiny. * Fixed addition of attribute to NULL. * Fixed bug where textures or normals caused `readOBJ()` to fail; added support for reading normals and texture coordinates. * `axes3d("bbox")` didn't send parameters to `bbox3d()`. * Fixed examples for `snapshot3d()` and `writeASY()` so that they don't change the working directory. # rgl 0.98.1 ## Minor changes * Cleaned up configure script. * Cleaned up dynamic entry points. * Added `add = FALSE` argument to `persp3d.deldir()`. * `"shiny.tag"` objects are now supported as inputs to `playwidget()`, so that `rglwidget()` values can be wrapped in `htmltools::div()` to set their style. * Added `figWidth()` and `figHeight()` functions for sizing `rgl` plots in R Markdown documents. ## Bug fixes * `layout3d()` handled multi-row cells incorrectly. (Reported by Felix Carbonell.) * Fixed a bug in `subsetControl()`, and added `toggleWidget()` * Renamed the `texture` argument to `persp3d.function()` to `texcoords` for consistency with other functions, and to avoid a collision with the `"texture"` material property. * Fixed bug in scene initialization that sometimes caused it to ignore initial control values. # rgl 0.97.0 ## Major changes * Added `plotmath3d()` function, and set `text3d()` to use it when necessary. ## Minor changes * Added `fixedSize` argument to `rgl.sprites()` and related functions. * ` material3d()` now silently ignores attempts to set read-only properties. * Added `setUserShaders()` for user-specified shaders (currently for WebGL only). * Added support for two-sided surfaces in WebGL. * Added `demo("rglExamples")` to display all the examples in the `rgl` help in a collection of web pages. This showed up a number of small bugs, which have been fixed. * `movie3d()` now optionally tries the R `magick` package first, then the external ImageMagick v7 command `magick` before trying `convert`. (The external change suggested by Earl F. Glynn.) * `par3d()` reports on the version of OpenGL that it sees (as component `"glVersion"`). ## Bug fixes * Fixed bug in conversion of bounding box decorations used in `rglwidget()`. * `addNormals()` gave an error if the mesh it was working with had degenerate triangles or quads. (Reported by Rolf Turner and Graham Griffiths.) * Auto-clipping sometimes changed result vectors into lists. * The controllers did not recycle some values correctly. * Fixed bug in initialization of `playwidget()`s. * Fixed some bugs in `pch3d()` (reported by Gina Joue). # rgl 0.96.0 ## Major changes * Added `as.mesh3d()` and `plot3d.deldir()` and `persp3d.deldir()` methods to allow plotting of surfaces defined by irregular collections of points. * Added `rglToLattice()` and `rglToBase()` functions to compute Euler angles for the `lattice::wireframe()`, `lattice::cloud()`, and base graphics `persp()` functions. * Added `arrow3d()` (based on the function of the same name in the `heplots` package). * Added `pch3d()` to give an approximation to plotting symbols using `pch=` in base graphics. * Added support for control of multiple subscenes to `spin3d()`, `par3dinterp()`, `play3d()` and `movie3d()`. * Added experimental function `writeASY()` for output in Asymptote format, which will allow inclusion in PDF files. * Added `rgl.attrib.info()` to display information about object attributes. * Merged `rglwidget` code back into `rgl`. * Functions that modify the scene now return their value with class `"rglLowlevel"` or `"rglHighlevel"` (using the new `lowlevel()` or `highlevel()` functions) to indicate that a low- or high-level plotting function has been called. If the new option `"rgl.printRglwidget"` is `TRUE`, printing objects of either class will trigger automatic printing of the `rgl` scene using `rglwidget()`. ## Minor changes * Gave better error when XQuartz is not found, tried for better test. * Added more information on backgrounds to `scene3d()` to allow them to be used in `rglwidget()`. * Now uses forward slashes in `rgl.postscript(fmt = "tex")` generated code. (Thanks to Uwe Ligges for the problem report.) * `cylinder3d()` now defaults to a rotation minimizing local frame. * Added this NEWS file. * Added better support for backgrounds. * Added support for orthographic projections (`FOV = 0`). * Added simple Shiny demo using tabs. * Added version dependency for `jsonlite` so that the new faster matrix code will be used. * The worker functions used by `subdivision3d()` have been exported for use on their own. * The `rglwidget()` code now supports textures on spheres. It now uses the same mesh as the one used inside R. (The lack of support was pointed out by Justin McManus.) ## Bug fixes * Background clearing was not handled properly. (Thanks to Paul Morse for a bug report on this.) * Fixed bug in rendering unlit 3D sprites. * Web browsers only support a finite number of active WebGL sessions; `rglwidget()` code now works to make more careful use of this finite resource, so that large numbers of `rgl` scenes can be present on a single web page without exhausting it. # rgl 0.95.1441 ## Bug fixes * Changed `rgl.pixels()` to attempt to avoid segfault on OSX. (Thanks to Greg Jefferis for testing and workaround.) # rgl 0.95.1435 ## Major changes * The Mac OS X native windowing system (`aglrgl.so`) has been dropped; it appears not to work in Yosemite and El Capitan. * WebGL code has been moved to the `rglwidget` package (though the functions in `rgl` still work). ## Minor changes * If `rgl.init()` fails, continue with the `NULL` device (with warnings). * `scene3d()` now returns the normals and offsets of "planes" objects, as with "clipplanes" objects. It still returns the triangles from embedding the planes in the most recent subscene. ## Bug fixes * A memory leak when drawing semi-transparent objects has been fixed. (Reported by Felix Kuehnl.) * Bounding box objects sometimes had miscalculated vertices in `scene3d()`. # rgl 0.95.1367 ## Major changes * Added `show2d()` to allow a 2d plot on a quadrilateral in a scene. * Added `matrixSetter()` function to allow multiple controls to modify one matrix. * Added `vertexSetter()` function to allow easier access to vertex attributes. ## Minor changes * Made error and warning text more consistent. * Dropped chunk option `"rgl.keepopen"`; replaced it with `"rgl.newwindow"`. * Added `accumulate` argument to the subset WebGL controls. * The `nticks` argument to `bbox3d()` was never used and has been removed. Use `xlen`, `ylen` or `zlen`. * Dependencies and imports have been updated. * Used Jeroen Ooms' `js::jshints()` function to clean up the WebGL Javascript code. * Allowed `values = NULL` in `propertySetter()` and `vertexSetter()` to allow code to directly set values. * Shaders are now stored in Javascript strings, not separate script sections. * Shape centers are now stored by `scene3d()`. * Font family and numeric font number (style) are now returned by `rgl.attrib()` and are stored by `scene3d()`. ## Bug fixes * Fixed bug that sometimes prevented textures from displaying. * `rgl.bbox()` (and hence `bbox3d()`, `decorate3d()`, `plot3d()`, etc.) did not return the correct id for the bounding box decoration. * Modified configure script to work with OS X 10.11 (suggestion of Brian Ripley). * Setting `xlen` etc. to zero in `bbox3d()` or `rgl.bbox()` now (correctly) suppresses tick marks. (Reported by Philipp Angerer.) * Specifying `normals` or `texcoords` in both a `"mesh3d"` object and a call to `shade3d()` to display it caused an error; now the `shade3d()` specified value has priority if `override = TRUE` (the default). * When used with clipping on the bounds, `persp3d()` and `plot3d()` did not work properly with a shared mouse. (Reported by Marian Talbert.) * Fixed a bug (reported by Dominick Samperi) that caused vignettes using WebGL code in `knitr` to fail to initialize properly. This required adding the `setupKnitr()` function, which should be called at the start of each vignette. It is *not* called automatically. * Fixed a bug (reported by Kurt Hornik) that caused `rgl` to fail to compile when `libfreetype` 2.6 was linked. * Fixed a bug in `writePLY()` (reported by Kurt Hornik). # rgl 0.95.1247 ## Major changes * Added `subsetSlider()`, `subsetSetter()`, `clipplaneSlider()`, `propertySlider()`, `ageSetter()`, `propertySetter()`, `par3dinterpSetter()` and `toggleButton()` functions to output HTML/Javascript controls for WebGL. * Added `hook_rgl()` and `hook_webgl()` functions, based on the `knitr` functions. * Added clipping regions to `plot3d()` and `persp3d()`. * Export the `GramSchmidt()` function (request of Remko Duursma) * Added `readOBJ()`, with a very limited ability to read OBJ shapefiles. ## Minor changes * If a template file is used in `writeWebGL()`, the string `%prefix%` will be replaced in it by the prefix argument. * `writeWebGL()` now outputs a Javascript global variable named `"rgl"` of class `"rglClass"` that allows access to many of the scene internals. (Inspired by patch submitted by Jeff Allen.) * User mouse callbacks can now be retrieved within R using `rgl.getMouseCallbacks()` and `rgl.getWheelCallback()`, and may be included in WebGL output. * `writeWebGL()` now outputs information on object ids to allow them to be re-used in multiple figures on the same page. See the `reuse` parameter and attribute of the result. * Started a vignette describing user interaction in WebGL. * Set the class of the main `"canvas"` element in `writeWebGL()` output to `"rglWebGL"`. * `rgl.snapshot()` now evaluates the `top` argument after `filename` and `fmt`, so windows created when those are evaluated don't overlay the `rgl` window. (Suggestion of Keith Jewell.) * `writeWebGL()` now includes an argument `commonParts`, to allow omission of common code in multi-figure displays. * If `template` is `NULL` in `writeWebGL()`, no template file is used. * The `persp.function()` method is now smarter about setting default axis labels. * The package now contains a vignette giving an overview of the functions. * `triangulate()` now supports polygons expressed with 3 coordinates (though they are still assumed to be planar). * `par3d()` now includes `"listeners"`, a list of subscenes that respond to mouse actions in the current subscene. * The Windows configuration file has been modified to work in R-devel (to become R 3.2.0). ## Bug fixes * Fixed bug in `abclines3d()` that caused it to skip lines that passed through the corners of the bounding box. (Reported by Sven Laur.) * The `NULL` device did not handle changes to `par3d("windowRect")` properly. * Subscenes with `ignoreExtent = TRUE` were not plotted. * The bounding box calculations now take clipping planes into account. * `writeWebGL()` did not display the `bboxdeco` properly when working in a subscene. # rgl 0.95.1158 ## Minor changes * `rgl.snapshot()` now works with the `NULL` device (but produces a black snapshot). This allows testing with `RGL_USE_NULL`. # rgl 0.95.1157 ## Major changes * Allowed background of window to show bitmap; added `bgplot3d()` and `legend3d()` functions. ## Bug fixes * Reverted misguided changes to `par3d("modelMatrix")` from 0.94. This affects `rgl.projection()` as well. * Fixed bug (introduced in 0.94) causing loss of rectangle showing selection area. (Reported by John Fox and others.) * The `NULL` device now does not make any spurious OpenGL calls. # rgl 0.94.1143 ## Major changes * Added function methods for `persp3d()` and `plot3d()`, to allow surfaces to be plotted just by specifying the function. ## Bug fixes * Fixed a bug introduced in 0.94 that made user callbacks crash R. (Reported by Dave Hadka.) * Fixed a bug exposed in 0.94 (but really introduced in 0.93.952) that caused `writeWebGL()` to fail when a `NULL` device was active. * Fixed a bug introduced in 0.94 with writing 3D sprite objects. * Fixed a bug computing the bounding box of an embedded subscene. # rgl 0.94 ## Major changes * Added "subscenes", i.e. scenes of objects nested within the main window. This affects a lot of other functions as well, which now act either on a single subscene or on the overall scene. * Added configurable mouse wheel actions via `par3d()` or `rgl.setWheelCallback()`. ## Minor changes * Allowed the coordinates of the viewport to be set. * Changed the behaviour of `pop3d()` and `rgl.pop()`: the type is now ignored if `id` is non-zero. * `par3d("modelMatrix")` no longer includes the observer translation * The `par3d()`, `par3dinterp()`, and `spin3d()` functions now have arguments dev and subscene to specify where they apply. * Included a copy of the source to `CanvasMatrix.js` (used by `writeWebGL()`) at the request of the Debian administrators. * Some of the animations have been sped up at the request of CRAN. ## Bug fixes * The `NULL` device was not removed from the device list when it was closed. (Reported by Henrik Bengtsson.) # rgl 0.93.1098 ## Minor changes * `rgl.material()` (for textures), `rgl.postscript()` and `rgl.snapshot()` now call `normalizePath()` on filenames, so tilde expansion should be supported. * internals are updated to be consistent with macOS 10.9 requirements * Improved the approximation to the surface normal for degenerate grids in `surface3d()` and `persp3d()`. (Problem found by Graham Griffiths using polar coordinates; all `r=0` points were at the same location.) * The new surface normals are now saved in memory, so `rgl.attrib()` will return them even if they were calculated by `rgl`. * `scene3d()` now records light settings. ## Bug fixes * `par3d()` could generate an error if an unnamed list was passed in. * ` material3d()` lost settings for textures * fixed a bug in triangulation code: it failed on `locator()` input. * The Aqua support now works again, XQuartz is only needed for command line use in Mac OSX. * Bounding box calculations for surfaces with user normals were incorrect. * An array-overrun bug in `rgl.attrib()` showed up in `writeWebGL()`. (Reported by Brian Ripley.) # rgl 0.93.991 ## Major changes * Added `clipplanes3d()` function to implement clip planes. (Still only partially implemented.) ## Minor changes * Some cleanup of the declarations (submitted by Karl Millar). # rgl 0.93.986 ## Bug fixes * The FTGL functions were mistakenly added to the `rgl` namespace on some OSX compiles. * Changes have been made to satisfy the stringent requirements of the Solaris compiler. # rgl 0.93.984 ## Minor changes * most `rgl` C++ functions and classes are now in namespace "rgl". Others have prefix rgl_, with the exception of gl2ps functions, which all have that prefix, and FTGL functions, which generally have an FT prefix. * entry points to the `rgl` DLL are now registered within the DLL, and on systems that support it, all entry points other than the registration function are hidden. ## Bug fixes * `writeWebGL()` and the other write methods did not handle material information properly after 0.93.975. # rgl 0.93.975 ## Minor changes * the `scene3d()` function now records complete information about the bounding box and the background. * `rgl` declares most of its C++ objects in the global namespace. Recently this has caused clashes with the `igraph` package, which does the same, and which also has a Shape class. As a temporary workaround the `rgl` class has been renamed to `"rglShape"`. A full `rgl` namespace will eventually be added, with only the API functions left in the global namespace. ## Bug fixes * `rgl.texts()` without a window failed because it queried the window before opening it. # rgl 0.93.963 ## Minor changes * font selection assumed `rgl` was on the search path; now it may be imported but not attached. Similarly, `r3dDefaults` need not be on the search path. # rgl 0.93.960 ## Minor changes * `writeWebGL()` now forces the position attribute to location 0, a recommended optimization strategy. The color attribute is forced to location 1. * gl2ps has been updated to version 1.3.8 and support for point and line sizes has been added (bug 4792) * internal functions `.check3d()` and `rgl.select()` have been exported, as they were used by the car package. * `rgl` now prints a warning when a requested font is unavailable and the default font is substituted. ## Bug fixes * we now check for invalid characters when drawing text using bitmapped fonts (bug 4787) * `writePLY()` had errors writing points and lines. # rgl 0.93.952 ## Major changes * added `triangulate()`, `polygon3d()`, `extrude3d()` and `turn3d()` for display of shapes based on two-dimensional polygons or curves. * added support for "headless" operation: see help for new function `rgl.useNULL()`. ## Minor changes * added name of device to result returned from `rgl.cur()`; added function `rgl.dev.list()` to list all open devices. * examples and demos now check `rgl.useNULL()`, and don't run invisible animations. ## Bug fixes * fixed formatting of vertex reference numbers in `writeOBJ()` (issue 4732, reported by Alejandro Baranek). # rgl 0.93.944 ## Major changes * added `identify3d()` function ## Minor changes * write the `rgl` version into the WebGL file * cleaned up use of `CHECKGLERROR`, so that setting `USE_GLGETERROR` to 1 in `R.h` will enable detailed checking ## Bug fixes * fixed bbox bug in `writeOBJ()` (reported by Matthias Zeeman), `writePLY()` and `writeSTL()`. * `aspect3d()` (called by `plot3d()`) caused the scene to be redrawn, even if `par3d("skipRedraw")` was `TRUE`. * `addNormals.mesh3d()` failed on objects when the matrices of triangles or quadrilaterals had zero columns. * `rotate3d.mesh3d()` did not transform normals properly * the `writeWebGL()` function produced fragment shaders that would not work in some browsers (e.g. Firefox and Chrome with the ANGLE WebGL engine). # rgl 0.93.935 ## Bug fixes * in certain circumstances since 0.93.930, text would fail to appear. (Reported by Karline Soetaert.) # rgl 0.93.932 ## Bug fixes * calling `rgl.material()` before any rendering caused a crash on OSX. (Reported by Dan Tenenbaum.) # rgl 0.93.930 ## Minor changes * Now handles local (not just directional) lighting. Based on code contributed by Alexander Senger.) * `writeWebGL()` handles lighting properly. Based on code contributed by Alexander Senger. ## Bug fixes * `writeWebGL()` did not handle `snapshot=FALSE` properly. (Reported by Yihui Xie.) # rgl 0.93.928 ## Minor changes * Updated the configure file using autoconf 2.69 * Forced OSX installs to put `/usr/X11/bin` at the head of the path when looking for freetype-config # rgl 0.92.879 ## Major changes * Added `writeWebGL()` function, to allow scenes to be viewed in a web browser. ## Minor changes * Removed `rgl.save.texture()`: textures are not saveable! * Added "centers" to the attributes that can be queried, for depth sorted transparent rendering. # rgl 0.92.880 ## Minor changes * Rearranged declarations for compatibility with gcc 4.7. # rgl 0.92.881 ## Bug fixes * Fixed degenerate (e.g. straight line) cases in `cylinder3d()`. # rgl 0.92.883 ## Major changes * Added 3d "sprites" -- shapes that maintain their initial orientation. # rgl 0.92.887 ## Minor changes * Added "caps" to the end of `cylinder3d()` objects. # rgl 0.92.891 ## Minor changes * Added support for 3d sprites to `writeWebGL()`. # rgl 0.92.892 ## Minor changes * Added declaration needed by Solaris. # rgl 0.92.893 ## Bug fixes * `rgl.light()` and `light3d()` did not return the light ID value. # rgl 0.92.894 ## Bug fixes * remove debugging code from `configure.win` that was causing problems on the CRAN WinBuilder system # rgl 0.93 ## Major changes * Added `readSTL()` and `writeSTL()` functions * Added `writePLY()` and `writeOBJ()` functions * Added `scene3d()` function * Added `selectpoints3d()` function to select points from the scene. ## Minor changes * Added `expand` argument to `decorate3d()` and `axes3d()` * Added `base` argument to `spin3d()` result * Added section argument to `cylinder3d()` * Added `res_name="rgl"` and `res_class="R_x11"` to the `WM_CLASS` property of X11 windows. (Contributed by Philip Johnson.) * Added code to work with R 3.0.0 `setHook()` changes * The `rgl` window now handles `ESC` key presses. During selection and `play3d()` they abort the process; otherwise they are ignored. * Copied the `R_pretty0()` function from R sources to avoid warning. ## Bug fixes * `writeWebGL()` did not render semi-transparent surfaces properly. (Reported by Robert Esswein.) # rgl 0.92.861 ## Minor changes * Added `rgl.save.texture()` to get texture from an object. ## Bug fixes * Fixed segfault on startup on Windows in MDI mode. # rgl 0.92.858 ## Major changes * Added `Sweave()` support through the `rgl.Sweave()` driver and the `Sweave.snapshot()` function. * Added `rgl.abclines()`, `rgl.planes()`, `abclines3d()` and `planes3d()` to draw lines and planes intersecting with the bounding box. * Functions `rgl.attrib.count()` and `rgl.attrib()` (and internal function `rgl.getmaterial()`) added to allow objects in the scene to be examined. ## Minor changes * Added declarations for Solaris compatibility (from Brian Ripley) * Fixed `configure.win` for bi-arch compatibility. Windows installers can set `HAVE_PNG` to a non-empty value, and `rgl` will look for the libpng files in the default `LOCAL_SOFT` location when installing. * Added `"depth_mask"` and `"depth_test"` material properties, to allow control over how objects are obscured by each other. * Added iterative computation of the bounding box to handle objects like spheres, which need to maintain their apparent shape as the scaling changes. * Improved the bounding box decoration in two ways: it can now draw the front faces (to surround the whole graph), and can label edges with pretty labels. `plot3d()` was modified to use this instead of manually setting axis locations and using `box3d()` to draw a box, allowing resizable labelled axes. * Removed some unnecessary declarations from `rglmath.h` that were causing problems in an old version of gcc on Solaris. * `rgl.postscript()` now adjusts the size of text following the `cex` setting. The `font` and `family` settings are still ignored. * Transparency in material textures was not always rendered properly. * In OSX, the Carbon system has been replaced by a Cocoa system. (Code contributed by Adam Strzelecki). For compatibility with the Windows build system, the new files have been put into `src/osx`. * Hardware antialiasing is now used if the OpenGL driver supports it. Set `options(rgl.antialias=0)` to disable it. * Updated gl2ps to version 1.3.6 ## Bug fixes * Bug fix for `divide.mesh3d()` in handling normals. * `rgl.ids()` did not return all object ids as documented. # rgl 0.92 ## Minor changes * Added detection of 64 bit MacPorts compiler to configure script. (Bug #861) * Allowed texture coordinates to be specified in mesh objects. * Updated gl2ps to version 1.3.5 * Should now install using `--merge-multiarch` on Windows # rgl 0.91 ## Minor changes * Added `R_ARCH*` macros to `configure.win` for Win64 compatibility ## Bug fixes * Fixed bug in `rgl.texts()`: zero-length texts argument caused crash. (Reported by Michael Friendly.) * Fixed bad declaration in `rglmath.h` # rgl 0.90 ## Minor changes * Added `startTime` argument to `play3d()` and `movie3d()`. * Fixed `configure.ac` as suggested by Jens Elkner. * Updated declarations for libpng 1.4.0 compatibility. ## Bug fixes * An off-by-one error caused the `"alpha"` component of the material properties to be messed up. (Bug #809) # rgl 0.89 ## Bug fixes * Fixed rounding errors and `Xvfb` errors in `rgl.pixels()` examples and demo. # rgl 0.88 ## Minor changes * Add `keepVars` argument to `cylinder3d()`, for debugging or special effects. * Add `BugReports` field to `DESCRIPTION`. # rgl 0.87 ## Minor changes * Allowed `FOV` to be set to 0, for an orthogonal projection. * Changed `seq(along=...)` to `seq_along(...)`. ## Bug fixes * Fixed crash when zero-length color vector was used. * Fixed crash in X11 after closing a window * Fixed typo in `cylinder3d()`. * Cleaned up bad links in Rd files. # rgl 0.85 ## Major changes * Added `addNormals()` generic, to add normals for smooth surface rendering. * Added `cylinder3d()` function, to make cylindrical or "tube" plots. ## Minor changes * Added some namespace declarations to the C++, and renamed `math.h`, for compatibility with Sun compilers (contributed by Brian Ripley). * Fixed visibility of some `shade3d()`, `wire3d()` and `points3d()` methods. ## Bug fixes * Fixed `material3d("color")` bug introduced in 0.82. # rgl 0.84 ## Major changes * Added triangle meshes, shape lists, the Platonic solids and a cuboctahedron. * Added classes `"mesh3d"` and `"shapelist3d"`; `"qmesh3d"` is only kept for back compatibility. ## Bug fixes * Bug fix to stop crashes when material is set before the first window is opened. # rgl 0.83-3 ## Bug fixes * Quick fix for R 2.9.x compatibility, and to remove accidental change introduced in v0.83 which caused errors on plotting without `open3d()`. # rgl 0.83-1 ## Minor changes * Don't try to build Carbon driver in 64 bit Mac OS (contributed by Brian Ripley). * Did not assume OpenGL 1.2 was available in material properties. * Added numerous error checks. ## Bug fixes * Fixed `rgl.pixels()` example for weird displays. * Fixed `demo(stereo)` to add sync in X11: X windows seemed to grab images before they were redrawn. * Rearranged headers for Win64 compatibility (contributed by Alex Chen). # rgl 0.82 ## Major changes * added `rgl.pixels()` to read the generated image, and `demo("stereo")` to illustrate its use. ## Minor changes * rewrote internal rendering of transparent and anti-aliased shapes, so they will be rendered better when there are several in the same scene * added material properties `"point_antialias"`, which causes points to be drawn as smooth circles, and `"line_antialias"`, which causes lines to be antialiased. * added material parameter `"lwd"` for line width; `"size"` now applies only to points. * increased default point size to 3 pixels across. * `movie3d()` gains a "type" argument to set the output type, and the `convert` argument is more flexible. * `rgl.snapshot()` gives more informative error messages when libpng is not available. * `axis3d()` now uses `format()` rather than `as.character()` to give nicer looking labels. * use R `warning()` to report messages, rather than popups or `REprintf`. ## Bug fixes * fixed a bug in the bounding box decoration which caused axis labels to be plotted in the wrong place. * fixed a bug in the Windows driver which caused the standard system font to disappear when justified. * fixed bug in `open3d()`: "..." was being ignored. * fixed bug in `qmesh3d()`: `homogeneous=FALSE` coordinates were not handled properly. * the clipping volume calculation was incorrect when scaling was used. * corrected the `?rgl` example to display this file. # rgl 0.81 ## Minor changes * converted Freetype font error into warning ## Bug fixes * `rglFonts()` was being set at install time, but it should be set at load time. * fixed configuration problems in OS X * fixed executable marker on a number of files # rgl 0.80 ## Minor changes * worked around bug(?) in Mac OSX FTGL rendering * updated FTGL to 2.1.3rc5 # rgl 0.79 ## Minor changes * added `mouseCallbacks()` demo, to show R implementations of standard mouse handlers, multiple connected windows, stereo view, etc. * added "silent" argument to `rgl.set()`, to allow temporary changes to focus without changing window labels. * added natural spline extrapolation to `par3dinterp()`. ## Bug fixes * `rgl.pop()` could cause corruption when multiple windows were open. # rgl 0.76 ## Minor changes * rename ChangeLog file to NEWS, as per discussion on R-devel * add `"windowRect"` to `par3d()` parameters to allow window size to be controlled from R. ## Bug fixes * put our own `assert()` macro in place to avoid crashing R. # rgl 0.77 ## Bug fixes * `par3d("windowRect")` returned garbage if there was no window open. * `persp3d()` and `plot3d()` sometimes miscalculated ranges involving NAs. * `select3d()` and `rgl.select()` produced a very inefficient test function. # rgl 0.78 ## Minor changes * `rgl.texts()` and `text3d()` can now handle font and size specifications using the FreeType library on any platform, or GDI on Windows. * `adj` is supported both horizontally and vertically in drawing text. ## Bug fixes * fix miscalculation of `mouseMatrix` that caused disappearing views. * `rgl.pop()` was very slow when given a long list of ids. * a workaround for OSX 10.5 OpenGL problems has been incorporated (thanks to mkv22@cam.ac.uk). # rgl 0.75 ## Major changes * add `play3d()`, `movie3d()`, `par3dinterp()`, and `spin3d()` functions, with flag demo ## Bug fixes * rounding error could cause `par3d("userMatrix")` to generate NaNs and fail * workaround for `Xvfb` on macOS problems # rgl 0.74 ## Major changes * add `rgl.setMouseCallbacks()` to allow user actions ## Minor changes * clean up `#include`s * clean up some calls for SunStudio 12 compiler # rgl 0.73 ## Minor changes * partial changes to avoid crash on macOS with `Xvfb` * change to `rgl_init()` for R 2.6.0 compatibility # rgl 0.72 ## Minor changes * declaration changes for compatibility with R 2.6.0 (from Brian Ripley) # rgl 0.71 ## Major changes * allowed normals and texture coordinates to be specified in triangles, quads and surfaces ## Minor changes * changes to configure script from Laszlo Kajan and Brian Ripley: should now be much more portable * removed deprecated OSX font setting calls * texture properties are now returned by `material3d()` * normals may be specified in `qmesh` objects, but (at present) `subdivision3d()` removes them * ` material3d()` now preserves the values of unspecified parameters (as documented, but not previously functioning) * `clear3d()` can now reset material properties to the defaults, and `open3d()` does this. * minor fix for gcc 4.3 compatibility * minor fix for R 2.5+ compatibility * allowed more general surfaces to be plotted by `rgl.surface()`, `surface3d()` and `persp3d()`, by specifying matrices for x and y coordinates * added world map texture, used in `example(persp3d)`. # rgl 0.70 ## Minor changes * OSX now builds two libraries, one for AGL, one for X11 * resolve entry points at load time, not call time * updated gl2ps to version 1.3.2 * tweaked positioning of labels in bounding box decoration * moved this file (ChangeLog) to inst directory, so it will be installed, and added code to display it to the `rgl` help topic. ## Bug fixes * fixed bug in `rgl.postscript()` in Linux, added text support to it * `snapshot3d()` wasn't being exported, and snapshots were from the back buffer * fixed bug that could cause crash on shutdown # rgl 0.69 ## Minor changes * allow selection to use any button * allow NA in primitives, surfaces, texts, and sprites * report error in OSX if the wrong configure options were used. ## Bug fixes * `persp3d()` partially ignored `add=TRUE` * `plot3d.qmesh3d()` did not return result * display was not being updated properly in OSX # rgl 0.68 ## Major changes * added `grid3d()`, added `nticks` argument to `bbox3d()`, `axis3d()` and `axes3d()`. ## Minor changes * fixed sphere drawing so spheres are spheres regardless of `par3d("scale")` * added `type="s"` to `plot3d()` to draw spheres * fixed handling of "..." in axis related functions * added full MDI support * removed use of `List` and `ListIterator` internally * fixed handling of axes and boxes when a coordinate had zero extent * changed `rgl.viewpoint()` default to be compatible with `r3dDefaults` * added id return values to primitives and higher level functions, and to `rgl.pop()`; added `rgl.ids()` to report on them. * updated gl2ps to version 1.3.1, adding support for svg and pgf output formats. # rgl 0.67-2 * minor correction # rgl 0.67 * added support for png files with palettes, and grayscale pngs with 1, 2 or 4 bits per pixel * added `"ignoreExtent"` option to `par3d()`: objects plotted when this is true are ignored when calculating the bounding box * added `axis3d()`, `axes3d()`, `box3d()`, `mtext3d()`, `title3d()` functions from `djmrgl` for annotating plots. * added `plot3d()` high level plot function * added ` material3d()`, which can both set and query material properties; changed most `*3d` functions so they leave material invariant across calls. * changed `open3d()` to set background and material defaults * added `aspect3d()` to control the aspect ratio of the bounding box. * added `xAxis`, `yAxis` and `zAxis` mouse modes, set `zAxis` as `r3d` default. * added `persp3d()` function * changed error messages to go through `REprintf` in X11 and OSX * fixed segfault if `rgl_init()` failed * converted type of `viewport` argument in `user2window()` and `window2user()` calls * if the `rgl_init()` call fails, the package will still load with a warning (but most function calls will result in errors). * added `par3d("scale")` to handle `aspect3d()` operations internally. * added `ellipse3d()` generic and methods for drawing confidence ellipsoids * added `decorate3d()` to draw all the decorations, `plot3d.qmesh3d()` method. * changed zoom to use ratio scale over larger range * fixed bug causing jump after resize in Mac OSX (and maybe other platforms) * `rgl.primitive()` now does sanity checks on inputs # rgl 0.66 * added `"all"` and `"viewpoint"` to `rgl.clear()` and `clear3d()` * added static libpng build support and user customizable prefix (unix) * used `xyz.coords()` in all functions taking x, y, z coordinates, allowing matrix or dataframe arguments (among others) * added `par3d(skipRedraw=TRUE)` to allow drawing to be done without being rendered * fixed display list memory leak when drawing shapes (e.g. spheres) * Changes for compatibility with strict enforcement of file naming rules in R 2.3.0. # rgl 0.65 * simplified build system: uses 'R' build system * added generic visualization/rendering interface (R3D) * text justification from 0 to 1 * added primitive type: `linestrip` * fixed `rgl.bringtotop()`, added stay option (win32) * added 4x4 matrix functions from `djmrgl` * added `rgl.user2window()` and `rgl.window2user()` functions * added user-selectable mouse handlers * added selection mouse handler * added trackball mouse handler * added z-distance sorted rendering of alpha-blended faces * added gl2ps patch ( contributed by Albrecht Gebhard ) * added port: native Mac OS X Carbon * bugfix: `rgl.close()`, `rgl.quit()` crashed on X11 occasionally. * generalized `rgl.surface()` to allow surface over any coordinate plane. * added `r3dDefaults` variable to allow user to set defaults * added environment texture-mapping # rgl 0.64-13 * DESCRIPTION fix: moved R 1.41 -> R 1.4.1 dependency # rgl 0.64-12 * CRAN bugfix: permissions of cleanup fixed. # rgl 0.64-11 * removed several redundant semicolons, required by gcc 3.4 ansi-pedantic mode. * win32: uses R's `zlib` and `libpng` sources * win32: added virtual destructor in `Win32GUIFactory` (removes warning) # rgl 0.64-10 * updated `.C()` calls using `PACKAGE="rgl"` * updated `Maintainer.mk` using correct `zlib` version * improved dynamic unload using `library.dynam.unload()` * conditional macOS x Darwin code in `.First.lib()` # rgl 0.64-9 * macOS X 'Panther' G5 fix for OpenGL library loading in .first.lib * removed `lpng` and `zlib` from source tree * support for automatic downloading of `zlib` and `lpng` on win32 * added demo directory with several examples using `demo(rgl)` # rgl 0.64-8 * build bugfix : removed `rgl/src/Makefile` * updated configure to check and setup `LDFLAGS` for `OpenGLU` library # rgl 0.64-7 * added mouse capturing * `rgl.sprites()` 'radius' bug fixed * memory leak bugfix: texture objects are now `AutoDestroy` and used through `Ref`'s * resource management improvement: pixmaps get `free`'d when they become unused e.g. texture objects are created. * no limitations on pixmap sizes * mipmap support * support for different texture minification and magnification filters # rgl 0.64-6 * updated build system: added `setversion.sh` * with MinGW version 3.0.1 pixmap loading does work * `project.mk`, `win32.mk` and `x11.mk` in `src/build` changed now a single variable MODS will extend. * MinGW build system changed. `rgl.dll` now contains an R compliant Resource information generated by R `perl` script * bug fix: R 1.8.0/win32 does not detach packages when quit it is safe now to call `rgl_quit()` and `lib_quit()` multiple times `win32lib.cpp`: added `dllmain` that calls `rgl_quit()` on process exit * added core support for `devcpp` IDE # rgl 0.64-5 * macOS X/X11 port # rgl 0.64-4 * manual update * acquired valid CRAN package status, `R CMD check` runs through with 2 WARNINGS (according to `latex`, and `codoc`) * uploaded to cvs # rgl 0.64-3 * configure.ac: X11 library path broken, fixed * `x11gui`: `glXChooseVisual()` part fixed * code cleanup: `rglview.h` * added: `man/maintainer.Rd` maintainer information # rgl 0.64-2 * `rgl.quads()`: `enum` id was broken, fixed ("quads" -> "quadrangles") # rgl 0.64 * autoconf build system * moved textures to `inst/` directory * x11 port * `win32/vc`: fixed fpu control word precision to remain on 64 bit links with `fp10.obj` * changed texture mapping t coordinate for Surface node # rgl 0.63 * API: added `rgl_init()`, `rgl_quit()`: explicit client initialization * added `setup.bat`: build setup for windows * win32 setup: MinGW compiler * win32 setup: visual c++ compiler through `gui` environment # rgl 0.62 * modified sphere set * support R color strings * use `system.file( , package="rgl" )` in examples to retrieve texture files * rewrote R code : * clear `enum` types * vertex vector datatype (internal representation matrix) # rgl 0.61 * added: `rgl.sprites()` * added: fps counter * added: `autoUpdate`, modified win32 main loop, on hide, `autoUpdate` disabled, on show enabled * modified material: added alpha vector # rgl 0.60 * (mini-thesis release) rgl/configure.ac0000644000176200001440000001600415011677075013336 0ustar liggesusers## ## This file is part of RGL ## ## Process configure.ac with autoconf to produce a configure script. ## NB: the files in src/build/autoconf may need updating for a new ## version of autoconf ## ## ## AC_PREREQ([2.69]) ## ---[ VERSION ]------------------------------------------------------------- AC_INIT AC_CONFIG_AUX_DIR(src/build/autoconf) ## pick up compiler as will be used by R CMD INSTALL/SHLIB if test -n "${R_HOME}"; then CC=`${R_HOME}/bin/R CMD config CC` CFLAGS=`${R_HOME}/bin/R CMD config CFLAGS` HIDE_IF_R42PLUS=`${R_HOME}/bin/Rscript -e 'cat(if (getRversion() >= "4.2.0") "#" else "")'` else HIDE_IF_R42PLUS="" fi AC_PROG_CPP AC_PROG_CC if test `uname` = "Darwin" ; then darwin="yes" else darwin="no" fi ## --- LibPNG ---------------------------------------------------------------- AC_ARG_ENABLE([libpng], [ --disable-libpng compile without PNG image support] ) AC_ARG_ENABLE([libpng-config], [ --disable-libpng-config disable libpng-config test and configuration] ) AC_ARG_ENABLE([libpng-dynamic], [ --disable-libpng-dynamic disable dynamic libpng linkage, force static version linkage (only with --enable-libpng-config)] ) if test "x$enable_libpng" != "xno"; then if test "x$enable_libpng_config" != "xno"; then AC_CHECK_PROG([HAVE_LIBPNG_CONFIG],[libpng-config],[yes],[no]) fi if test "x$HAVE_LIBPNG_CONFIG" = "xyes" ; then AC_MSG_NOTICE([using libpng-config]) CPPFLAGS="${CPPFLAGS} -DHAVE_PNG_H `libpng-config --I_opts`" if test "x$enable_libpng_dynamic" != "xno"; then AC_MSG_NOTICE([using libpng dynamic linkage]) LIBS="${LIBS} `libpng-config --ldflags`" else AC_MSG_NOTICE([using libpng static linkage]) LIBS="${LIBS} `libpng-config --static --L_opts`/libpng.a" fi else AC_MSG_CHECKING([libpng]) save_LIBS="${LIBS}" save_CPPFLAGS="${CPPFLAGS}" AC_CHECK_HEADERS(png.h) AC_CHECK_LIB(png, png_read_update_info) if test "${ac_cv_header_png_h}"; then if test "${ac_cv_lib_png_png_read_update_info}"; then CPPFLAGS="${CPPFLAGS} -DHAVE_PNG_H" LIBS="${LIBS} -lpng" AC_MSG_NOTICE([libpng header and lib found]) if test "x$enable_libpng_dynamic" != "xno"; then AC_MSG_NOTICE([using libpng dynamic linkage]) else AC_MSG_NOTICE([using libpng static linkage]) fi else LIBS=${save_LIBS} CPPFLAGS=${save_CPPFLAGS} AC_MSG_NOTICE([libpng header and lib not found]) fi fi fi fi # ---[ OpenGL enabled?]--------------------------------------------------------------- AC_ARG_ENABLE([opengl], [ --disable-opengl compile without OpenGL support] ) NULL_CPPFLAGS="${CPPFLAGS} -DRGL_NO_OPENGL" NULL_LIBS="${LIBS}" # ---[ X11 ]------------------------------------------------------------------ if test "x$enable_opengl" != "xno"; then AC_PATH_X if test x$no_x = xyes ; then AC_MSG_WARN([X11 not found, continuing without OpenGL support.]) enable_opengl=no else if test -n "${x_includes}"; then CPPFLAGS="${CPPFLAGS} -I${x_includes}" fi if test -n "${x_libraries}"; then LIBS="${LIBS} -L${x_libraries} -lX11" else LIBS="${LIBS} -lX11" fi if test $darwin = yes; then CPPFLAGS="${CPPFLAGS} -DDarwin" if test -e /System/Library/Frameworks/GLKit.framework ; then LIBS="-framework GLKit ${LIBS}" fi # X11 must come *after* the OpenGL stuff CPPFLAGS="${CPPFLAGS} -I/opt/X11/include" fi AC_CHECK_FUNC(XAllocClassHint, [], [enable_opengl=no]) fi fi if test "x$enable_opengl" != "xno"; then ## --- OpenGL ---------------------------------------------------------------- AC_ARG_WITH(gl-includes, [ --with-gl-includes=DIR specify location of OpenGL headers], [CPPFLAGS="${CPPFLAGS} -I${withval}"] ) if test $darwin != yes; then AC_CHECK_HEADERS(GL/gl.h GL/glu.h) if test "x$ac_cv_header_GL_gl_h" = xno; then AC_MSG_WARN(missing required header GL/gl.h, continuing without OpenGL) enable_opengl=no fi if test "x$ac_cv_header_GL_glu_h" = xno; then AC_MSG_WARN(missing required header GL/glu.h, continuing without OpenGL) enable_opengl=no fi fi fi if test "x$enable_opengl" != "xno"; then AC_ARG_WITH(gl-libs, [ --with-gl-libs=DIR specify location of OpenGL libs], [LDFLAGS="${LDFLAGS} -L${withval}" L_LIB="-L${withval}"] ) AC_ARG_WITH(gl-libname, [ --with-gl-libname=NAME specify Library name (defaults to "GL")], [lGL=${withval}], [lGL=GL] ) AC_CHECK_LIB($lGL, glEnd) this=`eval echo '${'$as_ac_Lib'}'` if test "x$this" != xyes; then AC_MSG_WARN(missing required library ${lGL}, continuing without OpenGL) enable_opengl=no else AC_CHECK_FUNC(glEnd, [], [enable_opengl=no]) fi fi if test "x$enable_opengl" != "xno"; then AC_ARG_WITH(glu-libname, [ --with-glu-libname=NAME specify GLU Library name (defaults to "GLU")], [lGLU=${withval}], [lGLU=GLU] ) AC_CHECK_LIB($lGLU, gluErrorString) this=`eval echo '${'$as_ac_Lib'}'` if test "x$this" != xyes; then AC_MSG_WARN(missing required library ${lGLU}, continuing without OpenGL) enable_opengl=no else AC_CHECK_FUNC(gluErrorString, [], [enable_opengl=no]) fi fi if test "x$enable_opengl" != "xno"; then if test x$L_LIB != x; then LIBS="${L_LIB} ${LIBS}" fi ## --- FTGL ------------------------------------------------------------------ AC_ARG_ENABLE([ftgl], [ --disable-ftgl compile without FTGL font support] ) if test "x$enable_ftgl" != "xno"; then if test "x$darwin" = "xyes"; then AC_MSG_NOTICE([Darwin, so ensuring /opt/X11/bin is at the head of the PATH...]) PATH=/opt/X11/bin:${PATH} fi ## new pkg-config bit AC_CHECK_PROG([HAVE_PKG_CONFIG],[pkg-config],[yes],[no]) if test "x$HAVE_PKG_CONFIG" = "xyes" && test "x`pkg-config freetype2 --cflags`" != "x"; then CPPFLAGS="${CPPFLAGS} -DHAVE_FREETYPE -Iext/ftgl `pkg-config freetype2 --cflags`" LIBS="${LIBS} `pkg-config freetype2 --static --libs`" AC_MSG_NOTICE([using Freetype and FTGL]) else AC_CHECK_PROG([HAVE_FREETYPE_CONFIG],[freetype-config],[yes],[no]) if test "x$HAVE_FREETYPE_CONFIG" = "xyes"; then CPPFLAGS="${CPPFLAGS} -DHAVE_FREETYPE -Iext/ftgl `freetype-config --cflags`" LIBS="${LIBS} `freetype-config --static --libs`" AC_MSG_NOTICE([using Freetype and FTGL]) else AC_MSG_NOTICE([compiling without FTGL support]) fi fi else AC_MSG_NOTICE([compiling without FTGL support]) fi fi if test "x$enable_opengl" = "xno"; then AC_MSG_NOTICE([compiling without OpenGL support]) HIDE_IF_NO_OPENGL="#" RGL_NO_OPENGL=TRUE else HIDE_IF_NO_OPENGL="" RGL_NO_OPENGL=FALSE fi ## --- Output ---------------------------------------------------------------- AC_SUBST(CPPFLAGS) AC_SUBST(LIBS) AC_SUBST(NULL_CPPFLAGS) AC_SUBST(NULL_LIBS) AC_SUBST(HIDE_IF_NO_OPENGL) AC_SUBST(RGL_NO_OPENGL) AC_SUBST(HIDE_IF_R42PLUS) AC_CONFIG_FILES([R/noOpenGL.R src/useNULL/Makevars]) AC_CONFIG_FILES([src/Makevars]) AC_OUTPUT rgl/inst/0000755000176200001440000000000015026603601012012 5ustar liggesusersrgl/inst/COPYING.GL2PS0000644000176200001440000000161115026603462013677 0ustar liggesusers GL2PS LICENSE Version 2, November 2003 Permission to use, copy, and distribute this software and its documentation for any purpose with or without fee is hereby granted, provided that the copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation. Permission to modify and distribute modified versions of this software is granted, provided that: 1) the modifications are licensed under the same terms as this software; 2) you make available the source code of any modifications that you distribute, either on the same media as you distribute any executable or other form of this software, or via a mechanism generally accepted in the software development community for the electronic transfer of data. This software is provided "as is" without express or implied warranty. rgl/inst/htmlwidgets/0000755000176200001440000000000015026603601014345 5ustar liggesusersrgl/inst/htmlwidgets/rglPlayer.js0000644000176200001440000000450214555455305016661 0ustar liggesusers/* el is the , holding x as el.rglPlayer x is the JSON encoded playwidget. instance holds x as instance.rglPlayer */ HTMLWidgets.widget({ name: 'rglPlayer', type: 'output', initialize: function(el, width, height) { return { }; }, renderValue: function(el, x, instance) { var ShowValue = function(value) { var rgldiv = document.getElementById(x.sceneId), rglinstance; x.value = value; /* We might be running before the scene exists. If so, it will have to apply our initial value. */ if (rgldiv && (rglinstance = rgldiv.rglinstance)) { rglinstance.Player(el, x); x.initialized = true; } else { if (x.initialized) rglwidgetClass.prototype.alertOnce("rgl widget '" + x.sceneId + "' not found."); x.initialized = false; instance.rglPlayer = x; } }; el.rglPlayer = x; instance.rglPlayer = x; if (x.respondTo) { var control = window[x.respondTo]; if (control) { var self = this, i, state = "idle"; /* Store the previous handler on the control, so multiple calls here don't pile up a chain of old handlers */ if (typeof control.rglOldhandler === "undefined") control.rglOldhandler = control.onchange; control.onchange = function() { var value; /* If we are called n>0 times while servicing a previous call, we want to finish the current call, then run again. But the old handler might want to see every change. */ if (state !== "idle") { state = "interrupted"; if (control.rglOldhandler !== null) control.rglOldhandler.call(this); } do { state = "busy"; if (control.rglOldhandler !== null) control.rglOldhandler.call(this); if (control.type == "checkbox") value = control.checked ? 0 : 1; else value = control.value; ShowValue(value); if (state === "busy") state = "idle"; } while (state !== "idle"); }; control.onchange(); } } ShowValue(x.value); }, resize: function(el, width, height, instance) { } }); rgl/inst/htmlwidgets/rglWebGL.js0000644000176200001440000000501615011674244016357 0ustar liggesusers/* el is the div, holding the rgl object as el.rglinstance, which holds x as el.rglinstance.scene x is the JSON encoded rglwidget. */ HTMLWidgets.widget({ name: 'rglWebGL', type: 'output', factory: function(el, width, height) { el.width = width; el.height = height; var rgl = new rglwidgetClass(), onchangeselection = function(e) { for (var i = 0; i < rgl.scene.crosstalk.sel_handle.length; i++) rgl.clearBrush(except = e.rglSubsceneId); rgl.selection(e, false); }, onchangefilter = function(e) { rgl.selection(e, true); }; return { renderValue: function(x) { var i, pel, player, groups, inShiny = (typeof Shiny !== "undefined"); x.crosstalk.group = groups = [].concat(x.crosstalk.group); x.crosstalk.id = [].concat(x.crosstalk.id); x.crosstalk.key = [].concat(x.crosstalk.key); x.crosstalk.sel_handle = new Array(groups.length); x.crosstalk.fil_handle = new Array(groups.length); x.crosstalk.selection = []; for (i = 0; i < groups.length; i++) { x.crosstalk.sel_handle[i] = new crosstalk.SelectionHandle(groups[i], {sharedId: x.crosstalk.id[i]}); x.crosstalk.sel_handle[i].on("change", onchangeselection); x.crosstalk.fil_handle[i] = new crosstalk.FilterHandle(groups[i], {sharedId: x.crosstalk.id[i]}); x.crosstalk.fil_handle[i].on("change", onchangefilter); } if (inShiny) { // Shiny calls this multiple times, so we need extra cleanup // between rgl.sphere = undefined; } rgl.initialize(el, x); rgl.initGL(); /* We might have been called after (some of) the players were rendered. We need to make sure we respond to their initial values. */ if (typeof x.players !== "undefined") { var players = [].concat(x.players); for (i = 0; i < players.length; i++) { pel = document.getElementById(players[i]); if (pel) { player = pel.rglPlayer; if (player && (!player.initialized || inShiny)) { rgl.Player(pel, player); player.initialized = true; } } } } rgl.drag = 0; rgl.drawScene(); }, resize: function(width, height) { el.width = width; el.height = height; el.rglinstance.resize(el); el.rglinstance.drawScene(); } }; } }); rgl/inst/htmlwidgets/lib/0000755000176200001440000000000015026603601015113 5ustar liggesusersrgl/inst/htmlwidgets/lib/CanvasMatrix/0000755000176200001440000000000015026603601017513 5ustar liggesusersrgl/inst/htmlwidgets/lib/CanvasMatrix/CanvasMatrix.min.js0000644000176200001440000002471315013427133023242 0ustar liggesusersCanvasMatrix4=function(m){if("object"==typeof m){if("length"in m&&m.length>=16)return void this.load(m[0],m[1],m[2],m[3],m[4],m[5],m[6],m[7],m[8],m[9],m[10],m[11],m[12],m[13],m[14],m[15]);if(m instanceof CanvasMatrix4)return void this.load(m)}this.makeIdentity()},CanvasMatrix4.prototype.load=function(){if(1==arguments.length&&"object"==typeof arguments[0]){var matrix=arguments[0];if("length"in matrix&&16==matrix.length)return this.m11=matrix[0],this.m12=matrix[1],this.m13=matrix[2],this.m14=matrix[3],this.m21=matrix[4],this.m22=matrix[5],this.m23=matrix[6],this.m24=matrix[7],this.m31=matrix[8],this.m32=matrix[9],this.m33=matrix[10],this.m34=matrix[11],this.m41=matrix[12],this.m42=matrix[13],this.m43=matrix[14],void(this.m44=matrix[15]);if(arguments[0]instanceof CanvasMatrix4)return this.m11=matrix.m11,this.m12=matrix.m12,this.m13=matrix.m13,this.m14=matrix.m14,this.m21=matrix.m21,this.m22=matrix.m22,this.m23=matrix.m23,this.m24=matrix.m24,this.m31=matrix.m31,this.m32=matrix.m32,this.m33=matrix.m33,this.m34=matrix.m34,this.m41=matrix.m41,this.m42=matrix.m42,this.m43=matrix.m43,void(this.m44=matrix.m44)}this.makeIdentity()},CanvasMatrix4.prototype.getAsArray=function(){return[this.m11,this.m12,this.m13,this.m14,this.m21,this.m22,this.m23,this.m24,this.m31,this.m32,this.m33,this.m34,this.m41,this.m42,this.m43,this.m44]},CanvasMatrix4.prototype.getAsWebGLFloatArray=function(){return new WebGLFloatArray(this.getAsArray())},CanvasMatrix4.prototype.makeIdentity=function(){this.m11=1,this.m12=0,this.m13=0,this.m14=0,this.m21=0,this.m22=1,this.m23=0,this.m24=0,this.m31=0,this.m32=0,this.m33=1,this.m34=0,this.m41=0,this.m42=0,this.m43=0,this.m44=1},CanvasMatrix4.prototype.transpose=function(){var tmp=this.m12;this.m12=this.m21,this.m21=tmp,tmp=this.m13,this.m13=this.m31,this.m31=tmp,tmp=this.m14,this.m14=this.m41,this.m41=tmp,tmp=this.m23,this.m23=this.m32,this.m32=tmp,tmp=this.m24,this.m24=this.m42,this.m42=tmp,tmp=this.m34,this.m34=this.m43,this.m43=tmp},CanvasMatrix4.prototype.invert=function(){var det=this._determinant4x4();return Math.abs(det)<1e-8?null:(this._makeAdjoint(),this.m11/=det,this.m12/=det,this.m13/=det,this.m14/=det,this.m21/=det,this.m22/=det,this.m23/=det,this.m24/=det,this.m31/=det,this.m32/=det,this.m33/=det,this.m34/=det,this.m41/=det,this.m42/=det,this.m43/=det,void(this.m44/=det))},CanvasMatrix4.prototype.translate=function(x,y,z){void 0===x&&(x=0),void 0===y&&(y=0),void 0===z&&(z=0);var matrix=new CanvasMatrix4;matrix.m41=x,matrix.m42=y,matrix.m43=z,this.multRight(matrix)},CanvasMatrix4.prototype.scale=function(x,y,z){void 0===x&&(x=1),void 0===z?void 0===y?(y=x,z=x):z=1:void 0===y&&(y=x);var matrix=new CanvasMatrix4;matrix.m11=x,matrix.m22=y,matrix.m33=z,this.multRight(matrix)},CanvasMatrix4.prototype.rotate=function(angle,x,y,z){angle=angle/180*Math.PI,angle/=2;var sinA=Math.sin(angle),cosA=Math.cos(angle),sinA2=sinA*sinA,length=Math.sqrt(x*x+y*y+z*z);0===length?(x=0,y=0,z=1):1!=length&&(x/=length,y/=length,z/=length);var mat=new CanvasMatrix4;if(1==x&&0===y&&0===z)mat.m11=1,mat.m12=0,mat.m13=0,mat.m21=0,mat.m22=1-2*sinA2,mat.m23=2*sinA*cosA,mat.m31=0,mat.m32=-2*sinA*cosA,mat.m33=1-2*sinA2,mat.m14=mat.m24=mat.m34=0,mat.m41=mat.m42=mat.m43=0,mat.m44=1;else if(0===x&&1==y&&0===z)mat.m11=1-2*sinA2,mat.m12=0,mat.m13=-2*sinA*cosA,mat.m21=0,mat.m22=1,mat.m23=0,mat.m31=2*sinA*cosA,mat.m32=0,mat.m33=1-2*sinA2,mat.m14=mat.m24=mat.m34=0,mat.m41=mat.m42=mat.m43=0,mat.m44=1;else if(0===x&&0===y&&1==z)mat.m11=1-2*sinA2,mat.m12=2*sinA*cosA,mat.m13=0,mat.m21=-2*sinA*cosA,mat.m22=1-2*sinA2,mat.m23=0,mat.m31=0,mat.m32=0,mat.m33=1,mat.m14=mat.m24=mat.m34=0,mat.m41=mat.m42=mat.m43=0,mat.m44=1;else{var x2=x*x,y2=y*y,z2=z*z;mat.m11=1-2*(y2+z2)*sinA2,mat.m12=2*(x*y*sinA2+z*sinA*cosA),mat.m13=2*(x*z*sinA2-y*sinA*cosA),mat.m21=2*(y*x*sinA2-z*sinA*cosA),mat.m22=1-2*(z2+x2)*sinA2,mat.m23=2*(y*z*sinA2+x*sinA*cosA),mat.m31=2*(z*x*sinA2+y*sinA*cosA),mat.m32=2*(z*y*sinA2-x*sinA*cosA),mat.m33=1-2*(x2+y2)*sinA2,mat.m14=mat.m24=mat.m34=0,mat.m41=mat.m42=mat.m43=0,mat.m44=1}this.multRight(mat)},CanvasMatrix4.prototype.multRight=function(mat){var m11=this.m11*mat.m11+this.m12*mat.m21+this.m13*mat.m31+this.m14*mat.m41,m12=this.m11*mat.m12+this.m12*mat.m22+this.m13*mat.m32+this.m14*mat.m42,m13=this.m11*mat.m13+this.m12*mat.m23+this.m13*mat.m33+this.m14*mat.m43,m14=this.m11*mat.m14+this.m12*mat.m24+this.m13*mat.m34+this.m14*mat.m44,m21=this.m21*mat.m11+this.m22*mat.m21+this.m23*mat.m31+this.m24*mat.m41,m22=this.m21*mat.m12+this.m22*mat.m22+this.m23*mat.m32+this.m24*mat.m42,m23=this.m21*mat.m13+this.m22*mat.m23+this.m23*mat.m33+this.m24*mat.m43,m24=this.m21*mat.m14+this.m22*mat.m24+this.m23*mat.m34+this.m24*mat.m44,m31=this.m31*mat.m11+this.m32*mat.m21+this.m33*mat.m31+this.m34*mat.m41,m32=this.m31*mat.m12+this.m32*mat.m22+this.m33*mat.m32+this.m34*mat.m42,m33=this.m31*mat.m13+this.m32*mat.m23+this.m33*mat.m33+this.m34*mat.m43,m34=this.m31*mat.m14+this.m32*mat.m24+this.m33*mat.m34+this.m34*mat.m44,m41=this.m41*mat.m11+this.m42*mat.m21+this.m43*mat.m31+this.m44*mat.m41,m42=this.m41*mat.m12+this.m42*mat.m22+this.m43*mat.m32+this.m44*mat.m42,m43=this.m41*mat.m13+this.m42*mat.m23+this.m43*mat.m33+this.m44*mat.m43,m44=this.m41*mat.m14+this.m42*mat.m24+this.m43*mat.m34+this.m44*mat.m44;this.m11=m11,this.m12=m12,this.m13=m13,this.m14=m14,this.m21=m21,this.m22=m22,this.m23=m23,this.m24=m24,this.m31=m31,this.m32=m32,this.m33=m33,this.m34=m34,this.m41=m41,this.m42=m42,this.m43=m43,this.m44=m44},CanvasMatrix4.prototype.multLeft=function(mat){var m11=mat.m11*this.m11+mat.m12*this.m21+mat.m13*this.m31+mat.m14*this.m41,m12=mat.m11*this.m12+mat.m12*this.m22+mat.m13*this.m32+mat.m14*this.m42,m13=mat.m11*this.m13+mat.m12*this.m23+mat.m13*this.m33+mat.m14*this.m43,m14=mat.m11*this.m14+mat.m12*this.m24+mat.m13*this.m34+mat.m14*this.m44,m21=mat.m21*this.m11+mat.m22*this.m21+mat.m23*this.m31+mat.m24*this.m41,m22=mat.m21*this.m12+mat.m22*this.m22+mat.m23*this.m32+mat.m24*this.m42,m23=mat.m21*this.m13+mat.m22*this.m23+mat.m23*this.m33+mat.m24*this.m43,m24=mat.m21*this.m14+mat.m22*this.m24+mat.m23*this.m34+mat.m24*this.m44,m31=mat.m31*this.m11+mat.m32*this.m21+mat.m33*this.m31+mat.m34*this.m41,m32=mat.m31*this.m12+mat.m32*this.m22+mat.m33*this.m32+mat.m34*this.m42,m33=mat.m31*this.m13+mat.m32*this.m23+mat.m33*this.m33+mat.m34*this.m43,m34=mat.m31*this.m14+mat.m32*this.m24+mat.m33*this.m34+mat.m34*this.m44,m41=mat.m41*this.m11+mat.m42*this.m21+mat.m43*this.m31+mat.m44*this.m41,m42=mat.m41*this.m12+mat.m42*this.m22+mat.m43*this.m32+mat.m44*this.m42,m43=mat.m41*this.m13+mat.m42*this.m23+mat.m43*this.m33+mat.m44*this.m43,m44=mat.m41*this.m14+mat.m42*this.m24+mat.m43*this.m34+mat.m44*this.m44;this.m11=m11,this.m12=m12,this.m13=m13,this.m14=m14,this.m21=m21,this.m22=m22,this.m23=m23,this.m24=m24,this.m31=m31,this.m32=m32,this.m33=m33,this.m34=m34,this.m41=m41,this.m42=m42,this.m43=m43,this.m44=m44},CanvasMatrix4.prototype.ortho=function(left,right,bottom,top,near,far){var tx=(left+right)/(left-right),ty=(top+bottom)/(bottom-top),tz=(far+near)/(near-far),matrix=new CanvasMatrix4;matrix.m11=2/(right-left),matrix.m12=0,matrix.m13=0,matrix.m14=0,matrix.m21=0,matrix.m22=2/(top-bottom),matrix.m23=0,matrix.m24=0,matrix.m31=0,matrix.m32=0,matrix.m33=-2/(far-near),matrix.m34=0,matrix.m41=tx,matrix.m42=ty,matrix.m43=tz,matrix.m44=1,this.multRight(matrix)},CanvasMatrix4.prototype.frustum=function(left,right,bottom,top,near,far){var matrix=new CanvasMatrix4,A=(right+left)/(right-left),B=(top+bottom)/(top-bottom),C=-(far+near)/(far-near),D=-(2*far*near)/(far-near);matrix.m11=2*near/(right-left),matrix.m12=0,matrix.m13=0,matrix.m14=0,matrix.m21=0,matrix.m22=2*near/(top-bottom),matrix.m23=0,matrix.m24=0,matrix.m31=A,matrix.m32=B,matrix.m33=C,matrix.m34=-1,matrix.m41=0,matrix.m42=0,matrix.m43=D,matrix.m44=0,this.multRight(matrix)},CanvasMatrix4.prototype.perspective=function(fovy,aspect,zNear,zFar){var top=Math.tan(fovy*Math.PI/360)*zNear,bottom=-top,left=aspect*bottom,right=aspect*top;this.frustum(left,right,bottom,top,zNear,zFar)},CanvasMatrix4.prototype.lookat=function(eyex,eyey,eyez,centerx,centery,centerz,upx,upy,upz){var xx,xy,xz,matrix=new CanvasMatrix4,zx=eyex-centerx,zy=eyey-centery,zz=eyez-centerz,mag=Math.sqrt(zx*zx+zy*zy+zz*zz);mag&&(zx/=mag,zy/=mag,zz/=mag);var yx=upx,yy=upy,yz=upz;xx=yy*zz-yz*zy,xy=-yx*zz+yz*zx,xz=yx*zy-yy*zx,yx=zy*xz-zz*xy,yy=-zx*xz+zz*xx,yx=zx*xy-zy*xx,mag=Math.sqrt(xx*xx+xy*xy+xz*xz),mag&&(xx/=mag,xy/=mag,xz/=mag),mag=Math.sqrt(yx*yx+yy*yy+yz*yz),mag&&(yx/=mag,yy/=mag,yz/=mag),matrix.m11=xx,matrix.m12=xy,matrix.m13=xz,matrix.m14=0,matrix.m21=yx,matrix.m22=yy,matrix.m23=yz,matrix.m24=0,matrix.m31=zx,matrix.m32=zy,matrix.m33=zz,matrix.m34=0,matrix.m41=0,matrix.m42=0,matrix.m43=0,matrix.m44=1,matrix.translate(-eyex,-eyey,-eyez),this.multRight(matrix)},CanvasMatrix4.prototype._determinant2x2=function(a,b,c,d){return a*d-b*c},CanvasMatrix4.prototype._determinant3x3=function(a1,a2,a3,b1,b2,b3,c1,c2,c3){return a1*this._determinant2x2(b2,b3,c2,c3)-b1*this._determinant2x2(a2,a3,c2,c3)+c1*this._determinant2x2(a2,a3,b2,b3)},CanvasMatrix4.prototype._determinant4x4=function(){var a1=this.m11,b1=this.m12,c1=this.m13,d1=this.m14,a2=this.m21,b2=this.m22,c2=this.m23,d2=this.m24,a3=this.m31,b3=this.m32,c3=this.m33,d3=this.m34,a4=this.m41,b4=this.m42,c4=this.m43,d4=this.m44;return a1*this._determinant3x3(b2,b3,b4,c2,c3,c4,d2,d3,d4)-b1*this._determinant3x3(a2,a3,a4,c2,c3,c4,d2,d3,d4)+c1*this._determinant3x3(a2,a3,a4,b2,b3,b4,d2,d3,d4)-d1*this._determinant3x3(a2,a3,a4,b2,b3,b4,c2,c3,c4)},CanvasMatrix4.prototype._makeAdjoint=function(){var a1=this.m11,b1=this.m12,c1=this.m13,d1=this.m14,a2=this.m21,b2=this.m22,c2=this.m23,d2=this.m24,a3=this.m31,b3=this.m32,c3=this.m33,d3=this.m34,a4=this.m41,b4=this.m42,c4=this.m43,d4=this.m44;this.m11=this._determinant3x3(b2,b3,b4,c2,c3,c4,d2,d3,d4),this.m21=-this._determinant3x3(a2,a3,a4,c2,c3,c4,d2,d3,d4),this.m31=this._determinant3x3(a2,a3,a4,b2,b3,b4,d2,d3,d4),this.m41=-this._determinant3x3(a2,a3,a4,b2,b3,b4,c2,c3,c4),this.m12=-this._determinant3x3(b1,b3,b4,c1,c3,c4,d1,d3,d4),this.m22=this._determinant3x3(a1,a3,a4,c1,c3,c4,d1,d3,d4),this.m32=-this._determinant3x3(a1,a3,a4,b1,b3,b4,d1,d3,d4),this.m42=this._determinant3x3(a1,a3,a4,b1,b3,b4,c1,c3,c4),this.m13=this._determinant3x3(b1,b2,b4,c1,c2,c4,d1,d2,d4),this.m23=-this._determinant3x3(a1,a2,a4,c1,c2,c4,d1,d2,d4),this.m33=this._determinant3x3(a1,a2,a4,b1,b2,b4,d1,d2,d4),this.m43=-this._determinant3x3(a1,a2,a4,b1,b2,b4,c1,c2,c4),this.m14=-this._determinant3x3(b1,b2,b3,c1,c2,c3,d1,d2,d3),this.m24=this._determinant3x3(a1,a2,a3,c1,c2,c3,d1,d2,d3),this.m34=-this._determinant3x3(a1,a2,a3,b1,b2,b3,d1,d2,d3),this.m44=this._determinant3x3(a1,a2,a3,b1,b2,b3,c1,c2,c3)}; rgl/inst/htmlwidgets/lib/CanvasMatrix/CanvasMatrix.src.js0000644000176200001440000005322014771520323023246 0ustar liggesusers/* globals CanvasMatrix4: true */ /* globals WebGLFloatArray */ /* jshint eqeqeq: false */ /* * Copyright (C) 2009 Apple Inc. All Rights Reserved. * * 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. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. OR * CONTRIBUTORS 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. * Copyright (2016) Duncan Murdoch - fixed CanvasMatrix4.ortho, * cleaned up. */ /* CanvasMatrix4 class This class implements a 4x4 matrix. It has functions which duplicate the functionality of the OpenGL matrix stack and glut functions. IDL: [ Constructor(in CanvasMatrix4 matrix), // copy passed matrix into new CanvasMatrix4 Constructor(in sequence array) // create new CanvasMatrix4 with 16 floats (row major) Constructor() // create new CanvasMatrix4 with identity matrix ] interface CanvasMatrix4 { attribute float m11; attribute float m12; attribute float m13; attribute float m14; attribute float m21; attribute float m22; attribute float m23; attribute float m24; attribute float m31; attribute float m32; attribute float m33; attribute float m34; attribute float m41; attribute float m42; attribute float m43; attribute float m44; void load(in CanvasMatrix4 matrix); // copy the values from the passed matrix void load(in sequence array); // copy 16 floats into the matrix sequence getAsArray(); // return the matrix as an array of 16 floats WebGLFloatArray getAsCanvasFloatArray(); // return the matrix as a WebGLFloatArray with 16 values void makeIdentity(); // replace the matrix with identity void transpose(); // replace the matrix with its transpose void invert(); // replace the matrix with its inverse void translate(in float x, in float y, in float z); // multiply the matrix by passed translation values on the right void scale(in float x, in float y, in float z); // multiply the matrix by passed scale values on the right void rotate(in float angle, // multiply the matrix by passed rotation values on the right in float x, in float y, in float z); // (angle is in degrees) void multRight(in CanvasMatrix matrix); // multiply the matrix by the passed matrix on the right void multLeft(in CanvasMatrix matrix); // multiply the matrix by the passed matrix on the left void ortho(in float left, in float right, // multiply the matrix by the passed ortho values on the right in float bottom, in float top, in float near, in float far); void frustum(in float left, in float right, // multiply the matrix by the passed frustum values on the right in float bottom, in float top, in float near, in float far); void perspective(in float fovy, in float aspect, // multiply the matrix by the passed perspective values on the right in float zNear, in float zFar); void lookat(in float eyex, in float eyey, in float eyez, // multiply the matrix by the passed lookat in float ctrx, in float ctry, in float ctrz, // values on the right in float upx, in float upy, in float upz); } */ CanvasMatrix4 = function(m) { if (typeof m == 'object') { if ("length" in m && m.length >= 16) { this.load(m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8], m[9], m[10], m[11], m[12], m[13], m[14], m[15]); return; } else if (m instanceof CanvasMatrix4) { this.load(m); return; } } this.makeIdentity(); }; CanvasMatrix4.prototype.load = function() { if (arguments.length == 1 && typeof arguments[0] == 'object') { var matrix = arguments[0]; if ("length" in matrix && matrix.length == 16) { this.m11 = matrix[0]; this.m12 = matrix[1]; this.m13 = matrix[2]; this.m14 = matrix[3]; this.m21 = matrix[4]; this.m22 = matrix[5]; this.m23 = matrix[6]; this.m24 = matrix[7]; this.m31 = matrix[8]; this.m32 = matrix[9]; this.m33 = matrix[10]; this.m34 = matrix[11]; this.m41 = matrix[12]; this.m42 = matrix[13]; this.m43 = matrix[14]; this.m44 = matrix[15]; return; } if (arguments[0] instanceof CanvasMatrix4) { this.m11 = matrix.m11; this.m12 = matrix.m12; this.m13 = matrix.m13; this.m14 = matrix.m14; this.m21 = matrix.m21; this.m22 = matrix.m22; this.m23 = matrix.m23; this.m24 = matrix.m24; this.m31 = matrix.m31; this.m32 = matrix.m32; this.m33 = matrix.m33; this.m34 = matrix.m34; this.m41 = matrix.m41; this.m42 = matrix.m42; this.m43 = matrix.m43; this.m44 = matrix.m44; return; } } this.makeIdentity(); }; CanvasMatrix4.prototype.getAsArray = function() { return [ this.m11, this.m12, this.m13, this.m14, this.m21, this.m22, this.m23, this.m24, this.m31, this.m32, this.m33, this.m34, this.m41, this.m42, this.m43, this.m44 ]; }; CanvasMatrix4.prototype.getAsWebGLFloatArray = function() { return new WebGLFloatArray(this.getAsArray()); }; CanvasMatrix4.prototype.makeIdentity = function() { this.m11 = 1; this.m12 = 0; this.m13 = 0; this.m14 = 0; this.m21 = 0; this.m22 = 1; this.m23 = 0; this.m24 = 0; this.m31 = 0; this.m32 = 0; this.m33 = 1; this.m34 = 0; this.m41 = 0; this.m42 = 0; this.m43 = 0; this.m44 = 1; }; CanvasMatrix4.prototype.transpose = function() { var tmp = this.m12; this.m12 = this.m21; this.m21 = tmp; tmp = this.m13; this.m13 = this.m31; this.m31 = tmp; tmp = this.m14; this.m14 = this.m41; this.m41 = tmp; tmp = this.m23; this.m23 = this.m32; this.m32 = tmp; tmp = this.m24; this.m24 = this.m42; this.m42 = tmp; tmp = this.m34; this.m34 = this.m43; this.m43 = tmp; }; CanvasMatrix4.prototype.invert = function() { // Calculate the 4x4 determinant // If the determinant is zero, // then the inverse matrix is not unique. var det = this._determinant4x4(); if (Math.abs(det) < 1e-8) return null; this._makeAdjoint(); // Scale the adjoint matrix to get the inverse this.m11 /= det; this.m12 /= det; this.m13 /= det; this.m14 /= det; this.m21 /= det; this.m22 /= det; this.m23 /= det; this.m24 /= det; this.m31 /= det; this.m32 /= det; this.m33 /= det; this.m34 /= det; this.m41 /= det; this.m42 /= det; this.m43 /= det; this.m44 /= det; }; CanvasMatrix4.prototype.translate = function(x,y,z) { if (x === undefined) x = 0; if (y === undefined) y = 0; if (z === undefined) z = 0; var matrix = new CanvasMatrix4(); matrix.m41 = x; matrix.m42 = y; matrix.m43 = z; this.multRight(matrix); }; CanvasMatrix4.prototype.scale = function(x,y,z) { if (x === undefined) x = 1; if (z === undefined) { if (y === undefined) { y = x; z = x; } else z = 1; } else if (y === undefined) y = x; var matrix = new CanvasMatrix4(); matrix.m11 = x; matrix.m22 = y; matrix.m33 = z; this.multRight(matrix); }; CanvasMatrix4.prototype.rotate = function(angle,x,y,z) { // angles are in degrees. Switch to radians angle = angle / 180 * Math.PI; angle /= 2; var sinA = Math.sin(angle); var cosA = Math.cos(angle); var sinA2 = sinA * sinA; // normalize var length = Math.sqrt(x * x + y * y + z * z); if (length === 0) { // bad vector, just use something reasonable x = 0; y = 0; z = 1; } else if (length != 1) { x /= length; y /= length; z /= length; } var mat = new CanvasMatrix4(); // optimize case where axis is along major axis if (x == 1 && y === 0 && z === 0) { mat.m11 = 1; mat.m12 = 0; mat.m13 = 0; mat.m21 = 0; mat.m22 = 1 - 2 * sinA2; mat.m23 = 2 * sinA * cosA; mat.m31 = 0; mat.m32 = -2 * sinA * cosA; mat.m33 = 1 - 2 * sinA2; mat.m14 = mat.m24 = mat.m34 = 0; mat.m41 = mat.m42 = mat.m43 = 0; mat.m44 = 1; } else if (x === 0 && y == 1 && z === 0) { mat.m11 = 1 - 2 * sinA2; mat.m12 = 0; mat.m13 = -2 * sinA * cosA; mat.m21 = 0; mat.m22 = 1; mat.m23 = 0; mat.m31 = 2 * sinA * cosA; mat.m32 = 0; mat.m33 = 1 - 2 * sinA2; mat.m14 = mat.m24 = mat.m34 = 0; mat.m41 = mat.m42 = mat.m43 = 0; mat.m44 = 1; } else if (x === 0 && y === 0 && z == 1) { mat.m11 = 1 - 2 * sinA2; mat.m12 = 2 * sinA * cosA; mat.m13 = 0; mat.m21 = -2 * sinA * cosA; mat.m22 = 1 - 2 * sinA2; mat.m23 = 0; mat.m31 = 0; mat.m32 = 0; mat.m33 = 1; mat.m14 = mat.m24 = mat.m34 = 0; mat.m41 = mat.m42 = mat.m43 = 0; mat.m44 = 1; } else { var x2 = x*x; var y2 = y*y; var z2 = z*z; mat.m11 = 1 - 2 * (y2 + z2) * sinA2; mat.m12 = 2 * (x * y * sinA2 + z * sinA * cosA); mat.m13 = 2 * (x * z * sinA2 - y * sinA * cosA); mat.m21 = 2 * (y * x * sinA2 - z * sinA * cosA); mat.m22 = 1 - 2 * (z2 + x2) * sinA2; mat.m23 = 2 * (y * z * sinA2 + x * sinA * cosA); mat.m31 = 2 * (z * x * sinA2 + y * sinA * cosA); mat.m32 = 2 * (z * y * sinA2 - x * sinA * cosA); mat.m33 = 1 - 2 * (x2 + y2) * sinA2; mat.m14 = mat.m24 = mat.m34 = 0; mat.m41 = mat.m42 = mat.m43 = 0; mat.m44 = 1; } this.multRight(mat); }; CanvasMatrix4.prototype.multRight = function(mat) { var m11 = (this.m11 * mat.m11 + this.m12 * mat.m21 + this.m13 * mat.m31 + this.m14 * mat.m41); var m12 = (this.m11 * mat.m12 + this.m12 * mat.m22 + this.m13 * mat.m32 + this.m14 * mat.m42); var m13 = (this.m11 * mat.m13 + this.m12 * mat.m23 + this.m13 * mat.m33 + this.m14 * mat.m43); var m14 = (this.m11 * mat.m14 + this.m12 * mat.m24 + this.m13 * mat.m34 + this.m14 * mat.m44); var m21 = (this.m21 * mat.m11 + this.m22 * mat.m21 + this.m23 * mat.m31 + this.m24 * mat.m41); var m22 = (this.m21 * mat.m12 + this.m22 * mat.m22 + this.m23 * mat.m32 + this.m24 * mat.m42); var m23 = (this.m21 * mat.m13 + this.m22 * mat.m23 + this.m23 * mat.m33 + this.m24 * mat.m43); var m24 = (this.m21 * mat.m14 + this.m22 * mat.m24 + this.m23 * mat.m34 + this.m24 * mat.m44); var m31 = (this.m31 * mat.m11 + this.m32 * mat.m21 + this.m33 * mat.m31 + this.m34 * mat.m41); var m32 = (this.m31 * mat.m12 + this.m32 * mat.m22 + this.m33 * mat.m32 + this.m34 * mat.m42); var m33 = (this.m31 * mat.m13 + this.m32 * mat.m23 + this.m33 * mat.m33 + this.m34 * mat.m43); var m34 = (this.m31 * mat.m14 + this.m32 * mat.m24 + this.m33 * mat.m34 + this.m34 * mat.m44); var m41 = (this.m41 * mat.m11 + this.m42 * mat.m21 + this.m43 * mat.m31 + this.m44 * mat.m41); var m42 = (this.m41 * mat.m12 + this.m42 * mat.m22 + this.m43 * mat.m32 + this.m44 * mat.m42); var m43 = (this.m41 * mat.m13 + this.m42 * mat.m23 + this.m43 * mat.m33 + this.m44 * mat.m43); var m44 = (this.m41 * mat.m14 + this.m42 * mat.m24 + this.m43 * mat.m34 + this.m44 * mat.m44); this.m11 = m11; this.m12 = m12; this.m13 = m13; this.m14 = m14; this.m21 = m21; this.m22 = m22; this.m23 = m23; this.m24 = m24; this.m31 = m31; this.m32 = m32; this.m33 = m33; this.m34 = m34; this.m41 = m41; this.m42 = m42; this.m43 = m43; this.m44 = m44; }; CanvasMatrix4.prototype.multLeft = function(mat) { var m11 = (mat.m11 * this.m11 + mat.m12 * this.m21 + mat.m13 * this.m31 + mat.m14 * this.m41); var m12 = (mat.m11 * this.m12 + mat.m12 * this.m22 + mat.m13 * this.m32 + mat.m14 * this.m42); var m13 = (mat.m11 * this.m13 + mat.m12 * this.m23 + mat.m13 * this.m33 + mat.m14 * this.m43); var m14 = (mat.m11 * this.m14 + mat.m12 * this.m24 + mat.m13 * this.m34 + mat.m14 * this.m44); var m21 = (mat.m21 * this.m11 + mat.m22 * this.m21 + mat.m23 * this.m31 + mat.m24 * this.m41); var m22 = (mat.m21 * this.m12 + mat.m22 * this.m22 + mat.m23 * this.m32 + mat.m24 * this.m42); var m23 = (mat.m21 * this.m13 + mat.m22 * this.m23 + mat.m23 * this.m33 + mat.m24 * this.m43); var m24 = (mat.m21 * this.m14 + mat.m22 * this.m24 + mat.m23 * this.m34 + mat.m24 * this.m44); var m31 = (mat.m31 * this.m11 + mat.m32 * this.m21 + mat.m33 * this.m31 + mat.m34 * this.m41); var m32 = (mat.m31 * this.m12 + mat.m32 * this.m22 + mat.m33 * this.m32 + mat.m34 * this.m42); var m33 = (mat.m31 * this.m13 + mat.m32 * this.m23 + mat.m33 * this.m33 + mat.m34 * this.m43); var m34 = (mat.m31 * this.m14 + mat.m32 * this.m24 + mat.m33 * this.m34 + mat.m34 * this.m44); var m41 = (mat.m41 * this.m11 + mat.m42 * this.m21 + mat.m43 * this.m31 + mat.m44 * this.m41); var m42 = (mat.m41 * this.m12 + mat.m42 * this.m22 + mat.m43 * this.m32 + mat.m44 * this.m42); var m43 = (mat.m41 * this.m13 + mat.m42 * this.m23 + mat.m43 * this.m33 + mat.m44 * this.m43); var m44 = (mat.m41 * this.m14 + mat.m42 * this.m24 + mat.m43 * this.m34 + mat.m44 * this.m44); this.m11 = m11; this.m12 = m12; this.m13 = m13; this.m14 = m14; this.m21 = m21; this.m22 = m22; this.m23 = m23; this.m24 = m24; this.m31 = m31; this.m32 = m32; this.m33 = m33; this.m34 = m34; this.m41 = m41; this.m42 = m42; this.m43 = m43; this.m44 = m44; }; CanvasMatrix4.prototype.ortho = function(left, right, bottom, top, near, far) { var tx = (left + right) / (left - right); var ty = (top + bottom) / (bottom - top); var tz = (far + near) / (near - far); var matrix = new CanvasMatrix4(); matrix.m11 = 2 / (right - left); matrix.m12 = 0; matrix.m13 = 0; matrix.m14 = 0; matrix.m21 = 0; matrix.m22 = 2 / (top - bottom); matrix.m23 = 0; matrix.m24 = 0; matrix.m31 = 0; matrix.m32 = 0; matrix.m33 = -2 / (far - near); matrix.m34 = 0; matrix.m41 = tx; matrix.m42 = ty; matrix.m43 = tz; matrix.m44 = 1; this.multRight(matrix); }; CanvasMatrix4.prototype.frustum = function(left, right, bottom, top, near, far) { var matrix = new CanvasMatrix4(); var A = (right + left) / (right - left); var B = (top + bottom) / (top - bottom); var C = -(far + near) / (far - near); var D = -(2 * far * near) / (far - near); matrix.m11 = (2 * near) / (right - left); matrix.m12 = 0; matrix.m13 = 0; matrix.m14 = 0; matrix.m21 = 0; matrix.m22 = 2 * near / (top - bottom); matrix.m23 = 0; matrix.m24 = 0; matrix.m31 = A; matrix.m32 = B; matrix.m33 = C; matrix.m34 = -1; matrix.m41 = 0; matrix.m42 = 0; matrix.m43 = D; matrix.m44 = 0; this.multRight(matrix); }; CanvasMatrix4.prototype.perspective = function(fovy, aspect, zNear, zFar) { var top = Math.tan(fovy * Math.PI / 360) * zNear; var bottom = -top; var left = aspect * bottom; var right = aspect * top; this.frustum(left, right, bottom, top, zNear, zFar); }; CanvasMatrix4.prototype.lookat = function(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz) { var matrix = new CanvasMatrix4(), xx, xy, xz; // Make rotation matrix // Z vector var zx = eyex - centerx; var zy = eyey - centery; var zz = eyez - centerz; var mag = Math.sqrt(zx * zx + zy * zy + zz * zz); if (mag) { zx /= mag; zy /= mag; zz /= mag; } // Y vector var yx = upx; var yy = upy; var yz = upz; // X vector = Y cross Z xx = yy * zz - yz * zy; xy = -yx * zz + yz * zx; xz = yx * zy - yy * zx; // Recompute Y = Z cross X yx = zy * xz - zz * xy; yy = -zx * xz + zz * xx; yx = zx * xy - zy * xx; // cross product gives area of parallelogram, which is < 1.0 for // non-perpendicular unit-length vectors; so normalize x, y here mag = Math.sqrt(xx * xx + xy * xy + xz * xz); if (mag) { xx /= mag; xy /= mag; xz /= mag; } mag = Math.sqrt(yx * yx + yy * yy + yz * yz); if (mag) { yx /= mag; yy /= mag; yz /= mag; } matrix.m11 = xx; matrix.m12 = xy; matrix.m13 = xz; matrix.m14 = 0; matrix.m21 = yx; matrix.m22 = yy; matrix.m23 = yz; matrix.m24 = 0; matrix.m31 = zx; matrix.m32 = zy; matrix.m33 = zz; matrix.m34 = 0; matrix.m41 = 0; matrix.m42 = 0; matrix.m43 = 0; matrix.m44 = 1; matrix.translate(-eyex, -eyey, -eyez); this.multRight(matrix); }; // Support functions CanvasMatrix4.prototype._determinant2x2 = function(a, b, c, d) { return a * d - b * c; }; CanvasMatrix4.prototype._determinant3x3 = function(a1, a2, a3, b1, b2, b3, c1, c2, c3) { return a1 * this._determinant2x2(b2, b3, c2, c3) - b1 * this._determinant2x2(a2, a3, c2, c3) + c1 * this._determinant2x2(a2, a3, b2, b3); }; CanvasMatrix4.prototype._determinant4x4 = function() { var a1 = this.m11; var b1 = this.m12; var c1 = this.m13; var d1 = this.m14; var a2 = this.m21; var b2 = this.m22; var c2 = this.m23; var d2 = this.m24; var a3 = this.m31; var b3 = this.m32; var c3 = this.m33; var d3 = this.m34; var a4 = this.m41; var b4 = this.m42; var c4 = this.m43; var d4 = this.m44; return a1 * this._determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4) - b1 * this._determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4) + c1 * this._determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4) - d1 * this._determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); }; CanvasMatrix4.prototype._makeAdjoint = function() { var a1 = this.m11; var b1 = this.m12; var c1 = this.m13; var d1 = this.m14; var a2 = this.m21; var b2 = this.m22; var c2 = this.m23; var d2 = this.m24; var a3 = this.m31; var b3 = this.m32; var c3 = this.m33; var d3 = this.m34; var a4 = this.m41; var b4 = this.m42; var c4 = this.m43; var d4 = this.m44; // Row column labeling reversed since we transpose rows & columns this.m11 = this._determinant3x3(b2, b3, b4, c2, c3, c4, d2, d3, d4); this.m21 = - this._determinant3x3(a2, a3, a4, c2, c3, c4, d2, d3, d4); this.m31 = this._determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4); this.m41 = - this._determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4); this.m12 = - this._determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4); this.m22 = this._determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4); this.m32 = - this._determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4); this.m42 = this._determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4); this.m13 = this._determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4); this.m23 = - this._determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4); this.m33 = this._determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4); this.m43 = - this._determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4); this.m14 = - this._determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3); this.m24 = this._determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3); this.m34 = - this._determinant3x3(a1, a2, a3, b1, b2, b3, d1, d2, d3); this.m44 = this._determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3); }; rgl/inst/htmlwidgets/lib/rglClass/0000755000176200001440000000000015026603601016665 5ustar liggesusersrgl/inst/htmlwidgets/lib/rglClass/draw.src.js0000644000176200001440000013462615011677075020774 0ustar liggesusers /** * Methods related to drawing * @name ___METHODS_FOR_DRAWING___ * @memberof rglwidgetClass * @kind function * @instance */ /** * Start drawing * @returns { boolean } Previous state */ rglwidgetClass.prototype.startDrawing = function() { var value = this.drawing; this.drawing = true; return value; }; /** * Stop drawing and check for context loss * @param { boolean } saved - Previous state */ rglwidgetClass.prototype.stopDrawing = function(saved) { this.drawing = saved; if (!saved && this.gl && this.gl.isContextLost()) this.restartCanvas(); }; /** * Update the triangles used to display a plane * @param { number } id - id of the plane * @param { Object } bbox - bounding box in which to display the plane */ rglwidgetClass.prototype.planeUpdateTriangles = function(obj, bbox) { var perms = [[0,0,1], [1,2,2], [2,1,0]], x, xrow, elem, A, d, nhits, i, j, k, u, v, w, intersect, which, v0, v2, vx, reverse, face1 = [], face2 = [], normals = [], nPlanes = obj.normals.length, idx, center; obj.bbox = bbox; obj.vertices = []; obj.centers = []; obj.initialized = false; for (elem = 0; elem < nPlanes; elem++) { // Vertex Av = normal.getRecycled(elem); x = []; A = obj.normals[elem]; d = obj.offsets[elem][0]; nhits = 0; for (i=0; i<3; i++) for (j=0; j<2; j++) for (k=0; k<2; k++) { u = perms[0][i]; v = perms[1][i]; w = perms[2][i]; if (A[w] !== 0.0) { intersect = -(d + A[u]*bbox[j+2*u] + A[v]*bbox[k+2*v])/A[w]; if (bbox[2*w] < intersect && intersect < bbox[1+2*w]) { xrow = []; xrow[u] = bbox[j+2*u]; xrow[v] = bbox[k+2*v]; xrow[w] = intersect; x.push(xrow); face1[nhits] = j + 2*u; face2[nhits] = k + 2*v; nhits++; } } } if (nhits > 3) { /* Re-order the intersections so the triangles work */ for (i=0; i i+1) { rglwidgetClass.swap(x, i+1, which); rglwidgetClass.swap(face1, i+1, which); rglwidgetClass.swap(face2, i+1, which); } } } if (nhits >= 3) { /* Put in order so that the normal points out the FRONT of the faces */ v0 = [x[0][0] - x[1][0] , x[0][1] - x[1][1], x[0][2] - x[1][2]]; v2 = [x[2][0] - x[1][0] , x[2][1] - x[1][1], x[2][2] - x[1][2]]; /* cross-product */ vx = rglwidgetClass.xprod(v0, v2); reverse = rglwidgetClass.dotprod(vx, A) > 0; for (i=0; i 0) { clipplanedata = new Float32Array(4*n); for (i=0; i < clipplaneids.length; i++) { clip = this.getObj(clipplaneids[i]); for (j=0; j < clip.offsets.length; j++) { clipplanedata.set(clip.IMVClip[j], clipcheck); clipcheck += 4; } } // Leftovers are initialized to zero, which is fine gl.uniform4fv(obj.clipLoc, clipplanedata); } }; /** * Do code for lighting * @param { object } obj - Object to work with * @param { object } subscene - Subscene to work with */ rglwidgetClass.prototype.doLighting = function(obj, subscene) { var gl = this.gl, i, j, n, light, ambient, specular, diffuse, lightDir, viewpoint, finite, ambient0, specular0; gl.uniform3fv( obj.emissionLoc, obj.emission); gl.uniform1f( obj.shininessLoc, obj.shininess); while ((typeof subscene.lights === "undefined" || subscene.lights.length === 0) && typeof subscene.parent !== "undefined") subscene = this.getObj(subscene.parent); if (typeof subscene.lights === "undefined") return; n = subscene.lights.length; ambient = new Float32Array(3*n); specular = new Float32Array(3*n); diffuse = new Float32Array(3*n); lightDir = new Float32Array(3*n); viewpoint = new Int32Array(n); finite = new Int32Array(n); for (i=0; i < n; i++) { light = this.getObj(subscene.lights[i]); if (!light.initialized) this.initObj(light); ambient0 = this.componentProduct(light.ambient, obj.ambient); specular0 = this.componentProduct(light.specular, obj.specular); for (j=0; j < 3; j++) { ambient[3*i + j] = ambient0[j]; specular[3*i + j] = specular0[j]; diffuse[3*i + j] = light.diffuse[j]; lightDir[3*i + j] = light.lightDir[j]; } viewpoint[i] = light.viewpoint; finite[i] = light.finite; } for (i = n; i < obj.nlights; i++) { for (j = 0; j < 3; j++) { ambient[3*i + j] = 0.0; specular[3*i + j] = 0.0; diffuse[3*i + j] = 0.0; } } gl.uniform3fv( obj.ambientLoc, ambient); gl.uniform3fv( obj.specularLoc, specular); gl.uniform3fv( obj.diffuseLoc, diffuse); gl.uniform3fv( obj.lightDirLoc, lightDir); gl.uniform1iv( obj.viewpointLoc, viewpoint); gl.uniform1iv( obj.finiteLoc, finite); }; /** * Do code for colors * @param { object } obj - Object to work with */ rglwidgetClass.prototype.doColors = function(obj) { var gl = this.gl; if (obj.colorCount === 1) { gl.disableVertexAttribArray( this.colLoc ); gl.vertexAttrib4fv( this.colLoc, new Float32Array(obj.onecolor)); return false; } else { gl.enableVertexAttribArray( this.colLoc ); gl.vertexAttribPointer(this.colLoc, 4, gl.FLOAT, false, 4*obj.vOffsets.stride, 4*obj.vOffsets.cofs); return true; } }; /** * Do code for normals * @param { object } obj - Object to work with */ rglwidgetClass.prototype.doNormals = function(obj) { var gl = this.gl; if (obj.vOffsets.nofs >= 0) { gl.enableVertexAttribArray( obj.normLoc ); gl.vertexAttribPointer(obj.normLoc, 3, gl.FLOAT, false, 4*obj.vOffsets.stride, 4*obj.vOffsets.nofs); return true; } else return false; }; /** * Do code for vNormal * @param { object } obj - Object to work with */ rglwidgetClass.prototype.doNormMat = function(obj) { var gl = this.gl; gl.uniformMatrix4fv( obj.normMatLoc, false, new Float32Array(this.normMatrix.getAsArray()) ); }; /** * Do code for textures * @param { object } obj - Object to work with */ rglwidgetClass.prototype.doTexture = function(obj) { var gl = this.gl, is_sphere = obj.type === "sphere"; gl.enableVertexAttribArray( obj.texLoc ); if (is_sphere) gl.vertexAttribPointer(obj.texLoc, 2, gl.FLOAT, false, 4*this.sphere.vOffsets.stride, 4*this.sphere.vOffsets.tofs); else gl.vertexAttribPointer(obj.texLoc, 2, gl.FLOAT, false, 4*obj.vOffsets.stride, 4*obj.vOffsets.tofs); gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, obj.texture); gl.uniform1i( obj.sampler, 0); return true; }; /** * Do code for user attributes * @param { object } obj - Object to work with */ rglwidgetClass.prototype.doUserAttributes = function(obj) { if (typeof obj.userAttributes !== "undefined") { var gl = this.gl; for (var attr in obj.userAttribSizes) { // Not all attributes may have been used gl.enableVertexAttribArray( obj.userAttribLocations[attr] ); gl.vertexAttribPointer( obj.userAttribLocations[attr], obj.userAttribSizes[attr], gl.FLOAT, false, 4*obj.vOffsets.stride, 4*obj.userAttribOffsets[attr]); } } }; /** * Do code for user uniforms * @param { object } obj - Object to work with */ rglwidgetClass.prototype.doUserUniforms = function(obj) { var gl = this.gl, attr; if (typeof obj.userUniforms !== "undefined") { for (attr in obj.userUniformLocations) { var loc = obj.userUniformLocations[attr]; if (loc !== null) { var uniform = obj.userUniforms[attr]; if (typeof uniform !== "undefined") { var dim = rglwidgetClass.arrayDim(uniform); if (dim.length === 0) gl.uniform1f(loc, uniform); else if (dim.length === 1) { uniform = new Float32Array(uniform); switch(uniform.length) { case 2: gl.uniform2fv(loc, uniform); break; case 3: gl.uniform3fv(loc, uniform); break; case 4: gl.uniform4fv(loc, uniform); break; default: console.warn("bad uniform length"); } } else if (dim.length === 2 && dim[0] === 4 && dim[1] === 4) gl.uniformMatrix4fv(loc, false, new Float32Array(rglwidgetClass.flatten(uniform))); else if (dim.length === 2) { uniform = new Float32Array(rglwidgetClass.flatten(uniform)); switch(dim[[1]]) { case 1: gl.uniform1fv(loc, uniform); break; case 2: gl.uniform2fv(loc, uniform); break; case 3: gl.uniform3fv(loc, uniform); break; case 4: gl.uniform4fv(loc, uniform); break; default: console.warn("bad uniform column count"); } } else console.warn("unsupported uniform shape"); } } } } if (typeof obj.userTextures !== "undefined") { var has_texture = rglwidgetClass.isSet(obj.flags, rglwidgetClass.f_has_texture), texnum = has_texture - 1; for (attr in obj.userTextures) { var texture = obj.userTextures[attr]; if (texture.sampler !== null) { texnum += 1; gl.activeTexture(gl.TEXTURE0 + texnum); gl.bindTexture(gl.TEXTURE_2D, texture.texture); gl.uniform1i( texture.sampler, texnum); } } } }; /** * Load indices for complex drawing * @param { object } obj - Object to work with * @param { numeric } pass - Which pass of drawing? * @param { array } indices - Indices to draw */ rglwidgetClass.prototype.doLoadIndices = function(obj, pass, indices) { var gl = this.gl, f = obj.f[pass], type = obj.type, fat_lines = rglwidgetClass.isSet(obj.flags, rglwidgetClass.f_fat_lines), fnew, step; switch(type){ case "points": step = 1; break; case "abclines": case "lines": if (fat_lines) step = 6; else step = 2; break; case "linestrip": if (fat_lines) step = 6; else step = 1; break; case "sphere": case "planes": case "triangles": step = 3; break; case "text": case "sprites": case "quads": case "surface": step = 6; break; default: console.error("loadIndices for "+type); return 0; } if (obj.index_uint) fnew = new Uint32Array(step * indices.length); else fnew = new Uint16Array(step * indices.length); for (var i = 0; i < indices.length; i++) { for (var j = 0; j < step; j++) { fnew[step*i + j] = f[step*indices[i] + j]; } } gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, fnew, gl.DYNAMIC_DRAW); return fnew.length; }; /** * Do code for depth masking * @param { boolean } mask - whether to mask */ rglwidgetClass.prototype.doMasking = function(mask) { var gl = this.gl; gl.depthMask(mask); }; /** * Do code for alpha blending * @param { boolean } blend - Whether to blend. * @param { integer } objid - Object id */ rglwidgetClass.prototype.doBlending = function(blend, objid) { var gl = this.gl, blendfunc, obj, blends = {zero: gl.ZERO, one: gl.ONE, src_color: gl.SRC_COLOR, one_minus_src_color: gl.ONE_MINUS_SRC_COLOR, dst_color: gl.DST_COLOR, one_minus_dst_color: gl.ONE_MINUS_DST_COLOR, src_alpha: gl.SRC_ALPHA, one_minus_src_alpha: gl.ONE_MINUS_SRC_ALPHA, dst_alpha: gl.DST_ALPHA, one_minus_dst_alpha: gl.ONE_MINUS_DST_ALPHA, constant_color: gl.CONSTANT_COLOR, one_minus_constant_color: gl.ONE_MINUS_CONSTANT_COLOR, constant_alpha: gl.CONSTANT_ALPHA, one_minus_constant_alpha: gl.ONE_MINUS_CONSTANT_ALPHA, src_alpha_saturate: gl.SRC_ALPHA_SATURATE}; if (blend) { obj = this.getObj(objid); blendfunc = this.getMaterial(obj, "blend"); gl.blendFuncSeparate(blends[blendfunc[0]], blends[blendfunc[1]], gl.ONE, gl.ONE); gl.enable(gl.BLEND); } else { gl.disable(gl.BLEND); } }; /** * Set up for fog in the subscene * @param { object } obj - background object * @param { object } subscene - which subscene */ rglwidgetClass.prototype.doFog = function(obj, subscene) { var gl = this.gl, fogmode, color, observer = subscene.par3d.observer[2], sintheta = Math.sin(subscene.par3d.FOV*Math.PI/180/2), parms = [this.frustum.near - 2*observer, this.frustum.far - 2*observer, this.fogScale, (1-sintheta)/(1+sintheta)]; if (typeof this.fogType === "undefined") this.fogType = "none"; if (typeof this.fogScale === "undefined") parms[2] = 1; if (sintheta === 0) parms[3] = 1/3; switch(this.fogType){ case "none": fogmode = 0; break; case "linear": fogmode = 1; break; case "exp": fogmode = 2; break; case "exp2": fogmode = 3; break; default: console.error("Unknown fogtype "+this.fogType); } gl.uniform1i(obj.uFogMode, fogmode); color = this.fogColor; gl.uniform3f(obj.uFogColor, color[0], color[1], color[2]); gl.uniform4f(obj.uFogParms, parms[0], parms[1], parms[2], parms[3]); }; /* The draw methods are called twice. When this.opaquePass is true, they should draw opaque parts of the scene, and return the list of transparent pieces. Here context is the context array on input, modified when the matrices are changed. When this.opaquePass is false, the context argument contains a "piece", i.e. an ordered list of parts of the object to draw. */ /** * Draw simple object * @param { object } obj - Object to draw * @param { object } subscene - which subscene * @param { array } context - Which context are we in? */ rglwidgetClass.prototype.drawSimple = function(obj, subscene, context) { var fl, is_transparent, type = obj.type, gl = this.gl || this.initGL(), count, pass, mode, pmode, enabled = {}; if (!obj.initialized) this.initObj(obj); if (this.texturesLoading) return[]; count = obj.vertexCount; if (!count) return []; fl = obj.defFlags; is_transparent = fl.is_transparent || obj.someHidden; if (is_transparent && this.opaquePass) return this.getPieces(context, obj.id, 0, obj); this.doDepthTest(obj); this.doMasking(this.getMaterial(obj, "depth_mask")); gl.useProgram(obj.prog); this.doPolygonOffset(obj); gl.bindBuffer(gl.ARRAY_BUFFER, obj.buf); gl.uniformMatrix4fv( obj.prMatLoc, false, new Float32Array(this.prMatrix.getAsArray()) ); gl.uniformMatrix4fv( obj.mvMatLoc, false, new Float32Array(this.mvMatrix.getAsArray()) ); this.doClipping(obj, subscene); if (fl.needs_vnormal) this.doNormMat(obj); if (fl.is_lit) this.doLighting(obj, subscene); if (fl.has_fog) this.doFog(obj, subscene); this.doUserAttributes(obj); this.doUserUniforms(obj); gl.enableVertexAttribArray( this.posLoc ); enabled.posLoc = true; if (fl.has_texture || obj.type === "text") enabled.texLoc = this.doTexture(obj); enabled.colLoc = this.doColors(obj); enabled.normLoc = this.doNormals(obj); if (fl.fixed_size) { gl.uniform3f( obj.textScaleLoc, 0.75/this.vp.width, 0.75/this.vp.height, 1.0); } if (fl.fixed_quads) { gl.enableVertexAttribArray( obj.ofsLoc ); enabled.ofsLoc = true; gl.vertexAttribPointer(obj.ofsLoc, 3, gl.FLOAT, false, 4*obj.vOffsets.stride, 4*obj.vOffsets.oofs); } for (pass = 0; pass < obj.passes; pass++) { pmode = obj.pmode[pass]; if (pmode === "culled") continue; mode = fl.fat_lines && (fl.is_lines || pmode === "lines") ? "TRIANGLES" : this.mode4type[type]; if (fl.is_twosided) { gl.uniform1i(obj.frontLoc, pass !== 0); if (fl.has_normals) { gl.uniformMatrix4fv(obj.invPrMatLoc, false, new Float32Array(this.invPrMatrix.getAsArray())); } } gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, obj.ibuf[pass]); if (!this.opaquePass) { if (type === "sphere" && obj.fastTransparency) count = this.doLoadIndices(obj, pass, this.sphere.fastpieces[0].indices); else count = this.doLoadIndices(obj, pass, context.indices); } else { count = obj.f[pass].length; gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, obj.f[pass], gl.STATIC_DRAW); } if (!fl.is_lines && pmode === "lines" && !fl.fat_lines) { mode = "LINES"; } else if (pmode === "points") { mode = "POINTS"; } if ((fl.is_lines || pmode === "lines") && fl.fat_lines) { gl.enableVertexAttribArray(obj.pointLoc); enabled.pointLoc = true; gl.vertexAttribPointer(obj.pointLoc, 2, gl.FLOAT, false, 4*obj.vOffsets.stride, 4*obj.vOffsets.pointofs); gl.enableVertexAttribArray(obj.nextLoc ); enabled.nextLoc = true; gl.vertexAttribPointer(obj.nextLoc, 3, gl.FLOAT, false, 4*obj.vOffsets.stride, 4*obj.vOffsets.nextofs); gl.uniform1f(obj.aspectLoc, this.vp.width/this.vp.height); gl.uniform1f(obj.lwdLoc, this.getMaterial(obj, "lwd")/this.vp.height); } gl.vertexAttribPointer(this.posLoc, 3, gl.FLOAT, false, 4*obj.vOffsets.stride, 4*obj.vOffsets.vofs); gl.drawElements(gl[mode], count, obj.index_uint ? gl.UNSIGNED_INT : gl.UNSIGNED_SHORT, 0); } this.disableArrays(obj, enabled); return []; }; /** * Draw planes object * @param { object } obj - Object to draw * @param { object } subscene - which subscene * @param { array } context - Which context are we in? */ rglwidgetClass.prototype.drawPlanes = function(obj, subscene, context) { if (this.opaquePass && (obj.bbox !== subscene.par3d.bbox || !obj.initialized)) { this.planeUpdateTriangles(obj, subscene.par3d.bbox); } return this.drawSimple(obj, subscene, context); }; /** * @param { object } obj - object to draw * @param { object } subscene * @param { array } context * @description * Draw spheres in a subscene
* * Drawing spheres happens in six ways:
* 1 opaquepass, not transparent: transform and draw this.sphere count times
* 2 opaquepass, transparent, not fast: transform & collect sphere pieces count times
* 3 opaquepass, transparent, fast: order the centres into separate pieces, order this.sphere once
* 4 not opaquepass, not transparent: do nothing
* 5 not opaquepass, transparent, not fast: transform for one sphere, draw one merged piece
* 6 not opaquepass, transparent, fast: transform for one sphere, draw this.sphere in fixed order.
**/ rglwidgetClass.prototype.drawSpheres = function(obj, subscene, context) { var flags = obj.flags, is_transparent = rglwidgetClass.isSet(flags, rglwidgetClass.f_is_transparent), sphereMV, baseofs, ofs, sscale, i, count, nc, scount, scale, indices, sphereNorm, enabled = {}, drawing, saveNorm = new CanvasMatrix4(this.normMatrix), saveMV = new CanvasMatrix4(this.mvMatrix), savePRMV = null, result = [], idx, margin = obj.material.margin; if (typeof margin !== "undefined") if (!this.marginVecToDataVec(obj, subscene)) return []; if (!obj.initialized) this.initObj(obj); count = obj.vertexCount; if (!count) return []; is_transparent = is_transparent || obj.someHidden; if (!this.opaquePass && !is_transparent) return []; if (this.prmvMatrix !== null) savePRMV = new CanvasMatrix4(this.prmvMatrix); scale = subscene.par3d.scale; sphereNorm = new CanvasMatrix4(); sphereNorm.scale(scale[0], scale[1], scale[2]); sphereNorm.multRight(saveNorm); this.normMatrix = sphereNorm; if (this.opaquePass) { context = context.slice(); context.push(obj.id); } drawing = this.opaquePass !== is_transparent; if (drawing) { nc = obj.colorCount; if (nc === 1) { this.sphere.onecolor = obj.onecolor; } } this.initShapeFromObj(this.sphere, obj); if (!this.opaquePass && obj.fastTransparency && typeof this.sphere.fastpieces === "undefined") { this.sphere.fastpieces = this.getPieces(context.context, obj.id, 0, this.sphere); this.sphere.fastpieces = this.sortPieces(this.sphere.fastpieces); this.sphere.fastpieces = this.mergePieces(this.sphere.fastpieces); } if (this.opaquePass) scount = count; else { indices = context.indices; if (obj.fastTransparency) scount = indices.length; /* Each item gives the center of a whole sphere */ else scount = 1; /* Each item is a fragment of the sphere, at location subid */ } for (i = 0; i < scount; i++) { sphereMV = new CanvasMatrix4(); if (this.opaquePass) idx = i; else if (obj.fastTransparency) idx = indices[i]; else idx = context.subid; if (typeof idx === "undefined") console.error("idx is undefined"); baseofs = idx*obj.vOffsets.stride; ofs = baseofs + obj.vOffsets.radofs; sscale = obj.values[ofs]; sphereMV.scale(sscale/scale[0], sscale/scale[1], sscale/scale[2]); sphereMV.translate(obj.values[baseofs], obj.values[baseofs+1], obj.values[baseofs+2]); sphereMV.multRight(saveMV); this.mvMatrix = sphereMV; this.setnormMatrix2(); this.setprmvMatrix(); if (drawing) { if (nc > 1) { this.sphere.onecolor = obj.values.slice(baseofs + obj.vOffsets.cofs, baseofs + obj.vOffsets.cofs + 4); } this.drawSimple(this.sphere, subscene, context); } else result = result.concat(this.getSpherePieces(context, i, obj)); } if (drawing) this.disableArrays(obj, enabled); this.normMatrix = saveNorm; this.mvMatrix = saveMV; this.prmvMatrix = savePRMV; return result; }; /** * Prepare clipplanes for drawing * @param { object } obj - clip planes object */ rglwidgetClass.prototype.drawClipplanes = function(obj) { var count = obj.offsets.length, IMVClip = []; for (var i=0; i < count; i++) { IMVClip[i] = rglwidgetClass.multMV(this.invMatrix, obj.vClipplane.slice(4*i, 4*(i+1))); } obj.IMVClip = IMVClip; return []; }; /** * Prepare linestrip for drawing * @param { object } obj - line strip object * @param { object } subscene * @param { array } context */ rglwidgetClass.prototype.drawLinestrip = function(obj, subscene, context) { var origIndices, i, j, margin = obj.material.margin; if (typeof margin !== "undefined") if (!this.marginVecToDataVec(obj, subscene)) return []; if (this.opaquePass) return this.drawSimple(obj, subscene, context); origIndices = context.indices.slice(); for (i=0; i < origIndices.length; i++) { j = origIndices[i]; if (j < obj.centers.length - 1) { context.indices = [j, j+1]; this.drawSimple(obj, subscene, context); } } context.indices = origIndices; return []; }; /** * Draw a sprites object in a subscene * @param { object } obj - object to draw * @param { object } subscene * @param { object } context */ rglwidgetClass.prototype.drawSprites = function(obj, subscene, context) { var flags = obj.flags, is_transparent = rglwidgetClass.isSet(flags, rglwidgetClass.f_is_transparent), sprites3d = rglwidgetClass.isSet(flags, rglwidgetClass.f_sprites_3d), fixed_size = rglwidgetClass.isSet(flags, rglwidgetClass.f_fixed_size), rotating = rglwidgetClass.isSet(flags, rglwidgetClass.f_rotating), i,j, origMV = new CanvasMatrix4( this.mvMatrix ), origPRMV = null, origPR, pos, radius, userMatrix, result = [], margin = obj.material.margin; if (typeof margin !== "undefined") if (!this.marginVecToDataVec(obj, subscene)) return []; if (!sprites3d) return this.drawSimple(obj, subscene, context); if (!obj.initialized) this.initObj(obj); if (!obj.vertexCount) return []; is_transparent = is_transparent || obj.someHidden; var norigs = obj.vertices.length, savenorm = new CanvasMatrix4(this.normMatrix), iOrig, adj, offset; userMatrix = obj.userMatrix; if (this.opaquePass) { context = context.slice(); context.push(obj.id); } else norigs = 1; if (this.prmvMatrix !== null) origPRMV = new CanvasMatrix4( this.prmvMatrix ); offset = obj.offset; if (fixed_size && !rotating) { origPR = this.prMatrix; this.prMatrix = new CanvasMatrix4(); } for (iOrig=0; iOrig < norigs; iOrig++) { if (this.opaquePass) j = iOrig; else j = context.subid; pos = [].concat(obj.vertices[j]).concat(1.0); radius = obj.radii.length > 1 ? obj.radii[j][0] : obj.radii[0][0]; this.mvMatrix = new CanvasMatrix4(userMatrix); adj = this.getAdj(obj, j, offset); this.mvMatrix.translate(1 - 2*adj[0], 1 - 2*adj[1], 1 - 2*adj[2]); this.mvMatrix.scale(radius, radius, radius); if (fixed_size) { var viewport = subscene.par3d.viewport, winwidth = viewport.width*this.canvas.width, winheight = viewport.height*this.canvas.height, scalex = 27/winwidth, scaley = 27/winheight, scale = Math.sqrt(scalex * scaley); if (!rotating) { pos = rglwidgetClass.multVM(pos, origMV); pos = rglwidgetClass.multVM(pos, origPR); this.mvMatrix.scale(scalex, scaley, scale); } else { scale = 4.0 * scale * subscene.par3d.zoom; this.mvMatrix.scale(scale, scale, scale); } this.mvMatrix.translate(pos[0]/pos[3], pos[1]/pos[3], pos[2]/pos[3]); if (rotating) this.mvMatrix.multRight(origMV); } else { if (!rotating) { pos = rglwidgetClass.multVM(pos, origMV); this.mvMatrix.translate(pos[0]/pos[3], pos[1]/pos[3], pos[2]/pos[3]); } else { this.mvMatrix.translate(pos[0]/pos[3], pos[1]/pos[3], pos[2]/pos[3]); this.mvMatrix.multRight(origMV); } } this.setnormMatrix2(); this.setprmvMatrix(); j = iOrig % obj.shapefirst.length; var first = obj.shapefirst[j]; for (i=0; i < obj.shapelens[j]; i++) if (this.opaquePass) result = result.concat(this.drawObjId(obj.objects[first + i], subscene.id, context.concat(j))); else this.drawObjId(obj.objects[i], subscene.id, context); } this.normMatrix = savenorm; this.mvMatrix = origMV; if (fixed_size && !rotating) this.prMatrix = origPR; if (origPRMV !== null) this.prmvMatrix = origPRMV; return result; }; /** * Draw object that might be in margin * @param { Object } obj - text object to draw * @param { Object } subscene - subscene holding it * @param { Object } context - context for drawing */ rglwidgetClass.prototype.drawMarginal = function(obj, subscene, context) { var margin = obj.material.margin; if (typeof margin !== "undefined") if (!this.marginVecToDataVec(obj, subscene)) return []; return this.drawSimple(obj, subscene, context); }; /** * Draw bounding box and decorations * @param { Object } obj - bboxdeco to draw * @param { Object } subscene - subscene holding it * @param { Object } context - context for drawing */ rglwidgetClass.prototype.drawBBox = function(obj, subscene, context) { var flags = obj.flags, is_transparent = rglwidgetClass.isSet(flags, rglwidgetClass.f_is_transparent), scale, bbox, indices, enabled = {}, drawing, result = [], idx, center, edges, saved; if (!obj.initialized) this.initBBox(obj); is_transparent = is_transparent || obj.someHidden; if (!this.opaquePass && !is_transparent) return result; this.setBbox(obj, subscene); saved = this.setBBoxMatrices(obj); bbox = obj.bbox; center = obj.center; scale = [bbox[1]-bbox[0], bbox[3]-bbox[2], bbox[5]-bbox[4]]; if (!obj.cube.initialized) { this.initObj(obj.cube); } if (this.opaquePass) { context = context.slice(); context.push(obj.id); } drawing = this.opaquePass !== is_transparent; this.cube.onecolor = obj.cube.onecolor; this.initShapeFromObj(this.cube, obj.cube); if (!this.opaquePass) indices = context.indices; if (this.opaquePass) idx = 0; else idx = context.subid; if (typeof idx === "undefined") console.error("idx is undefined"); if (drawing) { this.drawSimple(this.cube, subscene, context); } else result = result.concat(this.getCubePieces(context, obj)); if (!obj.ticks.initialized) { obj.ticks.locations = this.getTickLocations(obj); obj.ticks.edges = undefined; } edges = this.getTickEdges(this.prmvMatrix); if (obj.needsAxisCallback) this.doAxisCallback(obj, edges); if (!obj.ticks.edges || edges.toString() !== obj.ticks.edges.toString()) { obj.ticks.edges = edges; this.getTickVertices(obj.ticks); this.placeTickLabels(obj); this.setTickLabels(obj); } if (!obj.ticks.initialized) { this.initObj(obj.ticks); this.initObj(obj.labels); } if (drawing) { this.drawSimple(obj.ticks, subscene, context); this.drawSimple(obj.labels, subscene, context); this.disableArrays(obj, enabled); } else { result = result.concat(this.drawSimple(obj.ticks, subscene, context)); result = result.concat(this.drawSimple(obj.labels, subscene, context)); } this.restoreBBoxMatrices(saved); return result; }; /** * Use ids to choose object to draw * @param { numeric } id - object to draw * @param { numeric } subscene * @param { array } context */ rglwidgetClass.prototype.drawObjId = function(id, subsceneid, context) { if (typeof id !== "number") this.alertOnce("drawObjId id is "+typeof id); return this.drawObj(this.getObj(id), this.getObj(subsceneid), context); }; /** * Draw an object in a subscene * @param { object } obj - object to draw * @param { object } subscene * @param { array } context */ rglwidgetClass.prototype.drawObj = function(obj, subscene, context) { switch(obj.type) { case "abclines": case "surface": return this.drawSimple(obj, subscene, context); case "points": case "lines": case "triangles": case "quads": case "text": return this.drawMarginal(obj, subscene, context); case "linestrip": return this.drawLinestrip(obj, subscene, context); case "planes": return this.drawPlanes(obj, subscene, context); case "spheres": return this.drawSpheres(obj, subscene, context); case "clipplanes": return this.drawClipplanes(obj); case "sprites": return this.drawSprites(obj, subscene, context); case "light": return []; case "bboxdeco": return this.drawBBox(obj, subscene, context); } console.error("drawObj for type = "+obj.type); }; /** * Draw the background for a subscene * @param { number } id - id of background object * @param { number } subsceneid - id of subscene */ rglwidgetClass.prototype.drawBackground = function(id, subsceneid, context) { var gl = this.gl || this.initGL(), obj = this.getObj(id), subscene, bg, i, savepr, saveinvpr, savemv, savenorm, m, bbox, result = [], savedm = gl.getParameter(gl.DEPTH_WRITEMASK), savedt = gl.isEnabled(gl.DEPTH_TEST), saveblend = gl.isEnabled(gl.BLEND); if (!obj.initialized) this.initObj(obj); if (obj.colors.length) { bg = obj.colors[0]; gl.depthMask(true); gl.clear(gl.DEPTH_BUFFER_BIT); gl.clearColor(bg[0], bg[1], bg[2], bg[3]); gl.clear(gl.COLOR_BUFFER_BIT); this.fogColor = bg; } else { this.fogColor = [0,0,0,0]; obj.colors = [[0,0,0,0]]; } this.fogType = obj.fogtype; this.fogScale = obj.fogscale; gl.disable(gl.BLEND); gl.disable(gl.DEPTH_TEST); gl.depthMask(false); if (typeof obj.quad !== "undefined") { savepr = this.prMatrix; saveinvpr = this.invPrMatrix; savemv = this.mvMatrix; savenorm = this.normMatrix; this.prMatrix = new CanvasMatrix4(); this.invPrMatrix = new CanvasMatrix4(); this.mvMatrix = new CanvasMatrix4(); this.normMatrix = new CanvasMatrix4(); for (i=0; i < obj.quad.length; i++) result = result.concat(this.drawObjId(obj.quad[i], subsceneid)); this.prMatrix = savepr; this.invPrMatrix = saveinvpr; this.mvMatrix = savemv; this.normMatrix = savenorm; } else if (obj.sphere) { subscene = this.getObj(subsceneid); savemv = this.mvMatrix; savenorm = this.normMatrix; bbox = subscene.par3d.bbox; var center = [(bbox[0] + bbox[1])/2, (bbox[2] + bbox[3])/2, (bbox[4] + bbox[5])/2, 1], scale = subscene.par3d.scale, ranges = [bbox[1] - bbox[0], bbox[3] - bbox[2], bbox[5] - bbox[4]], avgscale = rglwidgetClass.vlen(ranges)/Math.sqrt(3), aspect = [ranges[0]*scale[0]/avgscale, ranges[1]*scale[1]/avgscale, ranges[2]*scale[2]/avgscale], maxaspect = Math.max(aspect[0], aspect[1], aspect[2]), zoom = subscene.par3d.zoom; m = new CanvasMatrix4(); m.rotate(90, 1, 0, 0); m.scale(zoom*2.0*maxaspect*ranges[0]/aspect[0], zoom*2.0*maxaspect*ranges[1]/aspect[1], zoom*2.0*maxaspect*ranges[2]/aspect[2]); m.translate(center[0], center[1], center[2]); m.multRight(savemv); center = rglwidgetClass.multVM(center, savemv); m.translate(-center[0], -center[1], -center[2]); m.scale(1, 1, 0.25/zoom); m.translate(center[0], center[1], center[2]); this.mvMatrix = m; this.initShapeFromObj(this.sphere, obj); this.sphere.onecolor = obj.colors.length > 1 ? obj.colors[1] : obj.colors[0]; this.normMatrix = new CanvasMatrix4(); this.setnormMatrix2(); this.setprmvMatrix(); result = result.concat(this.drawSimple(this.sphere, subscene, context)); this.mvMatrix = savemv; this.normMatrix = savenorm; } gl.depthMask(savedm); if (savedt) gl.enable(gl.DEPTH_TEST); if (saveblend) gl.enable(gl.BLEND); return result; }; /** * Draw a subscene * @param { number } subsceneid - id of subscene * @param { array } context */ rglwidgetClass.prototype.drawSubscene = function(subsceneid, context) { var sub = this.getObj(subsceneid), objects = this.scene.objects, clipids = sub.clipplanes, subids = sub.objects, subscene_has_faces = false, subscene_needs_sorting = false, flags, i, obj, result = []; if (sub.par3d.skipRedraw) return result; if (this.opaquePass) { for (i=0; i < subids.length; i++) { obj = objects[subids[i]]; flags = obj.flags; if (typeof flags !== "undefined") { subscene_has_faces = subscene_has_faces || (rglwidgetClass.isSet(flags, rglwidgetClass.f_is_lit) && !rglwidgetClass.isSet(flags, rglwidgetClass.f_fixed_quads)); obj.is_transparent = obj.someHidden || rglwidgetClass.isSet(flags, rglwidgetClass.f_is_transparent); subscene_needs_sorting = subscene_needs_sorting || obj.is_transparent || rglwidgetClass.isSet(flags, rglwidgetClass.f_depth_sort); } } } this.setViewport(subsceneid); this.setprMatrix(subsceneid); this.setInvPrMatrix(); this.setmvMatrix(subsceneid); this.setnormMatrix2(); this.setprmvMatrix(); this.invMatrix = new CanvasMatrix4(this.mvMatrix); this.invMatrix.invert(); if (this.opaquePass) { context = context.slice(); context.push(subsceneid); this.doBlending(false); this.subsceneid = subsceneid; if (typeof this.sphere !== "undefined") // reset this.sphere.fastpieces; it will be recreated if needed this.sphere.fastpieces = undefined; if (typeof sub.backgroundId !== "undefined") result = result.concat(this.drawBackground(sub.backgroundId, subsceneid, context)); } if (subids.length) { if (clipids.length > 0) { for (i = 0; i < clipids.length; i++) this.drawObjId(clipids[i], subsceneid); } subids = sub.opaque.concat(sub.transparent); if (this.opaquePass) { for (i = 0; i < subids.length; i++) result = result.concat(this.drawObjId(subids[i], subsceneid, context)); subids = sub.subscenes; for (i = 0; i < subids.length; i++) result = result.concat(this.drawSubscene(subids[i], context)); } } return result; }; /** * Set the context for drawing transparently * @param { array } context */ rglwidgetClass.prototype.setContext = function(context) { var result = [], objid, obj, type; context = context.slice(); context.reverse(); while (context.length > 0) { objid = context.pop(); obj = this.getObj(objid); type = obj.type; switch (type) { case "subscene": this.drawSubscene(objid, false); break; case "sprites": result = result.concat(context.pop()); break; case "spheres": // this.initSphereFromObj(obj); // FIXME: not needed? break; case "bboxdeco": result = result.concat(context.pop()); break; default: console.error("bad type '", type, "' in setContext"); } } return result; }; /** * Draw the transparent pieces of a scene * @param {object} pieces */ rglwidgetClass.prototype.drawPieces = function(pieces) { var i, prevcontext = [], context; for (i = 0; i < pieces.length; i++) { context = pieces[i].context.slice(); if (context !== prevcontext) { prevcontext = context.slice(); context = this.setContext(context); this.doBlending(true, pieces[i].objid); } this.drawObjId(pieces[i].objid, this.subsceneid, pieces[i]); } }; /** * Draw the whole scene */ rglwidgetClass.prototype.drawScene = function() { var wasDrawing = this.startDrawing(), pieces; if (!wasDrawing) { if (this.select.state !== "inactive") this.selectionChanged(); this.doStartScene(); this.opaquePass = true; pieces = this.drawSubscene(this.scene.rootSubscene, []); this.opaquePass = false; pieces = this.sortPieces(pieces); pieces = this.mergePieces(pieces); this.drawPieces(pieces); } this.stopDrawing(wasDrawing); }; rgl/inst/htmlwidgets/lib/rglClass/utils.src.js0000644000176200001440000004516214771520323021166 0ustar liggesusers /** * Utility methods * @name ___UTILITY_METHODS___ * @memberof rglwidgetClass * @kind function * @instance */ /** * Multiply matrix by vector * @returns {number[]} * @param M {number[][]} Left operand * @param v {number[]} Right operand */ rglwidgetClass.multMV = function(M, v) { return [ M.m11 * v[0] + M.m12 * v[1] + M.m13 * v[2] + M.m14 * v[3], M.m21 * v[0] + M.m22 * v[1] + M.m23 * v[2] + M.m24 * v[3], M.m31 * v[0] + M.m32 * v[1] + M.m33 * v[2] + M.m34 * v[3], M.m41 * v[0] + M.m42 * v[1] + M.m43 * v[2] + M.m44 * v[3] ]; }; /** * Multiply row vector by Matrix * @returns {number[]} * @param v {number[]} left operand * @param M {number[][]} right operand */ rglwidgetClass.multVM = function(v, M) { return [ M.m11 * v[0] + M.m21 * v[1] + M.m31 * v[2] + M.m41 * v[3], M.m12 * v[0] + M.m22 * v[1] + M.m32 * v[2] + M.m42 * v[3], M.m13 * v[0] + M.m23 * v[1] + M.m33 * v[2] + M.m43 * v[3], M.m14 * v[0] + M.m24 * v[1] + M.m34 * v[2] + M.m44 * v[3] ]; }; /** * Euclidean length of a vector * @returns {number} * @param v {number[]} */ rglwidgetClass.vlen = function(v) { return Math.sqrt(rglwidgetClass.dotprod(v, v)); }; /** * Dot product of two vectors * @instance rglwidgetClass * @returns {number} * @param a {number[]} * @param b {number[]} */ rglwidgetClass.dotprod = function(a, b) { return a[0]*b[0] + a[1]*b[1] + a[2]*b[2]; }; /** * Cross product of two vectors * @returns {number[]} * @param a {number[]} * @param b {number[]} */ rglwidgetClass.xprod = function(a, b) { return [a[1]*b[2] - a[2]*b[1], a[2]*b[0] - a[0]*b[2], a[0]*b[1] - a[1]*b[0]]; }; /** * Bind vectors or matrices by columns * @returns {number[][]} * @param a {number[][]} * @param b {number[]|number[][]} */ rglwidgetClass.cbind = function(a, b) { if (b.length < a.length) b = rglwidgetClass.repeatToLen(b, a.length); else if (a.length < b.length) a = rglwidgetClass.repeatToLen(a, b.length); return a.map(function(currentValue, index) { return [].concat(currentValue).concat(b[index]); }); }; /** * Swap elements * @returns {any[]} * @param a {any[]} * @param i {number} Element to swap * @param j {number} Other element to swap */ rglwidgetClass.swap = function(a, i, j) { var temp = a[i]; a[i] = a[j]; a[j] = temp; }; /** * Flatten a matrix into a vector * @returns {any[]} * @param a {any[][]} */ rglwidgetClass.flatten = function(arr, result) { var value; if (typeof result === "undefined") result = []; for (var i = 0, length = arr.length; i < length; i++) { value = arr[i]; if (Array.isArray(value)) { rglwidgetClass.flatten(value, result); } else { result.push(value); } } return result; }; /** * set element of 1d or 2d array as if it was flattened. * Column major, zero based! * @returns {any[]|any[][]} * @param {any[]|any[][]} a - array * @param {number} i - element * @param {any} value */ rglwidgetClass.prototype.setElement = function(a, i, value) { if (Array.isArray(a[0])) { var dim = a.length, col = Math.floor(i/dim), row = i % dim; a[row][col] = value; } else { a[i] = value; } }; /** * Transpose an array * @returns {any[][]} * @param {any[][]} a */ rglwidgetClass.prototype.transpose = function(a) { var newArray = [], n = a.length, m = a[0].length, i; for(i = 0; i < m; i++){ newArray.push([]); } for(i = 0; i < n; i++){ for(var j = 0; j < m; j++){ newArray[j].push(a[i][j]); } } return newArray; }; /** * Calculate sum of squares of a numeric vector * @returns {number} * @param {number[]} x */ rglwidgetClass.prototype.sumsq = function(x) { var result = 0, i; for (i=0; i < x.length; i++) result += x[i]*x[i]; return result; }; /** * Convert a matrix to a CanvasMatrix4 * @returns {CanvasMatrix4} * @param {number[][]|number[]} mat */ rglwidgetClass.prototype.toCanvasMatrix4 = function(mat) { if (mat instanceof CanvasMatrix4) return mat; var result = new CanvasMatrix4(); mat = rglwidgetClass.flatten(this.transpose(mat)); result.load(mat); return result; }; /** * Convert an R-style numeric colour string to an rgb vector * @returns {number[]} * @param {string} s */ /* jshint bitwise:false */ rglwidgetClass.prototype.stringToRgb = function(s) { s = s.replace("#", ""); var bigint = parseInt(s, 16); return [((bigint >> 16) & 255)/255, ((bigint >> 8) & 255)/255, (bigint & 255)/255]; }; /* jshint bitwise:true */ /** * Which list does a particular id come from? * @returns { string } * @param {number} id The id to look up. */ rglwidgetClass.prototype.whichList = function(id) { var obj = this.getObj(id), flags = obj.flags; if (obj.type === "light") return "lights"; if (rglwidgetClass.isSet(flags, rglwidgetClass.f_is_subscene)) return "subscenes"; if (rglwidgetClass.isSet(flags, rglwidgetClass.f_is_clipplanes)) return "clipplanes"; if (rglwidgetClass.isSet(flags, rglwidgetClass.f_is_transparent)) return "transparent"; return "opaque"; }; /** * Take a component-by-component product of two 3 vectors * @returns {number[]} * @param {number[]} x * @param {number[]} y */ rglwidgetClass.prototype.componentProduct = function(x, y) { if (typeof y === "undefined") { this.alertOnce("Bad arg to componentProduct"); } var result = new Float32Array(3), i; for (i = 0; i<3; i++) result[i] = x[i]*y[i]; return result; }; /** * Get next higher power of two * @returns { number } * @param { number } value - input value */ rglwidgetClass.prototype.getPowerOfTwo = function(value) { var pow = 1; while(pow= -windHeight && rect.left >= -windWidth && rect.bottom <= 2*windHeight && rect.right <= 2*windWidth); }; rglwidgetClass.keydiff = function(obj1, obj2) { var keys = Object.keys(obj1), i, result = []; for (i=0;i= 2 && cross(lower[lower.length - 2], lower[lower.length - 1], points[i]) <= 0) { lower.pop(); } lower.push(points[i]); } for (i = points.length - 1; i >= 0; i--) { while (upper.length >= 2 && cross(upper[upper.length - 2], upper[upper.length - 1], points[i]) <= 0) { upper.pop(); } upper.push(points[i]); } upper.pop(); lower.pop(); return lower.concat(upper); }; /** * Round number to given precision * @param { number } x * @param { number } digits * @returns { number } */ rglwidgetClass.signif = function(x, digits) { return parseFloat(x.toPrecision(digits)); }; /** * Check for NA, NaN, undefined, or null * @param x * @returns { bool } */ rglwidgetClass.missing = function(x) { return x !== "-Inf" && x !== "Inf" && (isNaN(x) || x === null || typeof(x) === "undefined"); }; /** * Write matrix to log * @param M */ rglwidgetClass.logMatrix = function(M) { console.log("matrix(c("+M.m11+","+M.m12+","+M.m13+","+M.m14+",\n"+ M.m21+","+M.m22+","+M.m23+","+M.m24+",\n"+ M.m31+","+M.m32+","+M.m33+","+M.m34+",\n"+ M.m41+","+M.m42+","+M.m43+","+M.m44+"), byrow=TRUE, ncol=4)"); }; /** * Write vector to log * @param {vector} v */ rglwidgetClass.logVec3 = function(v) { console.log("c("+v[0]+","+v[1]+","+v[2]+")"); }; /** * Sum two vectors * @param {vector} x * @param {vector} y */ rglwidgetClass.vsum = function(x, y) { var i, result = [].concat(x); for (i = 0; i < y.length; i++) result[i] += y[i]; return result; }; /** * difference of two vectors * @param {vector} x * @param {vector} y */ rglwidgetClass.vdiff = function(x, y) { return rglwidgetClass.vsum(x, rglwidgetClass.vscale(y, -1)); }; /** * Scale a vector * @param {number} s * @param {vector} x */ rglwidgetClass.vscale = function(x, s) { var i, result = [].concat(x); for (i = 0; i < x.length; i++) result[i] *= s; return result; }; /** * Normalize a vector * @param {vector} v */ rglwidgetClass.normalize = function(v) { return rglwidgetClass.vscale(v, 1/rglwidgetClass.vlen(v)); }; /** * Compute the dimensions of a regular array * without checking that it is regular */ rglwidgetClass.arrayDim = function(arr) { var result = []; while (typeof arr.length !== "undefined") { result = result.concat(arr.length); arr = arr[0]; } return result; }; rgl/inst/htmlwidgets/lib/rglClass/mouse.src.js0000644000176200001440000005077214771520323021161 0ustar liggesusers /** * Methods related to mouse handling * @name ___METHODS_FOR_MOUSE_HANDLING___ * @memberof rglwidgetClass * @kind function * @instance */ rglwidgetClass.prototype.getCursor = function(mode) { switch(mode) { case "none": return "none"; case "trackball": case "xAxis": case "yAxis": case "zAxis": case "polar": return "grab"; case "selecting": return "crosshair"; case "fov": case "zoom": return "zoom-in"; case "user": return "default"; } return "dragging"; }; /** * Set mouse mode for a subscene * @param { string } mode - name of mode * @param { number } button - button number (0 to 4) * @param { number } subscene - subscene id number * @param { number } stayActive - if truthy, don't clear brush */ rglwidgetClass.prototype.setMouseMode = function(mode, button, subscene, stayActive) { var sub = this.getObj(subscene), which = ["none", "left", "right", "middle", "wheel"][button]; if (!stayActive && sub.par3d.mouseMode[which] === "selecting") this.clearBrush(null); sub.par3d.mouseMode[which] = mode; if (button === 1 || (button === 0 && mode !== "none")) this.canvas.style.cursor = this.getCursor(mode); if (button === 0 && mode !== "none") sub.needsBegin = mode; }; /** * Compute mouse coordinates relative to current canvas * @returns { Object } * @param { Object } event - event object from mouse click */ rglwidgetClass.prototype.relMouseCoords = function(event) { var rect = this.canvas.getBoundingClientRect(); return {x:event.clientX-rect.left, y:event.clientY-rect.top}; }; /** * Send mouse selection to Shiny */ rglwidgetClass.prototype.recordSelection = function(subid) { var result = {}; if (typeof this.select !== "undefined" && typeof this.select.state !== "undefined" && this.select.state !== "inactive") { result = { subscene: subid, state: this.select.state, region: this.select.region }; this.setmvMatrix(subid); result.model = this.mvMatrix; this.setprMatrix(subid); result.proj = this.prMatrix; this.getViewport(subid); result.view = this.vp; } else result.state = "inactive"; Shiny.setInputValue(this.scene.selectionInput + ":shinyMouse3d", result); }; /** * Set mouse handlers for the scene */ rglwidgetClass.prototype.setMouseHandlers = function() { var self = this, activeSubscene, handler, handlers = {}, drag = 0; handlers.rotBase = 0; self.screenToVector = function(x, y) { var viewport = self.getObj(activeSubscene).par3d.viewport, width = viewport.width*self.canvas.width, height = viewport.height*self.canvas.height, radius = Math.max(width, height)/2.0, cx = width/2.0, cy = height/2.0, px = (x-cx)/radius, py = (y-cy)/radius, plen = Math.sqrt(px*px+py*py); if (plen > 1.e-6) { px = px/plen; py = py/plen; } var angle = (Math.SQRT2 - plen)/Math.SQRT2*Math.PI/2, z = Math.sin(angle), zlen = Math.sqrt(1.0 - z*z); px = px * zlen; py = py * zlen; return [px, py, z]; }; handlers.trackballdown = function(x,y) { var activeSub = self.getObj(activeSubscene), activeModel = self.getObj(self.useid(activeSub.id, "model")), i, l = activeModel.par3d.listeners; handlers.rotBase = self.screenToVector(x, y); self.saveMat = []; for (i = 0; i < l.length; i++) { activeSub = self.getObj(l[i]); activeSub.saveMat = new CanvasMatrix4(activeSub.par3d.userMatrix); } self.canvas.style.cursor = "grabbing"; }; handlers.trackballmove = function(x,y) { var rotCurrent = self.screenToVector(x,y), rotBase = handlers.rotBase, dot = rotBase[0]*rotCurrent[0] + rotBase[1]*rotCurrent[1] + rotBase[2]*rotCurrent[2], angle = Math.acos( dot/rglwidgetClass.vlen(rotBase)/rglwidgetClass.vlen(rotCurrent) )*180.0/Math.PI, axis = rglwidgetClass.xprod(rotBase, rotCurrent), objects = self.scene.objects, activeSub = self.getObj(activeSubscene), activeModel = self.getObj(self.useid(activeSub.id, "model")), l = activeModel.par3d.listeners, i; if (angle === 0.0) return; for (i = 0; i < l.length; i++) { activeSub = self.getObj(l[i]); activeSub.par3d.userMatrix.load(objects[l[i]].saveMat); activeSub.par3d.userMatrix.rotate(angle, axis[0], axis[1], axis[2]); } self.drawScene(); }; handlers.trackballend = 0; self.clamp = function(x, lo, hi) { return Math.max(lo, Math.min(x, hi)); }; self.screenToPolar = function(x,y) { var viewport = self.getObj(activeSubscene).par3d.viewport, width = viewport.width*self.canvas.width, height = viewport.height*self.canvas.height, r = Math.min(width, height)/2, dx = self.clamp(x - width/2, -r, r), dy = self.clamp(y - height/2, -r, r); return [Math.asin(dx/r), Math.asin(-dy/r)]; }; handlers.polardown = function(x,y) { var activeSub = self.getObj(activeSubscene), activeModel = self.getObj(self.useid(activeSub.id, "model")), i, l = activeModel.par3d.listeners; handlers.dragBase = self.screenToPolar(x, y); self.saveMat = []; for (i = 0; i < l.length; i++) { activeSub = self.getObj(l[i]); activeSub.saveMat = new CanvasMatrix4(activeSub.par3d.userMatrix); activeSub.camBase = [-Math.atan2(activeSub.saveMat.m13, activeSub.saveMat.m11), Math.atan2(activeSub.saveMat.m32, activeSub.saveMat.m22)]; } self.canvas.style.cursor = "grabbing"; }; handlers.polarmove = function(x,y) { var dragCurrent = self.screenToPolar(x,y), activeSub = self.getObj(activeSubscene), activeModel = self.getObj(self.useid(activeSub.id, "model")), objects = self.scene.objects, l = activeModel.par3d.listeners, i, j, changepos = []; for (i = 0; i < l.length; i++) { activeSub = self.getObj(l[i]); for (j=0; j<2; j++) changepos[j] = -(dragCurrent[j] - handlers.dragBase[j]); activeSub.par3d.userMatrix.makeIdentity(); activeSub.par3d.userMatrix.rotate(changepos[0]*180/Math.PI, 0,-1,0); activeSub.par3d.userMatrix.multRight(objects[l[i]].saveMat); activeSub.par3d.userMatrix.rotate(changepos[1]*180/Math.PI, -1,0,0); } self.drawScene(); }; handlers.polarend = 0; handlers.axisdown = function(x) { handlers.rotBase = self.screenToVector(x, self.canvas.height/2); var activeSub = self.getObj(activeSubscene), activeModel = self.getObj(self.useid(activeSub.id, "model")), i, l = activeModel.par3d.listeners; for (i = 0; i < l.length; i++) { activeSub = self.getObj(l[i]); activeSub.saveMat = new CanvasMatrix4(activeSub.par3d.userMatrix); } self.canvas.style.cursor = "grabbing"; }; handlers.axismove = function(x) { var rotCurrent = self.screenToVector(x, self.canvas.height/2), rotBase = handlers.rotBase, angle = (rotCurrent[0] - rotBase[0])*180/Math.PI, rotMat = new CanvasMatrix4(); rotMat.rotate(angle, handlers.axis[0], handlers.axis[1], handlers.axis[2]); var activeSub = self.getObj(activeSubscene), activeModel = self.getObj(self.useid(activeSub.id, "model")), i, l = activeModel.par3d.listeners; for (i = 0; i < l.length; i++) { activeSub = self.getObj(l[i]); activeSub.par3d.userMatrix.load(activeSub.saveMat); activeSub.par3d.userMatrix.multLeft(rotMat); } self.drawScene(); }; handlers.axisend = 0; handlers.y0zoom = 0; handlers.zoomdown = function(x, y) { var activeSub = self.getObj(activeSubscene), activeProjection = self.getObj(self.useid(activeSub.id, "projection")), i, l = activeProjection.par3d.listeners; handlers.y0zoom = y; for (i = 0; i < l.length; i++) { activeSub = self.getObj(l[i]); activeSub.zoom0 = Math.log(activeSub.par3d.zoom); } self.canvas.style.cursor = "zoom-in"; }; handlers.zoommove = function(x, y) { var activeSub = self.getObj(activeSubscene), activeProjection = self.getObj(self.useid(activeSub.id, "projection")), i, l = activeProjection.par3d.listeners; for (i = 0; i < l.length; i++) { activeSub = self.getObj(l[i]); activeSub.par3d.zoom = Math.exp(activeSub.zoom0 + (y-handlers.y0zoom)/self.canvas.height); } self.drawScene(); }; handlers.zoomend = 0; handlers.y0fov = 0; handlers.fovdown = function(x, y) { handlers.y0fov = y; var activeSub = self.getObj(activeSubscene), activeProjection = self.getObj(self.useid(activeSub.id, "projection")), i, l = activeProjection.par3d.listeners; for (i = 0; i < l.length; i++) { activeSub = self.getObj(l[i]); activeSub.fov0 = activeSub.par3d.FOV; } self.canvas.style.cursor = "zoom-in"; }; handlers.fovmove = function(x, y) { var activeSub = self.getObj(activeSubscene), activeProjection = self.getObj(self.useid(activeSub.id, "projection")), i, l = activeProjection.par3d.listeners; for (i = 0; i < l.length; i++) { activeSub = self.getObj(l[i]); activeSub.par3d.FOV = Math.max(1, Math.min(179, activeSub.fov0 + 180*(y-handlers.y0fov)/self.canvas.height)); } self.drawScene(); }; handlers.fovend = 0; handlers.selectingdown = function(x, y) { var viewport = self.getObj(activeSubscene).par3d.viewport, width = viewport.width*self.canvas.width, height = viewport.height*self.canvas.height, p = {x: 2.0*x/width - 1.0, y: 2.0*y/height - 1.0}; self.select.region = {p1: p, p2: p}; if (self.select.subscene && self.select.subscene !== activeSubscene) self.delFromSubscene(self.scene.brushId, self.select.subscene); self.select.subscene = activeSubscene; self.addToSubscene(self.scene.brushId, activeSubscene); self.select.state = "changing"; if (typeof self.scene.brushId !== "undefined") self.getObj(self.scene.brushId).initialized = false; if (typeof self.scene.selectionInput !== "undefined") self.recordSelection(activeSubscene); self.drawScene(); self.canvas.style.cursor = "crosshair"; }; handlers.selectingmove = function(x, y) { var viewport = self.getObj(activeSubscene).par3d.viewport, width = viewport.width*self.canvas.width, height = viewport.height*self.canvas.height; if (self.select.state === "inactive") return; self.select.region.p2 = {x: 2.0*x/width - 1.0, y: 2.0*y/height - 1.0}; if (typeof self.scene.brushId !== "undefined") self.getObj(self.scene.brushId).initialized = false; if (typeof self.scene.selectionInput !== "undefined") self.recordSelection(activeSubscene); self.drawScene(); }; handlers.selectingend = 0; /* jshint evil:true */ handlers.userdown = function(x, y) { var sub = self.getObj(activeSubscene), code = sub.callbacks[drag].begin; if (code) { var fn = Function('"use strict";return (' + code + ')')(); fn.call(self, x, y); } }; handlers.usermove = function(x, y) { var sub = self.getObj(activeSubscene), code = sub.callbacks[drag].update; if (code) { var fn = Function('"use strict";return (' + code + ')')(); fn.call(self, x, y); } }; handlers.userend = function() { var sub = self.getObj(activeSubscene), code = sub.callbacks[drag].end; if (code) { var fn = Function('"use strict";return (' + code + ')')(); fn.call(self); } }; self.canvas.onpointerdown = function ( ev ){ // pointers and mice differ in capture rules; // act like a mouse. if (ev.target.hasPointerCapture(ev.pointerId)) ev.target.releasePointerCapture(ev.pointerId); if (!ev.which) // Use w3c defns in preference to MS switch (ev.button) { case 0: ev.which = 1; break; case 1: case 4: ev.which = 2; break; case 2: ev.which = 3; } drag = ["none", "left", "middle", "right", "wheel"][ev.which]; var coords = self.relMouseCoords(ev); coords.y = self.canvas.height-coords.y; activeSubscene = self.whichSubscene(coords); var sub = self.getObj(activeSubscene), f; handler = sub.par3d.mouseMode[drag]; switch (handler) { case "xAxis": handler = "axis"; handlers.axis = [1.0, 0.0, 0.0]; break; case "yAxis": handler = "axis"; handlers.axis = [0.0, 1.0, 0.0]; break; case "zAxis": handler = "axis"; handlers.axis = [0.0, 0.0, 1.0]; break; } f = handlers[handler + "down"]; if (f) { coords = self.translateCoords(activeSubscene, coords); f.call(self, coords.x, coords.y); ev.preventDefault(); } else console.warn("Mouse handler '" + handler + "' is not implemented."); }; self.canvas.onpointerup = function ( ev ){ if ( !drag ) return; var f = handlers[handler + "end"]; if (f) { f.call(self); ev.preventDefault(); } drag = 0; handlers.onpointermove( ev ); }; self.canvas.onpointerout = self.canvas.onpointerup; handlers.onpointermove = function ( ev ) { var coords = self.relMouseCoords(ev), sub, f; coords.y = self.canvas.height - coords.y; if (ev.buttons === 0) { activeSubscene = self.whichSubscene(coords); drag = "none"; sub = self.getObj(activeSubscene); handler = sub.par3d.mouseMode.none; if (handler !== "none") { if (sub.needsBegin) { f = handlers[handler + "down"]; if (f) { coords = self.translateCoords(activeSubscene, coords); f.call(self, coords.x, coords.y); } sub.needsBegin = 0; } self.canvas.style.cursor = self.getCursor(sub.par3d.mouseMode.none); } else { self.canvas.style.cursor = self.getCursor(sub.par3d.mouseMode.left); return; } } f = handlers[handler + "move"]; if (f) { coords = self.translateCoords(activeSubscene, coords); f.call(self, coords.x, coords.y); } }; self.canvas.onpointerenter = function() { self.canvas.addEventListener("pointermove", handlers.onpointermove); }; self.canvas.onpointerleave = function() { self.canvas.removeEventListener("pointermove", handlers.onpointermove); }; handlers.setZoom = function(ds) { var i; if (typeof activeSubscene === "undefined") activeSubscene = self.scene.rootSubscene; var activeSub = self.getObj(activeSubscene), activeProjection = self.getObj(self.useid(activeSub.id, "projection")), l = activeProjection.par3d.listeners; for (i = 0; i < l.length; i++) { activeSub = self.getObj(l[i]); activeSub.par3d.zoom *= ds; } self.drawScene(); }; handlers.pushwheel = function(ev) { ev.deltaY = -ev.deltaY; handlers.pullwheel(ev); }; handlers.pullwheel = function(ev) { var del = 1.05; if (ev.shiftKey) del = 1.005; var ds = ev.deltaY < 0 ? del : (1 / del); handlers.setZoom(ds); }; handlers.user2wheel = function(ev) { var sub = self.getObj(activeSubscene), code = sub.callbacks.wheel.rotate; if (code) { var fn = Function('"use strict";return (' + code + ')')(); /* jshint evil:false */ fn.call(self, ev.deltaY < 0 ? 1 : 2); } }; handlers.wheelHandler = function(ev) { var coords = self.relMouseCoords(ev); coords.y = self.canvas.height - coords.y; activeSubscene = self.whichSubscene(coords); var sub = self.getObj(activeSubscene), f, handler = sub.par3d.mouseMode.wheel, evlocal; ev.deltaY = ev.deltaY || ev.detail || ev.deltaX || ev.wheelDelta; switch(handler) { case "none": break; case "push": case "pull": case "user2": f = handlers[handler + "wheel"]; if (f) { evlocal = {}; evlocal.deltaY = ev.deltaY; evlocal.shiftKey = ev.shiftKey; evlocal.preventDefault = function() { ev.preventDefault(); }; f.call(self, evlocal); } break; default: evlocal = {}; evlocal.preventDefault = function() { ev.preventDefault(); }; evlocal.which = 4; evlocal.clientX = self.canvas.width/2; evlocal.clientY = self.canvas.height/2; self.canvas.onpointerdown(evlocal); evlocal.clientX += ev.deltaX; evlocal.clientY += ev.deltaY; handlers.onpointermove(evlocal); self.canvas.onpointerup(evlocal); } ev.preventDefault(); }; handlers.get_finger_dist = function(ev) { var diffX = ev.touches[0].clientX - ev.touches[1].clientX, diffY = ev.touches[0].clientY - ev.touches[1].clientY; return Math.sqrt(diffX * diffX + diffY * diffY); }; handlers.touchstart = function(ev) { var touch = ev.touches[0], mouseEvent = new MouseEvent("pointerdown", { clientX: touch.clientX, clientY: touch.clientY }); ev.preventDefault(); if (ev.touches.length === 2) { var coords = self.relMouseCoords(touch); coords.y = self.canvas.height-coords.y; activeSubscene = self.whichSubscene(coords); handlers.finger_dist0 = handlers.get_finger_dist(ev); handlers.zoomdown(coords.x, coords.y); } self.dispatchEvent(mouseEvent); }; handlers.touchend = function(ev) { var mouseEvent; ev.preventDefault(); if (ev.touches.length === 1) { mouseEvent = new MouseEvent("pointerup", {}); self.dispatchEvent(mouseEvent); } }; handlers.touchmove = function(ev) { var touch = ev.touches[0], mouseEvent; ev.preventDefault(); if (ev.touches.length > 1) { var coords = self.relMouseCoords(touch), new_dist = handlers.get_finger_dist(ev); coords.y = self.canvas.height*Math.log(handlers.finger_dist0/new_dist) + handlers.y0zoom; handlers.zoommove(coords.x, coords.y); } else { mouseEvent = new MouseEvent("pointermove", { clientX: touch.clientX, clientY: touch.clientY }); self.dispatchEvent(mouseEvent); } }; self.canvas.addEventListener("DOMMouseScroll", handlers.wheelHandler, false); self.canvas.addEventListener("mousewheel", handlers.wheelHandler, false); self.canvas.addEventListener("touchstart", handlers.touchstart, {passive: false}); self.canvas.addEventListener("touchend", handlers.touchend, {passive: false}); self.canvas.addEventListener("touchmove", handlers.touchmove, {passive: false}); }; rgl/inst/htmlwidgets/lib/rglClass/selection.src.js0000644000176200001440000001062114771520323022003 0ustar liggesusers /** * Methods related to selection * @name ___METHODS_FOR_SELECTION___ * @memberof rglwidgetClass * @kind function * @instance */ /** * Respond to brush change */ rglwidgetClass.prototype.selectionChanged = function() { var i, j, k, id, subid = this.select.subscene, subscene, objids, obj, p1 = this.select.region.p1, p2 = this.select.region.p2, filter, selection = [], handle, keys, xmin, x, xmax, ymin, y, ymax, z, v, someHidden; if (!subid) return; subscene = this.getObj(subid); objids = subscene.objects; filter = this.scene.crosstalk.filter; this.setmvMatrix(subid); this.setprMatrix(subid); this.setprmvMatrix(); xmin = Math.min(p1.x, p2.x); xmax = Math.max(p1.x, p2.x); ymin = Math.min(p1.y, p2.y); ymax = Math.max(p1.y, p2.y); for (i = 0; i < objids.length; i++) { id = objids[i]; j = this.scene.crosstalk.id.indexOf(id); if (j >= 0) { keys = this.scene.crosstalk.key[j]; obj = this.getObj(id); someHidden = false; for (k = 0; k < keys.length; k++) { if (filter && filter.indexOf(keys[k]) < 0) { someHidden = true; continue; } v = [].concat(obj.vertices[k]).concat(1.0); v = rglwidgetClass.multVM(v, this.prmvMatrix); x = v[0]/v[3]; y = v[1]/v[3]; z = v[2]/v[3]; if (xmin <= x && x <= xmax && ymin <= y && y <= ymax && -1.0 <= z && z <= 1.0) { selection.push(keys[k]); } else someHidden = true; } obj.someHidden = someHidden && (filter || selection.length); obj.initialized = false; /* Who should we notify? Only shared data in the current subscene, or everyone? */ if (!this.equalArrays(selection, this.scene.crosstalk.selection)) { handle = this.scene.crosstalk.sel_handle[j]; handle.set(selection, {rglSubsceneId: this.select.subscene}); } } } }; /** * Respond to selection or filter change from crosstalk * @param { Object } event - crosstalk event * @param { boolean } filter - filter or selection? */ rglwidgetClass.prototype.selection = function(event, filter) { var i, j, ids, obj, keys, crosstalk = this.scene.crosstalk, selection, someHidden; // Record the message and find out if this event makes some objects have mixed values: crosstalk = this.scene.crosstalk; if (filter) { filter = crosstalk.filter = event.value; selection = crosstalk.selection; } else { selection = crosstalk.selection = event.value; filter = crosstalk.filter; } ids = crosstalk.id; for (i = 0; i < ids.length ; i++) { obj = this.getObj(ids[i]); obj.initialized = false; keys = crosstalk.key[i]; someHidden = false; for (j = 0; j < keys.length && !someHidden; j++) { if ((filter && filter.indexOf(keys[j]) < 0) || (selection.length && selection.indexOf(keys[j]) < 0)) someHidden = true; } obj.someHidden = someHidden; } this.drawScene(); }; /** * Clear the selection brush * @param { number } except - Subscene that should ignore this request */ rglwidgetClass.prototype.clearBrush = function(except) { if (this.select.subscene !== except) { this.select.region = {p1: {x:Infinity, y:Infinity}, p2: {x:Infinity, y:Infinity}}; this.selectionChanged(); this.select.state = "inactive"; this.delFromSubscene(this.scene.brushId, this.select.subscene); } this.drawScene(); }; /** * Set the vertices in the selection box object */ rglwidgetClass.prototype.initSelection = function(id) { if (typeof this.select.region === "undefined") return; var obj = this.getObj(id), p1 = this.select.region.p1, p2 = this.select.region.p2; obj.vertices = [[p1.x, p1.y, 0.0], [p2.x, p1.y, 0.0], [p2.x, p2.y, 0.0], [p1.x, p2.y, 0.0], [p1.x, p1.y, 0.0]]; }; rgl/inst/htmlwidgets/lib/rglClass/axes.src.js0000644000176200001440000003572115011677075020773 0ustar liggesusers /** * Methods related to axes * @name ___METHODS_FOR_AXES___ * @memberof rglwidgetClass * @kind function * @instance */ /** * Choose edges for ticks * @param { Matrix } prmv - projection-model-view matrix */ rglwidgetClass.prototype.getTickEdges = function(prmv){ var vertices = [[0,0,0,1], [0,0,1,1], [0,1,0,1], [0,1,1,1], [1,0,0,1], [1,0,1,1], [1,1,0,1], [1,1,1,1]], dim, i, j, k, edges, hull, step, result = [], proj = [], // Filter to edges that are on sides that would // be shown with a filled backing. has_back = function(edge) { var normals = [[], []], verts = [vertices[edge[0]], vertices[edge[1]]], normal, m, n; n = 0; for (m=0; m<3; m++) { if (verts[0][m] === verts[1][m]) { normals[n] = [0,0,0,1]; normals[n][m] = 2*verts[0][m] - 1; n++; } } for (n=0; n<2; n++) { normal = rglwidgetClass.multVM(normals[n], self.normMatrix); if (normal[2] < 0 || (normal[2] === 0 && normal[0] < 0)) return true; } return false; }, self = this; for (i = 0; i < vertices.length; i++) { proj[i] = rglwidgetClass.multVM(vertices[i], prmv); proj[i][0] = proj[i][0]/proj[i][3]; proj[i][1] = proj[i][1]/proj[i][3]; proj[i][2] = i; } hull = rglwidgetClass.chull(proj.slice()); for (i = 0; i < hull.length; i++) hull[i] = hull[i][2]; hull.push(hull[0]); for (dim = 0; dim < 3; dim++) { edges = []; step = Math.pow(2, 2-dim); for (i = 0; i < 4; i++) { j = (dim === 0) ? i : (dim === 1) ? i + 2*(i>1) : 2*i; for (k = 0; k < hull.length - 1; k++) { if ((hull[k] === j && hull[k+1] === j + step) || (hull[k] === j+step && hull[k+1] === j)) edges.push([j, j+step], [j+step, j]); } } edges = edges.filter(has_back); // Find the edge with a vertex closest // to the bottom left corner if (edges.length) { var best, best2, val = Infinity, newval; for (i = 0; i < edges.length; i++) { j = edges[i][0]; newval = proj[j][0] + proj[j][1]; if (newval < val) { best = j; best2 = edges[i][1]; val = newval; } } if (typeof best !== "undefined") { result[dim] = vertices[best].slice(0,3); result[dim][dim] = undefined; } else result[dim] = undefined; } } return result; }; /** * Choose tick locations * @param { Object } obj - The bboxdeco */ rglwidgetClass.prototype.getTickLocations = function(obj){ var dim, i, limits, locations = [], result = [[],[],[]], value, len, delta, range, bbox = obj.bbox; obj.needsAxisCallback = false; for (dim = 0; dim < 3; dim++) { limits = bbox.slice(2*dim, 2*dim + 2); range = limits[1] - limits[0]; switch(obj.axes.mode[dim]) { case "custom": for (i=0; i < obj.vertices.length; i++) { value = (obj.vertices[i][dim] - limits[0])/range; if (typeof value !== "undefined" && !isNaN(value)) result[dim].push(value); } break; case "fixedstep": len = Math.floor(range/obj.axes.step[dim]); delta = obj.axes.step[dim]; for (i = 0; i < len; i++) result[dim].push(i*delta); break; case "fixednum": len = obj.axes.nticks[dim]; delta = (len > 1) ? range/(len-1) : 0; for (i = 0; i < len; i++) result[dim].push(i*delta/range); break; case "pretty": locations = this.R_pretty(limits[0], limits[1], obj.axes.nticks[dim], 3, // min_n 0.75, // shrink_sml [1.5, 2.75], // high_u_fact 0, // eps_correction 0); // return_bounds) for (i = locations.lo; i <= locations.up; i++) { value = (i*locations.unit - limits[0])/range; if (0 < value && value < 1) result[dim].push(value); } break; case "user": obj.needsAxisCallback = true; break; } } return result; }; /** * Set tick vertices * @param { Object } ticks - the tick object * @param { Array } edges - Which edges get the ticks? */ rglwidgetClass.prototype.getTickVertices = function(ticks) { var dim, i, j, vertices = [], locations, edges = ticks.edges, edge; for (dim = 0; dim < 3; dim++) { locations = ticks.locations[dim]; if (locations.length) for (i = 0; i < locations.length; i++) if (typeof edges[dim] !== "undefined") { edge = edges[dim].slice(); edge[dim] = locations[i]; vertices.push(edge); edge = edge.slice(); for (j = 0; j < 3; j++) if ((dim < 2 && j === 1 - dim) || (dim === 2 && j === 0)) edge[j] += 2*(edge[j] - 0.5)/ticks.axes.marklen[dim]; vertices.push(edge); } } ticks.vertices = vertices; ticks.vertexCount = vertices.length; ticks.values = new Float32Array(rglwidgetClass.flatten(vertices)); ticks.initialized = false; }; /** * Set tick label positions * @param { Object } obj - the bbox object */ rglwidgetClass.prototype.placeTickLabels = function(obj) { var ticks = obj.ticks, labels = obj.labels, i,j,k, vertices = [], tickvertices = ticks.vertices, vertex, locations, dim, edges = obj.ticks.edges; j = 0; for (dim = 0; dim < 3; dim++) { if (typeof edges[dim] === "undefined") continue; locations = ticks.locations[dim]; if (locations.length) for (i = 0; i < locations.length; i++) { if (isNaN(locations[i])) continue; while (j < tickvertices.length && tickvertices[j][dim] !== locations[i]) j++; if (j >= tickvertices.length) break; vertex = tickvertices[j].slice(); for (k = 0; k < 3; k++) vertex[k] += 2*(tickvertices[j+1][k] - vertex[k]); vertices.push(vertex); j += 2; } } labels.vertices = vertices; labels.centers = labels.vertices; labels.initialized = false; }; /** * Set tick labels * @param { Object } obj - the bbox object */ rglwidgetClass.prototype.setTickLabels = function(obj) { var ticks = obj.ticks, mode, locations, labels = [], start = 0, nticks, dim, i, limits, range, values, max, edges = obj.ticks.edges; for (dim = 0; dim < 3; dim++) { if (typeof edges[dim] === "undefined") continue; mode = obj.axes.mode[dim]; nticks = obj.axes.nticks[dim]; // used on input only for custom! if (mode === "custom") labels = labels.concat(obj.texts.slice(start, start + nticks)); else { limits = obj.bbox.slice(2*dim, 2*(dim+1)); range = limits[1] - limits[0]; locations = ticks.locations[dim]; max = -Infinity; values = []; for (i = 0; i < locations.length; i++) { values.push(limits[0] + range*locations[i]); max = Math.max(max, Math.abs(values[i])); } for (i = 0; i < locations.length; i++) { if (Math.abs(values[i])/max < Math.pow(10, -5)) values[i] = 0; labels.push(rglwidgetClass.signif(values[i], 4).toString()); } obj.axes.nticks[dim] = locations.length; } start += nticks; } obj.labels.texts = labels; }; /** * Set bboxdeco bbox and center vector * @param { Object } obj - the bbox object */ rglwidgetClass.prototype.setBbox = function(obj, subscene) { var i, expand, center = [], bbox; if (!obj.initialized) this.initBBox(obj); bbox = [].concat(subscene.par3d.bbox); for (i = 0; i < 3; i++) { expand = obj.axes.expand[i]; center[i] = (bbox[2*i] + bbox[2*i + 1])/2; bbox[2*i] = center[i] - expand*(bbox[2*i + 1] - center[i]); bbox[2*i+1] = center[i] + expand*(bbox[2*i + 1] - center[i]); } obj.bbox = bbox; obj.center = center; }; rglwidgetClass.prototype.setBBoxMatrices = function(obj) { var saved = {normMatrix: new CanvasMatrix4(this.normMatrix), mvMatrix: new CanvasMatrix4(this.mvMatrix)}, bboxNorm, bboxMV, bbox = obj.bbox, scale; bboxNorm = new CanvasMatrix4(); scale = [bbox[1]-bbox[0], bbox[3]-bbox[2], bbox[5]-bbox[4]]; bboxNorm.scale(1/scale[0], 1/scale[1], 1/scale[2]); bboxNorm.multRight(saved.normMatrix); this.normMatrix = bboxNorm; bboxMV = new CanvasMatrix4(); bboxMV.scale(scale[0], scale[1], scale[2]); bboxMV.translate(bbox[0], bbox[2], bbox[4]); bboxMV.multRight(saved.mvMatrix); this.mvMatrix = obj.mvMatrix = bboxMV; if (this.prmvMatrix === null) saved.prmvMatrix = null; else saved.prmvMatrix = new CanvasMatrix4(this.prmvMatrix); this.setprmvMatrix(); obj.prmvMatrix = this.prmvMatrix; return saved; }; rglwidgetClass.prototype.restoreBBoxMatrices = function(saved) { this.normMatrix = saved.normMatrix; this.mvMatrix = saved.mvMatrix; this.prmvMatrix = saved.prmvMatrix; }; rglwidgetClass.prototype.getMarginParameters = function(bboxdeco, material) { // Assume we've run this.setBbox(bboxdeco, subscene); var bbox = bboxdeco.bbox, edge = [].concat(material.edge), saved, edges, i, at = material.margin, line, level, trans, scale; if (material.floating) { saved = this.setBBoxMatrices(bboxdeco); edges = this.getTickEdges(this.prmvMatrix)[at]; this.restoreBBoxMatrices(saved); if (typeof edges !== "undefined") for (i = 0; i < 3; i++) { if (edges[i] < 1) edges[i] = -1; edge[i] = edge[i]*edges[i]; } else return undefined; } switch(at) { case 0: line = 1; level = 2; break; case 1: line = 0; level = 2; break; case 2: line = 0; level = 1; break; } scale = [edge[0]*(bbox[1]-bbox[0])/bboxdeco.axes.marklen[0], edge[1]*(bbox[3]-bbox[2])/bboxdeco.axes.marklen[1], edge[2]*(bbox[5]-bbox[4])/bboxdeco.axes.marklen[2]]; trans = [edge[0] === 1 ? bbox[1] : bbox[0], edge[1] === 1 ? bbox[3] : bbox[2], edge[2] === 1 ? bbox[5] : bbox[4]]; return {at: at, line: line, level: level, trans: trans, scale: scale}; }; rglwidgetClass.prototype.fixVertex = function(orig, parms, center, bbox) { var vertex = [0,0,0]; if (rglwidgetClass.missing(orig[0])) vertex[parms.at] = center[parms.at]; else if (orig[0] === "-Inf") vertex[parms.at] = bbox[2*parms.at]; else if (orig[0] === "Inf") vertex[parms.at] = bbox[2*parms.at + 1]; else vertex[parms.at] = orig[0]; vertex[parms.line] = parms.scale[parms.line]*orig[1] + parms.trans[parms.line]; vertex[parms.level] = parms.scale[parms.level]*orig[2] + parms.trans[parms.level]; return vertex; }; rglwidgetClass.prototype.fixNormal = function(orig, parms) { var vertex = [0,0,0]; vertex[parms.at] = orig[0]; vertex[parms.line] = orig[1]/parms.scale[parms.line]; vertex[parms.level] = orig[2]/parms.scale[parms.level]; return vertex; }; rglwidgetClass.prototype.marginVecToDataVec = function(obj, subscene) { var bboxdeco = this.getBBoxDeco(subscene), center, bbox, parms, parmsjson, orig = obj.orig, vertices = [], normals = [], centers = [], i, vertex; if (typeof orig === "undefined") { orig = {vert: obj.vertices, norm: obj.normals, cent: obj.centers, doNormals: typeof obj.normals !== "undefined", doCenters: typeof obj.centers !== "undefined", parms: "" }; obj.orig = orig; } if (typeof bboxdeco !== "undefined") { this.setBbox(bboxdeco, subscene); center = bboxdeco.center; bbox = bboxdeco.bbox; parms = this.getMarginParameters(bboxdeco, obj.material); if (typeof parms === "undefined") return false; /* axis is not currently shown */ parmsjson = JSON.stringify(parms); if (parmsjson === orig.parms) return true; /* nothing has changed */ orig.parms = parmsjson; for (i=0; i < orig.vert.length; i++) { vertex = this.fixVertex(orig.vert[i], parms, center, bbox); vertices.push(vertex); } obj.vertices = vertices; if (orig.doNormals) { for (i=0; i < orig.norm.length; i++) { vertex = this.fixNormal(orig.norm[i], parms); normals.push(vertex); } obj.normals = normals; } if (orig.doCenters) { for (i=0; i < orig.cent.length; i++) { vertex = this.fixVertex(orig.cent[i], parms, center, bbox); centers.push(vertex); } obj.centers = centers; } obj.initialized = false; return true; } else { console.warn("bboxdeco not found"); return false; } }; rglwidgetClass.prototype.doAxisCallback = function(obj, edges) { var i, j, code, axis, fn; for (i = 0; i < 3; i++) { if (obj.axes.mode[i] === "user") { axis = ["x", "y", "z"][i]; if (typeof obj.callbacks !== "undefined" && typeof (code = obj.callbacks[axis]) !== "undefined") { if (typeof edges[i] !== "undefined") for (j = 0; j < 3; j++) if (typeof edges[i][j] !== "undefined") axis = axis + (edges[i][j] > 0 ? "+" : "-"); /* jshint evil:true */ fn = Function('"use strict";return (' + code + ')')(); /* jshint evil:false */ fn.call(this, axis); } } } }; rgl/inst/htmlwidgets/lib/rglClass/buffer.src.js0000644000176200001440000001325614771520323021276 0ustar liggesusers/** * Methods related to buffered data * @name ___METHODS_FOR_BUFFERS___ * @memberof rglwidgetClass * @kind function * @instance */ /** * Detect rglBuffered object * @param { Object } obj - vertices or similar */ rglwidgetClass.prototype.isBuffered = function(obj) { return typeof obj === "string"; }; /* The next two functions are taken from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding They were written by Mozilla Contributors and dedicated to the public domain under CC0. */ /* Array of bytes to Base64 string decoding */ rglwidgetClass.prototype.b64ToUint6 = function(nChr) { return nChr > 64 && nChr < 91 ? nChr - 65 : nChr > 96 && nChr < 123 ? nChr - 71 : nChr > 47 && nChr < 58 ? nChr + 4 : nChr === 43 ? 62 : nChr === 47 ? 63 : 0; }; /* jshint bitwise:false */ rglwidgetClass.prototype.base64DecToArr = function(sBase64, nBlocksSize) { var sB64Enc = sBase64.replace(/[^A-Za-z0-9\+\/]/g, ""), nInLen = sB64Enc.length, nOutLen = nBlocksSize ? Math.ceil((nInLen * 3 + 1 >> 2) / nBlocksSize) * nBlocksSize : nInLen * 3 + 1 >> 2, taBytes = new Uint8Array(nOutLen); for (var nMod3, nMod4, nUint24 = 0, nOutIdx = 0, nInIdx = 0; nInIdx < nInLen; nInIdx++) { nMod4 = nInIdx & 3; nUint24 |= this.b64ToUint6(sB64Enc.charCodeAt(nInIdx)) << 6 * (3 - nMod4); if (nMod4 === 3 || nInLen - nInIdx === 1) { for (nMod3 = 0; nMod3 < 3 && nOutIdx < nOutLen; nMod3++, nOutIdx++) { taBytes[nOutIdx] = nUint24 >>> (16 >>> nMod3 & 24) & 255; } nUint24 = 0; } } return taBytes; }; /* jshint bitwise:true */ rglwidgetClass.prototype.getArrayBuffer = function(base64) { return this.base64DecToArr(base64, 4).buffer; }; rglwidgetClass.prototype.getBufferedData = function(v) { return this.readAccessor(parseInt(v, 10), this.scene.buffer); }; rglwidgetClass.prototype.readAccessor = function(acc, buf) { var typeSignedByte = 5120, typeUnsignedByte = 5121, typeSignedShort = 5122, typeUnsignedShort = 5123, typeSignedInt = 5124, typeUnsignedInt = 5125, typeFloat = 5126, typeDouble = 5130, accessor = buf.accessors[acc], bufferView = buf.bufferViews[accessor.bufferView], buffer = buf.buffers[bufferView.buffer], bytes, lens = { SCALAR: 1, VEC2: 2, VEC3: 3, VEC4: 4, MAT2: 4, MAT3: 9, MAT4: 16 }, rowsizes = { SCALAR: 1, VEC2: 2, VEC3: 3, VEC4: 4, MAT2: 2, MAT3: 3, MAT4: 4 }, offset = 0, len = lens[accessor.type], rowsize = rowsizes[accessor.type], count = len * accessor.count, nrows = count / rowsize, values, arr = [], row, i, j, k; if (typeof buffer.bytes === "string") buffer.bytes = this.getArrayBuffer(buffer.bytes); bytes = buffer.bytes; if (typeof accessor.byteOffset !== "undefined") offset += accessor.byteOffset; if (typeof bufferView.byteOffset !== "undefined") offset += bufferView.byteOffset; switch (accessor.componentType) { case typeSignedByte: values = new Int8Array(buffer.bytes, offset, count); break; case typeUnsignedByte: values = new Uint8Array(buffer.bytes, offset, count); break; case typeSignedShort: values = new Int16Array(buffer.bytes, offset, count); break; case typeUnsignedShort: values = new Uint16Array(buffer.bytes, offset, count); break; case typeSignedInt: values = new Int32Array(buffer.bytes, offset, count); break; case typeUnsignedInt: values = new Uint32Array(buffer.bytes, offset, count); break; case typeFloat: values = new Float32Array(buffer.bytes, offset, count); break; case typeDouble: values = new Float64Array(buffer.bytes, offset, count); break; } /* This is all very inefficient, but is convenient to work with the old code. */ k = 0; for (i = 0; i < nrows; i++) { row = []; for (j = 0; j < rowsize; j++) { if (accessor.normalized) { switch(accessor.componentType) { case typeSignedByte: row.push(Math.max(values[k++]/127, -1.0)); break; case typeSignedShort: row.push(Math.max(values[k++]/32767, -1.0)); break; case typeUnsignedByte: row.push(values[k++]/255); break; case typeUnsignedShort: row.push(values[k++]/65535); break; } } else row.push(values[k++]); } arr.push(row); } return arr; }; rglwidgetClass.prototype.expandBufferedFields = function(obj) { /* this list needs to match the one in convertScene.R */ var fields = ["vertices", "normals", "indices", "texcoords", "colors", "centers"], i, field; for (i = 0; i < fields.length; i++) { field = obj[fields[i]]; if (this.isBuffered(field)) obj[fields[i]] = this.getBufferedData(field); } }; rgl/inst/htmlwidgets/lib/rglClass/shadersrc.src.js0000644000176200001440000003226715026467234022013 0ustar liggesusersrglwidgetClass.rgl_vertex_shader = function() { return "#line 2 1\n"+ "// File 1 is the vertex shader\n"+ "#ifdef GL_ES\n"+ "#ifdef GL_FRAGMENT_PRECISION_HIGH\n"+ "precision highp float;\n"+ "#else\n"+ "precision mediump float;\n"+ "#endif\n"+ "#endif\n"+ "\n"+ "attribute vec3 aPos;\n"+ "attribute vec4 aCol;\n"+ "uniform mat4 mvMatrix;\n"+ "uniform mat4 prMatrix;\n"+ "varying vec4 vCol;\n"+ "varying vec4 vPosition;\n"+ "\n"+ "#ifdef NEEDS_VNORMAL\n"+ "attribute vec3 aNorm;\n"+ "uniform mat4 normMatrix;\n"+ "varying vec4 vNormal;\n"+ "#endif\n"+ "\n"+ "#if defined(HAS_TEXTURE) || defined (IS_TEXT)\n"+ "attribute vec2 aTexcoord;\n"+ "varying vec2 vTexcoord;\n"+ "#endif\n"+ "\n"+ "#ifdef FIXED_SIZE\n"+ "uniform vec3 textScale;\n"+ "#endif\n"+ "\n"+ "#ifdef FIXED_QUADS\n"+ "attribute vec3 aOfs;\n"+ "#endif\n"+ "\n"+ "#ifdef IS_TWOSIDED\n"+ "#ifdef HAS_NORMALS\n"+ "varying float normz;\n"+ "uniform mat4 invPrMatrix;\n"+ "#else\n"+ "attribute vec3 aPos1;\n"+ "attribute vec3 aPos2;\n"+ "varying float normz;\n"+ "#endif\n"+ "#endif // IS_TWOSIDED\n"+ "\n"+ "#ifdef FAT_LINES\n"+ "attribute vec3 aNext;\n"+ "attribute vec2 aPoint;\n"+ "varying vec2 vPoint;\n"+ "varying float vLength;\n"+ "uniform float uAspect;\n"+ "uniform float uLwd;\n"+ "#endif\n"+ "\n"+ "#ifdef USE_ENVMAP\n"+ "varying vec3 vReflection;\n"+ "#endif\n"+ "\n"+ "void main(void) {\n"+ " \n"+ "#ifndef IS_BRUSH\n"+ "#if defined(NCLIPPLANES) || !defined(FIXED_QUADS) || defined(HAS_FOG) || defined(USE_ENVMAP)\n"+ " vPosition = mvMatrix * vec4(aPos, 1.);\n"+ "#endif\n"+ " \n"+ "#ifndef FIXED_QUADS\n"+ " gl_Position = prMatrix * vPosition;\n"+ "#endif\n"+ "#endif // !IS_BRUSH\n"+ " \n"+ "#ifdef IS_POINTS\n"+ " gl_PointSize = POINTSIZE;\n"+ "#endif\n"+ " \n"+ " vCol = aCol;\n"+ " \n"+ "// USE_ENVMAP implies NEEDS_VNORMAL\n"+ "\n"+ "#ifdef NEEDS_VNORMAL\n"+ " vNormal = normMatrix * vec4(-aNorm, dot(aNorm, aPos));\n"+ "#endif\n"+ "\n"+ "#ifdef USE_ENVMAP\n"+ " vReflection = normalize(reflect(vPosition.xyz/vPosition.w, \n"+ " normalize(vNormal.xyz/vNormal.w)));\n"+ "#endif\n"+ " \n"+ "#ifdef IS_TWOSIDED\n"+ "#ifdef HAS_NORMALS\n"+ " /* normz should be calculated *after* projection */\n"+ " normz = (invPrMatrix*vNormal).z;\n"+ "#else\n"+ " vec4 pos1 = prMatrix*(mvMatrix*vec4(aPos1, 1.));\n"+ " pos1 = pos1/pos1.w - gl_Position/gl_Position.w;\n"+ " vec4 pos2 = prMatrix*(mvMatrix*vec4(aPos2, 1.));\n"+ " pos2 = pos2/pos2.w - gl_Position/gl_Position.w;\n"+ " normz = pos1.x*pos2.y - pos1.y*pos2.x;\n"+ "#endif\n"+ "#endif // IS_TWOSIDED\n"+ " \n"+ "#ifdef NEEDS_VNORMAL\n"+ " vNormal = vec4(normalize(vNormal.xyz), 1);\n"+ "#endif\n"+ " \n"+ "#if defined(HAS_TEXTURE) || defined(IS_TEXT)\n"+ " vTexcoord = aTexcoord;\n"+ "#endif\n"+ " \n"+ "#if defined(FIXED_SIZE) && !defined(ROTATING)\n"+ " vec4 pos = prMatrix * mvMatrix * vec4(aPos, 1.);\n"+ " pos = pos/pos.w;\n"+ " gl_Position = pos + vec4(aOfs*textScale, 0.);\n"+ "#endif\n"+ " \n"+ "#if defined(IS_SPRITES) && !defined(FIXED_SIZE)\n"+ " vec4 pos = mvMatrix * vec4(aPos, 1.);\n"+ " pos = pos/pos.w + vec4(aOfs, 0.);\n"+ " gl_Position = prMatrix*pos;\n"+ "#endif\n"+ " \n"+ "#ifdef FAT_LINES\n"+ " /* This code was inspired by Matt Deslauriers' code in \n"+ " https://mattdesl.svbtle.com/drawing-lines-is-hard */\n"+ " vec2 aspectVec = vec2(uAspect, 1.0);\n"+ " mat4 projViewModel = prMatrix * mvMatrix;\n"+ " vec4 currentProjected = projViewModel * vec4(aPos, 1.0);\n"+ " currentProjected = currentProjected/currentProjected.w;\n"+ " vec4 nextProjected = projViewModel * vec4(aNext, 1.0);\n"+ " vec2 currentScreen = currentProjected.xy * aspectVec;\n"+ " vec2 nextScreen = (nextProjected.xy / nextProjected.w) * aspectVec;\n"+ " float len = uLwd;\n"+ " vec2 dir = vec2(1.0, 0.0);\n"+ " vPoint = aPoint;\n"+ " vLength = length(nextScreen - currentScreen)/2.0;\n"+ " vLength = vLength/(vLength + len);\n"+ " if (vLength > 0.0) {\n"+ " dir = normalize(nextScreen - currentScreen);\n"+ " }\n"+ " vec2 normal = vec2(-dir.y, dir.x);\n"+ " dir.x /= uAspect;\n"+ " normal.x /= uAspect;\n"+ " vec4 offset = vec4(len*(normal*aPoint.x*aPoint.y - dir), 0.0, 0.0);\n"+ " gl_Position = currentProjected + offset;\n"+ "#endif\n"+ " \n"+ "#ifdef IS_BRUSH\n"+ " gl_Position = vec4(aPos, 1.);\n"+ "#endif\n"+ "}\n" ;}; rglwidgetClass.rgl_fragment_shader = function() { return "#line 2 2\n"+ "// File 2 is the fragment shader\n"+ "#ifdef GL_ES\n"+ "#ifdef GL_FRAGMENT_PRECISION_HIGH\n"+ "precision highp float;\n"+ "#else\n"+ "precision mediump float;\n"+ "#endif\n"+ "#endif\n"+ "varying vec4 vCol; // carries alpha\n"+ "varying vec4 vPosition;\n"+ "#if defined(HAS_TEXTURE) || defined (IS_TEXT)\n"+ "varying vec2 vTexcoord;\n"+ "uniform sampler2D uSampler;\n"+ "#endif\n"+ "\n"+ "#ifdef HAS_FOG\n"+ "uniform int uFogMode;\n"+ "uniform vec3 uFogColor;\n"+ "uniform vec4 uFogParms;\n"+ "#endif\n"+ "\n"+ "#if defined(IS_LIT) && !defined(FIXED_QUADS)\n"+ "varying vec4 vNormal;\n"+ "#endif\n"+ "\n"+ "#if NCLIPPLANES > 0\n"+ "uniform vec4 vClipplane[NCLIPPLANES];\n"+ "#endif\n"+ "\n"+ "#if NLIGHTS > 0\n"+ "uniform mat4 mvMatrix;\n"+ "#endif\n"+ "\n"+ "#ifdef IS_LIT\n"+ "uniform vec3 emission;\n"+ "uniform float shininess;\n"+ "#if NLIGHTS > 0\n"+ "uniform vec3 ambient[NLIGHTS];\n"+ "uniform vec3 specular[NLIGHTS]; // light*material\n"+ "uniform vec3 diffuse[NLIGHTS];\n"+ "uniform vec3 lightDir[NLIGHTS];\n"+ "uniform bool viewpoint[NLIGHTS];\n"+ "uniform bool finite[NLIGHTS];\n"+ "#endif\n"+ "#endif // IS_LIT\n"+ "\n"+ "#ifdef IS_TWOSIDED\n"+ "uniform bool front;\n"+ "varying float normz;\n"+ "#endif\n"+ "\n"+ "#ifdef FAT_LINES\n"+ "varying vec2 vPoint;\n"+ "varying float vLength;\n"+ "#endif\n"+ "\n"+ "#ifdef USE_ENVMAP\n"+ "varying vec3 vReflection;\n"+ "#endif\n"+ "\n"+ "void main(void) {\n"+ " vec4 fragColor;\n"+ "#ifdef FAT_LINES\n"+ " vec2 point = vPoint;\n"+ " bool neg = point.y < 0.0;\n"+ " point.y = neg ? (point.y + vLength)/(1.0 - vLength) :\n"+ " -(point.y - vLength)/(1.0 - vLength);\n"+ "#if defined(IS_TRANSPARENT) && defined(IS_LINESTRIP)\n"+ " if (neg && length(point) <= 1.0) discard;\n"+ "#endif\n"+ " point.y = min(point.y, 0.0);\n"+ " if (length(point) > 1.0) discard;\n"+ "#endif // FAT_LINES\n"+ " \n"+ "#ifdef ROUND_POINTS\n"+ " vec2 coord = gl_PointCoord - vec2(0.5);\n"+ " if (length(coord) > 0.5) discard;\n"+ "#endif\n"+ " \n"+ "#if NCLIPPLANES > 0\n"+ " for (int i = 0; i < NCLIPPLANES; i++)\n"+ " if (dot(vPosition, vClipplane[i]) < 0.0) discard;\n"+ "#endif\n"+ " \n"+ "#ifdef FIXED_QUADS\n"+ " vec3 n = vec3(0., 0., 1.);\n"+ "#elif defined(IS_LIT)\n"+ " vec3 n = normalize(vNormal.xyz);\n"+ "#endif\n"+ " \n"+ "#ifdef IS_TWOSIDED\n"+ " if ((normz <= 0.) != front) discard;\n"+ "#endif\n"+ "\n"+ "#ifdef IS_LIT\n"+ " vec3 eye = normalize(-vPosition.xyz/vPosition.w);\n"+ " vec3 lightdir;\n"+ " vec4 colDiff;\n"+ " vec3 halfVec;\n"+ " vec4 lighteffect = vec4(emission, 0.);\n"+ " vec3 col;\n"+ " float nDotL;\n"+ "#ifdef FIXED_QUADS\n"+ " n = -faceforward(n, n, eye);\n"+ "#endif\n"+ " \n"+ "#if NLIGHTS > 0\n"+ " // Simulate two-sided lighting\n"+ " if (n.z < 0.0)\n"+ " n = -n;\n"+ " for (int i=0;i 0) {\n"+ " fogF = (uFogParms.y - vPosition.z/vPosition.w)/(uFogParms.y - uFogParms.x);\n"+ " if (uFogMode > 1)\n"+ " fogF = mix(uFogParms.w, 1.0, fogF);\n"+ " fogF = fogF*uFogParms.z;\n"+ " if (uFogMode == 2)\n"+ " fogF = 1.0 - exp(-fogF);\n"+ " // Docs are wrong: use (density*c)^2, not density*c^2\n"+ " // https://gitlab.freedesktop.org/mesa/mesa/-/blob/master/src/mesa/swrast/s_fog.c#L58\n"+ " else if (uFogMode == 3)\n"+ " fogF = 1.0 - exp(-fogF*fogF);\n"+ " fogF = clamp(fogF, 0.0, 1.0);\n"+ " gl_FragColor = vec4(mix(fragColor.rgb, uFogColor, fogF), fragColor.a);\n"+ " } else gl_FragColor = fragColor;\n"+ "#else\n"+ " gl_FragColor = fragColor;\n"+ "#endif // HAS_FOG\n"+ " \n"+ "}\n" ;}; rgl/inst/htmlwidgets/lib/rglClass/pretty.src.js0000644000176200001440000001356614771520323021360 0ustar liggesusers/** * Pretty function from R * @name ___PRETTY_FROM_R___ * @memberof rglwidgetClass * @kind function * @instance */ /* This file is translated from pretty.c, which was taken from the R sources, r61744 of src/appl/pretty.c, with minimal changes */ /* * R : A Computer Language for Statistical Data Analysis * Copyright (C) 1995-2012 The R Core Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, a copy is available at * http://www.r-project.org/Licenses/ */ /** * Construct pretty values to cover an interval * @param { number } lo - lower end of interval * @param { number } up - upper end of interval * @param { number } ndiv - requested number of divisions * @param { number } min_n - minimum divisions * @param { number } shrink_sml - if too many cells, amount to shrink by * @param { number } high_u_fact - bias in favour of larger units * @param { number } eps_correction - correction to bounds * @param { Boolean } return_bounds - whether to return bounds * @description * Pretty Intervals * Constructs m "pretty" values which cover the given interval *lo <= *up * m ~= *ndiv + 1 (i.e., ndiv := approximate number of INTERVALS) * * It is not quite clear what should happen for *lo = *up; * S itself behaves quite funilly, then. * * In my opinion, a proper 'pretty' should always ensure * *lo < *up, and hence *ndiv >=1 in the result. * However, in S and here, we allow *lo == *up, and *ndiv = 0. * Note however, that we are NOT COMPATIBLE to S. [Martin M.] * * NEW (0.63.2): ns, nu are double (==> no danger of integer overflow) * * We determine * if the interval (up - lo) is ``small'' [<==> i_small == TRUE, below]. * For the ``i_small'' situation, there is a parameter shrink_sml, * the factor by which the "scale" is shrunk. ~~~~~~~~~~ * It is advisable to set it to some (smaller) integer power of 2, * since this enables exact floating point division. */ rglwidgetClass.prototype.R_pretty = function( lo, up, ndiv, min_n, shrink_sml, high_u_fact, eps_correction, return_bounds) { /* From version 0.65 on, we had rounding_eps := 1e-5, before, r..eps = 0 * 1e-7 is consistent with seq.default() */ var rounding_eps = 1e-7, h = high_u_fact[0], h5 = high_u_fact[1], dx, cell, unit, base, U, ns, nu, k, i_small, DBL_EPSILON = Number.EPSILON, DBL_MIN = Number.MIN_VALUE, DBL_MAX = Number.MAX_VALUE; dx = up - lo; /* cell := "scale" here */ if (dx === 0 && up === 0) { /* up == lo == 0 */ cell = 1; i_small = true; } else { cell = Math.max(Math.abs(lo), Math.abs(up)); /* U = upper bound on cell/unit */ U = (1 + (h5 >= 1.5*h+0.5)) ? 1/(1+h) : 1.5/(1+h5); /* added times 3, as several calculations here */ i_small = dx < cell * U * Math.max(1,ndiv) * DBL_EPSILON *3; } /*OLD: cell = FLT_EPSILON+ dx / *ndiv; FLT_EPSILON = 1.192e-07 */ if(i_small) { if(cell > 10) cell = 9 + cell/10; cell *= shrink_sml; if(min_n > 1) cell /= min_n; } else { cell = dx; if(ndiv > 1) cell /= ndiv; } if(cell < 20*DBL_MIN) { /* warning(_("Internal(pretty()): very small range.. corrected")); */ cell = 20*DBL_MIN; } else if(cell * 10 > DBL_MAX) { /* warning(_("Internal(pretty()): very large range.. corrected")); */ cell = 0.1*DBL_MAX; } base = Math.pow(10, Math.floor(Math.log10(cell))); /* base <= cell < 10*base */ /* unit : from { 1,2,5,10 } * base * such that |u - cell| is small, * favoring larger (if h > 1, else smaller) u values; * favor '5' more than '2' if h5 > h (default h5 = .5 + 1.5 h) */ unit = base; if((U = 2*base)-cell < h*(cell-unit)) { unit = U; if((U = 5*base)-cell < h5*(cell-unit)) { unit = U; if((U =10*base)-cell < h*(cell-unit)) unit = U; }} /* Result: c := cell, u := unit, b := base * c in [ 1, (2+ h) /(1+h) ] b ==> u= b * c in ( (2+ h)/(1+h), (5+2h5)/(1+h5)] b ==> u= 2b * c in ( (5+2h)/(1+h), (10+5h) /(1+h) ] b ==> u= 5b * c in ((10+5h)/(1+h), 10 ) b ==> u=10b * * ===> 2/5 *(2+h)/(1+h) <= c/u <= (2+h)/(1+h) */ ns = Math.floor(lo/unit+rounding_eps); nu = Math.ceil (up/unit-rounding_eps); if(eps_correction && (eps_correction > 1 || !i_small)) { if(lo !== 0.0) lo *= (1- DBL_EPSILON); else lo = -DBL_MIN; if(up !== 0.0) up *= (1+ DBL_EPSILON); else up = +DBL_MIN; } while(ns*unit > lo + rounding_eps*unit) ns--; while(nu*unit < up - rounding_eps*unit) nu++; k = Math.floor(0.5 + nu - ns); if(k < min_n) { /* ensure that nu - ns == min_n */ k = min_n - k; if(ns >= 0) { nu += k/2; ns -= k/2 + k%2;/* ==> nu-ns = old(nu-ns) + min_n -k = min_n */ } else { ns -= k/2; nu += k/2 + k%2; } ndiv = min_n; } else { ndiv = k; } if(return_bounds) { /* if()'s to ensure that result covers original range */ if(ns * unit < lo) lo = ns * unit; if(nu * unit > up) up = nu * unit; } else { lo = ns; up = nu; } return {lo:lo, up:up, ndiv:ndiv, unit:unit}; }; rgl/inst/htmlwidgets/lib/rglClass/textures.src.js0000644000176200001440000001430614771520323021705 0ustar liggesusers /** * Methods related to textures * @name ___METHODS_FOR_TEXTURES___ * @memberof rglwidgetClass * @kind function * @instance */ rglwidgetClass.prototype.getTexFilter = function(filter) { var gl = this.gl || this.initGL(); switch(filter) { case "nearest": return gl.NEAREST; case "linear": return gl.LINEAR; case "nearest.mipmap.nearest": return gl.NEAREST_MIPMAP_NEAREST; case "linear.mipmap.nearest": return gl.LINEAR_MIPMAP_NEAREST; case "nearest.mipmap.linear": return gl.NEAREST_MIPMAP_LINEAR; case "linear.mipmap.linear": return gl.LINEAR_MIPMAP_LINEAR; default: console.error("Unknown filter: "+filter); } }; /** * Handle a texture after its image has been loaded * @param { Object } texture - the gl texture object * @param { Object } textureCanvas - the canvas holding the image */ rglwidgetClass.prototype.handleLoadedTexture = function(texture, textureCanvas) { var gl = this.gl || this.initGL(); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true); gl.bindTexture(gl.TEXTURE_2D, texture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, textureCanvas); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST); gl.generateMipmap(gl.TEXTURE_2D); gl.bindTexture(gl.TEXTURE_2D, null); }; /** * Get maximum dimension of texture in current browser. * @returns {number} */ rglwidgetClass.prototype.getMaxTexSize = function() { var gl = this.gl || this.initGL(); return Math.min(4096, gl.getParameter(gl.MAX_TEXTURE_SIZE)); }; /** * Load an image to a texture * @param { string } uri - The image location * @param { Object } texture - the gl texture object */ rglwidgetClass.prototype.loadImageToTexture = function(uri, texture) { var canvas = this.textureCanvas, ctx = canvas.getContext("2d"), image = new Image(), self = this; image.onload = function() { var w = image.width, h = image.height, canvasX = self.getPowerOfTwo(w), canvasY = self.getPowerOfTwo(h), maxTexSize = self.getMaxTexSize(); while (canvasX > 1 && canvasY > 1 && (canvasX > maxTexSize || canvasY > maxTexSize)) { canvasX /= 2; canvasY /= 2; } canvas.width = canvasX; canvas.height = canvasY; ctx.imageSmoothingEnabled = true; ctx.drawImage(image, 0, 0, canvasX, canvasY); self.handleLoadedTexture(texture, canvas); self.texturesLoading -= 1; if (!self.texturesLoading) self.drawScene(); }; if (!self.texturesLoading) self.texturesLoading = 0; // may have been undefined self.texturesLoading += 1; image.src = uri; }; /** * Draw text to the texture canvas * @returns { Object } object with text measurements * @param { string } text - the text * @param { number } cex - expansion * @param { string } family - font family * @param { number } font - font number */ rglwidgetClass.prototype.drawTextToCanvas = function(text, cex, family, font) { var canvasX, canvasY, scaling = 20, textColour = "white", backgroundColour = "rgba(0,0,0,0)", canvas = this.textureCanvas, ctx = canvas.getContext("2d"), i, textHeight = 0, textHeights = [], width, widths = [], offsetx, offsety = 0, line, lines = [], offsetsx = [], offsetsy = [], lineoffsetsy = [], fontStrings = [], maxTexSize = this.getMaxTexSize(), getFontString = function(i) { textHeights[i] = scaling*cex[i]; var fontString = textHeights[i] + "px", family0 = family[i], font0 = font[i]; if (family0 === "sans") family0 = "sans-serif"; else if (family0 === "mono") family0 = "monospace"; fontString = fontString + " " + family0; if (font0 === 2 || font0 === 4) fontString = "bold " + fontString; if (font0 === 3 || font0 === 4) fontString = "italic " + fontString; return fontString; }; cex = rglwidgetClass.repeatToLen(cex, text.length); family = rglwidgetClass.repeatToLen(family, text.length); font = rglwidgetClass.repeatToLen(font, text.length); canvasX = 1; line = -1; offsetx = maxTexSize; for (i = 0; i < text.length; i++) { ctx.font = fontStrings[i] = getFontString(i); width = widths[i] = ctx.measureText(text[i]).width; if (offsetx + width > maxTexSize) { offsety = offsety + 2*textHeight; if (line >= 0) lineoffsetsy[line] = offsety; line += 1; if (offsety > maxTexSize) console.error("Too many strings for texture."); textHeight = 0; offsetx = 0; } textHeight = Math.max(textHeight, textHeights[i]); offsetsx[i] = offsetx; offsetx += width; canvasX = Math.max(canvasX, offsetx); lines[i] = line; } offsety = lineoffsetsy[line] = offsety + 2*textHeight; for (i = 0; i < text.length; i++) { offsetsy[i] = lineoffsetsy[lines[i]]; } canvasX = this.getPowerOfTwo(canvasX); canvasY = this.getPowerOfTwo(offsety); canvas.width = canvasX; canvas.height = canvasY; ctx.fillStyle = backgroundColour; ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); ctx.textBaseline = "alphabetic"; for(i = 0; i < text.length; i++) { ctx.font = fontStrings[i]; ctx.fillStyle = textColour; ctx.textAlign = "left"; ctx.fillText(text[i], offsetsx[i], offsetsy[i]); } return {canvasX:canvasX, canvasY:canvasY, widths:widths, textHeights:textHeights, offsetsx:offsetsx, offsetsy:offsetsy}; }; rgl/inst/htmlwidgets/lib/rglClass/init.src.js0000644000176200001440000013432115011677075020772 0ustar liggesusers /** * Methods related to initialization * @name ___METHODS_FOR_INITIALIZATION___ * @memberof rglwidgetClass * @kind function * @instance */ /** * Initial test for WebGL */ rglwidgetClass.prototype.initGL0 = function() { if (!window.WebGLRenderingContext){ this.alertOnce("Your browser does not support WebGL. See http://get.webgl.org"); return; } }; /** * Initialize WebGL * @returns { Object } the WebGL context */ rglwidgetClass.prototype.initGL = function() { var self = this, success = false; if (this.gl) { if (!this.drawing && this.gl.isContextLost()) this.restartCanvas(); else return this.gl; } // if (!this.isInBrowserViewport()) return; Return what??? At this point we know this.gl is null. this.canvas.addEventListener("webglcontextrestored", this.onContextRestored, false); this.canvas.addEventListener("webglcontextlost", this.onContextLost, false); this.gl = this.canvas.getContext("webgl", this.webGLoptions) || this.canvas.getContext("experimental-webgl", this.webGLoptions); success = !!(this.gl && this.gl instanceof WebGLRenderingContext); if (!success) this.alertOnce("Your browser does not support WebGL. See http://get.webgl.org"); this.index_uint = this.gl.getExtension("OES_element_index_uint"); var save = this.startDrawing(); Object.keys(this.scene.objects).forEach(function(key){ self.initObjId(parseInt(key, 10)); }); this.stopDrawing(save); return this.gl; }; /** * Resize the display to match element * @param { Object } el - DOM element to match */ rglwidgetClass.prototype.resize = function(el) { this.canvas.width = el.width; this.canvas.height = el.height; }; /** * Initialize the sphere object */ rglwidgetClass.prototype.initSphere = function(sections, segments) { var v = [], phi = [], theta = [], it = [], centers = [], i, j, k, ind, result = {}; for (i = 0; i <= sections; i++) { phi.push(i/sections - 0.5); } for (j = 0; j <= segments; j++) { theta.push(2*j/segments); for (i = 0; i <= sections; i++) { /* These are [x,y,z,s,t]: */ v.push([Math.sin(Math.PI*theta[j]) * Math.cos(Math.PI*phi[i]), Math.sin(Math.PI*phi[i]), Math.cos(Math.PI*theta[j]) * Math.cos(Math.PI*phi[i]), theta[j]/2, phi[i] + 0.5]); // console.log("xyzst="+v[v.length-1]); } } result.values = new Float32Array(rglwidgetClass.flatten(v)); result.vertexCount = v.length; for (j = 0; j < segments; j++) { for (i = 0; i < sections; i++) { ind = i + (sections + 1)*j; if (i > 0) // Not south pole it.push([ind, ind + sections + 1, ind + 1]); if (i < sections - 1) // Not north pole it.push([ind + sections + 1, ind + sections + 2, ind + 1]); } } result.it = new Uint16Array(rglwidgetClass.flatten(it)); for (i = 0; i < it.length; i++) { centers.push([0,0,0]); for (j = 0; j < 3; j++) { // x,y,z for (k = 0; k < 3; k++) {// vertices centers[i][j] += v[it[i][k]][j]/3; } } } result.centers = centers; result.vOffsets = {vofs:0, cofs:-1, nofs:0, radofs:-1, oofs:-1, tofs:3, nextofs:-1, pointofs:-1, stride:5}; result.f = []; result.indices = {}; result.colorCount = 1; result.type = "sphere"; this.sphere = result; this.initShapeGL(this.sphere); }; /** * Initialize the cube object */ rglwidgetClass.prototype.initCube = function() { var v = [[0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0], [0, 0, 1], [1, 0, 1], [0, 1, 1], [1, 1, 1]], ib = [[0, 2, 3, 1], [2, 6, 7, 3], [1, 3, 7, 5], [0, 4, 6, 2], [0, 1, 5, 4], [4, 5, 7, 6]], centers = [], i, j, k, i0, i1, i2, normal, result = {}; for (i = 0; i < ib.length; i++) { centers.push([0,0,0]); for (j = 0; j < 3; j++) { // x,y,z for (k = 0; k < 4; k++) {// vertices centers[i][j] += v[ib[i][k]][j]/4; } } } result.centers = centers; result.values = new Float32Array(6*4*3*2); result.vertexCount = 24; result.vertices = new Array(24); result.normals = new Array(24); for (i=0; i < 6; i++) { for (j=0; j < 4; j++) { i0 = ib[i][j]; result.vertices[4*i + j] = v[i0]; i1 = ib[i][(j + 1) % 4]; i2 = ib[i][(j + 2) % 4]; if (j === 0) normal = rglwidgetClass.normalize(rglwidgetClass.xprod(rglwidgetClass.vdiff(v[i1], v[i0]), rglwidgetClass.vdiff(v[i2], v[i0]))); result.normals[4*i + j] = normal; for (k=0; k < 3; k++) { result.values[i*24 + j*6 + k] = v[i0][k]; result.values[i*24 + j*6 + 3 + k] = normal[k]; } } for (j=0; j<4; j++) ib[i][j] = 4*i + j; } result.ib = new Uint16Array(rglwidgetClass.flatten(ib)); result.vOffsets = {vofs:0, cofs:-1, nofs:3, radofs:-1, oofs:-1, tofs:-1, nextofs:-1, pointofs:-1, stride:6}; result.f = []; result.indices = {}; result.colorCount = 1; result.type = "quads"; this.cube = result; this.initShapeGL(this.cube); }; /** * Do the gl part of initializing the sphere and cube */ rglwidgetClass.prototype.initShapeGL = function(shape) { var gl = this.gl || this.initGL(); if (gl.isContextLost()) return; shape.buf = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, shape.buf); gl.bufferData(gl.ARRAY_BUFFER, shape.values, gl.STATIC_DRAW); shape.ibuf = [gl.createBuffer(), gl.createBuffer()]; return; }; /* Initialize common sphere object from spheres object */ rglwidgetClass.prototype.initShapeFromObj = function(shape, obj) { var i, pass, f, mode, self = this, /* This function selects things that would be the back, ignoring perspective -- this is what we want for the bounding box decoration. */ is_back = function(i) { var normal = [].concat(shape.normals[i]), pt = shape.vertices[i]; normal.push(-rglwidgetClass.dotprod(normal, pt)); normal = rglwidgetClass.multVM(normal, self.normMatrix); return normal[2] < 0 || (normal[2] === 0 && normal[0] < 0); }; shape.ofsLoc = obj.ofsLoc; shape.texLoc = obj.texLoc; shape.texture = obj.texture; shape.sampler = obj.sampler; shape.uFogMode = obj.uFogMode; shape.uFogColor = obj.uFogColor; shape.uFogParms = obj.uFogParms; shape.userAttribLocations = obj.userAttribLocations; shape.userUniformLocations = obj.userUniformLocations; shape.normLoc = obj.normLoc; shape.invPrMatLoc = obj.invPrMatLoc; shape.clipLoc = obj.clipLoc; shape.nextLoc = obj.nextLoc; shape.pointLoc = obj.pointLoc; shape.aspectLoc = obj.aspectLoc; shape.lwdLoc = obj.lwdLoc; shape.prog = obj.prog; shape.material = obj.material; shape.flags = obj.flags; shape.defFlags = obj.defFlags; shape.someHidden = obj.someHidden; shape.fastTransparency = obj.fastTransparency; shape.nlights = obj.nlights; shape.emission = obj.emission; shape.emissionLoc = obj.emissionLoc; shape.shininess = obj.shininess; shape.shininessLoc = obj.shininessLoc; shape.ambient = obj.ambient; shape.ambientLoc = obj.ambientLoc; shape.specular = obj.specular; shape.specularLoc = obj.specularLoc; shape.diffuse = obj.diffuse; shape.diffuseLoc = obj.diffuseLoc; shape.lightDir = obj.lightDir; shape.lightDirLoc = obj.lightDirLoc; shape.viewpoint = obj.viewpoint; shape.viewpointLoc = obj.viewpointLoc; shape.finite = obj.finite; shape.finiteLoc = obj.finiteLoc; shape.prMatLoc = obj.prMatLoc; shape.mvMatLoc = obj.mvMatLoc; shape.normMatLoc = obj.normMatLoc; shape.frontLoc = obj.frontLoc; shape.index_uint = false; shape.is_transparent = obj.is_transparent; shape.ignoreExtent = obj.ignoreExtent; if (shape.passes !== obj.passes || JSON.stringify( shape.pmode) !== JSON.stringify(obj.pmode)) { shape.passes = obj.passes; shape.pmode = obj.pmode; for (pass = 0; pass < obj.passes; pass++) { mode = shape.pmode[pass]; if (typeof shape.indices[mode] === "undefined") { f = []; switch (mode) { case "culled": break; case "points": f.length = shape.vertexCount; for (i=0; i < f.length; i++) f[i] = i; break; case "lines": if (typeof shape.it !== "undefined") { f.length = 2* shape.it.length; for (i=0; i < shape.it.length/3; i++) { f[6*i] = shape.it[3*i]; f[6*i + 1] = shape.it[3*i + 1]; f[6*i + 2] = shape.it[3*i + 1]; f[6*i + 3] = shape.it[3*i + 2]; f[6*i + 4] = shape.it[3*i + 2]; f[6*i + 5] = shape.it[3*i]; } } else { f.length = 2*shape.ib.length; for (i=0; i < shape.ib.length/4; i++) { f[8*i] = shape.ib[4*i]; f[8*i + 1] = shape.ib[4*i + 1]; f[8*i + 2] = shape.ib[4*i + 1]; f[8*i + 3] = shape.ib[4*i + 2]; f[8*i + 4] = shape.ib[4*i + 2]; f[8*i + 5] = shape.ib[4*i + 3]; f[8*i + 6] = shape.ib[4*i + 3]; f[8*i + 7] = shape.ib[4*i]; } } break; case "filled": if (typeof shape.it !== "undefined") f = shape.it; else if (typeof shape.ib !== "undefined") { f.length = 1.5*shape.ib.length; for (i=0; i < shape.ib.length/4; i++) { f[6*i] = shape.ib[4*i]; f[6*i+1] = shape.ib[4*i + 1]; f[6*i+2] = shape.ib[4*i + 2]; f[6*i+3] = shape.ib[4*i]; f[6*i+4] = shape.ib[4*i + 2]; f[6*i+5] = shape.ib[4*i + 3]; } } break; } shape.indices[mode] = new Uint16Array(f); } } } for (pass = 0; pass < obj.passes; pass++) { mode = shape.pmode[pass]; shape.f[pass] = shape.indices[mode]; if (typeof obj.draw_front !== "undefined" && !obj.draw_front) { shape.f[pass] = shape.f[pass].filter(is_back); } } // console.log("Names in shapes not in shape:"+JSON.stringify(rglwidgetClass.keydiff(obj, shape))); shape.initialized = true; }; /** * Initialize a subscene * @param { number } id - id of subscene. */ rglwidgetClass.prototype.initSubscene = function(id) { var sub = this.getObj(id), i, obj; if (sub.type !== "subscene") return; sub.par3d.userMatrix = this.toCanvasMatrix4(sub.par3d.userMatrix); sub.par3d.userProjection = this.toCanvasMatrix4(sub.par3d.userProjection); sub.par3d.userProjection.transpose(); sub.par3d.listeners = [].concat(sub.par3d.listeners); sub.backgroundId = undefined; sub.subscenes = []; sub.clipplanes = []; sub.transparent = []; sub.opaque = []; sub.lights = []; sub.needsBegin = true; if (typeof sub.objects !== "undefined") sub.objects = [].concat(sub.objects); /* make sure it's an array */ for (i=0; i < sub.objects.length; i++) { obj = this.getObj(sub.objects[i]); if (typeof obj === "undefined") { sub.objects.splice(i, 1); i--; } else if (obj.type === "background") sub.backgroundId = obj.id; else sub[this.whichList(obj.id)].push(obj.id); } }; rglwidgetClass.prototype.initBBox = function(obj) { if (!this.cube) this.initCube(); obj.cube = {id: obj.id + 0.1, type: "quads", flags: obj.flags, material: obj.material, colors: [obj.colors[0]], vertices: this.cube.vertices, normals: this.cube.normals, draw_front: obj.draw_front, initialized: false }; if (this.getMaterial(obj.cube, "front") !== this.getMaterial(obj.cube, "back")) /* jshint bitwise: false */ obj.cube.flags |= rglwidgetClass.f_is_twosided; /* jshint bitwise: true */ this.scene.objects[obj.cube.id] = obj.cube; obj.ticks = {id: obj.id + 0.2, type: "lines", flags: rglwidgetClass.f_has_fog, material: obj.material, colors: (obj.colors.length > 1 ? [obj.colors[1]] : [obj.colors[0]]), axes: obj.axes, initialized: false }; this.scene.objects[obj.ticks.id] = obj.ticks; obj.labels = {id: obj.id + 0.3, type: "text", flags: rglwidgetClass.f_has_fog + rglwidgetClass.f_fixed_size + rglwidgetClass.f_fixed_quads, material: {lit: false}, colors: (obj.colors.length > 1 ? [obj.colors[1]] : [obj.colors[0]]), cex: [[1]], family: [["sans"]], font: [[1]], adj: [[0.5, 0.5, 0.5]], ignoreExtent: true, initialized: false }; this.scene.objects[obj.labels.id] = obj.labels; obj.initialized = true; }; rglwidgetClass.prototype.initBackground = function(obj) { var material, fl = obj.defFlags; if (typeof obj.ids !== "undefined") obj.quad = rglwidgetClass.flatten([].concat(obj.ids)); else if (obj.sphere) { fl.has_normals = true; fl.needs_vnormal = true; obj.defFlags = fl; material = obj.material; material.front = "culled"; obj.vertices = [[0,0,0]]; obj.texcoords = [[0,0]]; } }; /** * Initialize object for display * @param { number } id - id of object to initialize */ rglwidgetClass.prototype.initObjId = function(id) { if (typeof id !== "number") { this.alertOnce("initObj id is "+typeof id); } return this.initObj(this.getObj(id)); }; /** * Initialize object for display * @param { Object } obj - object to initialize */ rglwidgetClass.prototype.initObj = function(obj) { var type = obj.type, flags = obj.flags, normals = obj.normals, round_points = (typeof obj.material === "undefined") ? false : this.getMaterial(obj, "point_antialias"), has_indices = typeof obj.indices !== "undefined", has_spheres = type === "spheres" || (type === "background" && obj.sphere), sprites_3d = rglwidgetClass.isSet(flags, rglwidgetClass.f_sprites_3d), depth_sort = rglwidgetClass.isSet(flags, rglwidgetClass.f_depth_sort), gl = this.gl || this.initGL(), fl, polygon_offset, texinfo, drawtype, nclipplanes, f, nrows, oldrows, i,j,v,v1,v2, mat, uri, matobj, pass, pmode, dim, nx, nz, nrow, shaders; obj.initialized = true; obj.someHidden = false; // used in selection this.expandBufferedFields(obj); if (type === "subscene") return; obj.defFlags = fl = rglwidgetClass.getDefFlags(flags, type, normals, round_points); obj.is_transparent = fl.is_transparent; if (type === "bboxdeco") return this.initBBox(obj); if (has_spheres && typeof this.sphere === "undefined") this.initSphere(16, 16); if (type === "light") { obj.ambient = new Float32Array(obj.colors[0].slice(0,3)); obj.diffuse = new Float32Array(obj.colors[1].slice(0,3)); obj.specular = new Float32Array(obj.colors[2].slice(0,3)); obj.lightDir = new Float32Array(obj.vertices[0]); return; } if (type === "clipplanes") { obj.vClipplane = rglwidgetClass.flatten(rglwidgetClass.cbind(obj.normals, obj.offsets)); return; } if (type === "background") { this.initBackground(obj); if (!obj.sphere) return; } polygon_offset = this.getMaterial(obj, "polygon_offset"); if (polygon_offset[0] !== 0 || polygon_offset[1] !== 0) obj.polygon_offset = polygon_offset; if (fl.is_transparent) { depth_sort = ["triangles", "quads", "surface", "spheres", "sprites", "text", "planes"].indexOf(type) >= 0; } if (fl.is_brush) this.initSelection(obj.id); if (typeof obj.vertices === "undefined") obj.vertices = []; v = obj.vertices; if (has_indices) obj.vertexCount = obj.indices.length; else obj.vertexCount = v.length; if (!obj.vertexCount) return; if (fl.is_twosided && !fl.has_normals && type !== "background") { if (typeof obj.userAttributes === "undefined") obj.userAttributes = {}; v1 = Array(v.length); v2 = Array(v.length); if (obj.type === "triangles" || obj.type === "quads") { if (obj.type === "triangles") nrow = 3; else nrow = 4; for (i=0; i= 0) { key = this.scene.crosstalk.key[j]; options = this.scene.crosstalk.options[j]; colors = colors.slice(0); for (i = 0; i < v.length; i++) colors[i] = obj.colors[i % obj.colors.length].slice(0); if ( (selection = this.scene.crosstalk.selection) && (selection.length || !options.selectedIgnoreNone) ) for (i = 0; i < v.length; i++) { if (!selection.includes(key[i])) { if (options.deselectedColor) colors[i] = options.deselectedColor.slice(0); colors[i][3] = colors[i][3]*options.deselectedFade; /* default: mostly transparent if not selected */ } else if (options.selectedColor) colors[i] = options.selectedColor.slice(0); } if ( (filter = this.scene.crosstalk.filter) ) for (i = 0; i < v.length; i++) if (!filter.includes(key[i])) { if (options.filteredColor) colors[i] = options.filteredColor.slice(0); colors[i][3] = colors[i][3]*options.filteredFade; /* default: completely hidden if filtered */ } } nc = obj.colorCount = colors.length; if (nc > 1) { cofs = stride; stride = stride + 4; v = rglwidgetClass.cbind(v, colors); } else { cofs = -1; obj.onecolor = rglwidgetClass.flatten(colors); } if (fl.has_normals && !has_spheres) { nofs = stride; stride = stride + 3; v = rglwidgetClass.cbind(v, typeof obj.pnormals !== "undefined" ? obj.pnormals : obj.normals); } else nofs = -1; if (typeof obj.radii !== "undefined") { radofs = stride; stride = stride + 1; // FIXME: always concat the radii? if (obj.radii.length === v.length) { v = rglwidgetClass.cbind(v, obj.radii); } else if (obj.radii.length === 1) { v = v.map(function(row) { return row.concat(obj.radii[0]);}); } } else radofs = -1; // Add default indices if (has_indices) { f = Array(obj.indices.length); for (i = 0; i < f.length; i++) f[i] = obj.indices[i] - 1; } else { f = Array(v.length); for (i = 0; i < v.length; i++) f[i] = i; } obj.f = [f,f]; if (type === "sprites" && !sprites_3d) { tofs = stride; stride += 2; oofs = stride; stride += 3; vnew = new Array(4*v.length); fnew = new Array(4*v.length); alias = new Array(v.length); var rescale = fl.fixed_size ? 72 : 1, size = obj.radii, s = rescale*size[0]/2; last = v.length; f = obj.f[0]; obj.adj = rglwidgetClass.flatten(obj.adj); if (typeof obj.pos !== "undefined") { obj.pos = rglwidgetClass.flatten(obj.pos); offset = obj.adj[0]; } else offset = 0; for (i=0; i < v.length; i++) { adj = this.getAdj(obj, i, offset); if (size.length > 1) s = rescale*size[i]/2; adj[0] = 2*s*(adj[0] - 0.5); adj[1] = 2*s*(adj[1] - 0.5); adj[2] = 2*s*(adj[2] - 0.5); vnew[i] = v[i].concat([0,0]).concat([-s-adj[0], -s-adj[1], -adj[2]]); fnew[4*i] = f[i]; vnew[last]= v[i].concat([1,0]).concat([s-adj[0], -s-adj[1], -adj[2]]); fnew[4*i+1] = last++; vnew[last]= v[i].concat([1,1]).concat([s-adj[0], s-adj[1], -adj[2]]); fnew[4*i+2] = last++; vnew[last]= v[i].concat([0,1]).concat([-s-adj[0], s-adj[1], -adj[2]]); fnew[4*i+3] = last++; alias[i] = [last-3, last-2, last-1]; } v = vnew; obj.vertexCount = v.length; obj.f = [fnew, fnew]; } else if (type === "text") { tofs = stride; stride += 2; oofs = stride; stride += 3; vnew = new Array(4*v.length); f = obj.f[0]; fnew = new Array(4*f.length); alias = new Array(v.length); last = v.length; adj = rglwidgetClass.flatten(obj.adj); if (typeof obj.pos !== "undefined") { obj.pos = rglwidgetClass.flatten(obj.pos); offset = adj[0]; } else offset = 0; for (i=0; i < v.length; i++) { adj = this.getAdj(obj, i, offset, obj.texts[i]); vnew[i] = v[i].concat([0,-0.5]).concat(adj); fnew[4*i] = f[i]; vnew[last] = v[i].concat([1,-0.5]).concat(adj); fnew[4*i+1] = last++; vnew[last] = v[i].concat([1, 1.5]).concat(adj); fnew[4*i+2] = last++; vnew[last] = v[i].concat([0, 1.5]).concat(adj); fnew[4*i+3] = last++; alias[i] = [last-3, last-2, last-1]; for (j=0; j < 4; j++) { v1 = vnew[fnew[4*i+j]]; v1[oofs] = 2*(v1[tofs]-v1[oofs])*texinfo.widths[i]; v1[oofs+1] = 2*(v1[tofs+1]-v1[oofs+1])*texinfo.textHeights[i]; v1[oofs+2] = 2*(0.5-v1[oofs+2])*texinfo.textHeights[i]/1000.0; v1[tofs] = (texinfo.offsetsx[i] + v1[tofs]*texinfo.widths[i])/texinfo.canvasX; v1[tofs+1] = 1.0-(texinfo.offsetsy[i] - v1[tofs+1]*texinfo.textHeights[i])/texinfo.canvasY; vnew[fnew[4*i+j]] = v1; } } v = vnew; obj.vertexCount = v.length; obj.f = [fnew, fnew]; } else if (typeof obj.texcoords !== "undefined") { tofs = stride; stride += 2; oofs = -1; v = rglwidgetClass.cbind(v, obj.texcoords); } else { tofs = -1; oofs = -1; } obj.alias = alias; if (typeof obj.userAttributes !== "undefined") { obj.userAttribOffsets = {}; obj.userAttribLocations = {}; obj.userAttribSizes = {}; for (attr in obj.userAttributes) { obj.userAttribLocations[attr] = gl.getAttribLocation(obj.prog, attr); if (obj.userAttribLocations[attr] >= 0) { // Attribute may not have been used obj.userAttribOffsets[attr] = stride; v = rglwidgetClass.cbind(v, obj.userAttributes[attr]); stride = v[0].length; obj.userAttribSizes[attr] = stride - obj.userAttribOffsets[attr]; } else console.warn("attribute '"+attr+"' not found in object "+obj.id+"."); } } if (typeof obj.userUniforms !== "undefined" || typeof obj.userTextures !== "undefined") { obj.userUniformLocations = {}; for (attr in obj.userUniforms) { obj.userUniformLocations[attr] = gl.getUniformLocation(obj.prog, attr); if (obj.userUniformLocations[attr] === null) console.warn("uniform '"+attr+"' not found in object "+obj.id+"."); } for (attr in obj.userTextures) { var texture = obj.userTextures[attr]; texture.texture = gl.createTexture(); // This is a trick from https://stackoverflow.com/a/19748905/2554330 to avoid warnings gl.bindTexture(gl.TEXTURE_2D, texture.texture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array([255,255,255, 255])); // white texture.sampler = gl.getUniformLocation(obj.prog, attr); if (texture.sampler === null) console.warn("sampler '"+attr+"' not found in object "+obj.id+"."); uri = texture.uri; this.loadImageToTexture(uri, texture.texture); } } if (sprites_3d) { obj.userMatrix = new CanvasMatrix4(); obj.userMatrix.load(rglwidgetClass.flatten(obj.usermatrix)); obj.objects = rglwidgetClass.flatten([].concat(obj.ids)); fl.is_lit = false; obj.adj = rglwidgetClass.flatten(obj.adj); if (typeof obj.pos !== "undefined") { obj.pos = rglwidgetClass.flatten(obj.pos); obj.offset = obj.adj[0]; } else obj.offset = 0; var shapenum = rglwidgetClass.flatten(obj.shapenum); obj.shapelens = []; obj.shapefirst = []; obj.shapefirst.push(0); len = 0; current = 0; for (i = 0; i < shapenum.length; i++) { if (shapenum[i] === shapenum[current]) { len++; } else { obj.shapelens.push(len); len = 1; current = i; obj.shapefirst.push(i); } } obj.shapelens.push(len); for (i=0; i < obj.objects.length; i++) this.initObjId(obj.objects[i]); } nclipplanes = this.countClipplanes(); if (nclipplanes && !sprites_3d) { obj.clipLoc = gl.getUniformLocation(obj.prog,"vClipplane"); } if (fl.is_lit) { obj.emissionLoc = gl.getUniformLocation(obj.prog, "emission"); obj.emission = new Float32Array(this.stringToRgb(this.getMaterial(obj, "emission"))); obj.shininessLoc = gl.getUniformLocation(obj.prog, "shininess"); obj.shininess = this.getMaterial(obj, "shininess"); obj.nlights = this.countLights(); if (obj.nlights > 0) { obj.ambient = new Float32Array(this.stringToRgb(this.getMaterial(obj, "ambient"))); obj.specular = new Float32Array(this.stringToRgb(this.getMaterial(obj, "specular"))); obj.ambientLoc = gl.getUniformLocation(obj.prog, "ambient"); obj.specularLoc = gl.getUniformLocation(obj.prog, "specular"); obj.diffuseLoc = gl.getUniformLocation(obj.prog, "diffuse" ); obj.lightDirLoc = gl.getUniformLocation(obj.prog, "lightDir"); obj.viewpointLoc = gl.getUniformLocation(obj.prog, "viewpoint"); obj.finiteLoc = gl.getUniformLocation(obj.prog, "finite" ); } } obj.passes = fl.is_twosided + 1; obj.pmode = new Array(obj.passes); for (pass = 0; pass < obj.passes; pass++) { if (type === "triangles" || type === "quads" || type === "surface" || has_spheres) pmode = this.getMaterial(obj, (pass === 0) ? "front" : "back"); else pmode = "filled"; obj.pmode[pass] = pmode; } if (!has_spheres) { obj.f.length = obj.passes; for (pass = 0; pass < obj.passes; pass++) { f = fnew = obj.f[pass]; pmode = obj.pmode[pass]; if (pmode === "culled") fnew = []; else if (pmode === "points") { // stay with default } else if ((type === "quads" || type === "text" || type === "sprites") && !sprites_3d) { nrows = Math.floor(obj.vertexCount/4); if (pmode === "filled") { fnew = Array(6*nrows); for (i=0; i < nrows; i++) { fnew[6*i] = f[4*i]; fnew[6*i+1] = f[4*i + 1]; fnew[6*i+2] = f[4*i + 2]; fnew[6*i+3] = f[4*i]; fnew[6*i+4] = f[4*i + 2]; fnew[6*i+5] = f[4*i + 3]; } } else { fnew = Array(8*nrows); for (i=0; i < nrows; i++) { fnew[8*i] = f[4*i]; fnew[8*i+1] = f[4*i + 1]; fnew[8*i+2] = f[4*i + 1]; fnew[8*i+3] = f[4*i + 2]; fnew[8*i+4] = f[4*i + 2]; fnew[8*i+5] = f[4*i + 3]; fnew[8*i+6] = f[4*i + 3]; fnew[8*i+7] = f[4*i]; } } } else if (type === "triangles") { nrows = Math.floor(obj.vertexCount/3); if (pmode === "filled") { fnew = Array(3*nrows); for (i=0; i < fnew.length; i++) { fnew[i] = f[i]; } } else if (pmode === "lines") { fnew = Array(6*nrows); for (i=0; i < nrows; i++) { fnew[6*i] = f[3*i]; fnew[6*i + 1] = f[3*i + 1]; fnew[6*i + 2] = f[3*i + 1]; fnew[6*i + 3] = f[3*i + 2]; fnew[6*i + 4] = f[3*i + 2]; fnew[6*i + 5] = f[3*i]; } } } else if (has_spheres) { // default } else if (type === "surface") { dim = obj.dim[0]; nx = dim[0]; nz = dim[1]; if (pmode === "filled") { fnew = []; for (j=0; j 65535) { if (this.index_uint) { obj.f[pass] = new Uint32Array(obj.f[pass]); obj.index_uint = true; } else this.alertOnce("Object has "+obj.vertexCount+" vertices, not supported in this browser."); } else { obj.f[pass] = new Uint16Array(obj.f[pass]); obj.index_uint = false; } } if (stride !== v[0].length) { this.alertOnce("problem in stride calculation"); } obj.vOffsets = {vofs:0, cofs:cofs, nofs:nofs, radofs:radofs, oofs:oofs, tofs:tofs, nextofs:nextofs, pointofs:pointofs, stride:stride}; obj.values = new Float32Array(rglwidgetClass.flatten(v)); if (!has_spheres && !sprites_3d) { obj.buf = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, obj.buf); gl.bufferData(gl.ARRAY_BUFFER, obj.values, gl.STATIC_DRAW); // obj.ibuf = Array(obj.passes); obj.ibuf[0] = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, obj.ibuf[0]); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, obj.f[0], gl[drawtype]); if (fl.is_twosided) { obj.ibuf[1] = gl.createBuffer(); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, obj.ibuf[1]); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, obj.f[1], gl[drawtype]); } } if (!sprites_3d) { obj.mvMatLoc = gl.getUniformLocation(obj.prog, "mvMatrix"); obj.prMatLoc = gl.getUniformLocation(obj.prog, "prMatrix"); if (fl.fixed_size) { obj.textScaleLoc = gl.getUniformLocation(obj.prog, "textScale"); } } if (fl.needs_vnormal) { obj.normLoc = gl.getAttribLocation(obj.prog, "aNorm"); obj.normMatLoc = gl.getUniformLocation(obj.prog, "normMatrix"); } if (fl.is_twosided) { obj.frontLoc = gl.getUniformLocation(obj.prog, "front"); if (fl.has_normals) obj.invPrMatLoc = gl.getUniformLocation(obj.prog, "invPrMatrix"); } }; /** * Initialize the DOM object * @param { Object } el - the DOM object * @param { Object } x - the scene data sent by JSON from R */ rglwidgetClass.prototype.initialize = function(el, x) { this.textureCanvas = document.createElement("canvas"); this.textureCanvas.style.display = "block"; this.scene = x; this.normMatrix = new CanvasMatrix4(); this.invPrMatrix = new CanvasMatrix4(); this.saveMat = {}; this.distance = null; this.posLoc = 0; this.colLoc = 1; if (el) { el.rglinstance = this; this.el = el; this.webGLoptions = el.rglinstance.scene.webGLoptions; this.initCanvas(); } if (typeof Shiny !== "undefined") { var self = this; Shiny.addCustomMessageHandler("shinyGetPar3d", function(message) { var i, param, subscene = self.getObj(message.subscene), parameters = [].concat(message.parameters), result = {tag: message.tag, subscene: message.subscene}; if (typeof subscene !== "undefined") { for (i = 0; i < parameters.length; i++) { param = parameters[i]; result[param] = subscene.par3d[param]; } } else { console.log("subscene "+message.subscene+" undefined."); } Shiny.setInputValue("par3d:shinyPar3d", result, {priority: "event"}); }); Shiny.addCustomMessageHandler("shinySetPar3d", function(message) { var param = message.parameter, subscene = self.getObj(message.subscene); if (typeof subscene !== "undefined") { subscene.par3d[param] = message.value; subscene.initialized = false; self.drawScene(); } else { console.log("subscene "+message.subscene+" undefined."); } }); Shiny.addCustomMessageHandler("resetBrush", function(message) { if (message === self.scene.selectionInput) { self.clearBrush(null); self.recordSelection(0); } }); } }; /** * Restart the WebGL canvas */ rglwidgetClass.prototype.restartCanvas = function() { var newcanvas = document.createElement("canvas"), self = this, labelid = this.el.getAttribute("aria-labelledby"); newcanvas.width = this.el.width; newcanvas.height = this.el.height; newcanvas.setAttribute("aria-labelledby", labelid); if (typeof this.scene.altText !== "undefined") { // We're in Shiny, so alter the label var label = document.getElementById(labelid); if (label) label.innerHTML = this.scene.altText; } newcanvas.addEventListener("webglcontextrestored", this.onContextRestored, false); newcanvas.addEventListener("webglcontextlost", this.onContextLost, false); while (this.el.firstChild) { this.el.removeChild(this.el.firstChild); } this.el.appendChild(newcanvas); this.canvas = newcanvas; if (this.scene.javascript) { /* jshint evil:true */ Function('"use strict";' + this.scene.javascript)(); /* jshint evil:false */ } this.setMouseHandlers(); if (this.gl) Object.keys(this.scene.objects).forEach(function(key){ self.getObj(parseInt(key, 10)).texture = undefined; }); this.gl = null; }; /** * Initialize the WebGL canvas */ rglwidgetClass.prototype.initCanvas = function() { this.restartCanvas(); var objs = this.scene.objects, self = this; /* These hold context specific data. In Shiny, they need to be deleted. Elsewhere, they don't exist and these are no-ops. */ delete this.cube; delete this.sphere; Object.keys(objs).forEach(function(key){ self.initSubscene(parseInt(key, 10)); }); this.onContextRestored = function() { self.initGL(); self.drawScene(); }; this.onContextLost = function(event) { if (!self.drawing) this.gl = null; event.preventDefault(); }; this.initGL0(); this.lazyLoadScene = function() { if (typeof self.slide === "undefined") self.slide = self.getSlide(); if (self.isInBrowserViewport()) { if (!self.gl || self.gl.isContextLost()) self.initGL(); self.drawScene(); } }; window.addEventListener("DOMContentLoaded", this.lazyLoadScene, false); window.addEventListener("load", this.lazyLoadScene, false); window.addEventListener("resize", this.lazyLoadScene, false); window.addEventListener("scroll", this.lazyLoadScene, false); this.slide = this.getSlide(); if (this.slide) { if (typeof this.slide.rgl === "undefined") this.slide.rgl = [this]; else this.slide.rgl.push(this); if (this.scene.context.rmarkdown) if (this.scene.context.rmarkdown === "ioslides_presentation") { this.slide.setAttribute("slideenter", "this.rgl.forEach(function(scene) { scene.lazyLoadScene.call(window);})"); } else if (this.scene.context.rmarkdown === "slidy_presentation") { // This method would also work in ioslides, but it gets triggered // something like 5 times per slide for every slide change, so // you'd need a quicker function than lazyLoadScene. var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver, observer = new MutationObserver(function(mutations) { mutations.forEach(function() { self.slide.rgl.forEach(function(scene) { scene.lazyLoadScene.call(window); });});}); observer.observe(this.slide, { attributes: true, attributeFilter:["class"] }); } } }; rgl/inst/htmlwidgets/lib/rglClass/rglClass.min.js0000644000176200001440000041366515013427133021576 0ustar liggesusersrglwidgetClass=function(){this.canvas=null,this.userMatrix=new CanvasMatrix4,this.types=[],this.prMatrix=new CanvasMatrix4,this.mvMatrix=new CanvasMatrix4,this.vp=null,this.prmvMatrix=null,this.origs=null,this.gl=null,this.scene=null,this.select={state:"inactive",subscene:null,region:{p1:{x:0,y:0},p2:{x:0,y:0}}},this.drawing=!1},rglwidgetClass.f_is_lit=1,rglwidgetClass.f_is_smooth=2,rglwidgetClass.f_has_texture=4,rglwidgetClass.f_depth_sort=8,rglwidgetClass.f_fixed_quads=16,rglwidgetClass.f_is_transparent=32,rglwidgetClass.f_is_lines=64,rglwidgetClass.f_sprites_3d=128,rglwidgetClass.f_is_subscene=256,rglwidgetClass.f_is_clipplanes=512,rglwidgetClass.f_fixed_size=1024,rglwidgetClass.f_is_points=2048,rglwidgetClass.f_is_twosided=4096,rglwidgetClass.f_fat_lines=8192,rglwidgetClass.f_is_brush=16384,rglwidgetClass.f_has_fog=32768,rglwidgetClass.f_rotating=65536,rglwidgetClass.prototype.fogNone=0,rglwidgetClass.prototype.fogLinear=1,rglwidgetClass.prototype.fogExp=2,rglwidgetClass.prototype.fogExp2=3,rglwidgetClass.prototype.start=function(){"undefined"!=typeof this.prefix&&(this.debugelement=document.getElementById(this.prefix+"debug"),this.debug("")),this.drag=0,this.drawScene()},rglwidgetClass.multMV=function(M,v){return[M.m11*v[0]+M.m12*v[1]+M.m13*v[2]+M.m14*v[3],M.m21*v[0]+M.m22*v[1]+M.m23*v[2]+M.m24*v[3],M.m31*v[0]+M.m32*v[1]+M.m33*v[2]+M.m34*v[3],M.m41*v[0]+M.m42*v[1]+M.m43*v[2]+M.m44*v[3]]},rglwidgetClass.multVM=function(v,M){return[M.m11*v[0]+M.m21*v[1]+M.m31*v[2]+M.m41*v[3],M.m12*v[0]+M.m22*v[1]+M.m32*v[2]+M.m42*v[3],M.m13*v[0]+M.m23*v[1]+M.m33*v[2]+M.m43*v[3],M.m14*v[0]+M.m24*v[1]+M.m34*v[2]+M.m44*v[3]]},rglwidgetClass.vlen=function(v){return Math.sqrt(rglwidgetClass.dotprod(v,v))},rglwidgetClass.dotprod=function(a,b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]},rglwidgetClass.xprod=function(a,b){return[a[1]*b[2]-a[2]*b[1],a[2]*b[0]-a[0]*b[2],a[0]*b[1]-a[1]*b[0]]},rglwidgetClass.cbind=function(a,b){return b.lengthi;i++)value=arr[i],Array.isArray(value)?rglwidgetClass.flatten(value,result):result.push(value);return result},rglwidgetClass.prototype.setElement=function(a,i,value){if(Array.isArray(a[0])){var dim=a.length,col=Math.floor(i/dim),row=i%dim;a[row][col]=value}else a[i]=value},rglwidgetClass.prototype.transpose=function(a){var i,newArray=[],n=a.length,m=a[0].length;for(i=0;m>i;i++)newArray.push([]);for(i=0;n>i;i++)for(var j=0;m>j;j++)newArray[j].push(a[i][j]);return newArray},rglwidgetClass.prototype.sumsq=function(x){var i,result=0;for(i=0;i>16&255)/255,(bigint>>8&255)/255,(255&bigint)/255]},rglwidgetClass.prototype.whichList=function(id){var obj=this.getObj(id),flags=obj.flags;return"light"===obj.type?"lights":rglwidgetClass.isSet(flags,rglwidgetClass.f_is_subscene)?"subscenes":rglwidgetClass.isSet(flags,rglwidgetClass.f_is_clipplanes)?"clipplanes":rglwidgetClass.isSet(flags,rglwidgetClass.f_is_transparent)?"transparent":"opaque"},rglwidgetClass.prototype.componentProduct=function(x,y){"undefined"==typeof y&&this.alertOnce("Bad arg to componentProduct");var i,result=new Float32Array(3);for(i=0;3>i;i++)result[i]=x[i]*y[i];return result},rglwidgetClass.prototype.getPowerOfTwo=function(value){for(var pow=1;value>pow;)pow*=2;return pow},rglwidgetClass.prototype.unique=function(arr){return arr=[].concat(arr),arr.filter(function(value,index,self){return self.indexOf(value)===index})},rglwidgetClass.prototype.equalArrays=function(a,b){return a===b||a&&b&&a.length===b.length&&a.every(function(v,i){return v===b[i]})},rglwidgetClass.repeatToLen=function(arr,len){if(arr=[].concat(arr),!arr.length)throw new RangeError("array is length 0");for(;arr.length=-windHeight&&rect.left>=-windWidth&&rect.bottom<=2*windHeight&&rect.right<=2*windWidth},rglwidgetClass.keydiff=function(obj1,obj2){var i,keys=Object.keys(obj1),result=[];for(i=0;i=2&&cross(lower[lower.length-2],lower[lower.length-1],points[i])<=0;)lower.pop();lower.push(points[i])}for(i=points.length-1;i>=0;i--){for(;upper.length>=2&&cross(upper[upper.length-2],upper[upper.length-1],points[i])<=0;)upper.pop();upper.push(points[i])}return upper.pop(),lower.pop(),lower.concat(upper)},rglwidgetClass.signif=function(x,digits){return parseFloat(x.toPrecision(digits))},rglwidgetClass.missing=function(x){return"-Inf"!==x&&"Inf"!==x&&(isNaN(x)||null===x||"undefined"==typeof x)},rglwidgetClass.logMatrix=function(M){console.log("matrix(c("+M.m11+","+M.m12+","+M.m13+","+M.m14+",\n"+M.m21+","+M.m22+","+M.m23+","+M.m24+",\n"+M.m31+","+M.m32+","+M.m33+","+M.m34+",\n"+M.m41+","+M.m42+","+M.m43+","+M.m44+"), byrow=TRUE, ncol=4)")},rglwidgetClass.logVec3=function(v){console.log("c("+v[0]+","+v[1]+","+v[2]+")")},rglwidgetClass.vsum=function(x,y){var i,result=[].concat(x);for(i=0;i64&&91>nChr?nChr-65:nChr>96&&123>nChr?nChr-71:nChr>47&&58>nChr?nChr+4:43===nChr?62:47===nChr?63:0},rglwidgetClass.prototype.base64DecToArr=function(sBase64,nBlocksSize){for(var nMod3,nMod4,sB64Enc=sBase64.replace(/[^A-Za-z0-9\+\/]/g,""),nInLen=sB64Enc.length,nOutLen=nBlocksSize?Math.ceil((3*nInLen+1>>2)/nBlocksSize)*nBlocksSize:3*nInLen+1>>2,taBytes=new Uint8Array(nOutLen),nUint24=0,nOutIdx=0,nInIdx=0;nInLen>nInIdx;nInIdx++)if(nMod4=3&nInIdx,nUint24|=this.b64ToUint6(sB64Enc.charCodeAt(nInIdx))<<6*(3-nMod4),3===nMod4||nInLen-nInIdx===1){for(nMod3=0;3>nMod3&&nOutLen>nOutIdx;nMod3++,nOutIdx++)taBytes[nOutIdx]=nUint24>>>(16>>>nMod3&24)&255;nUint24=0}return taBytes},rglwidgetClass.prototype.getArrayBuffer=function(base64){return this.base64DecToArr(base64,4).buffer},rglwidgetClass.prototype.getBufferedData=function(v){return this.readAccessor(parseInt(v,10),this.scene.buffer)},rglwidgetClass.prototype.readAccessor=function(acc,buf){var bytes,values,row,i,j,k,typeSignedByte=5120,typeUnsignedByte=5121,typeSignedShort=5122,typeUnsignedShort=5123,typeSignedInt=5124,typeUnsignedInt=5125,typeFloat=5126,typeDouble=5130,accessor=buf.accessors[acc],bufferView=buf.bufferViews[accessor.bufferView],buffer=buf.buffers[bufferView.buffer],lens={SCALAR:1,VEC2:2,VEC3:3,VEC4:4,MAT2:4,MAT3:9,MAT4:16},rowsizes={SCALAR:1,VEC2:2,VEC3:3,VEC4:4,MAT2:2,MAT3:3,MAT4:4},offset=0,len=lens[accessor.type],rowsize=rowsizes[accessor.type],count=len*accessor.count,nrows=count/rowsize,arr=[];switch("string"==typeof buffer.bytes&&(buffer.bytes=this.getArrayBuffer(buffer.bytes)),bytes=buffer.bytes,"undefined"!=typeof accessor.byteOffset&&(offset+=accessor.byteOffset),"undefined"!=typeof bufferView.byteOffset&&(offset+=bufferView.byteOffset),accessor.componentType){case typeSignedByte:values=new Int8Array(buffer.bytes,offset,count);break;case typeUnsignedByte:values=new Uint8Array(buffer.bytes,offset,count);break;case typeSignedShort:values=new Int16Array(buffer.bytes,offset,count);break;case typeUnsignedShort:values=new Uint16Array(buffer.bytes,offset,count);break;case typeSignedInt:values=new Int32Array(buffer.bytes,offset,count);break;case typeUnsignedInt:values=new Uint32Array(buffer.bytes,offset,count);break;case typeFloat:values=new Float32Array(buffer.bytes,offset,count);break;case typeDouble:values=new Float64Array(buffer.bytes,offset,count)}for(k=0,i=0;nrows>i;i++){for(row=[],j=0;rowsize>j;j++)if(accessor.normalized)switch(accessor.componentType){case typeSignedByte:row.push(Math.max(values[k++]/127,-1));break;case typeSignedShort:row.push(Math.max(values[k++]/32767,-1));break;case typeUnsignedByte:row.push(values[k++]/255);break;case typeUnsignedShort:row.push(values[k++]/65535)}else row.push(values[k++]);arr.push(row)}return arr},rglwidgetClass.prototype.expandBufferedFields=function(obj){var i,field,fields=["vertices","normals","indices","texcoords","colors","centers"];for(i=0;i-1},rglwidgetClass.prototype.translateCoords=function(subsceneid,coords){var viewport=this.getObj(subsceneid).par3d.viewport;return{x:coords.x-viewport.x*this.canvas.width,y:coords.y-viewport.y*this.canvas.height}},rglwidgetClass.prototype.inViewport=function(coords,subsceneid){var viewport=this.getObj(subsceneid).par3d.viewport,x0=coords.x-viewport.x*this.canvas.width,y0=coords.y-viewport.y*this.canvas.height;return x0>=0&&x0<=viewport.width*this.canvas.width&&y0>=0&&y0<=viewport.height*this.canvas.height},rglwidgetClass.prototype.whichSubscene=function(coords){var self=this,recurse=function(subsceneid){var i,id,subscenes=self.getChildSubscenes(subsceneid);for(i=0;i-1&&(thesub.objects.splice(i,1),thelist=this.whichList(id),i=thesub[thelist].indexOf(id),thesub[thelist].splice(i,1))},rglwidgetClass.prototype.setSubsceneEntries=function(ids,subsceneid){var sub=this.getObj(subsceneid);sub.objects=ids,this.initSubscene(subsceneid)},rglwidgetClass.prototype.getSubsceneEntries=function(subscene){return this.getObj(subscene).objects},rglwidgetClass.prototype.getChildSubscenes=function(subscene){return this.getObj(subscene).subscenes},rglwidgetClass.prototype.useid=function(subsceneid,type){var sub=this.getObj(subsceneid);return"inherit"===sub.embeddings[type]?this.useid(sub.parent,type):subsceneid},rglwidgetClass.prototype.getBBoxDeco=function(sub){var i,obj,objects=sub.objects;for(i=0;i 0.0) {\n dir = normalize(nextScreen - currentScreen);\n }\n vec2 normal = vec2(-dir.y, dir.x);\n dir.x /= uAspect;\n normal.x /= uAspect;\n vec4 offset = vec4(len*(normal*aPoint.x*aPoint.y - dir), 0.0, 0.0);\n gl_Position = currentProjected + offset;\n#endif\n \n#ifdef IS_BRUSH\n gl_Position = vec4(aPos, 1.);\n#endif\n}\n"},rglwidgetClass.rgl_fragment_shader=function(){return"#line 2 2\n// File 2 is the fragment shader\n#ifdef GL_ES\n#ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#else\nprecision mediump float;\n#endif\n#endif\nvarying vec4 vCol; // carries alpha\nvarying vec4 vPosition;\n#if defined(HAS_TEXTURE) || defined (IS_TEXT)\nvarying vec2 vTexcoord;\nuniform sampler2D uSampler;\n#endif\n\n#ifdef HAS_FOG\nuniform int uFogMode;\nuniform vec3 uFogColor;\nuniform vec4 uFogParms;\n#endif\n\n#if defined(IS_LIT) && !defined(FIXED_QUADS)\nvarying vec4 vNormal;\n#endif\n\n#if NCLIPPLANES > 0\nuniform vec4 vClipplane[NCLIPPLANES];\n#endif\n\n#if NLIGHTS > 0\nuniform mat4 mvMatrix;\n#endif\n\n#ifdef IS_LIT\nuniform vec3 emission;\nuniform float shininess;\n#if NLIGHTS > 0\nuniform vec3 ambient[NLIGHTS];\nuniform vec3 specular[NLIGHTS]; // light*material\nuniform vec3 diffuse[NLIGHTS];\nuniform vec3 lightDir[NLIGHTS];\nuniform bool viewpoint[NLIGHTS];\nuniform bool finite[NLIGHTS];\n#endif\n#endif // IS_LIT\n\n#ifdef IS_TWOSIDED\nuniform bool front;\nvarying float normz;\n#endif\n\n#ifdef FAT_LINES\nvarying vec2 vPoint;\nvarying float vLength;\n#endif\n\n#ifdef USE_ENVMAP\nvarying vec3 vReflection;\n#endif\n\nvoid main(void) {\n vec4 fragColor;\n#ifdef FAT_LINES\n vec2 point = vPoint;\n bool neg = point.y < 0.0;\n point.y = neg ? (point.y + vLength)/(1.0 - vLength) :\n -(point.y - vLength)/(1.0 - vLength);\n#if defined(IS_TRANSPARENT) && defined(IS_LINESTRIP)\n if (neg && length(point) <= 1.0) discard;\n#endif\n point.y = min(point.y, 0.0);\n if (length(point) > 1.0) discard;\n#endif // FAT_LINES\n \n#ifdef ROUND_POINTS\n vec2 coord = gl_PointCoord - vec2(0.5);\n if (length(coord) > 0.5) discard;\n#endif\n \n#if NCLIPPLANES > 0\n for (int i = 0; i < NCLIPPLANES; i++)\n if (dot(vPosition, vClipplane[i]) < 0.0) discard;\n#endif\n \n#ifdef FIXED_QUADS\n vec3 n = vec3(0., 0., 1.);\n#elif defined(IS_LIT)\n vec3 n = normalize(vNormal.xyz);\n#endif\n \n#ifdef IS_TWOSIDED\n if ((normz <= 0.) != front) discard;\n#endif\n\n#ifdef IS_LIT\n vec3 eye = normalize(-vPosition.xyz/vPosition.w);\n vec3 lightdir;\n vec4 colDiff;\n vec3 halfVec;\n vec4 lighteffect = vec4(emission, 0.);\n vec3 col;\n float nDotL;\n#ifdef FIXED_QUADS\n n = -faceforward(n, n, eye);\n#endif\n \n#if NLIGHTS > 0\n // Simulate two-sided lighting\n if (n.z < 0.0)\n n = -n;\n for (int i=0;i 0) {\n fogF = (uFogParms.y - vPosition.z/vPosition.w)/(uFogParms.y - uFogParms.x);\n if (uFogMode > 1)\n fogF = mix(uFogParms.w, 1.0, fogF);\n fogF = fogF*uFogParms.z;\n if (uFogMode == 2)\n fogF = 1.0 - exp(-fogF);\n // Docs are wrong: use (density*c)^2, not density*c^2\n // https://gitlab.freedesktop.org/mesa/mesa/-/blob/master/src/mesa/swrast/s_fog.c#L58\n else if (uFogMode == 3)\n fogF = 1.0 - exp(-fogF*fogF);\n fogF = clamp(fogF, 0.0, 1.0);\n gl_FragColor = vec4(mix(fragColor.rgb, uFogColor, fogF), fragColor.a);\n } else gl_FragColor = fragColor;\n#else\n gl_FragColor = fragColor;\n#endif // HAS_FOG\n \n}\n"},rglwidgetClass.prototype.getTexFilter=function(filter){var gl=this.gl||this.initGL();switch(filter){case"nearest":return gl.NEAREST;case"linear":return gl.LINEAR;case"nearest.mipmap.nearest":return gl.NEAREST_MIPMAP_NEAREST;case"linear.mipmap.nearest":return gl.LINEAR_MIPMAP_NEAREST;case"nearest.mipmap.linear":return gl.NEAREST_MIPMAP_LINEAR;case"linear.mipmap.linear":return gl.LINEAR_MIPMAP_LINEAR;default:console.error("Unknown filter: "+filter)}},rglwidgetClass.prototype.handleLoadedTexture=function(texture,textureCanvas){var gl=this.gl||this.initGL();gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,!0),gl.bindTexture(gl.TEXTURE_2D,texture),gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,gl.RGBA,gl.UNSIGNED_BYTE,textureCanvas),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR_MIPMAP_NEAREST),gl.generateMipmap(gl.TEXTURE_2D),gl.bindTexture(gl.TEXTURE_2D,null) },rglwidgetClass.prototype.getMaxTexSize=function(){var gl=this.gl||this.initGL();return Math.min(4096,gl.getParameter(gl.MAX_TEXTURE_SIZE))},rglwidgetClass.prototype.loadImageToTexture=function(uri,texture){var canvas=this.textureCanvas,ctx=canvas.getContext("2d"),image=new Image,self=this;image.onload=function(){for(var w=image.width,h=image.height,canvasX=self.getPowerOfTwo(w),canvasY=self.getPowerOfTwo(h),maxTexSize=self.getMaxTexSize();canvasX>1&&canvasY>1&&(canvasX>maxTexSize||canvasY>maxTexSize);)canvasX/=2,canvasY/=2;canvas.width=canvasX,canvas.height=canvasY,ctx.imageSmoothingEnabled=!0,ctx.drawImage(image,0,0,canvasX,canvasY),self.handleLoadedTexture(texture,canvas),self.texturesLoading-=1,self.texturesLoading||self.drawScene()},self.texturesLoading||(self.texturesLoading=0),self.texturesLoading+=1,image.src=uri},rglwidgetClass.prototype.drawTextToCanvas=function(text,cex,family,font){var canvasX,canvasY,i,width,offsetx,line,scaling=20,textColour="white",backgroundColour="rgba(0,0,0,0)",canvas=this.textureCanvas,ctx=canvas.getContext("2d"),textHeight=0,textHeights=[],widths=[],offsety=0,lines=[],offsetsx=[],offsetsy=[],lineoffsetsy=[],fontStrings=[],maxTexSize=this.getMaxTexSize(),getFontString=function(i){textHeights[i]=scaling*cex[i];var fontString=textHeights[i]+"px",family0=family[i],font0=font[i];return"sans"===family0?family0="sans-serif":"mono"===family0&&(family0="monospace"),fontString=fontString+" "+family0,(2===font0||4===font0)&&(fontString="bold "+fontString),(3===font0||4===font0)&&(fontString="italic "+fontString),fontString};for(cex=rglwidgetClass.repeatToLen(cex,text.length),family=rglwidgetClass.repeatToLen(family,text.length),font=rglwidgetClass.repeatToLen(font,text.length),canvasX=1,line=-1,offsetx=maxTexSize,i=0;imaxTexSize&&(offsety+=2*textHeight,line>=0&&(lineoffsetsy[line]=offsety),line+=1,offsety>maxTexSize&&console.error("Too many strings for texture."),textHeight=0,offsetx=0),textHeight=Math.max(textHeight,textHeights[i]),offsetsx[i]=offsetx,offsetx+=width,canvasX=Math.max(canvasX,offsetx),lines[i]=line;for(offsety=lineoffsetsy[line]=offsety+2*textHeight,i=0;i=radius&&(radius=1);var hlen,observer=subscene.par3d.observer,distance=observer[2],FOV=subscene.par3d.FOV,ortho=0===FOV,t=ortho?1:Math.tan(FOV*Math.PI/360),near=distance-radius,far=distance+radius,aspect=this.vp.width/this.vp.height,z=subscene.par3d.zoom,userProjection=subscene.par3d.userProjection;0>far&&(far=1),far/100>near&&(near=far/100),this.frustum={near:near,far:far},hlen=t*near,ortho?aspect>1?this.prMatrix.ortho(-hlen*aspect*z,hlen*aspect*z,-hlen*z,hlen*z,near,far):this.prMatrix.ortho(-hlen*z,hlen*z,-hlen*z/aspect,hlen*z/aspect,near,far):aspect>1?this.prMatrix.frustum(-hlen*aspect*z,hlen*aspect*z,-hlen*z,hlen*z,near,far):this.prMatrix.frustum(-hlen*z,hlen*z,-hlen*z/aspect,hlen*z/aspect,near,far),this.prMatrix.multRight(userProjection)}},rglwidgetClass.prototype.setmvMatrix=function(id){var observer=this.getObj(id).par3d.observer;this.mvMatrix.makeIdentity(),this.setmodelMatrix(id),this.mvMatrix.translate(-observer[0],-observer[1],-observer[2])},rglwidgetClass.prototype.setmodelMatrix=function(id){var subscene=this.getObj(id),embedding=subscene.embeddings.model;if("replace"===embedding){var bbox=subscene.par3d.bbox,center=[(bbox[0]+bbox[1])/2,(bbox[2]+bbox[3])/2,(bbox[4]+bbox[5])/2];this.mvMatrix.translate(-center[0],-center[1],-center[2])}if("inherit"!==embedding){var scale=subscene.par3d.scale;this.mvMatrix.scale(scale[0],scale[1],scale[2]),this.mvMatrix.multRight(subscene.par3d.userMatrix)}"replace"!==embedding&&this.setmodelMatrix(subscene.parent)},rglwidgetClass.prototype.setnormMatrix2=function(){this.normMatrix=new CanvasMatrix4(this.mvMatrix),this.normMatrix.invert(),this.normMatrix.transpose()},rglwidgetClass.prototype.setprmvMatrix=function(){this.prmvMatrix=new CanvasMatrix4(this.mvMatrix),this.prmvMatrix.multRight(this.prMatrix)},rglwidgetClass.prototype.setInvPrMatrix=function(){this.invPrMatrix=new CanvasMatrix4(this.prMatrix),this.invPrMatrix.invert(),this.invPrMatrix.transpose()},rglwidgetClass.prototype.getCursor=function(mode){switch(mode){case"none":return"none";case"trackball":case"xAxis":case"yAxis":case"zAxis":case"polar":return"grab";case"selecting":return"crosshair";case"fov":case"zoom":return"zoom-in";case"user":return"default"}return"dragging"},rglwidgetClass.prototype.setMouseMode=function(mode,button,subscene,stayActive){var sub=this.getObj(subscene),which=["none","left","right","middle","wheel"][button];stayActive||"selecting"!==sub.par3d.mouseMode[which]||this.clearBrush(null),sub.par3d.mouseMode[which]=mode,(1===button||0===button&&"none"!==mode)&&(this.canvas.style.cursor=this.getCursor(mode)),0===button&&"none"!==mode&&(sub.needsBegin=mode)},rglwidgetClass.prototype.relMouseCoords=function(event){var rect=this.canvas.getBoundingClientRect();return{x:event.clientX-rect.left,y:event.clientY-rect.top}},rglwidgetClass.prototype.recordSelection=function(subid){var result={};"undefined"!=typeof this.select&&"undefined"!=typeof this.select.state&&"inactive"!==this.select.state?(result={subscene:subid,state:this.select.state,region:this.select.region},this.setmvMatrix(subid),result.model=this.mvMatrix,this.setprMatrix(subid),result.proj=this.prMatrix,this.getViewport(subid),result.view=this.vp):result.state="inactive",Shiny.setInputValue(this.scene.selectionInput+":shinyMouse3d",result)},rglwidgetClass.prototype.setMouseHandlers=function(){var activeSubscene,handler,self=this,handlers={},drag=0;handlers.rotBase=0,self.screenToVector=function(x,y){var viewport=self.getObj(activeSubscene).par3d.viewport,width=viewport.width*self.canvas.width,height=viewport.height*self.canvas.height,radius=Math.max(width,height)/2,cx=width/2,cy=height/2,px=(x-cx)/radius,py=(y-cy)/radius,plen=Math.sqrt(px*px+py*py);plen>1e-6&&(px/=plen,py/=plen);var angle=(Math.SQRT2-plen)/Math.SQRT2*Math.PI/2,z=Math.sin(angle),zlen=Math.sqrt(1-z*z);return px*=zlen,py*=zlen,[px,py,z]},handlers.trackballdown=function(x,y){var i,activeSub=self.getObj(activeSubscene),activeModel=self.getObj(self.useid(activeSub.id,"model")),l=activeModel.par3d.listeners;for(handlers.rotBase=self.screenToVector(x,y),self.saveMat=[],i=0;ij;j++)changepos[j]=-(dragCurrent[j]-handlers.dragBase[j]);activeSub.par3d.userMatrix.makeIdentity(),activeSub.par3d.userMatrix.rotate(180*changepos[0]/Math.PI,0,-1,0),activeSub.par3d.userMatrix.multRight(objects[l[i]].saveMat),activeSub.par3d.userMatrix.rotate(180*changepos[1]/Math.PI,-1,0,0)}self.drawScene()},handlers.polarend=0,handlers.axisdown=function(x){handlers.rotBase=self.screenToVector(x,self.canvas.height/2);var i,activeSub=self.getObj(activeSubscene),activeModel=self.getObj(self.useid(activeSub.id,"model")),l=activeModel.par3d.listeners;for(i=0;i1){var coords=self.relMouseCoords(touch),new_dist=handlers.get_finger_dist(ev);coords.y=self.canvas.height*Math.log(handlers.finger_dist0/new_dist)+handlers.y0zoom,handlers.zoommove(coords.x,coords.y)}else mouseEvent=new MouseEvent("pointermove",{clientX:touch.clientX,clientY:touch.clientY}),self.dispatchEvent(mouseEvent)},self.canvas.addEventListener("DOMMouseScroll",handlers.wheelHandler,!1),self.canvas.addEventListener("mousewheel",handlers.wheelHandler,!1),self.canvas.addEventListener("touchstart",handlers.touchstart,{passive:!1}),self.canvas.addEventListener("touchend",handlers.touchend,{passive:!1}),self.canvas.addEventListener("touchmove",handlers.touchmove,{passive:!1})},rglwidgetClass.prototype.initGL0=function(){return window.WebGLRenderingContext?void 0:void this.alertOnce("Your browser does not support WebGL. See http://get.webgl.org")},rglwidgetClass.prototype.initGL=function(){var self=this,success=!1;if(this.gl){if(this.drawing||!this.gl.isContextLost())return this.gl;this.restartCanvas()}this.canvas.addEventListener("webglcontextrestored",this.onContextRestored,!1),this.canvas.addEventListener("webglcontextlost",this.onContextLost,!1),this.gl=this.canvas.getContext("webgl",this.webGLoptions)||this.canvas.getContext("experimental-webgl",this.webGLoptions),success=!!(this.gl&&this.gl instanceof WebGLRenderingContext),success||this.alertOnce("Your browser does not support WebGL. See http://get.webgl.org"),this.index_uint=this.gl.getExtension("OES_element_index_uint");var save=this.startDrawing();return Object.keys(this.scene.objects).forEach(function(key){self.initObjId(parseInt(key,10))}),this.stopDrawing(save),this.gl},rglwidgetClass.prototype.resize=function(el){this.canvas.width=el.width,this.canvas.height=el.height},rglwidgetClass.prototype.initSphere=function(sections,segments){var i,j,k,ind,v=[],phi=[],theta=[],it=[],centers=[],result={};for(i=0;sections>=i;i++)phi.push(i/sections-.5);for(j=0;segments>=j;j++)for(theta.push(2*j/segments),i=0;sections>=i;i++)v.push([Math.sin(Math.PI*theta[j])*Math.cos(Math.PI*phi[i]),Math.sin(Math.PI*phi[i]),Math.cos(Math.PI*theta[j])*Math.cos(Math.PI*phi[i]),theta[j]/2,phi[i]+.5]);for(result.values=new Float32Array(rglwidgetClass.flatten(v)),result.vertexCount=v.length,j=0;segments>j;j++)for(i=0;sections>i;i++)ind=i+(sections+1)*j,i>0&&it.push([ind,ind+sections+1,ind+1]),sections-1>i&&it.push([ind+sections+1,ind+sections+2,ind+1]);for(result.it=new Uint16Array(rglwidgetClass.flatten(it)),i=0;ij;j++)for(k=0;3>k;k++)centers[i][j]+=v[it[i][k]][j]/3;result.centers=centers,result.vOffsets={vofs:0,cofs:-1,nofs:0,radofs:-1,oofs:-1,tofs:3,nextofs:-1,pointofs:-1,stride:5},result.f=[],result.indices={},result.colorCount=1,result.type="sphere",this.sphere=result,this.initShapeGL(this.sphere)},rglwidgetClass.prototype.initCube=function(){var i,j,k,i0,i1,i2,normal,v=[[0,0,0],[1,0,0],[0,1,0],[1,1,0],[0,0,1],[1,0,1],[0,1,1],[1,1,1]],ib=[[0,2,3,1],[2,6,7,3],[1,3,7,5],[0,4,6,2],[0,1,5,4],[4,5,7,6]],centers=[],result={};for(i=0;ij;j++)for(k=0;4>k;k++)centers[i][j]+=v[ib[i][k]][j]/4;for(result.centers=centers,result.values=new Float32Array(144),result.vertexCount=24,result.vertices=new Array(24),result.normals=new Array(24),i=0;6>i;i++){for(j=0;4>j;j++)for(i0=ib[i][j],result.vertices[4*i+j]=v[i0],i1=ib[i][(j+1)%4],i2=ib[i][(j+2)%4],0===j&&(normal=rglwidgetClass.normalize(rglwidgetClass.xprod(rglwidgetClass.vdiff(v[i1],v[i0]),rglwidgetClass.vdiff(v[i2],v[i0])))),result.normals[4*i+j]=normal,k=0;3>k;k++)result.values[24*i+6*j+k]=v[i0][k],result.values[24*i+6*j+3+k]=normal[k];for(j=0;4>j;j++)ib[i][j]=4*i+j}result.ib=new Uint16Array(rglwidgetClass.flatten(ib)),result.vOffsets={vofs:0,cofs:-1,nofs:3,radofs:-1,oofs:-1,tofs:-1,nextofs:-1,pointofs:-1,stride:6},result.f=[],result.indices={},result.colorCount=1,result.type="quads",this.cube=result,this.initShapeGL(this.cube)},rglwidgetClass.prototype.initShapeGL=function(shape){var gl=this.gl||this.initGL();gl.isContextLost()||(shape.buf=gl.createBuffer(),gl.bindBuffer(gl.ARRAY_BUFFER,shape.buf),gl.bufferData(gl.ARRAY_BUFFER,shape.values,gl.STATIC_DRAW),shape.ibuf=[gl.createBuffer(),gl.createBuffer()])},rglwidgetClass.prototype.initShapeFromObj=function(shape,obj){var i,pass,f,mode,self=this,is_back=function(i){var normal=[].concat(shape.normals[i]),pt=shape.vertices[i];return normal.push(-rglwidgetClass.dotprod(normal,pt)),normal=rglwidgetClass.multVM(normal,self.normMatrix),normal[2]<0||0===normal[2]&&normal[0]<0};if(shape.ofsLoc=obj.ofsLoc,shape.texLoc=obj.texLoc,shape.texture=obj.texture,shape.sampler=obj.sampler,shape.uFogMode=obj.uFogMode,shape.uFogColor=obj.uFogColor,shape.uFogParms=obj.uFogParms,shape.userAttribLocations=obj.userAttribLocations,shape.userUniformLocations=obj.userUniformLocations,shape.normLoc=obj.normLoc,shape.invPrMatLoc=obj.invPrMatLoc,shape.clipLoc=obj.clipLoc,shape.nextLoc=obj.nextLoc,shape.pointLoc=obj.pointLoc,shape.aspectLoc=obj.aspectLoc,shape.lwdLoc=obj.lwdLoc,shape.prog=obj.prog,shape.material=obj.material,shape.flags=obj.flags,shape.defFlags=obj.defFlags,shape.someHidden=obj.someHidden,shape.fastTransparency=obj.fastTransparency,shape.nlights=obj.nlights,shape.emission=obj.emission,shape.emissionLoc=obj.emissionLoc,shape.shininess=obj.shininess,shape.shininessLoc=obj.shininessLoc,shape.ambient=obj.ambient,shape.ambientLoc=obj.ambientLoc,shape.specular=obj.specular,shape.specularLoc=obj.specularLoc,shape.diffuse=obj.diffuse,shape.diffuseLoc=obj.diffuseLoc,shape.lightDir=obj.lightDir,shape.lightDirLoc=obj.lightDirLoc,shape.viewpoint=obj.viewpoint,shape.viewpointLoc=obj.viewpointLoc,shape.finite=obj.finite,shape.finiteLoc=obj.finiteLoc,shape.prMatLoc=obj.prMatLoc,shape.mvMatLoc=obj.mvMatLoc,shape.normMatLoc=obj.normMatLoc,shape.frontLoc=obj.frontLoc,shape.index_uint=!1,shape.is_transparent=obj.is_transparent,shape.ignoreExtent=obj.ignoreExtent,shape.passes!==obj.passes||JSON.stringify(shape.pmode)!==JSON.stringify(obj.pmode))for(shape.passes=obj.passes,shape.pmode=obj.pmode,pass=0;pass1?[obj.colors[1]]:[obj.colors[0]],axes:obj.axes,initialized:!1},this.scene.objects[obj.ticks.id]=obj.ticks,obj.labels={id:obj.id+.3,type:"text",flags:rglwidgetClass.f_has_fog+rglwidgetClass.f_fixed_size+rglwidgetClass.f_fixed_quads,material:{lit:!1},colors:obj.colors.length>1?[obj.colors[1]]:[obj.colors[0]],cex:[[1]],family:[["sans"]],font:[[1]],adj:[[.5,.5,.5]],ignoreExtent:!0,initialized:!1},this.scene.objects[obj.labels.id]=obj.labels,obj.initialized=!0},rglwidgetClass.prototype.initBackground=function(obj){var material,fl=obj.defFlags;"undefined"!=typeof obj.ids?obj.quad=rglwidgetClass.flatten([].concat(obj.ids)):obj.sphere&&(fl.has_normals=!0,fl.needs_vnormal=!0,obj.defFlags=fl,material=obj.material,material.front="culled",obj.vertices=[[0,0,0]],obj.texcoords=[[0,0]])},rglwidgetClass.prototype.initObjId=function(id){return"number"!=typeof id&&this.alertOnce("initObj id is "+typeof id),this.initObj(this.getObj(id))},rglwidgetClass.prototype.initObj=function(obj){var fl,polygon_offset,texinfo,drawtype,nclipplanes,f,nrows,oldrows,i,j,v,v1,v2,mat,uri,matobj,pass,pmode,dim,nx,nz,nrow,shaders,type=obj.type,flags=obj.flags,normals=obj.normals,round_points="undefined"==typeof obj.material?!1:this.getMaterial(obj,"point_antialias"),has_indices="undefined"!=typeof obj.indices,has_spheres="spheres"===type||"background"===type&&obj.sphere,sprites_3d=rglwidgetClass.isSet(flags,rglwidgetClass.f_sprites_3d),depth_sort=rglwidgetClass.isSet(flags,rglwidgetClass.f_depth_sort),gl=this.gl||this.initGL();if(obj.initialized=!0,obj.someHidden=!1,this.expandBufferedFields(obj),"subscene"!==type){if(obj.defFlags=fl=rglwidgetClass.getDefFlags(flags,type,normals,round_points),obj.is_transparent=fl.is_transparent,"bboxdeco"===type)return this.initBBox(obj);if(has_spheres&&"undefined"==typeof this.sphere&&this.initSphere(16,16),"light"===type)return obj.ambient=new Float32Array(obj.colors[0].slice(0,3)),obj.diffuse=new Float32Array(obj.colors[1].slice(0,3)),obj.specular=new Float32Array(obj.colors[2].slice(0,3)),void(obj.lightDir=new Float32Array(obj.vertices[0]));if("clipplanes"===type)return void(obj.vClipplane=rglwidgetClass.flatten(rglwidgetClass.cbind(obj.normals,obj.offsets)));if(("background"!==type||(this.initBackground(obj),obj.sphere))&&(polygon_offset=this.getMaterial(obj,"polygon_offset"),(0!==polygon_offset[0]||0!==polygon_offset[1])&&(obj.polygon_offset=polygon_offset),fl.is_transparent&&(depth_sort=["triangles","quads","surface","spheres","sprites","text","planes"].indexOf(type)>=0),fl.is_brush&&this.initSelection(obj.id),"undefined"==typeof obj.vertices&&(obj.vertices=[]),v=obj.vertices,obj.vertexCount=has_indices?obj.indices.length:v.length,obj.vertexCount)){if(fl.is_twosided&&!fl.has_normals&&"background"!==type){if("undefined"==typeof obj.userAttributes&&(obj.userAttributes={}),v1=Array(v.length),v2=Array(v.length),"triangles"===obj.type||"quads"===obj.type)for(nrow="triangles"===obj.type?3:4,i=0;ij;j++)v1[nrow*i+j]=v[nrow*i+(j+1)%nrow],v2[nrow*i+j]=v[nrow*i+(j+2)%nrow];else if("surface"===obj.type)for(dim=obj.dim[0],nx=dim[0],nz=dim[1],j=0;nx>j;j++)for(i=0;nz>i;i++)nz>i+1&&nx>j+1?(v2[j+nx*i]=v[j+nx*(i+1)],v1[j+nx*i]=v[j+1+nx*(i+1)]):nz>i+1?(v2[j+nx*i]=v[j-1+nx*i],v1[j+nx*i]=v[j+nx*(i+1)]):(v2[j+nx*i]=v[j+nx*(i-1)],v1[j+nx*i]=v[j-1+nx*(i-1)]);obj.userAttributes.aPos1=v1,obj.userAttributes.aPos2=v2}if(!sprites_3d){if(gl.isContextLost())return;"undefined"!=typeof obj.prog&&(gl.deleteProgram(obj.prog),obj.prog=void 0),shaders=this.getShaders(obj),obj.prog=gl.createProgram(),gl.attachShader(obj.prog,this.getShader(gl.VERTEX_SHADER,shaders.vertex)),gl.attachShader(obj.prog,this.getShader(gl.FRAGMENT_SHADER,shaders.fragment)),gl.bindAttribLocation(obj.prog,0,"aPos"),gl.bindAttribLocation(obj.prog,1,"aCol"),gl.linkProgram(obj.prog);var linked=gl.getProgramParameter(obj.prog,gl.LINK_STATUS);if(!linked){var lastError=gl.getProgramInfoLog(obj.prog);return console.warn("Error in program linking:"+lastError),void gl.deleteProgram(obj.prog)}}"text"===type&&(texinfo=this.drawTextToCanvas(obj.texts,rglwidgetClass.flatten(obj.cex),rglwidgetClass.flatten(obj.family),rglwidgetClass.flatten(obj.family))),fl.fixed_quads&&!sprites_3d&&(obj.ofsLoc=gl.getAttribLocation(obj.prog,"aOfs")),(fl.has_texture||"text"===type)&&(obj.texture||(obj.texture=gl.createTexture(),gl.bindTexture(gl.TEXTURE_2D,obj.texture),gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,1,1,0,gl.RGBA,gl.UNSIGNED_BYTE,new Uint8Array([255,255,255,255]))),obj.texLoc=gl.getAttribLocation(obj.prog,"aTexcoord"),obj.sampler=gl.getUniformLocation(obj.prog,"uSampler")),fl.has_fog&&!sprites_3d&&(obj.uFogMode=gl.getUniformLocation(obj.prog,"uFogMode"),obj.uFogColor=gl.getUniformLocation(obj.prog,"uFogColor"),obj.uFogParms=gl.getUniformLocation(obj.prog,"uFogParms")),fl.has_texture&&(mat=obj.material,"undefined"!=typeof mat.uri?uri=mat.uri:"undefined"==typeof mat.uriElementId?(matobj=this.getObj(mat.uriId),uri="undefined"!=typeof matobj?matobj.material.uri:""):uri=document.getElementById(mat.uriElementId).rglinstance.getObj(mat.uriId).material.uri,this.loadImageToTexture(uri,obj.texture)),"text"===type&&this.handleLoadedTexture(obj.texture,this.textureCanvas); var nc,cofs,nofs,radofs,oofs,tofs,vnew,fnew,alias,colors,key,selection,filter,adj,offset,attr,last,options,len,current,stride=3,nextofs=-1,pointofs=-1;if(obj.alias=void 0,colors=obj.colors,j=this.scene.crosstalk.id.indexOf(obj.id),j>=0){for(key=this.scene.crosstalk.key[j],options=this.scene.crosstalk.options[j],colors=colors.slice(0),i=0;i1?(cofs=stride,stride+=4,v=rglwidgetClass.cbind(v,colors)):(cofs=-1,obj.onecolor=rglwidgetClass.flatten(colors)),fl.has_normals&&!has_spheres?(nofs=stride,stride+=3,v=rglwidgetClass.cbind(v,"undefined"!=typeof obj.pnormals?obj.pnormals:obj.normals)):nofs=-1,"undefined"!=typeof obj.radii?(radofs=stride,stride+=1,obj.radii.length===v.length?v=rglwidgetClass.cbind(v,obj.radii):1===obj.radii.length&&(v=v.map(function(row){return row.concat(obj.radii[0])}))):radofs=-1,has_indices)for(f=Array(obj.indices.length),i=0;ij;j++)v1=vnew[fnew[4*i+j]],v1[oofs]=2*(v1[tofs]-v1[oofs])*texinfo.widths[i],v1[oofs+1]=2*(v1[tofs+1]-v1[oofs+1])*texinfo.textHeights[i],v1[oofs+2]=2*(.5-v1[oofs+2])*texinfo.textHeights[i]/1e3,v1[tofs]=(texinfo.offsetsx[i]+v1[tofs]*texinfo.widths[i])/texinfo.canvasX,v1[tofs+1]=1-(texinfo.offsetsy[i]-v1[tofs+1]*texinfo.textHeights[i])/texinfo.canvasY,vnew[fnew[4*i+j]]=v1;v=vnew,obj.vertexCount=v.length,obj.f=[fnew,fnew]}else"undefined"!=typeof obj.texcoords?(tofs=stride,stride+=2,oofs=-1,v=rglwidgetClass.cbind(v,obj.texcoords)):(tofs=-1,oofs=-1);else{tofs=stride,stride+=2,oofs=stride,stride+=3,vnew=new Array(4*v.length),fnew=new Array(4*v.length),alias=new Array(v.length);var rescale=fl.fixed_size?72:1,size=obj.radii,s=rescale*size[0]/2;for(last=v.length,f=obj.f[0],obj.adj=rglwidgetClass.flatten(obj.adj),"undefined"!=typeof obj.pos?(obj.pos=rglwidgetClass.flatten(obj.pos),offset=obj.adj[0]):offset=0,i=0;i1&&(s=rescale*size[i]/2),adj[0]=2*s*(adj[0]-.5),adj[1]=2*s*(adj[1]-.5),adj[2]=2*s*(adj[2]-.5),vnew[i]=v[i].concat([0,0]).concat([-s-adj[0],-s-adj[1],-adj[2]]),fnew[4*i]=f[i],vnew[last]=v[i].concat([1,0]).concat([s-adj[0],-s-adj[1],-adj[2]]),fnew[4*i+1]=last++,vnew[last]=v[i].concat([1,1]).concat([s-adj[0],s-adj[1],-adj[2]]),fnew[4*i+2]=last++,vnew[last]=v[i].concat([0,1]).concat([-s-adj[0],s-adj[1],-adj[2]]),fnew[4*i+3]=last++,alias[i]=[last-3,last-2,last-1];v=vnew,obj.vertexCount=v.length,obj.f=[fnew,fnew]}if(obj.alias=alias,"undefined"!=typeof obj.userAttributes){obj.userAttribOffsets={},obj.userAttribLocations={},obj.userAttribSizes={};for(attr in obj.userAttributes)obj.userAttribLocations[attr]=gl.getAttribLocation(obj.prog,attr),obj.userAttribLocations[attr]>=0?(obj.userAttribOffsets[attr]=stride,v=rglwidgetClass.cbind(v,obj.userAttributes[attr]),stride=v[0].length,obj.userAttribSizes[attr]=stride-obj.userAttribOffsets[attr]):console.warn("attribute '"+attr+"' not found in object "+obj.id+".")}if("undefined"!=typeof obj.userUniforms||"undefined"!=typeof obj.userTextures){obj.userUniformLocations={};for(attr in obj.userUniforms)obj.userUniformLocations[attr]=gl.getUniformLocation(obj.prog,attr),null===obj.userUniformLocations[attr]&&console.warn("uniform '"+attr+"' not found in object "+obj.id+".");for(attr in obj.userTextures){var texture=obj.userTextures[attr];texture.texture=gl.createTexture(),gl.bindTexture(gl.TEXTURE_2D,texture.texture),gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,1,1,0,gl.RGBA,gl.UNSIGNED_BYTE,new Uint8Array([255,255,255,255])),texture.sampler=gl.getUniformLocation(obj.prog,attr),null===texture.sampler&&console.warn("sampler '"+attr+"' not found in object "+obj.id+"."),uri=texture.uri,this.loadImageToTexture(uri,texture.texture)}}if(sprites_3d){obj.userMatrix=new CanvasMatrix4,obj.userMatrix.load(rglwidgetClass.flatten(obj.usermatrix)),obj.objects=rglwidgetClass.flatten([].concat(obj.ids)),fl.is_lit=!1,obj.adj=rglwidgetClass.flatten(obj.adj),"undefined"!=typeof obj.pos?(obj.pos=rglwidgetClass.flatten(obj.pos),obj.offset=obj.adj[0]):obj.offset=0;var shapenum=rglwidgetClass.flatten(obj.shapenum);for(obj.shapelens=[],obj.shapefirst=[],obj.shapefirst.push(0),len=0,current=0,i=0;i0&&(obj.ambient=new Float32Array(this.stringToRgb(this.getMaterial(obj,"ambient"))),obj.specular=new Float32Array(this.stringToRgb(this.getMaterial(obj,"specular"))),obj.ambientLoc=gl.getUniformLocation(obj.prog,"ambient"),obj.specularLoc=gl.getUniformLocation(obj.prog,"specular"),obj.diffuseLoc=gl.getUniformLocation(obj.prog,"diffuse"),obj.lightDirLoc=gl.getUniformLocation(obj.prog,"lightDir"),obj.viewpointLoc=gl.getUniformLocation(obj.prog,"viewpoint"),obj.finiteLoc=gl.getUniformLocation(obj.prog,"finite"))),obj.passes=fl.is_twosided+1,obj.pmode=new Array(obj.passes),pass=0;passi;i++)fnew[6*i]=f[3*i],fnew[6*i+1]=f[3*i+1],fnew[6*i+2]=f[3*i+1],fnew[6*i+3]=f[3*i+2],fnew[6*i+4]=f[3*i+2],fnew[6*i+5]=f[3*i]}else if(has_spheres);else if("surface"===type)if(dim=obj.dim[0],nx=dim[0],nz=dim[1],"filled"===pmode)for(fnew=[],j=0;nx-1>j;j++)for(i=0;nz-1>i;i++)fnew.push(f[j+nx*i],f[j+nx*(i+1)],f[j+1+nx*(i+1)],f[j+nx*i],f[j+1+nx*(i+1)],f[j+1+nx*i]);else if("lines"===pmode)for(fnew=[],j=0;nx>j;j++)for(i=0;nz>i;i++)nz>i+1&&fnew.push(f[j+nx*i],f[j+nx*(i+1)]),nx>j+1&&fnew.push(f[j+nx*i],f[j+1+nx*i])}else if(nrows=Math.floor(obj.vertexCount/4),"filled"===pmode)for(fnew=Array(6*nrows),i=0;nrows>i;i++)fnew[6*i]=f[4*i],fnew[6*i+1]=f[4*i+1],fnew[6*i+2]=f[4*i+2],fnew[6*i+3]=f[4*i],fnew[6*i+4]=f[4*i+2],fnew[6*i+5]=f[4*i+3];else for(fnew=Array(8*nrows),i=0;nrows>i;i++)fnew[8*i]=f[4*i],fnew[8*i+1]=f[4*i+1],fnew[8*i+2]=f[4*i+1],fnew[8*i+3]=f[4*i+2],fnew[8*i+4]=f[4*i+2],fnew[8*i+5]=f[4*i+3],fnew[8*i+6]=f[4*i+3],fnew[8*i+7]=f[4*i];obj.f[pass]=fnew,drawtype=depth_sort?"DYNAMIC_DRAW":"STATIC_DRAW"}if(fl.fat_lines){for(alias=void 0,obj.nextLoc=gl.getAttribLocation(obj.prog,"aNext"),obj.pointLoc=gl.getAttribLocation(obj.prog,"aPoint"),obj.aspectLoc=gl.getUniformLocation(obj.prog,"uAspect"),obj.lwdLoc=gl.getUniformLocation(obj.prog,"uLwd"),pass=0;passj;j++)vnew[k][nextofs+j]=vnew[f[i+1]][j];for(vnew[k][pointofs]=-1,vnew[k][pointofs+1]=-1,fnew[ind]=k,last++,vnew[last]=vnew[k].slice(),vnew[last][pointofs]=1,fnew[ind+1]=last,alias[f[i]].push(last-1,last),last++,k=last,vnew[k]=vnew[f[i+1]].slice(),j=0;3>j;j++)vnew[k][nextofs+j]=vnew[f[i]][j];vnew[k][pointofs]=-1,vnew[k][pointofs+1]=1,fnew[ind+2]=k,fnew[ind+3]=fnew[ind+1],last++,vnew[last]=vnew[k].slice(),vnew[last][pointofs]=1,fnew[ind+4]=last,fnew[ind+5]=fnew[ind+2],ind+=6,alias[f[i+1]].push(last-1,last)}if(vnew.length=last+1,v=vnew,obj.vertexCount=v.length,"undefined"!=typeof alias&&"undefined"!=typeof obj.alias){var oldalias=obj.alias,newalias=Array(obj.alias.length);for(i=0;i65535?this.index_uint?(obj.f[pass]=new Uint32Array(obj.f[pass]),obj.index_uint=!0):this.alertOnce("Object has "+obj.vertexCount+" vertices, not supported in this browser."):(obj.f[pass]=new Uint16Array(obj.f[pass]),obj.index_uint=!1);stride!==v[0].length&&this.alertOnce("problem in stride calculation"),obj.vOffsets={vofs:0,cofs:cofs,nofs:nofs,radofs:radofs,oofs:oofs,tofs:tofs,nextofs:nextofs,pointofs:pointofs,stride:stride},obj.values=new Float32Array(rglwidgetClass.flatten(v)),has_spheres||sprites_3d||(obj.buf=gl.createBuffer(),gl.bindBuffer(gl.ARRAY_BUFFER,obj.buf),gl.bufferData(gl.ARRAY_BUFFER,obj.values,gl.STATIC_DRAW),obj.ibuf=Array(obj.passes),obj.ibuf[0]=gl.createBuffer(),gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,obj.ibuf[0]),gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,obj.f[0],gl[drawtype]),fl.is_twosided&&(obj.ibuf[1]=gl.createBuffer(),gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER,obj.ibuf[1]),gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,obj.f[1],gl[drawtype]))),sprites_3d||(obj.mvMatLoc=gl.getUniformLocation(obj.prog,"mvMatrix"),obj.prMatLoc=gl.getUniformLocation(obj.prog,"prMatrix"),fl.fixed_size&&(obj.textScaleLoc=gl.getUniformLocation(obj.prog,"textScale"))),fl.needs_vnormal&&(obj.normLoc=gl.getAttribLocation(obj.prog,"aNorm"),obj.normMatLoc=gl.getUniformLocation(obj.prog,"normMatrix")),fl.is_twosided&&(obj.frontLoc=gl.getUniformLocation(obj.prog,"front"),fl.has_normals&&(obj.invPrMatLoc=gl.getUniformLocation(obj.prog,"invPrMatrix")))}}},rglwidgetClass.prototype.initialize=function(el,x){if(this.textureCanvas=document.createElement("canvas"),this.textureCanvas.style.display="block",this.scene=x,this.normMatrix=new CanvasMatrix4,this.invPrMatrix=new CanvasMatrix4,this.saveMat={},this.distance=null,this.posLoc=0,this.colLoc=1,el&&(el.rglinstance=this,this.el=el,this.webGLoptions=el.rglinstance.scene.webGLoptions,this.initCanvas()),"undefined"!=typeof Shiny){var self=this;Shiny.addCustomMessageHandler("shinyGetPar3d",function(message){var i,param,subscene=self.getObj(message.subscene),parameters=[].concat(message.parameters),result={tag:message.tag,subscene:message.subscene};if("undefined"!=typeof subscene)for(i=0;ii;i++)z=this.prmvMatrix.m13*obj.centers[i][0]+this.prmvMatrix.m23*obj.centers[i][1]+this.prmvMatrix.m33*obj.centers[i][2]+this.prmvMatrix.m43,w=this.prmvMatrix.m14*obj.centers[i][0]+this.prmvMatrix.m24*obj.centers[i][1]+this.prmvMatrix.m34*obj.centers[i][2]+this.prmvMatrix.m44,depth=z/w,meandepth+=depth,result[i]={context:context,objid:objid,subid:subid,index:i,depth:depth,meandepth:0};for(meandepth/=n,i=0;n>i;i++)result[i].meandepth=meandepth;return result},rglwidgetClass.prototype.getSpherePieces=function(context,subid,obj){return obj.fastTransparency?0===subid?this.getPieces(context,obj.id,-1,obj):[]:this.getPieces(context,obj.id,subid,this.sphere)},rglwidgetClass.prototype.getCubePieces=function(context,obj){return this.getPieces(context,obj.id,0,this.cube)},rglwidgetClass.prototype.mergePieces=function(pieces){var result=[];if(pieces.length>0){var i,thiscontext=pieces[0].context,thisobjid=pieces[0].objid,thissubid=pieces[0].subid,indices=[];for(i=0;i0;)diff=c1.pop()-c2.pop();return 0!==diff?diff:diff=j.depth-i.depth},result=[];return pieces.length&&(result=pieces.sort(compare)),result},rglwidgetClass.prototype.startDrawing=function(){var value=this.drawing;return this.drawing=!0,value},rglwidgetClass.prototype.stopDrawing=function(saved){this.drawing=saved,!saved&&this.gl&&this.gl.isContextLost()&&this.restartCanvas()},rglwidgetClass.prototype.planeUpdateTriangles=function(obj,bbox){var x,xrow,elem,A,d,nhits,i,j,k,u,v,w,intersect,which,v0,v2,vx,reverse,idx,center,perms=[[0,0,1],[1,2,2],[2,1,0]],face1=[],face2=[],normals=[],nPlanes=obj.normals.length;for(obj.bbox=bbox,obj.vertices=[],obj.centers=[],obj.initialized=!1,elem=0;nPlanes>elem;elem++){for(x=[],A=obj.normals[elem],d=obj.offsets[elem][0],nhits=0,i=0;3>i;i++)for(j=0;2>j;j++)for(k=0;2>k;k++)u=perms[0][i],v=perms[1][i],w=perms[2][i],0!==A[w]&&(intersect=-(d+A[u]*bbox[j+2*u]+A[v]*bbox[k+2*v])/A[w],bbox[2*w]3)for(i=0;nhits-2>i;i++){for(which=0,j=i+1;nhits>j;j++)if(face1[i]===face1[j]||face1[i]===face2[j]||face2[i]===face1[j]||face2[i]===face2[j]){which=j;break}which>i+1&&(rglwidgetClass.swap(x,i+1,which),rglwidgetClass.swap(face1,i+1,which),rglwidgetClass.swap(face2,i+1,which))}if(nhits>=3)for(v0=[x[0][0]-x[1][0],x[0][1]-x[1][1],x[0][2]-x[1][2]],v2=[x[2][0]-x[1][0],x[2][1]-x[1][1],x[2][2]-x[1][2]],vx=rglwidgetClass.xprod(v0,v2),reverse=rglwidgetClass.dotprod(vx,A)>0,i=0;nhits-2>i;i++){for(obj.vertices.push(x[0]),center=[],k=0;3>k;k++)center.push(x[0][k]/3);for(normals.push(A),j=1;3>j;j++){for(idx=i+(reverse?3-j:j),obj.vertices.push(x[idx]),k=0;3>k;k++)center[k]+=x[idx][k]/3;normals.push(A)}obj.centers.push(center)}}obj.pnormals=normals},rglwidgetClass.prototype.mode4type={points:"POINTS",linestrip:"LINE_STRIP",abclines:"LINES",lines:"LINES",sprites:"TRIANGLES",planes:"TRIANGLES",text:"TRIANGLES",quads:"TRIANGLES",surface:"TRIANGLES",triangles:"TRIANGLES",sphere:"TRIANGLES"},rglwidgetClass.prototype.disableArrays=function(obj,enabled){var i,attr,gl=this.gl||this.initGL(),objLocs=["normLoc","texLoc","ofsLoc","pointLoc","nextLoc"],thisLocs=["posLoc","colLoc"];for(i=0;i0){for(clipplanedata=new Float32Array(4*n),i=0;ii;i++){for(light=this.getObj(subscene.lights[i]),light.initialized||this.initObj(light),ambient0=this.componentProduct(light.ambient,obj.ambient),specular0=this.componentProduct(light.specular,obj.specular),j=0;3>j;j++)ambient[3*i+j]=ambient0[j],specular[3*i+j]=specular0[j],diffuse[3*i+j]=light.diffuse[j],lightDir[3*i+j]=light.lightDir[j];viewpoint[i]=light.viewpoint,finite[i]=light.finite}for(i=n;ij;j++)ambient[3*i+j]=0,specular[3*i+j]=0,diffuse[3*i+j]=0;gl.uniform3fv(obj.ambientLoc,ambient),gl.uniform3fv(obj.specularLoc,specular),gl.uniform3fv(obj.diffuseLoc,diffuse),gl.uniform3fv(obj.lightDirLoc,lightDir),gl.uniform1iv(obj.viewpointLoc,viewpoint),gl.uniform1iv(obj.finiteLoc,finite)}},rglwidgetClass.prototype.doColors=function(obj){var gl=this.gl;return 1===obj.colorCount?(gl.disableVertexAttribArray(this.colLoc),gl.vertexAttrib4fv(this.colLoc,new Float32Array(obj.onecolor)),!1):(gl.enableVertexAttribArray(this.colLoc),gl.vertexAttribPointer(this.colLoc,4,gl.FLOAT,!1,4*obj.vOffsets.stride,4*obj.vOffsets.cofs),!0)},rglwidgetClass.prototype.doNormals=function(obj){var gl=this.gl;return obj.vOffsets.nofs>=0?(gl.enableVertexAttribArray(obj.normLoc),gl.vertexAttribPointer(obj.normLoc,3,gl.FLOAT,!1,4*obj.vOffsets.stride,4*obj.vOffsets.nofs),!0):!1},rglwidgetClass.prototype.doNormMat=function(obj){var gl=this.gl;gl.uniformMatrix4fv(obj.normMatLoc,!1,new Float32Array(this.normMatrix.getAsArray()))},rglwidgetClass.prototype.doTexture=function(obj){var gl=this.gl,is_sphere="sphere"===obj.type;return gl.enableVertexAttribArray(obj.texLoc),is_sphere?gl.vertexAttribPointer(obj.texLoc,2,gl.FLOAT,!1,4*this.sphere.vOffsets.stride,4*this.sphere.vOffsets.tofs):gl.vertexAttribPointer(obj.texLoc,2,gl.FLOAT,!1,4*obj.vOffsets.stride,4*obj.vOffsets.tofs),gl.activeTexture(gl.TEXTURE0),gl.bindTexture(gl.TEXTURE_2D,obj.texture),gl.uniform1i(obj.sampler,0),!0},rglwidgetClass.prototype.doUserAttributes=function(obj){if("undefined"!=typeof obj.userAttributes){var gl=this.gl;for(var attr in obj.userAttribSizes)gl.enableVertexAttribArray(obj.userAttribLocations[attr]),gl.vertexAttribPointer(obj.userAttribLocations[attr],obj.userAttribSizes[attr],gl.FLOAT,!1,4*obj.vOffsets.stride,4*obj.userAttribOffsets[attr])}},rglwidgetClass.prototype.doUserUniforms=function(obj){var attr,gl=this.gl;if("undefined"!=typeof obj.userUniforms)for(attr in obj.userUniformLocations){var loc=obj.userUniformLocations[attr];if(null!==loc){var uniform=obj.userUniforms[attr];if("undefined"!=typeof uniform){var dim=rglwidgetClass.arrayDim(uniform);if(0===dim.length)gl.uniform1f(loc,uniform);else if(1===dim.length)switch(uniform=new Float32Array(uniform),uniform.length){case 2:gl.uniform2fv(loc,uniform);break;case 3:gl.uniform3fv(loc,uniform);break;case 4:gl.uniform4fv(loc,uniform);break;default:console.warn("bad uniform length")}else if(2===dim.length&&4===dim[0]&&4===dim[1])gl.uniformMatrix4fv(loc,!1,new Float32Array(rglwidgetClass.flatten(uniform)));else if(2===dim.length)switch(uniform=new Float32Array(rglwidgetClass.flatten(uniform)),dim[[1]]){case 1:gl.uniform1fv(loc,uniform);break;case 2:gl.uniform2fv(loc,uniform);break;case 3:gl.uniform3fv(loc,uniform);break;case 4:gl.uniform4fv(loc,uniform);break;default:console.warn("bad uniform column count")}else console.warn("unsupported uniform shape")}}}if("undefined"!=typeof obj.userTextures){var has_texture=rglwidgetClass.isSet(obj.flags,rglwidgetClass.f_has_texture),texnum=has_texture-1;for(attr in obj.userTextures){var texture=obj.userTextures[attr];null!==texture.sampler&&(texnum+=1,gl.activeTexture(gl.TEXTURE0+texnum),gl.bindTexture(gl.TEXTURE_2D,texture.texture),gl.uniform1i(texture.sampler,texnum))}}},rglwidgetClass.prototype.doLoadIndices=function(obj,pass,indices){var fnew,step,gl=this.gl,f=obj.f[pass],type=obj.type,fat_lines=rglwidgetClass.isSet(obj.flags,rglwidgetClass.f_fat_lines);switch(type){case"points":step=1;break;case"abclines":case"lines":step=fat_lines?6:2;break;case"linestrip":step=fat_lines?6:1;break;case"sphere":case"planes":case"triangles":step=3;break;case"text":case"sprites":case"quads":case"surface":step=6;break;default:return console.error("loadIndices for "+type),0}fnew=obj.index_uint?new Uint32Array(step*indices.length):new Uint16Array(step*indices.length);for(var i=0;ij;j++)fnew[step*i+j]=f[step*indices[i]+j];return gl.bufferData(gl.ELEMENT_ARRAY_BUFFER,fnew,gl.DYNAMIC_DRAW),fnew.length},rglwidgetClass.prototype.doMasking=function(mask){var gl=this.gl;gl.depthMask(mask)},rglwidgetClass.prototype.doBlending=function(blend,objid){var blendfunc,obj,gl=this.gl,blends={zero:gl.ZERO,one:gl.ONE,src_color:gl.SRC_COLOR,one_minus_src_color:gl.ONE_MINUS_SRC_COLOR,dst_color:gl.DST_COLOR,one_minus_dst_color:gl.ONE_MINUS_DST_COLOR,src_alpha:gl.SRC_ALPHA,one_minus_src_alpha:gl.ONE_MINUS_SRC_ALPHA,dst_alpha:gl.DST_ALPHA,one_minus_dst_alpha:gl.ONE_MINUS_DST_ALPHA,constant_color:gl.CONSTANT_COLOR,one_minus_constant_color:gl.ONE_MINUS_CONSTANT_COLOR,constant_alpha:gl.CONSTANT_ALPHA,one_minus_constant_alpha:gl.ONE_MINUS_CONSTANT_ALPHA,src_alpha_saturate:gl.SRC_ALPHA_SATURATE};blend?(obj=this.getObj(objid),blendfunc=this.getMaterial(obj,"blend"),gl.blendFuncSeparate(blends[blendfunc[0]],blends[blendfunc[1]],gl.ONE,gl.ONE),gl.enable(gl.BLEND)):gl.disable(gl.BLEND)},rglwidgetClass.prototype.doFog=function(obj,subscene){var fogmode,color,gl=this.gl,observer=subscene.par3d.observer[2],sintheta=Math.sin(subscene.par3d.FOV*Math.PI/180/2),parms=[this.frustum.near-2*observer,this.frustum.far-2*observer,this.fogScale,(1-sintheta)/(1+sintheta)];switch("undefined"==typeof this.fogType&&(this.fogType="none"),"undefined"==typeof this.fogScale&&(parms[2]=1),0===sintheta&&(parms[3]=1/3),this.fogType){case"none":fogmode=0;break;case"linear":fogmode=1;break;case"exp":fogmode=2;break;case"exp2":fogmode=3;break;default:console.error("Unknown fogtype "+this.fogType)}gl.uniform1i(obj.uFogMode,fogmode),color=this.fogColor,gl.uniform3f(obj.uFogColor,color[0],color[1],color[2]),gl.uniform4f(obj.uFogParms,parms[0],parms[1],parms[2],parms[3])},rglwidgetClass.prototype.drawSimple=function(obj,subscene,context){var fl,is_transparent,count,pass,mode,pmode,type=obj.type,gl=this.gl||this.initGL(),enabled={};if(obj.initialized||this.initObj(obj),this.texturesLoading)return[];if(count=obj.vertexCount,!count)return[];if(fl=obj.defFlags,is_transparent=fl.is_transparent||obj.someHidden,is_transparent&&this.opaquePass)return this.getPieces(context,obj.id,0,obj);for(this.doDepthTest(obj),this.doMasking(this.getMaterial(obj,"depth_mask")),gl.useProgram(obj.prog),this.doPolygonOffset(obj),gl.bindBuffer(gl.ARRAY_BUFFER,obj.buf),gl.uniformMatrix4fv(obj.prMatLoc,!1,new Float32Array(this.prMatrix.getAsArray())),gl.uniformMatrix4fv(obj.mvMatLoc,!1,new Float32Array(this.mvMatrix.getAsArray())),this.doClipping(obj,subscene),fl.needs_vnormal&&this.doNormMat(obj),fl.is_lit&&this.doLighting(obj,subscene),fl.has_fog&&this.doFog(obj,subscene),this.doUserAttributes(obj),this.doUserUniforms(obj),gl.enableVertexAttribArray(this.posLoc),enabled.posLoc=!0,(fl.has_texture||"text"===obj.type)&&(enabled.texLoc=this.doTexture(obj)),enabled.colLoc=this.doColors(obj),enabled.normLoc=this.doNormals(obj),fl.fixed_size&&gl.uniform3f(obj.textScaleLoc,.75/this.vp.width,.75/this.vp.height,1),fl.fixed_quads&&(gl.enableVertexAttribArray(obj.ofsLoc),enabled.ofsLoc=!0,gl.vertexAttribPointer(obj.ofsLoc,3,gl.FLOAT,!1,4*obj.vOffsets.stride,4*obj.vOffsets.oofs)),pass=0;passi;i++)sphereMV=new CanvasMatrix4,idx=this.opaquePass?i:obj.fastTransparency?indices[i]:context.subid,"undefined"==typeof idx&&console.error("idx is undefined"),baseofs=idx*obj.vOffsets.stride,ofs=baseofs+obj.vOffsets.radofs,sscale=obj.values[ofs],sphereMV.scale(sscale/scale[0],sscale/scale[1],sscale/scale[2]),sphereMV.translate(obj.values[baseofs],obj.values[baseofs+1],obj.values[baseofs+2]),sphereMV.multRight(saveMV),this.mvMatrix=sphereMV,this.setnormMatrix2(),this.setprmvMatrix(),drawing?(nc>1&&(this.sphere.onecolor=obj.values.slice(baseofs+obj.vOffsets.cofs,baseofs+obj.vOffsets.cofs+4)),this.drawSimple(this.sphere,subscene,context)):result=result.concat(this.getSpherePieces(context,i,obj)); return drawing&&this.disableArrays(obj,enabled),this.normMatrix=saveNorm,this.mvMatrix=saveMV,this.prmvMatrix=savePRMV,result},rglwidgetClass.prototype.drawClipplanes=function(obj){for(var count=obj.offsets.length,IMVClip=[],i=0;count>i;i++)IMVClip[i]=rglwidgetClass.multMV(this.invMatrix,obj.vClipplane.slice(4*i,4*(i+1)));return obj.IMVClip=IMVClip,[]},rglwidgetClass.prototype.drawLinestrip=function(obj,subscene,context){var origIndices,i,j,margin=obj.material.margin;if("undefined"!=typeof margin&&!this.marginVecToDataVec(obj,subscene))return[];if(this.opaquePass)return this.drawSimple(obj,subscene,context);for(origIndices=context.indices.slice(),i=0;iiOrig;iOrig++){if(j=this.opaquePass?iOrig:context.subid,pos=[].concat(obj.vertices[j]).concat(1),radius=obj.radii.length>1?obj.radii[j][0]:obj.radii[0][0],this.mvMatrix=new CanvasMatrix4(userMatrix),adj=this.getAdj(obj,j,offset),this.mvMatrix.translate(1-2*adj[0],1-2*adj[1],1-2*adj[2]),this.mvMatrix.scale(radius,radius,radius),fixed_size){var viewport=subscene.par3d.viewport,winwidth=viewport.width*this.canvas.width,winheight=viewport.height*this.canvas.height,scalex=27/winwidth,scaley=27/winheight,scale=Math.sqrt(scalex*scaley);rotating?(scale=4*scale*subscene.par3d.zoom,this.mvMatrix.scale(scale,scale,scale)):(pos=rglwidgetClass.multVM(pos,origMV),pos=rglwidgetClass.multVM(pos,origPR),this.mvMatrix.scale(scalex,scaley,scale)),this.mvMatrix.translate(pos[0]/pos[3],pos[1]/pos[3],pos[2]/pos[3]),rotating&&this.mvMatrix.multRight(origMV)}else rotating?(this.mvMatrix.translate(pos[0]/pos[3],pos[1]/pos[3],pos[2]/pos[3]),this.mvMatrix.multRight(origMV)):(pos=rglwidgetClass.multVM(pos,origMV),this.mvMatrix.translate(pos[0]/pos[3],pos[1]/pos[3],pos[2]/pos[3]));this.setnormMatrix2(),this.setprmvMatrix(),j=iOrig%obj.shapefirst.length;var first=obj.shapefirst[j];for(i=0;i1?obj.colors[1]:obj.colors[0],this.normMatrix=new CanvasMatrix4,this.setnormMatrix2(),this.setprmvMatrix(),result=result.concat(this.drawSimple(this.sphere,subscene,context)),this.mvMatrix=savemv,this.normMatrix=savenorm}return gl.depthMask(savedm),savedt&&gl.enable(gl.DEPTH_TEST),saveblend&&gl.enable(gl.BLEND),result},rglwidgetClass.prototype.drawSubscene=function(subsceneid,context){var flags,i,obj,sub=this.getObj(subsceneid),objects=this.scene.objects,clipids=sub.clipplanes,subids=sub.objects,subscene_has_faces=!1,subscene_needs_sorting=!1,result=[];if(sub.par3d.skipRedraw)return result;if(this.opaquePass)for(i=0;i0)for(i=0;i0;)switch(objid=context.pop(),obj=this.getObj(objid),type=obj.type){case"subscene":this.drawSubscene(objid,!1);break;case"sprites":result=result.concat(context.pop());break;case"spheres":break;case"bboxdeco":result=result.concat(context.pop());break;default:console.error("bad type '",type,"' in setContext")}return result},rglwidgetClass.prototype.drawPieces=function(pieces){var i,context,prevcontext=[];for(i=0;i=i;i++)adds=adds.concat(control.subsets[i]);else adds=adds.concat(control.subsets[value]);for(deletes=fullset.filter(function(x){return adds.indexOf(x)<0}),i=0;ivalue-svals[j-1]&&(j-=1);break}if(obj=this.getObj(control.objid),"undefined"!=typeof obj.vOffsets){for(varies=!0,k=0;ncol>k;k++)if(attrib=attributes[k],"undefined"!=typeof attrib&&(ofs=obj.vOffsets[ofss[attrib]],0>ofs)){switch(attrib){case"alpha":case"red":case"green":case"blue":obj.colors=[obj.colors[0],obj.colors[0]]}varies=!1}varies||this.initObjId(control.objid)}for(propvals=obj.values,aliases=obj.alias,"undefined"==typeof aliases&&(aliases=[]),k=0;ncol>k;k++)if(newval=direct?value:interp?p*values[j-1][k]+(1-p)*values[j][k]:values[j][k],attrib=attributes[k],vertex=vertices[k],alias=aliases[vertex],("planes"===obj.type||"clipplanes"===obj.type)&&(ofs=["nx","ny","nz","offset"].indexOf(attrib),ofs>=0))3>ofs?obj.normals[vertex][ofs]!==newval&&(obj.normals[vertex][ofs]=newval,obj.initialized=!1):obj.offsets[vertex][0]!==newval&&(obj.offsets[vertex][0]=newval,obj.initialized=!1);else if(ofs=obj.vOffsets[ofss[attrib]],0>ofs)this.alertOnce("Attribute '"+attrib+"' not found in object "+control.objid);else if(stride=obj.vOffsets.stride,ofs+=pos[attrib],entry=vertex*stride+ofs,propvals[entry]=newval,"undefined"!=typeof alias)for(a=0;ai;i++)if(null!==births[i]){for(age=time-births[i],j0=1;age>ages[j0];j0++);p[i]=1/0===ages[j0]?1:ages[j0]>ages[j0-1]?(ages[j0]-age)/(ages[j0]-ages[j0-1]):0,j[i]=j0}for(l=0;nobjs>l;l++)if(objid=objids[l],obj=this.getObj(objid),varies=!0,"undefined"!=typeof obj.vOffsets){for(k=0;kofs)){switch(attribs[k]){case"colors":case"alpha":case"red":case"green":case"blue":obj.colors=[obj.colors[0],obj.colors[0]]}varies=!1}varies||this.initObjId(objid)}for(l=0;nobjs>l;l++)if(objid=objids[l],obj=this.getObj(objid),"undefined"!=typeof obj.vOffsets){for(aliases=obj.alias,"undefined"==typeof aliases&&(aliases=[]),propvals=obj.values,stride=obj.vOffsets.stride,k=0;k=0){for(dim=dims[k],ofs+=pos[k],i=0;steps>i;i++)if(alias=aliases[i],null!==births[i])for(d=0;dim>d;d++)if(propvals[i*stride+ofs+d]=p[i]*attrib[dim*(j[i]-1)+d]+(1-p[i])*attrib[dim*j[i]+d],"undefined"!=typeof alias)for(a=0;a=0){for(keys=this.scene.crosstalk.key[j],obj=this.getObj(id),someHidden=!1,k=0;k=xmin&&xmax>=x&&y>=ymin&&ymax>=y&&z>=-1&&1>=z?selection.push(keys[k]):someHidden=!0);obj.someHidden=someHidden&&(filter||selection.length),obj.initialized=!1,this.equalArrays(selection,this.scene.crosstalk.selection)||(handle=this.scene.crosstalk.sel_handle[j],handle.set(selection,{rglSubsceneId:this.select.subscene}))}},rglwidgetClass.prototype.selection=function(event,filter){var i,j,ids,obj,keys,selection,someHidden,crosstalk=this.scene.crosstalk;for(crosstalk=this.scene.crosstalk,filter?(filter=crosstalk.filter=event.value,selection=crosstalk.selection):(selection=crosstalk.selection=event.value,filter=crosstalk.filter),ids=crosstalk.id,i=0;ithis.stopTime+this.stepSize/2||this.value=1.5*h+.5)?1/(1+h):1.5/(1+h5),i_small=dx10&&(cell=9+cell/10),cell*=shrink_sml,min_n>1&&(cell/=min_n)):(cell=dx,ndiv>1&&(cell/=ndiv)),20*DBL_MIN>cell?cell=20*DBL_MIN:10*cell>DBL_MAX&&(cell=.1*DBL_MAX),base=Math.pow(10,Math.floor(Math.log10(cell))),unit=base,(U=2*base)-cell1||!i_small)&&(0!==lo?lo*=1-DBL_EPSILON:lo=-DBL_MIN,0!==up?up*=1+DBL_EPSILON:up=+DBL_MIN);ns*unit>lo+rounding_eps*unit;)ns--;for(;up-rounding_eps*unit>nu*unit;)nu++;return k=Math.floor(.5+nu-ns),min_n>k?(k=min_n-k,ns>=0?(nu+=k/2,ns-=k/2+k%2):(ns-=k/2,nu+=k/2+k%2),ndiv=min_n):ndiv=k,return_bounds?(lo>ns*unit&&(lo=ns*unit),nu*unit>up&&(up=nu*unit)):(lo=ns,up=nu),{lo:lo,up:up,ndiv:ndiv,unit:unit}},rglwidgetClass.prototype.getTickEdges=function(prmv){var dim,i,j,k,edges,hull,step,vertices=[[0,0,0,1],[0,0,1,1],[0,1,0,1],[0,1,1,1],[1,0,0,1],[1,0,1,1],[1,1,0,1],[1,1,1,1]],result=[],proj=[],has_back=function(edge){var normal,m,n,normals=[[],[]],verts=[vertices[edge[0]],vertices[edge[1]]];for(n=0,m=0;3>m;m++)verts[0][m]===verts[1][m]&&(normals[n]=[0,0,0,1],normals[n][m]=2*verts[0][m]-1,n++);for(n=0;2>n;n++)if(normal=rglwidgetClass.multVM(normals[n],self.normMatrix),normal[2]<0||0===normal[2]&&normal[0]<0)return!0;return!1},self=this;for(i=0;idim;dim++){for(edges=[],step=Math.pow(2,2-dim),i=0;4>i;i++)for(j=0===dim?i:1===dim?i+2*(i>1):2*i,k=0;knewval&&(best=j,best2=edges[i][1],val=newval);"undefined"!=typeof best?(result[dim]=vertices[best].slice(0,3),result[dim][dim]=void 0):result[dim]=void 0}}return result},rglwidgetClass.prototype.getTickLocations=function(obj){var dim,i,limits,value,len,delta,range,locations=[],result=[[],[],[]],bbox=obj.bbox;for(obj.needsAxisCallback=!1,dim=0;3>dim;dim++)switch(limits=bbox.slice(2*dim,2*dim+2),range=limits[1]-limits[0],obj.axes.mode[dim]){case"custom":for(i=0;ii;i++)result[dim].push(i*delta);break;case"fixednum":for(len=obj.axes.nticks[dim],delta=len>1?range/(len-1):0,i=0;len>i;i++)result[dim].push(i*delta/range);break;case"pretty":for(locations=this.R_pretty(limits[0],limits[1],obj.axes.nticks[dim],3,.75,[1.5,2.75],0,0),i=locations.lo;i<=locations.up;i++)value=(i*locations.unit-limits[0])/range,value>0&&1>value&&result[dim].push(value);break;case"user":obj.needsAxisCallback=!0}return result},rglwidgetClass.prototype.getTickVertices=function(ticks){var dim,i,j,locations,edge,vertices=[],edges=ticks.edges;for(dim=0;3>dim;dim++)if(locations=ticks.locations[dim],locations.length)for(i=0;ij;j++)(2>dim&&j===1-dim||2===dim&&0===j)&&(edge[j]+=2*(edge[j]-.5)/ticks.axes.marklen[dim]);vertices.push(edge)}ticks.vertices=vertices,ticks.vertexCount=vertices.length,ticks.values=new Float32Array(rglwidgetClass.flatten(vertices)),ticks.initialized=!1 },rglwidgetClass.prototype.placeTickLabels=function(obj){var i,j,k,vertex,locations,dim,ticks=obj.ticks,labels=obj.labels,vertices=[],tickvertices=ticks.vertices,edges=obj.ticks.edges;for(j=0,dim=0;3>dim;dim++)if("undefined"!=typeof edges[dim]&&(locations=ticks.locations[dim],locations.length))for(i=0;i=tickvertices.length)break;for(vertex=tickvertices[j].slice(),k=0;3>k;k++)vertex[k]+=2*(tickvertices[j+1][k]-vertex[k]);vertices.push(vertex),j+=2}labels.vertices=vertices,labels.centers=labels.vertices,labels.initialized=!1},rglwidgetClass.prototype.setTickLabels=function(obj){var mode,locations,nticks,dim,i,limits,range,values,max,ticks=obj.ticks,labels=[],start=0,edges=obj.ticks.edges;for(dim=0;3>dim;dim++)if("undefined"!=typeof edges[dim]){if(mode=obj.axes.mode[dim],nticks=obj.axes.nticks[dim],"custom"===mode)labels=labels.concat(obj.texts.slice(start,start+nticks));else{for(limits=obj.bbox.slice(2*dim,2*(dim+1)),range=limits[1]-limits[0],locations=ticks.locations[dim],max=-1/0,values=[],i=0;ii;i++)expand=obj.axes.expand[i],center[i]=(bbox[2*i]+bbox[2*i+1])/2,bbox[2*i]=center[i]-expand*(bbox[2*i+1]-center[i]),bbox[2*i+1]=center[i]+expand*(bbox[2*i+1]-center[i]);obj.bbox=bbox,obj.center=center},rglwidgetClass.prototype.setBBoxMatrices=function(obj){var bboxNorm,bboxMV,scale,saved={normMatrix:new CanvasMatrix4(this.normMatrix),mvMatrix:new CanvasMatrix4(this.mvMatrix)},bbox=obj.bbox;return bboxNorm=new CanvasMatrix4,scale=[bbox[1]-bbox[0],bbox[3]-bbox[2],bbox[5]-bbox[4]],bboxNorm.scale(1/scale[0],1/scale[1],1/scale[2]),bboxNorm.multRight(saved.normMatrix),this.normMatrix=bboxNorm,bboxMV=new CanvasMatrix4,bboxMV.scale(scale[0],scale[1],scale[2]),bboxMV.translate(bbox[0],bbox[2],bbox[4]),bboxMV.multRight(saved.mvMatrix),this.mvMatrix=obj.mvMatrix=bboxMV,saved.prmvMatrix=null===this.prmvMatrix?null:new CanvasMatrix4(this.prmvMatrix),this.setprmvMatrix(),obj.prmvMatrix=this.prmvMatrix,saved},rglwidgetClass.prototype.restoreBBoxMatrices=function(saved){this.normMatrix=saved.normMatrix,this.mvMatrix=saved.mvMatrix,this.prmvMatrix=saved.prmvMatrix},rglwidgetClass.prototype.getMarginParameters=function(bboxdeco,material){var saved,edges,i,line,level,trans,scale,bbox=bboxdeco.bbox,edge=[].concat(material.edge),at=material.margin;if(material.floating){if(saved=this.setBBoxMatrices(bboxdeco),edges=this.getTickEdges(this.prmvMatrix)[at],this.restoreBBoxMatrices(saved),"undefined"==typeof edges)return void 0;for(i=0;3>i;i++)edges[i]<1&&(edges[i]=-1),edge[i]=edge[i]*edges[i]}switch(at){case 0:line=1,level=2;break;case 1:line=0,level=2;break;case 2:line=0,level=1}return scale=[edge[0]*(bbox[1]-bbox[0])/bboxdeco.axes.marklen[0],edge[1]*(bbox[3]-bbox[2])/bboxdeco.axes.marklen[1],edge[2]*(bbox[5]-bbox[4])/bboxdeco.axes.marklen[2]],trans=[1===edge[0]?bbox[1]:bbox[0],1===edge[1]?bbox[3]:bbox[2],1===edge[2]?bbox[5]:bbox[4]],{at:at,line:line,level:level,trans:trans,scale:scale}},rglwidgetClass.prototype.fixVertex=function(orig,parms,center,bbox){var vertex=[0,0,0];return vertex[parms.at]=rglwidgetClass.missing(orig[0])?center[parms.at]:"-Inf"===orig[0]?bbox[2*parms.at]:"Inf"===orig[0]?bbox[2*parms.at+1]:orig[0],vertex[parms.line]=parms.scale[parms.line]*orig[1]+parms.trans[parms.line],vertex[parms.level]=parms.scale[parms.level]*orig[2]+parms.trans[parms.level],vertex},rglwidgetClass.prototype.fixNormal=function(orig,parms){var vertex=[0,0,0];return vertex[parms.at]=orig[0],vertex[parms.line]=orig[1]/parms.scale[parms.line],vertex[parms.level]=orig[2]/parms.scale[parms.level],vertex},rglwidgetClass.prototype.marginVecToDataVec=function(obj,subscene){var center,bbox,parms,parmsjson,i,vertex,bboxdeco=this.getBBoxDeco(subscene),orig=obj.orig,vertices=[],normals=[],centers=[];if("undefined"==typeof orig&&(orig={vert:obj.vertices,norm:obj.normals,cent:obj.centers,doNormals:"undefined"!=typeof obj.normals,doCenters:"undefined"!=typeof obj.centers,parms:""},obj.orig=orig),"undefined"!=typeof bboxdeco){if(this.setBbox(bboxdeco,subscene),center=bboxdeco.center,bbox=bboxdeco.bbox,parms=this.getMarginParameters(bboxdeco,obj.material),"undefined"==typeof parms)return!1;if(parmsjson=JSON.stringify(parms),parmsjson===orig.parms)return!0;for(orig.parms=parmsjson,i=0;ii;i++)if("user"===obj.axes.mode[i]&&(axis=["x","y","z"][i],"undefined"!=typeof obj.callbacks&&"undefined"!=typeof(code=obj.callbacks[axis]))){if("undefined"!=typeof edges[i])for(j=0;3>j;j++)"undefined"!=typeof edges[i][j]&&(axis+=edges[i][j]>0?"+":"-");fn=Function('"use strict";return ('+code+")")(),fn.call(this,axis)}},rglwidgetClass.bisect=function(x,newx){for(var mid,lo=0,hi=x.length-1;hi-1>lo;)mid=Math.round((lo+hi)/2),x[mid]=x[n-1]?v[n-1]:(lo=this.bisect(x,newx),v[lo]))},rglwidgetClass.lerp=function(x,v,newx){var i,n,lo,hi,alpha,result;if(newx<=x[0])return v[0];if(n=x.length,newx>=x[n-1])return v[n-1];if(lo=this.bisect(x,newx),newx===x[lo])return v[lo];if(hi=lo+1,newx===x[hi])return v[hi];if(alpha=(newx-x[lo])/(x[hi]-x[lo]),result=v[lo],n=result.length,"undefined"!=typeof n)for(i=0;n>i;i++)result[i]=(1-alpha)*result[i]+alpha*v[hi][i];else result=(1-alpha)*result+alpha*v[hi];return result},rglwidgetClass.slerp=function(x,v,newx){var n,lo,hi,alpha,result,p0,p1,dot,Omega,alpha0,alpha1,len;return newx<=x[0]?v[0]:newx>=x[n-1]?v[n-1]:(lo=this.bisect(x,newx),newx===x[lo]?v[lo]:(hi=lo+1,newx===x[hi]?v[hi]:(p0=v[lo],p1=v[hi],dot=p0[0]*p1[0]+p0[1]*p1[1]+p0[2]*p1[2]+p0[3]*p1[3],0>dot&&(p1=[-p1[0],-p1[1],-p1[2],-p1[3]],dot=-dot),dot>=1?result=p1:(alpha=(newx-x[lo])/(x[hi]-x[lo]),Omega=Math.acos(dot),alpha0=Math.sin((1-alpha)*Omega),alpha1=Math.sin(alpha*Omega),result=[alpha0*p0[0]+alpha1*p1[0],alpha0*p0[1]+alpha1*p1[1],alpha0*p0[2]+alpha1*p1[2],alpha0*p0[3]+alpha1*p1[3]]),len=Math.sqrt(result[0]*result[0]+result[1]*result[1]+result[2]*result[2]+result[3]*result[3]),[result[0]/len,result[1]/len,result[2]/len,result[3]/len])))},rglwidgetClass.rotateByQuaternion=function(M,q){var xx=q[0]*q[0],xy=q[0]*q[1],xz=q[0]*q[2],xw=q[0]*q[3],yy=q[1]*q[1],yz=q[1]*q[2],yw=q[1]*q[3],zz=q[2]*q[2],zw=q[2]*q[3],matrix=new CanvasMatrix4;matrix.m11=1-2*(yy+zz),matrix.m12=2*(xy+zw),matrix.m13=2*(xz-yw),matrix.m21=2*(xy-zw),matrix.m22=1-2*(xx+zz),matrix.m23=2*(yz+xw),matrix.m31=2*(xz+yw),matrix.m32=2*(yz-xw),matrix.m33=1-2*(xx+yy),M.multRight(matrix)}; rgl/inst/htmlwidgets/lib/rglClass/rglTimer.src.js0000644000176200001440000001050414771520323021603 0ustar liggesusers /* globals rgltimerClass: true */ /** * The class of an rgl timer object * @class */ /** * Construct an rgltimerClass object * @constructor * @param { function } Tick - action when timer fires * @param { number } startTime - nominal start time in seconds * @param { number } interval - seconds between updates * @param { number } stopTime - nominal stop time in seconds * @param { number } stepSize - nominal step size * @param { number } value - current nominal time * @param { number } rate - nominal units per second * @param { string } loop - "none", "cycle" or "oscillate" * @param { Object } actions - list of actions */ rgltimerClass = function(Tick, startTime, interval, stopTime, stepSize, value, rate, loop, actions) { this.enabled = false; this.timerId = 0; /** nominal start time in seconds */ this.startTime = startTime; /** current nominal time */ this.value = value; /** seconds between updates */ this.interval = interval; /** nominal stop time */ this.stopTime = stopTime; /** nominal step size */ this.stepSize = stepSize; /** nominal units per second */ this.rate = rate; /** "none", "cycle", or "oscillate" */ this.loop = loop; /** real world start time */ this.realStart = undefined; /** multiplier for fast-forward or reverse */ this.multiplier = 1; this.actions = actions; this.Tick = Tick; }; /** * Methods related to players * @name ___METHODS_FOR_PLAYERS___ * @memberof rgltimerClass * @kind function * @instance */ /** * Start playing * @memberof rgltimerClass */ rgltimerClass.prototype.play = function() { if (this.enabled) { this.enabled = false; window.clearInterval(this.timerId); this.timerId = 0; return; } var tick = function(self) { var now = new Date(); self.value = self.multiplier*self.rate*(now - self.realStart)/1000 + self.startTime; self.forceToRange(); if (typeof self.Tick !== "undefined") { self.Tick(self.value); } }; this.realStart = new Date() - 1000*(this.value - this.startTime)/this.rate/this.multiplier; this.timerId = window.setInterval(tick, 1000*this.interval, this); this.enabled = true; }; /** * Force value into legal range */ rgltimerClass.prototype.forceToRange = function() { if (this.value > this.stopTime + this.stepSize/2 || this.value < this.startTime - this.stepSize/2) { if (!this.loop) { this.reset(); } else { var cycle = this.stopTime - this.startTime + this.stepSize, newval = (this.value - this.startTime) % cycle + this.startTime; if (newval < this.startTime) { newval += cycle; } this.realStart += (this.value - newval)*1000/this.multiplier/this.rate; this.value = newval; } } }; /** * Reset to start values */ rgltimerClass.prototype.reset = function() { this.value = this.startTime; this.newmultiplier(1); if (typeof this.Tick !== "undefined") { this.Tick(this.value); } if (this.enabled) this.play(); /* really pause... */ if (typeof this.PlayButton !== "undefined") this.PlayButton.value = "Play"; }; /** * Increase the multiplier to play faster */ rgltimerClass.prototype.faster = function() { this.newmultiplier(Math.SQRT2*this.multiplier); }; /** * Decrease the multiplier to play slower */ rgltimerClass.prototype.slower = function() { this.newmultiplier(this.multiplier/Math.SQRT2); }; /** * Change sign of multiplier to reverse direction */ rgltimerClass.prototype.reverse = function() { this.newmultiplier(-this.multiplier); }; /** * Set multiplier for play speed * @param { number } newmult - new value */ rgltimerClass.prototype.newmultiplier = function(newmult) { if (newmult !== this.multiplier) { this.realStart += 1000*(this.value - this.startTime)/this.rate*(1/this.multiplier - 1/newmult); this.multiplier = newmult; } }; /** * Take one step */ rgltimerClass.prototype.step = function() { this.value += this.rate*this.multiplier; this.forceToRange(); if (typeof this.Tick !== "undefined") this.Tick(this.value); }; rgl/inst/htmlwidgets/lib/rglClass/pieces.src.js0000644000176200001440000001176215011677075021302 0ustar liggesusers/** * Methods related to drawing transparent objects * @name ___METHODS_FOR_TRANSPARENCY___ * @memberof rglwidgetClass * @kind function * @instance * These functions order the centers of displayed objects so they * can be drawn using the painters algorithm, necessary to support * transparency. * Note that objid is not obj.id when drawing spheres. */ /** * Break objects into pieces * @returns { array } Array of pieces */ rglwidgetClass.prototype.getPieces = function(context, objid, subid, obj) { var n = obj.centers.length, depth, result = new Array(n), z, w, i, meandepth = 0; context = context.slice(); for(i=0; i 0) { var i, thiscontext = pieces[0].context, thisobjid = pieces[0].objid, thissubid = pieces[0].subid, indices = []; for (i= 0; i < pieces.length; i++) { if (pieces[i].context !== thiscontext || pieces[i].objid !== thisobjid || pieces[i].subid !== thissubid) { result.push({context: thiscontext, objid: thisobjid, subid: thissubid, indices: indices}); thiscontext = pieces[i].context; thisobjid = pieces[i].objid; thissubid = pieces[i].subid; indices = []; } indices.push(pieces[i].index); } result.push({context: thiscontext, objid: thisobjid, subid: thissubid, indices: indices}); } return result; }; /** * Sort pieces by depth * @returns { array } * @param { array } pieces - array of pieces */ rglwidgetClass.prototype.sortPieces = function(pieces) { var fastTransparency = this.scene.fastTransparency, compare = function(i,j) { var c1, c2, diff = fastTransparency ? j.meandepth - i.meandepth : j.depth - i.depth; // Check for different object depths if (diff !== 0.0) return diff; // At this point we are either on the same object or // two different objects that are at the same mean // depth. Context changes are expensive so arbitrarily // split the two objects. // Check for different objects diff = j.objid - i.objid; if (diff !== 0) return diff; // Check for different nested objects c1 = j.context.slice(); c2 = i.context.slice(); diff = c1.length - c2.length; while (diff === 0 && c1.length > 0) { diff = c1.pop() - c2.pop(); } if (diff !== 0) return diff; // Both pieces are in the same object, so // check for different piece depths // If fastTransparency is not set, this is redundant, // but a test would probably be slower. diff = j.depth - i.depth; return diff; }, result = []; if (pieces.length) result = pieces.sort(compare); return result; }; rgl/inst/htmlwidgets/lib/rglClass/shaders/0000755000176200001440000000000015026777212020330 5ustar liggesusersrgl/inst/htmlwidgets/lib/rglClass/shaders/rgl_fragment.glsl0000644000176200001440000001666015011677075023673 0ustar liggesusers#line 2 2 // File 2 is the fragment shader #ifdef GL_ES #ifdef GL_FRAGMENT_PRECISION_HIGH precision highp float; #else precision mediump float; #endif #endif varying vec4 vCol; // carries alpha varying vec4 vPosition; #if defined(HAS_TEXTURE) || defined (IS_TEXT) varying vec2 vTexcoord; uniform sampler2D uSampler; #endif #ifdef HAS_FOG uniform int uFogMode; uniform vec3 uFogColor; uniform vec4 uFogParms; #endif #if defined(IS_LIT) && !defined(FIXED_QUADS) varying vec4 vNormal; #endif #if NCLIPPLANES > 0 uniform vec4 vClipplane[NCLIPPLANES]; #endif #if NLIGHTS > 0 uniform mat4 mvMatrix; #endif #ifdef IS_LIT uniform vec3 emission; uniform float shininess; #if NLIGHTS > 0 uniform vec3 ambient[NLIGHTS]; uniform vec3 specular[NLIGHTS]; // light*material uniform vec3 diffuse[NLIGHTS]; uniform vec3 lightDir[NLIGHTS]; uniform bool viewpoint[NLIGHTS]; uniform bool finite[NLIGHTS]; #endif #endif // IS_LIT #ifdef IS_TWOSIDED uniform bool front; varying float normz; #endif #ifdef FAT_LINES varying vec2 vPoint; varying float vLength; #endif #ifdef USE_ENVMAP varying vec3 vReflection; #endif void main(void) { vec4 fragColor; #ifdef FAT_LINES vec2 point = vPoint; bool neg = point.y < 0.0; point.y = neg ? (point.y + vLength)/(1.0 - vLength) : -(point.y - vLength)/(1.0 - vLength); #if defined(IS_TRANSPARENT) && defined(IS_LINESTRIP) if (neg && length(point) <= 1.0) discard; #endif point.y = min(point.y, 0.0); if (length(point) > 1.0) discard; #endif // FAT_LINES #ifdef ROUND_POINTS vec2 coord = gl_PointCoord - vec2(0.5); if (length(coord) > 0.5) discard; #endif #if NCLIPPLANES > 0 for (int i = 0; i < NCLIPPLANES; i++) if (dot(vPosition, vClipplane[i]) < 0.0) discard; #endif #ifdef FIXED_QUADS vec3 n = vec3(0., 0., 1.); #elif defined(IS_LIT) vec3 n = normalize(vNormal.xyz); #endif #ifdef IS_TWOSIDED if ((normz <= 0.) != front) discard; #endif #ifdef IS_LIT vec3 eye = normalize(-vPosition.xyz/vPosition.w); vec3 lightdir; vec4 colDiff; vec3 halfVec; vec4 lighteffect = vec4(emission, 0.); vec3 col; float nDotL; #ifdef FIXED_QUADS n = -faceforward(n, n, eye); #endif #if NLIGHTS > 0 // Simulate two-sided lighting if (n.z < 0.0) n = -n; for (int i=0;i 0) { fogF = (uFogParms.y - vPosition.z/vPosition.w)/(uFogParms.y - uFogParms.x); if (uFogMode > 1) fogF = mix(uFogParms.w, 1.0, fogF); fogF = fogF*uFogParms.z; if (uFogMode == 2) fogF = 1.0 - exp(-fogF); // Docs are wrong: use (density*c)^2, not density*c^2 // https://gitlab.freedesktop.org/mesa/mesa/-/blob/master/src/mesa/swrast/s_fog.c#L58 else if (uFogMode == 3) fogF = 1.0 - exp(-fogF*fogF); fogF = clamp(fogF, 0.0, 1.0); gl_FragColor = vec4(mix(fragColor.rgb, uFogColor, fogF), fragColor.a); } else gl_FragColor = fragColor; #else gl_FragColor = fragColor; #endif // HAS_FOG } rgl/inst/htmlwidgets/lib/rglClass/shaders/rgl_vertex.glsl0000644000176200001440000000666615011677075023412 0ustar liggesusers#line 2 1 // File 1 is the vertex shader #ifdef GL_ES #ifdef GL_FRAGMENT_PRECISION_HIGH precision highp float; #else precision mediump float; #endif #endif attribute vec3 aPos; attribute vec4 aCol; uniform mat4 mvMatrix; uniform mat4 prMatrix; varying vec4 vCol; varying vec4 vPosition; #ifdef NEEDS_VNORMAL attribute vec3 aNorm; uniform mat4 normMatrix; varying vec4 vNormal; #endif #if defined(HAS_TEXTURE) || defined (IS_TEXT) attribute vec2 aTexcoord; varying vec2 vTexcoord; #endif #ifdef FIXED_SIZE uniform vec3 textScale; #endif #ifdef FIXED_QUADS attribute vec3 aOfs; #endif #ifdef IS_TWOSIDED #ifdef HAS_NORMALS varying float normz; uniform mat4 invPrMatrix; #else attribute vec3 aPos1; attribute vec3 aPos2; varying float normz; #endif #endif // IS_TWOSIDED #ifdef FAT_LINES attribute vec3 aNext; attribute vec2 aPoint; varying vec2 vPoint; varying float vLength; uniform float uAspect; uniform float uLwd; #endif #ifdef USE_ENVMAP varying vec3 vReflection; #endif void main(void) { #ifndef IS_BRUSH #if defined(NCLIPPLANES) || !defined(FIXED_QUADS) || defined(HAS_FOG) || defined(USE_ENVMAP) vPosition = mvMatrix * vec4(aPos, 1.); #endif #ifndef FIXED_QUADS gl_Position = prMatrix * vPosition; #endif #endif // !IS_BRUSH #ifdef IS_POINTS gl_PointSize = POINTSIZE; #endif vCol = aCol; // USE_ENVMAP implies NEEDS_VNORMAL #ifdef NEEDS_VNORMAL vNormal = normMatrix * vec4(-aNorm, dot(aNorm, aPos)); #endif #ifdef USE_ENVMAP vReflection = normalize(reflect(vPosition.xyz/vPosition.w, normalize(vNormal.xyz/vNormal.w))); #endif #ifdef IS_TWOSIDED #ifdef HAS_NORMALS /* normz should be calculated *after* projection */ normz = (invPrMatrix*vNormal).z; #else vec4 pos1 = prMatrix*(mvMatrix*vec4(aPos1, 1.)); pos1 = pos1/pos1.w - gl_Position/gl_Position.w; vec4 pos2 = prMatrix*(mvMatrix*vec4(aPos2, 1.)); pos2 = pos2/pos2.w - gl_Position/gl_Position.w; normz = pos1.x*pos2.y - pos1.y*pos2.x; #endif #endif // IS_TWOSIDED #ifdef NEEDS_VNORMAL vNormal = vec4(normalize(vNormal.xyz), 1); #endif #if defined(HAS_TEXTURE) || defined(IS_TEXT) vTexcoord = aTexcoord; #endif #if defined(FIXED_SIZE) && !defined(ROTATING) vec4 pos = prMatrix * mvMatrix * vec4(aPos, 1.); pos = pos/pos.w; gl_Position = pos + vec4(aOfs*textScale, 0.); #endif #if defined(IS_SPRITES) && !defined(FIXED_SIZE) vec4 pos = mvMatrix * vec4(aPos, 1.); pos = pos/pos.w + vec4(aOfs, 0.); gl_Position = prMatrix*pos; #endif #ifdef FAT_LINES /* This code was inspired by Matt Deslauriers' code in https://mattdesl.svbtle.com/drawing-lines-is-hard */ vec2 aspectVec = vec2(uAspect, 1.0); mat4 projViewModel = prMatrix * mvMatrix; vec4 currentProjected = projViewModel * vec4(aPos, 1.0); currentProjected = currentProjected/currentProjected.w; vec4 nextProjected = projViewModel * vec4(aNext, 1.0); vec2 currentScreen = currentProjected.xy * aspectVec; vec2 nextScreen = (nextProjected.xy / nextProjected.w) * aspectVec; float len = uLwd; vec2 dir = vec2(1.0, 0.0); vPoint = aPoint; vLength = length(nextScreen - currentScreen)/2.0; vLength = vLength/(vLength + len); if (vLength > 0.0) { dir = normalize(nextScreen - currentScreen); } vec2 normal = vec2(-dir.y, dir.x); dir.x /= uAspect; normal.x /= uAspect; vec4 offset = vec4(len*(normal*aPoint.x*aPoint.y - dir), 0.0, 0.0); gl_Position = currentProjected + offset; #endif #ifdef IS_BRUSH gl_Position = vec4(aPos, 1.); #endif } rgl/inst/htmlwidgets/lib/rglClass/rglClass.src.js0000644000176200001440000000414214771520323021571 0ustar liggesusers//// To generate the help pages for this library, use // jsdoc --template /usr/local/lib/node_modules/foodoc/template *.src.js -R README.md -c JSDoc.json // To test, set environment variable RGL_DEBUGGING=true // before building. /* globals rglwidgetClass: true */ /** * The class of an rgl widget * @class */ rglwidgetClass = function() { this.canvas = null; this.userMatrix = new CanvasMatrix4(); this.types = []; this.prMatrix = new CanvasMatrix4(); this.mvMatrix = new CanvasMatrix4(); this.vp = null; this.prmvMatrix = null; this.origs = null; this.gl = null; this.scene = null; this.select = {state: "inactive", subscene: null, region: {p1: {x:0, y:0}, p2: {x:0, y:0}}}; this.drawing = false; }; rglwidgetClass.f_is_lit = 1; rglwidgetClass.f_is_smooth = 2; rglwidgetClass.f_has_texture = 4; rglwidgetClass.f_depth_sort = 8; rglwidgetClass.f_fixed_quads = 16; rglwidgetClass.f_is_transparent = 32; rglwidgetClass.f_is_lines = 64; rglwidgetClass.f_sprites_3d = 128; rglwidgetClass.f_is_subscene = 256; rglwidgetClass.f_is_clipplanes = 512; rglwidgetClass.f_fixed_size = 1024; rglwidgetClass.f_is_points = 2048; rglwidgetClass.f_is_twosided = 4096; rglwidgetClass.f_fat_lines = 8192; rglwidgetClass.f_is_brush = 16384; rglwidgetClass.f_has_fog = 32768; rglwidgetClass.f_rotating = 65536; rglwidgetClass.prototype.fogNone = 0; rglwidgetClass.prototype.fogLinear = 1; rglwidgetClass.prototype.fogExp = 2; rglwidgetClass.prototype.fogExp2 = 3; /** * Methods related to obsolete approaches. * @name ___OBSOLETE_METHODS___ * @memberof rglwidgetClass * @kind function * @instance */ /** * Start the writeWebGL scene. This is only used by writeWebGL; rglwidget has no debug element. */ rglwidgetClass.prototype.start = function() { if (typeof this.prefix !== "undefined") { this.debugelement = document.getElementById(this.prefix + "debug"); this.debug(""); } this.drag = 0; this.drawScene(); }; rgl/inst/htmlwidgets/lib/rglClass/controls.src.js0000644000176200001440000005146214771520323021671 0ustar liggesusers /** * Change the displayed subset * @param { Object } el - Element of the control; not used. * @param { Object } control - The subset control data. */ rglwidgetClass.prototype.subsetSetter = function(el, control) { if (typeof control.subscenes === "undefined" || control.subscenes === null) control.subscenes = this.scene.rootSubscene; var value = Math.round(control.value), subscenes = [].concat(control.subscenes), fullset = [].concat(control.fullset), i, j, subsceneid, adds = [], deletes = []; if (rglwidgetClass.missing(value)) value = control.value = 0; if (control.accumulate) for (i=0; i <= value; i++) adds = adds.concat(control.subsets[i]); else adds = adds.concat(control.subsets[value]); deletes = fullset.filter(function(x) { return adds.indexOf(x) < 0; }); for (i = 0; i < subscenes.length; i++) { subsceneid = subscenes[i]; if (typeof this.getObj(subsceneid) === "undefined") this.alertOnce("typeof object is undefined"); for (j = 0; j < adds.length; j++) this.addToSubscene(adds[j], subsceneid); for (j = 0; j < deletes.length; j++) this.delFromSubscene(deletes[j], subsceneid); } }; /** * Change the requested property * @param { Object } el - Element of the control; not used. * @param { Object } control - The property setter control data. */ rglwidgetClass.prototype.propertySetter = function(el, control) { var value = control.value, values = [].concat(control.values), svals = [].concat(control.param), direct = values[0] === null, entries = [].concat(control.entries), ncol = entries.length, nrow = values.length/ncol, properties = rglwidgetClass.repeatToLen(control.properties, ncol), objids = rglwidgetClass.repeatToLen(control.objids, ncol), property, objid = objids[0], obj = this.getObj(objid), propvals, i, j, v1, v2, p, entry, gl, needsBinding, newprop, newid, getPropvals = function() { if (property === "userMatrix") return obj.par3d.userMatrix.getAsArray(); else if (property === "scale" || property === "FOV" || property === "zoom") return [].concat(obj.par3d[property]); else return [].concat(obj[property]); }, putPropvals = function(newvals) { if (newvals.length === 1) newvals = newvals[0]; if (property === "userMatrix") obj.par3d.userMatrix.load(newvals); else if (property === "scale" || property === "FOV" || property === "zoom") obj.par3d[property] = newvals; else obj[property] = newvals; }; if (direct && typeof value === "undefined") return; if (control.interp) { values = values.slice(0, ncol).concat(values). concat(values.slice(ncol*(nrow-1), ncol*nrow)); svals = [-Infinity].concat(svals).concat(Infinity); for (i = 1; i < svals.length; i++) { if (value <= svals[i]) { if (svals[i] === Infinity) p = 1; else p = (svals[i] - value)/(svals[i] - svals[i-1]); break; } } } else if (!direct) { value = Math.round(value); } for (j=0; j value - svals[j-1]) j = j - 1; } break; } } obj = this.getObj(control.objid); // First, make sure color attributes vary in original if (typeof obj.vOffsets !== "undefined") { varies = true; for (k = 0; k < ncol; k++) { attrib = attributes[k]; if (typeof attrib !== "undefined") { ofs = obj.vOffsets[ofss[attrib]]; if (ofs < 0) { switch(attrib) { case "alpha": case "red": case "green": case "blue": obj.colors = [obj.colors[0], obj.colors[0]]; break; } varies = false; } } } if (!varies) this.initObjId(control.objid); } propvals = obj.values; aliases = obj.alias; if (typeof aliases === "undefined") aliases = []; for (k=0; k= 0) { if (ofs < 3) { if (obj.normals[vertex][ofs] !== newval) { // Assume no aliases here... obj.normals[vertex][ofs] = newval; obj.initialized = false; } } else { if (obj.offsets[vertex][0] !== newval) { obj.offsets[vertex][0] = newval; obj.initialized = false; } } continue; } } // Not a plane setting... ofs = obj.vOffsets[ofss[attrib]]; if (ofs < 0) this.alertOnce("Attribute '"+attrib+"' not found in object "+control.objid); else { stride = obj.vOffsets.stride; ofs = ofs + pos[attrib]; entry = vertex*stride + ofs; propvals[entry] = newval; if (typeof alias !== "undefined") for (a = 0; a < alias.length; a++) propvals[alias[a]*stride + ofs] = newval; } } if (typeof obj.buf !== "undefined") { var gl = this.gl || this.initGL(); gl.bindBuffer(gl.ARRAY_BUFFER, obj.buf); gl.bufferData(gl.ARRAY_BUFFER, propvals, gl.STATIC_DRAW); } }; /** * Change the requested vertex properties by age * @param { Object } el - Element of the control; not used. * @param { Object } control - The age setter control data. */ rglwidgetClass.prototype.ageSetter = function(el, control) { var objids = [].concat(control.objids), nobjs = objids.length, time = control.value, births = [].concat(control.births), ages = [].concat(control.ages), steps = births.length, j = Array(steps), p = Array(steps), i, k, l, age, j0, propvals, stride, ofs, objid, obj, attrib, dim, varies, alias, aliases, a, d, attribs = ["colors", "alpha", "radii", "vertices", "normals", "origins", "texcoords", "x", "y", "z", "red", "green", "blue"], ofss = ["cofs", "cofs", "radofs", "vofs", "nofs", "oofs", "tofs", "vofs", "vofs", "vofs", "cofs", "cofs", "cofs"], dims = [3,1,1,3, 3,2,2, 1,1,1, 1,1,1], pos = [0,3,0,0, 0,0,0, 0,1,2, 0,1,2]; /* Infinity doesn't make it through JSON */ ages[0] = -Infinity; ages[ages.length-1] = Infinity; for (i = 0; i < steps; i++) { if (births[i] !== null) { // NA in R becomes null age = time - births[i]; for (j0 = 1; age > ages[j0]; j0++); if (ages[j0] === Infinity) p[i] = 1; else if (ages[j0] > ages[j0-1]) p[i] = (ages[j0] - age)/(ages[j0] - ages[j0-1]); else p[i] = 0; j[i] = j0; } } // First, make sure color attributes vary in original for (l = 0; l < nobjs; l++) { objid = objids[l]; obj = this.getObj(objid); varies = true; if (typeof obj.vOffsets === "undefined") continue; for (k = 0; k < attribs.length; k++) { attrib = control[attribs[k]]; if (typeof attrib !== "undefined") { ofs = obj.vOffsets[ofss[k]]; if (ofs < 0) { switch(attribs[k]) { case "colors": case "alpha": case "red": case "green": case "blue": obj.colors = [obj.colors[0], obj.colors[0]]; break; } varies = false; } } } if (!varies) this.initObjId(objid); } for (l = 0; l < nobjs; l++) { objid = objids[l]; obj = this.getObj(objid); if (typeof obj.vOffsets === "undefined") continue; aliases = obj.alias; if (typeof aliases === "undefined") aliases = []; propvals = obj.values; stride = obj.vOffsets.stride; for (k = 0; k < attribs.length; k++) { attrib = control[attribs[k]]; if (typeof attrib !== "undefined") { ofs = obj.vOffsets[ofss[k]]; if (ofs >= 0) { dim = dims[k]; ofs = ofs + pos[k]; for (i = 0; i < steps; i++) { alias = aliases[i]; if (births[i] !== null) { for (d=0; d < dim; d++) { propvals[i*stride + ofs + d] = p[i]*attrib[dim*(j[i]-1) + d] + (1-p[i])*attrib[dim*j[i] + d]; if (typeof alias !== "undefined") for (a=0; a < alias.length; a++) propvals[alias[a]*stride + ofs + d] = propvals[i*stride + ofs + d]; } } } } else this.alertOnce("\'"+attribs[k]+"\' property not found in object "+objid); } } obj.values = propvals; if (typeof obj.buf !== "undefined") { var gl = this.gl || this.initGL(); gl.bindBuffer(gl.ARRAY_BUFFER, obj.buf); gl.bufferData(gl.ARRAY_BUFFER, obj.values, gl.STATIC_DRAW); } } }; /** * Bridge to old style control * @param { Object } el - Element of the control; not used. * @param { Object } control - The bridge control data. */ rglwidgetClass.prototype.oldBridge = function(el, control) { var attrname, global = window[control.prefix + "rgl"]; if (global) for (attrname in global) this[attrname] = global[attrname]; window[control.prefix + "rgl"] = this; }; /** * Set up a player control * @param { Object } el - The player control element * @param { Object } control - The player data. */ rglwidgetClass.prototype.Player = function(el, control) { var self = this, components = [].concat(control.components), buttonLabels = [].concat(control.buttonLabels), Tick = function() { /* "this" will be a timer */ var i, nominal = this.value, slider = this.Slider, labels = this.outputLabels, output = this.Output, step; if (typeof slider !== "undefined" && nominal !== slider.value) slider.value = nominal; if (typeof output !== "undefined") { step = Math.round((nominal - output.sliderMin)/output.sliderStep); if (labels !== null) { output.innerHTML = labels[step]; } else { step = step*output.sliderStep + output.sliderMin; output.innerHTML = step.toPrecision(output.outputPrecision); } } for (i=0; i < this.actions.length; i++) { this.actions[i].value = nominal; } self.applyControls(el, this.actions, false); self.drawScene(); }, OnSliderInput = function() { /* "this" will be the slider */ this.rgltimer.value = Number(this.value); this.rgltimer.Tick(); }, addSlider = function(min, max, step, value) { var slider = document.createElement("input"); slider.type = "range"; slider.min = min; slider.max = max; slider.step = step; slider.value = value; slider.oninput = OnSliderInput; slider.sliderActions = control.actions; slider.sliderScene = this; slider.className = "rgl-slider"; slider.id = el.id + "-slider"; el.rgltimer.Slider = slider; slider.rgltimer = el.rgltimer; el.appendChild(slider); }, addLabel = function(labels, min, step, precision) { var output = document.createElement("output"); output.sliderMin = min; output.sliderStep = step; output.outputPrecision = precision; output.className = "rgl-label"; output.id = el.id + "-label"; el.rgltimer.Output = output; el.rgltimer.outputLabels = labels; el.appendChild(output); }, addButton = function(which, label, active) { var button = document.createElement("input"), onclicks = {Reverse: function() { this.rgltimer.reverse();}, Play: function() { this.rgltimer.play(); this.value = this.rgltimer.enabled ? this.inactiveValue : this.activeValue; }, Slower: function() { this.rgltimer.slower(); }, Faster: function() { this.rgltimer.faster(); }, Reset: function() { this.rgltimer.reset(); }, Step: function() { this.rgltimer.step(); } }; button.rgltimer = el.rgltimer; button.type = "button"; button.value = label; button.activeValue = label; button.inactiveValue = active; if (which === "Play") button.rgltimer.PlayButton = button; button.onclick = onclicks[which]; button.className = "rgl-button"; button.id = el.id + "-" + which; el.appendChild(button); }; if (typeof control.reinit !== "undefined" && control.reinit !== null) { control.actions.reinit = control.reinit; } el.rgltimer = new rgltimerClass(Tick, control.start, control.interval, control.stop, control.step, control.value, control.rate, control.loop, control.actions); for (var i=0; i < components.length; i++) { switch(components[i]) { case "Slider": addSlider(control.start, control.stop, control.step, control.value); break; case "Label": addLabel(control.labels, control.start, control.step, control.precision); break; default: addButton(components[i], buttonLabels[i], control.pause); } } el.rgltimer.Tick(); }; /** * Apply all registered controls * @param { Object } el - DOM element of the control * @param { Object } x - List of actions to apply * @param { boolean } [draw=true] - Whether to redraw after applying */ rglwidgetClass.prototype.applyControls = function(el, x, draw) { var self = this, reinit = x.reinit, i, control, type; for (i = 0; i < x.length; i++) { control = x[i]; type = control.type; self[type](el, control); } if (typeof reinit !== "undefined" && reinit !== null) { reinit = [].concat(reinit); for (i = 0; i < reinit.length; i++) self.getObj(reinit[i]).initialized = false; } if (typeof draw === "undefined" || draw) self.drawScene(); }; /** * Handler for scene change * @param { Object } message - What sort of scene change to do? */ rglwidgetClass.prototype.sceneChangeHandler = function(message) { var self = document.getElementById(message.elementId).rglinstance, objs = message.objects, mat = message.material, root = message.rootSubscene, initSubs = message.initSubscenes, redraw = message.redrawScene, skipRedraw = message.skipRedraw, deletes, subs, allsubs = [], i,j; if (typeof message.delete !== "undefined") { deletes = [].concat(message.delete); if (typeof message.delfromSubscenes !== "undefined") subs = [].concat(message.delfromSubscenes); else subs = []; for (i = 0; i < deletes.length; i++) { for (j = 0; j < subs.length; j++) { self.delFromSubscene(deletes[i], subs[j]); } delete self.scene.objects[deletes[i]]; } } if (typeof objs !== "undefined") { Object.keys(objs).forEach(function(key){ key = parseInt(key, 10); self.scene.objects[key] = objs[key]; self.initObjId(key); var obj = self.getObj(key), subs = [].concat(obj.inSubscenes), k; allsubs = allsubs.concat(subs); for (k = 0; k < subs.length; k++) self.addToSubscene(key, subs[k]); }); } if (typeof mat !== "undefined") { self.scene.material = mat; } if (typeof root !== "undefined") { self.scene.rootSubscene = root; } if (typeof initSubs !== "undefined") allsubs = allsubs.concat(initSubs); allsubs = self.unique(allsubs); for (i = 0; i < allsubs.length; i++) { self.initSubscene(allsubs[i]); } if (typeof skipRedraw !== "undefined") { root = self.getObj(self.scene.rootSubscene); root.par3d.skipRedraw = skipRedraw; } if (redraw) self.drawScene(); }; rgl/inst/htmlwidgets/lib/rglClass/shaders.src.js0000644000176200001440000001457214771520323021460 0ustar liggesusers /** * Methods related to shaders * @name ___METHODS_FOR_SHADERS___ * @memberof rglwidgetClass * @kind function * @instance */ /** * Get flags that will end up as shader defines. * Static method so it can be called from R */ rglwidgetClass.getDefFlags = function(flags, type, normals, round_points) { var f = {}; f.fat_lines = rglwidgetClass.isSet(flags, rglwidgetClass.f_fat_lines); f.fixed_quads = rglwidgetClass.isSet(flags, rglwidgetClass.f_fixed_quads); f.fixed_size = rglwidgetClass.isSet(flags, rglwidgetClass.f_fixed_size); f.has_fog = rglwidgetClass.isSet(flags, rglwidgetClass.f_has_fog); f.has_normals = (typeof normals !== "undefined") || type === "spheres"; f.has_texture = rglwidgetClass.isSet(flags, rglwidgetClass.f_has_texture); f.is_brush = rglwidgetClass.isSet(flags, rglwidgetClass.f_is_brush); f.is_lines = rglwidgetClass.isSet(flags, rglwidgetClass.f_is_lines); f.is_lit = rglwidgetClass.isSet(flags, rglwidgetClass.f_is_lit); f.is_points = rglwidgetClass.isSet(flags, rglwidgetClass.f_is_points); f.is_transparent = rglwidgetClass.isSet(flags, rglwidgetClass.f_is_transparent); f.is_twosided = rglwidgetClass.isSet(flags, rglwidgetClass.f_is_twosided); f.needs_vnormal = !rglwidgetClass.isSet(flags, rglwidgetClass.f_sprites_3d) && (f.is_lit && !f.fixed_quads && !f.is_brush) || (f.is_twosided && f.has_normals); f.rotating = rglwidgetClass.isSet(flags, rglwidgetClass.f_rotating); f.round_points = round_points; return f; }; /** * Generate the defines for the shader code for an object. * * This is a static method so it can be called from R. * * @returns {string} * @param id - id of object * @param type - type of object * @param flags - object flags * @param nclipplanes - number of clipping planes in scene * (may not all be active) * @param nlights - number of lights in scene (ditto) * @param normals - normals for object * @param pointSize - point size for object * @param textype - texture type for object * @param antialias - use antialiasing? */ rglwidgetClass.getDefines = function(id, type, flags, nclipplanes, nlights, normals, pointSize, textype, texmode, texenvmap, antialias, fl) { var title, defines; if (typeof fl === "undefined") fl = rglwidgetClass.getDefFlags(flags, type, normals, antialias); title = " /* ****** "+type+" object "+id+" shader ****** */\n"; defines = "#define NCLIPPLANES " + nclipplanes + "\n"+ "#define NLIGHTS " + nlights + "\n"; if (fl.fat_lines) defines = defines + "#define FAT_LINES 1\n"; if (fl.fixed_quads) defines = defines + "#define FIXED_QUADS 1\n"; if (fl.fixed_size) defines = defines + "#define FIXED_SIZE 1\n"; if (fl.has_fog) defines = defines + "#define HAS_FOG 1\n"; if (fl.has_normals) defines = defines + "#define HAS_NORMALS 1\n"; if (fl.has_texture) { defines = defines + "#define HAS_TEXTURE 1\n"; defines = defines + "#define TEXTURE_" + textype + "\n"; defines = defines + "#define TEXMODE_" + texmode + "\n"; if (texenvmap) defines = defines + "#define USE_ENVMAP 1\n"; } if (fl.is_brush) defines = defines + "#define IS_BRUSH 1\n"; if (type === "linestrip") defines = defines + "#define IS_LINESTRIP 1\n"; if (fl.is_lit) defines = defines + "#define IS_LIT 1\n"; if (fl.is_points) { defines = defines + "#define IS_POINTS 1\n"; defines = defines + "#define POINTSIZE " + Number.parseFloat(pointSize).toFixed(1) + "\n"; } if (type === "sprites") defines = defines + "#define IS_SPRITES 1\n"; if (type === "text") defines = defines + "#define IS_TEXT 1\n"; if (fl.is_transparent) defines = defines + "#define IS_TRANSPARENT 1\n"; if (fl.is_twosided) defines = defines + "#define IS_TWOSIDED 1\n"; if (fl.needs_vnormal) defines = defines + "#define NEEDS_VNORMAL 1\n"; if (fl.rotating) defines = defines + "#define ROTATING 1\n"; if (fl.round_points) defines = defines + "#define ROUND_POINTS 1\n"; // console.log(result); return title + defines; }; /** * Create code for vertex and fragment shaders * @returns {Object} * @param { number } shaderType - gl code for shader type * @param { string } code - code for the shader */ rglwidgetClass.prototype.getShaders = function(obj) { var header, vertex = obj.userVertexShader, fragment = obj.userFragmentShader; header = rglwidgetClass.getDefines( obj.id, obj.type, obj.flags, this.countClipplanes(), this.countLights(), obj.normals, this.getMaterial(obj, "size"), this.getMaterial(obj, "textype"), this.getMaterial(obj, "texmode"), this.getMaterial(obj, "texenvmap"), this.getMaterial(obj, "point_antialias"), obj.defFlags ); if (typeof vertex === "undefined") vertex = rglwidgetClass.rgl_vertex_shader(); if (typeof fragment === "undefined") fragment = rglwidgetClass.rgl_fragment_shader(); // console.log("vertex:"); // console.log(header + vertex); // console.log("fragment:"); // console.log(header + fragment); return {vertex: header + vertex, fragment: header + fragment}; }; /** * Call gl functions to create and compile shader from code * @returns {Object} * @param { number } shaderType - gl code for shader type * @param { string } code - code for the shader */ rglwidgetClass.prototype.getShader = function(shaderType, code) { var gl = this.gl, shader; shader = gl.createShader(shaderType); gl.shaderSource(shader, code); gl.compileShader(shader); if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS) && !gl.isContextLost()) alert(gl.getShaderInfoLog(shader)); return shader; }; rgl/inst/htmlwidgets/lib/rglClass/projection.src.js0000644000176200001440000001200414771520323022167 0ustar liggesusers /** * Methods related to projections * @name ___METHODS_FOR_PROJECTIONS___ * @memberof rglwidgetClass * @kind function * @instance */ /** * Get the viewport */ rglwidgetClass.prototype.getViewport = function(id) { var vp = this.getObj(id).par3d.viewport, x = vp.x*this.canvas.width, y = vp.y*this.canvas.height, width = vp.width*this.canvas.width, height = vp.height*this.canvas.height; this.vp = {x:x, y:y, width:width, height:height}; }; /** * Set the gl viewport and scissor test * @param { number } id - id of subscene */ rglwidgetClass.prototype.setViewport = function(id) { var gl = this.gl || this.initGL(); this.getViewport(id); gl.viewport(this.vp.x, this.vp.y, this.vp.width, this.vp.height); gl.scissor(this.vp.x, this.vp.y, this.vp.width, this.vp.height); gl.enable(gl.SCISSOR_TEST); }; /** * Set the projection matrix for a subscene * @param { number } id - id of subscene */ rglwidgetClass.prototype.setprMatrix = function(id) { var subscene = this.getObj(id), embedding = subscene.embeddings.projection; if (embedding === "replace") this.prMatrix.makeIdentity(); else this.setprMatrix(subscene.parent); if (embedding === "inherit") return; // This is based on the Frustum::enclose code from geom.cpp var bbox = subscene.par3d.bbox, scale = subscene.par3d.scale, ranges = [(bbox[1]-bbox[0])*scale[0]/2, (bbox[3]-bbox[2])*scale[1]/2, (bbox[5]-bbox[4])*scale[2]/2], radius = Math.sqrt(this.sumsq(ranges))*1.1; // A bit bigger to handle labels if (radius <= 0) radius = 1; var observer = subscene.par3d.observer, distance = observer[2], FOV = subscene.par3d.FOV, ortho = FOV === 0, t = ortho ? 1 : Math.tan(FOV*Math.PI/360), near = distance - radius, far = distance + radius, hlen, aspect = this.vp.width/this.vp.height, z = subscene.par3d.zoom, userProjection = subscene.par3d.userProjection; if (far < 0.0) far = 1.0; if (near < far/100.0) near = far/100.0; this.frustum = {near:near, far:far}; hlen = t*near; if (ortho) { if (aspect > 1) this.prMatrix.ortho(-hlen*aspect*z, hlen*aspect*z, -hlen*z, hlen*z, near, far); else this.prMatrix.ortho(-hlen*z, hlen*z, -hlen*z/aspect, hlen*z/aspect, near, far); } else { if (aspect > 1) this.prMatrix.frustum(-hlen*aspect*z, hlen*aspect*z, -hlen*z, hlen*z, near, far); else this.prMatrix.frustum(-hlen*z, hlen*z, -hlen*z/aspect, hlen*z/aspect, near, far); } this.prMatrix.multRight(userProjection); }; /** * Set the model-view matrix for a subscene * @param { number } id - id of the subscene */ rglwidgetClass.prototype.setmvMatrix = function(id) { var observer = this.getObj(id).par3d.observer; this.mvMatrix.makeIdentity(); this.setmodelMatrix(id); this.mvMatrix.translate(-observer[0], -observer[1], -observer[2]); }; /** * Set the model matrix for a subscene * @param { number } id - id of the subscene */ rglwidgetClass.prototype.setmodelMatrix = function(id) { var subscene = this.getObj(id), embedding = subscene.embeddings.model; if (embedding === "replace") { var bbox = subscene.par3d.bbox, center = [(bbox[0]+bbox[1])/2, (bbox[2]+bbox[3])/2, (bbox[4]+bbox[5])/2]; this.mvMatrix.translate(-center[0], -center[1], -center[2]); } if (embedding !== "inherit") { var scale = subscene.par3d.scale; this.mvMatrix.scale(scale[0], scale[1], scale[2]); this.mvMatrix.multRight( subscene.par3d.userMatrix ); } if (embedding !== "replace") this.setmodelMatrix(subscene.parent); }; /** * Set the normals matrix for a subscene * @param { number } subsceneid - id of the subscene */ rglwidgetClass.prototype.setnormMatrix2 = function() { this.normMatrix = new CanvasMatrix4(this.mvMatrix); this.normMatrix.invert(); this.normMatrix.transpose(); }; /** * Set the combined projection-model-view matrix */ rglwidgetClass.prototype.setprmvMatrix = function() { this.prmvMatrix = new CanvasMatrix4( this.mvMatrix ); this.prmvMatrix.multRight( this.prMatrix ); }; rglwidgetClass.prototype.setInvPrMatrix = function() { this.invPrMatrix = new CanvasMatrix4( this.prMatrix ); this.invPrMatrix.invert(); this.invPrMatrix.transpose(); }; rgl/inst/htmlwidgets/lib/rglClass/animation.src.js0000644000176200001440000001036614771520323022003 0ustar liggesusers/** * Methods related to animations * @name ___METHODS_FOR_ANIMATION___ * @memberof rglwidgetClass * @kind function * @instance */ /** * Binary search * @param x - x coordinates in increasing order * @param newx - value to find, assumed to be in the range of x * @result index of largest x value below newx */ rglwidgetClass.bisect = function(x, newx) { var lo = 0, hi = x.length - 1, mid; while (lo < hi - 1) { mid = Math.round((lo + hi)/2); if (x[mid] < newx) lo = mid; else hi = mid; } return lo; }; /** * Step interpolation (constant outside bounds) * @param x - x coordinates in increasing order * @param v - values at x; either a vector or matrix * @param newx - value at which to evaluate */ rglwidgetClass.step = function(x, v, newx) { var n, lo; if (newx <= x[0]) return v[0]; n = x.length; if (newx >= x[n-1]) return v[n-1]; lo = this.bisect(x, newx); return v[lo]; }; /** * Linear interpolation (constant outside bounds) * @param x - x coordinates in increasing order * @param v - values at x; either a vector or matrix * @param newx - value at which to evaluate */ rglwidgetClass.lerp = function(x, v, newx) { var i, n, lo, hi, alpha, result; if (newx <= x[0]) return v[0]; n = x.length; if (newx >= x[n-1]) return v[n-1]; lo = this.bisect(x, newx); if (newx === x[lo]) return v[lo]; hi = lo + 1; if (newx === x[hi]) return v[hi]; alpha = (newx - x[lo])/(x[hi] - x[lo]); result = v[lo]; n = result.length; if (typeof n !== "undefined") { for (i = 0; i < n; i++) result[i] = (1 - alpha)*result[i] + alpha*v[hi][i]; } else result = (1 - alpha)*result + alpha*v[hi]; return result; }; /** * Spherical linear interpolation (constant outside bounds) * @param x - x coordinates in increasing order * @param v - a matrix of unit quaternions * @param newx - value at which to evaluate */ rglwidgetClass.slerp = function(x, v, newx) { var n, lo, hi, alpha, result, p0, p1, dot, Omega, alpha0, alpha1, len; if (newx <= x[0]) return v[0]; if (newx >= x[n-1]) return v[n-1]; lo = this.bisect(x, newx); if (newx === x[lo]) return v[lo]; hi = lo + 1; if (newx === x[hi]) return v[hi]; p0 = v[lo]; p1 = v[hi]; dot = p0[0]*p1[0] + p0[1]*p1[1] + p0[2]*p1[2] + p0[3]*p1[3]; if (dot < 0) { p1 = [-p1[0], -p1[1], -p1[2], -p1[3]]; dot = -dot; } if (dot >= 1) result = p1; else { alpha = (newx - x[lo])/(x[hi] - x[lo]); Omega = Math.acos(dot); alpha0 = Math.sin((1 - alpha)*Omega); alpha1 = Math.sin(alpha*Omega); result = [alpha0*p0[0] + alpha1*p1[0], alpha0*p0[1] + alpha1*p1[1], alpha0*p0[2] + alpha1*p1[2], alpha0*p0[3] + alpha1*p1[3]]; } len = Math.sqrt(result[0]*result[0] + result[1]*result[1] + result[2]*result[2] + result[3]*result[3]); return [result[0]/len, result[1]/len, result[2]/len, result[3]/len]; }; /** * Rotate using unit quaternion * @param q - a single unit quaternion */ rglwidgetClass.rotateByQuaternion = function(M, q) { var xx = q[0]*q[0], xy = q[0]*q[1], xz = q[0]*q[2], xw = q[0]*q[3], yy = q[1]*q[1], yz = q[1]*q[2], yw = q[1]*q[3], zz = q[2]*q[2], zw = q[2]*q[3], matrix = new CanvasMatrix4(); matrix.m11 = 1 - 2*(yy + zz); matrix.m12 = 2*(xy + zw); matrix.m13 = 2*(xz - yw); matrix.m21 = 2*(xy - zw); matrix.m22 = 1 - 2*(xx + zz); matrix.m23 = 2*(yz + xw); matrix.m31 = 2*(xz + yw); matrix.m32 = 2*(yz - xw); matrix.m33 = 1 - 2*(xx + yy); M.multRight(matrix); }; rgl/inst/htmlwidgets/lib/rglClass/rgl.css0000644000176200001440000000044014265301464020167 0ustar liggesusers.rglPlayer { width: auto; height: auto; } .rglPlayer .rgl-button { width: auto; display: inline-block; font-size: 75%; } .rglPlayer .rgl-slider { display: inline-block; width: 30%; } .rglPlayer .rgl-label { display: inline; padding-left: 6px; padding-right: 6px; } rgl/inst/htmlwidgets/lib/rglClass/subscenes.src.js0000644000176200001440000001346514771520323022021 0ustar liggesusers /** * Methods related to subscenes * @name ___METHODS_FOR_SUBSCENES___ * @memberof rglwidgetClass * @kind function * @instance */ /** * Is a particular id in a subscene? * @returns { boolean } * @param {number} id Which id? * @param {number} subscene Which subscene id? */ rglwidgetClass.prototype.inSubscene = function(id, subscene) { return this.getObj(subscene).objects.indexOf(id) > -1; }; /** * Translate from window coordinates to viewport coordinates * @returns { Object } translated coordinates * @param { number } subsceneid - which subscene to use? * @param { Object } coords - point to translate */ rglwidgetClass.prototype.translateCoords = function(subsceneid, coords) { var viewport = this.getObj(subsceneid).par3d.viewport; return {x: coords.x - viewport.x*this.canvas.width, y: coords.y - viewport.y*this.canvas.height}; }; /** * Check whether point is in viewport of subscene * @returns {boolean} * @param { Object } coords - screen coordinates of point * @param { number } subsceneid - subscene to check */ rglwidgetClass.prototype.inViewport = function(coords, subsceneid) { var viewport = this.getObj(subsceneid).par3d.viewport, x0 = coords.x - viewport.x*this.canvas.width, y0 = coords.y - viewport.y*this.canvas.height; return 0 <= x0 && x0 <= viewport.width*this.canvas.width && 0 <= y0 && y0 <= viewport.height*this.canvas.height; }; /** * Find which subscene contains a point * @returns { number } subscene id * @param { Object } coords - coordinates of point */ rglwidgetClass.prototype.whichSubscene = function(coords) { var self = this, recurse = function(subsceneid) { var subscenes = self.getChildSubscenes(subsceneid), i, id; for (i=0; i < subscenes.length; i++) { id = recurse(subscenes[i]); if (typeof(id) !== "undefined") return(id); } if (self.inViewport(coords, subsceneid)) return(subsceneid); else return undefined; }, rootid = this.scene.rootSubscene, result = recurse(rootid); if (typeof(result) === "undefined") result = rootid; return result; }; /** * Add an id to a subscene. * @param {number} id Which id? * @param {number} subscene Which subscene id? */ rglwidgetClass.prototype.addToSubscene = function(id, subscene) { var thelist, thesub = this.getObj(subscene), ids = [id], obj = this.getObj(id), i; if (typeof obj !== "undefined" && typeof (obj.newIds) !== "undefined") { ids = ids.concat(obj.newIds); } thesub.objects = [].concat(thesub.objects); for (i = 0; i < ids.length; i++) { id = ids[i]; if (thesub.objects.indexOf(id) === -1) { thelist = this.whichList(id); thesub.objects.push(id); thesub[thelist].push(id); } } }; /** * Delete an id from a subscene * @param { number } id - the id to add * @param { number } subscene - the id of the subscene */ rglwidgetClass.prototype.delFromSubscene = function(id, subscene) { var thelist, thesub = this.getObj(subscene), obj = this.getObj(id), ids = [id], i, j; if (typeof obj !== "undefined" && typeof (obj.newIds) !== "undefined") ids = ids.concat(obj.newIds); thesub.objects = [].concat(thesub.objects); // It might be a scalar for (j=0; j -1) { thesub.objects.splice(i, 1); thelist = this.whichList(id); i = thesub[thelist].indexOf(id); thesub[thelist].splice(i, 1); } } }; /** * Set the ids in a subscene * @param { number[] } ids - the ids to set * @param { number } subsceneid - the id of the subscene */ rglwidgetClass.prototype.setSubsceneEntries = function(ids, subsceneid) { var sub = this.getObj(subsceneid); sub.objects = ids; this.initSubscene(subsceneid); }; /** * Get the ids in a subscene * @returns {number[]} * @param { number } subscene - the id of the subscene */ rglwidgetClass.prototype.getSubsceneEntries = function(subscene) { return this.getObj(subscene).objects; }; /** * Get the ids of the subscenes within a subscene * @returns { number[] } * @param { number } subscene - the id of the subscene */ rglwidgetClass.prototype.getChildSubscenes = function(subscene) { return this.getObj(subscene).subscenes; }; /** * Find a particular subscene by inheritance * @returns { number } id of subscene to use * @param { number } subsceneid - child subscene * @param { string } type - type of inheritance: "projection" or "model" */ rglwidgetClass.prototype.useid = function(subsceneid, type) { var sub = this.getObj(subsceneid); if (sub.embeddings[type] === "inherit") return(this.useid(sub.parent, type)); else return subsceneid; }; /** * Find bboxdeco for a subscene * @returns { number } id of bboxdeco, or undefined if none * @param { number } sub- subscene */ rglwidgetClass.prototype.getBBoxDeco = function(sub) { var objects = sub.objects, i, obj; for (i = 0; i < objects.length; i++) { obj = this.getObj(objects[i]); if (obj.type === "bboxdeco") return obj; } if (sub.parent) return this.getBBoxDeco(this.getObj(sub.parent)); else return undefined; }; rgl/inst/htmlwidgets/lib/rglClass/JSDoc.json0000644000176200001440000000076614771520323020540 0ustar liggesusers{ "opts": { "encoding" : "utf8", "destination" : ".JSDoc/rglClass" }, "templates": { "systemName" : "rglClass", "systemSummary" : "Javascript support for `rglwidget`", "copyright" : "rglClass copyright Duncan Murdoch", "includeDate" : false, "dateFormat" : "DD MMM YYYY", "collapseSymbols" : false, "sort" : "source,name", "outputSourceFiles" : true } } rgl/inst/doc/0000755000176200001440000000000015026603600012556 5ustar liggesusersrgl/inst/doc/rgl.R0000644000176200001440000001032515026603577013503 0ustar liggesusers## ----setup, echo=FALSE, results="asis"---------------------------------------- source("setup.R") setupKnitr(autoprint = TRUE) set.seed(123) ## ----"plot3d()"--------------------------------------------------------------- with(iris, plot3d(Sepal.Length, Sepal.Width, Petal.Length, type="s", col=as.numeric(Species))) ## ----"persp3d()", fig.height=3, fig.width=6, fig.keep="last", eval=requireNamespace("MASS",quietly=TRUE)---- # This example requires the MASS package library(MASS) # from the fitdistr example set.seed(123) x <- rgamma(100, shape = 5, rate = 0.1) fit <- fitdistr(x, dgamma, list(shape = 1, rate = 0.1), lower = 0.001) loglik <- function(shape, rate) sum(dgamma(x, shape=shape, rate=rate, log=TRUE)) loglik <- Vectorize(loglik) xlim <- fit$estimate[1]+4*fit$sd[1]*c(-1,1) ylim <- fit$estimate[2]+4*fit$sd[2]*c(-1,1) mfrow3d(1, 2, sharedMouse = TRUE) persp3d(loglik, xlim = xlim, ylim = ylim, n = 30) zlim <- fit$loglik + c(-qchisq(0.99, 2)/2, 0) next3d() persp3d(loglik, xlim = xlim, ylim = ylim, zlim = zlim, n = 30) ## ----------------------------------------------------------------------------- methods(plot3d) methods(persp3d) ## ----"triangles3d()", fig.width=3, fig.height=3------------------------------- triangles3d(cbind(x=rnorm(9), y=rnorm(9), z=rnorm(9)), col = "green") decorate3d() bg3d("lightgray") aspect3d(1,1,1) ## ----eval = FALSE------------------------------------------------------------- # myview <- par3d("userMatrix") # # ... later ... # par3d(userMatrix = myview) ## ----Texture------------------------------------------------------------------ filename <- tempfile(fileext = ".png") png(filename = filename) plot(rnorm(1000), rnorm(1000)) safe.dev.off() open3d() xyz <- cbind(c(0,1,1,0), 0, c(0,0,1,1)) quads3d(xyz, texture = filename, texcoords = xyz[,c(1, 3)]*2, col = "white", specular = "black") ## ----Solids------------------------------------------------------------------- cols <- rainbow(7) layout3d(matrix(1:16, 4,4), heights=c(1,3,1,3)) text3d(0,0,0,"tetrahedron3d"); next3d() shade3d(tetrahedron3d(col=cols[1])); next3d() text3d(0,0,0,"cube3d"); next3d() shade3d(cube3d(col=cols[2])); next3d() text3d(0,0,0,"octahedron3d"); next3d() shade3d(octahedron3d(col=cols[3])); next3d() text3d(0,0,0,"dodecahedron3d"); next3d() shade3d(dodecahedron3d(col=cols[4])); next3d() text3d(0,0,0,"icosahedron3d"); next3d() shade3d(icosahedron3d(col=cols[5])); next3d() text3d(0,0,0,"cuboctahedron3d"); next3d() shade3d(cuboctahedron3d(col=cols[6])); next3d() text3d(0,0,0,"oh3d"); next3d() shade3d(oh3d(col=cols[7])) ## ----Autoprint---------------------------------------------------------------- xyz <- matrix(rnorm(27), ncol = 3) triangles3d(xyz, col = rainbow(9)) spheres3d(xyz, col = rainbow(9), radius = 0.1) ## ----eval = FALSE------------------------------------------------------------- # plots <- NULL # for (i in 1:3) { # plot3d(rnorm(10), rnorm(10), rnorm(10)) # plots <- htmltools::tagList(plots, rglwidget()) # close3d() # } # plots ## ----eval = FALSE------------------------------------------------------------- # foreignHigh() # Produces a high level plot, but doesn't return # # an appropriate value # highlevel() # foreignLow() # Modifies the previous plot # lowlevel() ## ----------------------------------------------------------------------------- par3d("mouseMode") ## ----fig.alt="Volcano in rgl", echo = 2:3------------------------------------- close3d() persp3d(volcano, col = "green") ## ----eval=requireNamespace("orientlib", quietly = TRUE) && requireNamespace("lattice", quietly = TRUE), fig.alt=paste0("Volcano in ", c("lattice", "base"), "graphics.")---- # Only evaluated if the lattice & orientlib packages are installed lattice::wireframe(volcano, col = "green", screen = rglToLattice()) angles <- rglToBase() persp(volcano, col = "green", shade = TRUE, theta = angles$theta, phi = angles$phi) ## ----echo=FALSE--------------------------------------------------------------- setdiff(ls("package:rgl"), c(documentedfns, deprecatedfns)) ## ----echo=FALSE, results="asis"----------------------------------------------- writeIndex(cols = if (knitr::is_html_output()) 5 else 4) rgl/inst/doc/demos.R0000644000176200001440000005051415026603565014027 0ustar liggesusers## ----setup, include = FALSE--------------------------------------------------- knitr::opts_chunk$set( collapse = FALSE, # Bug in knitr 1.42 requires FALSE here comment = "#>", snapshot = FALSE, screenshot.force = FALSE) library(rgl) setupKnitr(autoprint = TRUE) ## ----------------------------------------------------------------------------- ########## ### 3D HIST EXAMPLE: ########## ################################################################################ ##### Required functions 'binplot' and 'hist3d': binplot.3d<-function(x,y,z,alpha=1,topcol="#ff0000",sidecol="#aaaaaa") { save <- par3d(skipRedraw=TRUE) on.exit(par3d(save)) x1<-c(rep(c(x[1],x[2],x[2],x[1]),3),rep(x[1],4),rep(x[2],4)) z1<-c(rep(0,4),rep(c(0,0,z,z),4)) y1<-c(y[1],y[1],y[2],y[2],rep(y[1],4),rep(y[2],4),rep(c(y[1],y[2],y[2],y[1]),2)) x2<-c(rep(c(x[1],x[1],x[2],x[2]),2),rep(c(x[1],x[2],rep(x[1],3),rep(x[2],3)),2)) z2<-c(rep(c(0,z),4),rep(0,8),rep(z,8) ) y2<-c(rep(y[1],4),rep(y[2],4),rep(c(rep(y[1],3),rep(y[2],3),y[1],y[2]),2) ) quads3d(x1,z1,y1,col=rep(sidecol,each=4),alpha=alpha) quads3d(c(x[1],x[2],x[2],x[1]),rep(z,4),c(y[1],y[1],y[2],y[2]), col=rep(topcol,each=4),alpha=1) segments3d(x2,z2,y2,col="#000000") } hist3d<-function(x,y=NULL,nclass="auto",alpha=1,col="#ff0000",scale=10) { save <- par3d(skipRedraw=TRUE) on.exit(par3d(save)) xy <- xy.coords(x,y) x <- xy$x y <- xy$y n<-length(x) if (nclass == "auto") nclass<-ceiling(sqrt(nclass.Sturges(x))) breaks.x <- seq(min(x),max(x),length=(nclass+1)) breaks.y <- seq(min(y),max(y),length=(nclass+1)) z<-matrix(0,(nclass),(nclass)) for (i in seq_len(nclass)) { for (j in seq_len(nclass)) { z[i, j] <- (1/n)*sum(x < breaks.x[i+1] & y < breaks.y[j+1] & x >= breaks.x[i] & y >= breaks.y[j]) binplot.3d(c(breaks.x[i],breaks.x[i+1]),c(breaks.y[j],breaks.y[j+1]), scale*z[i,j],alpha=alpha,topcol=col) } } } ################################################################################ open3d() bg3d(color="gray") light3d(0, 0) # Drawing a 'bin' for given coordinates: binplot.3d(c(-0.5,0.5),c(4.5,5.5),2,alpha=0.6) # Setting the viewpoint ('theta' and 'phi' have the same meaning as in persp): view3d(theta=40,phi=40) ##### QUADS FORMING BIN open3d() # Defining transparency and colors: alpha<-0.7; topcol<-"#ff0000"; sidecol<-"#aaaaaa" # Setting up coordinates for the quads and adding them to the scene: y<-x<-c(-1,1) ; z<-4; of<-0.3 x12<-c(x[1],x[2],x[2],x[1]); x11<-rep(x[1],4); x22<-rep(x[2],4) z00<-rep(0,4); z0z<-c(0,0,z,z); zzz<-rep(z,4); y11<-rep(y[1],4) y1122<-c(y[1],y[1],y[2],y[2]); y12<-c(y[1],y[2],y[2],y[1]); y22<-rep(y[2],4) quads3d(c(x12,x12,x11-of,x12,x22+of,x12), c(z00-of,rep(z0z,4),zzz+of), c(y1122,y11-of,y12,y22+of,y12,y1122), col=rep(c(rep(sidecol,5),topcol),each=4),alpha=c(rep(alpha,5),1)) # Setting up coordinates for the border-lines of the quads and drawing them: yl1<-c(y[1],y[2],y[1],y[2]); yl2<-c(y[1]-of,y[1]-of) xl<-c(rep(x[1],8),rep(x[1]-of,8),rep(c(x[1],x[2]),8),rep(x[2],8),rep(x[2]+of,8)) zl<-c(0,z,0,z,z+of,z+of,-of,-of,0,0,z,z,0,z,0,z,rep(0,4),rep(z,4),rep(-of,4), rep(z+of,4),z+of,z+of,-of,-of,rep(c(0,z),4),0,0,z,z) yl<-c(yl2,y[2]+of,y[2]+of,rep(c(y[1],y[2]),4),y[1],y[1],y[2],y[2],yl2, rep(y[2]+of,4),yl2,y[2],y[2],rep(y[1],4),y[2],y[2],yl1,yl2,y[2]+of, y[2]+of,y[1],y[1],y[2],y[2],yl1) lines3d(xl,zl,yl,col="#000000") view3d(theta=40,phi=40) ##### COMPLETE HISTOGRAM: open3d() # Setting the rng to a fixed value: set.seed(1000) # Drawing a 3d histogramm of 2500 normaly distributed observations: hist3d(rnorm(2500),rnorm(2500),alpha=0.4,nclass=7,scale=30) # Choosing a lightgrey background: bg3d(col="#cccccc") view3d(theta=40,phi=40) ## ----------------------------------------------------------------------------- # rgl demo: rgl-bivar.r # author: Daniel Adler rgl.demo.bivar <- function() { if (!requireNamespace("MASS", quietly = TRUE)) stop("This demo requires MASS") # parameters: n<-50; ngrid<-40 # generate samples: set.seed(31415) x<-rnorm(n); y<-rnorm(n) # estimate non-parameteric density surface via kernel smoothing denobj <- MASS::kde2d(x, y, n=ngrid) den.z <-denobj$z # generate parametric density surface of a bivariate normal distribution xgrid <- denobj$x ygrid <- denobj$y bi.z <- dnorm(xgrid)%*%t(dnorm(ygrid)) # visualize: zscale<-20 # New window open3d() # clear scene: clear3d("all") # setup env: bg3d(color="#887777") light3d() # Draws the simulated data as spheres on the baseline spheres3d(x,y,rep(0,n),radius=0.1,color="#CCCCFF") # Draws non-parametric density surface3d(xgrid,ygrid,den.z*zscale,color="#FF2222",alpha=0.5) # Draws parametric density surface3d(xgrid,ygrid,bi.z*zscale,color="#CCCCFF",front="lines") } rgl.demo.bivar() ## ----------------------------------------------------------------------------- # RGL-Demo: animal abundance # Authors: Oleg Nenadic, Daniel Adler rgl.demo.abundance <- function() { open3d() clear3d("all") # remove all shapes, lights, bounding-box, and restore viewpoint # Setup environment: bg3d(col="#cccccc") # setup background light3d() # setup head-light # Importing animal data (created with wisp) terrain<-dget(system.file("demodata/region.dat",package="rgl")) pop<-dget(system.file("demodata/population.dat",package="rgl")) # Define colors for terrain zlim <- range(terrain) colorlut <- terrain.colors(82) col1 <- colorlut[9*sqrt(3.6*(terrain-zlim[1])+2)] # Set color to (water-)blue for regions with zero 'altitude' col1[terrain==0]<-"#0000FF" # Add terrain surface shape (i.e. population density): surface3d( 1:100,seq(1,60,length=100),terrain, col=col1,spec="#000000", ambient="#333333", back="lines" ) # Define colors for simulated populations (males:blue, females:red): col2<-pop[,4] col2[col2==0]<-"#3333ff" col2[col2==1]<-"#ff3333" # Add simulated populations as sphere-set shape spheres3d( pop[,1], pop[,2], terrain[cbind( ceiling(pop[,1]),ceiling(pop[,2]*10/6) )]+0.5, radius=0.2*pop[,3], col=col2, alpha=(1-(pop[,5])/10 ) ) } rgl.demo.abundance() ## ----------------------------------------------------------------------------- # demo: lsystem.r # author: Daniel Adler # # geometry # deg2rad <- function( degree ) { return( degree*pi/180 ) } rotZ.m3x3 <- function( degree ) { kc <- cos(deg2rad(degree)) ks <- sin(deg2rad(degree)) return( matrix( c( kc, -ks, 0, ks, kc, 0, 0, 0, 1 ),ncol=3,byrow=TRUE ) ) } rotX.m3x3 <- function( degree ) { kc <- cos(deg2rad(degree)) ks <- sin(deg2rad(degree)) return( matrix( c( 1, 0, 0, 0, kc, -ks, 0, ks, kc ),ncol=3,byrow=TRUE ) ) } rotY.m3x3 <- function( degree ) { kc <- cos(deg2rad(degree)) ks <- sin(deg2rad(degree)) return( matrix( c( kc, 0, ks, 0, 1, 0, -ks, 0, kc ),ncol=3,byrow=TRUE ) ) } rotZ <- function( v, degree ) { return( rotZ.m3x3(degree) %*% v) } rotX <- function( v, degree ) { return( rotX.m3x3(degree) %*% v) } rotY <- function( v, degree ) { return( rotY.m3x3(degree) %*% v) } # # turtle graphics, rgl implementation: # turtle.init <- function(pos=c(0,0,0),head=0,pitch=90,roll=0,level=0) { clear3d("all") bg3d(color="gray") light3d() return( list(pos=pos,head=head,pitch=pitch,roll=roll,level=level) ) } turtle.move <- function(turtle, steps, color) { rm <- rotX.m3x3(turtle$pitch) %*% rotY.m3x3(turtle$head) %*% rotZ.m3x3(turtle$roll) from <- as.vector( turtle$pos ) dir <- rm %*% c(0,0,-1) to <- from + dir * steps x <- c( from[1], to[1] ) y <- c( from[2], to[2] ) z <- c( from[3], to[3] ) lines3d(x,y,z,col=color,size=1.5,alpha=0.5) turtle$pos <- to return(turtle) } turtle.pitch <- function(turtle, degree) { turtle$pitch <- turtle$pitch + degree return(turtle) } turtle.head <- function(turtle, degree) { turtle$head <- turtle$head + degree return(turtle) } turtle.roll <- function(turtle, degree) { turtle$roll <- turtle$roll + degree return(turtle) } # # l-system general # lsystem.code <- function( x ) substitute( x ) lsystem.gen <- function( x, grammar, levels=0 ) { code <- eval( substitute( substitute( REPLACE , grammar ), list(REPLACE=x) ) ) if (levels) return( lsystem.gen( code , grammar , levels-1 ) ) else return( code ) } # # l-system plot # lsystem.plot <- function( expr, level ) { turtle <- turtle.init(level=level) lsystem.eval( expr, turtle ) } lsystem.eval <- function( expr, turtle ) { if ( length(expr) == 3 ) { turtle <- lsystem.eval( expr[[2]], turtle ) turtle <- lsystem.eval( expr[[3]], turtle ) turtle <- lsystem.eval( expr[[1]], turtle ) } else if ( length(expr) == 2 ) { saved <- turtle turtle <- lsystem.eval( expr[[1]], turtle ) turtle <- lsystem.eval( expr[[2]], turtle ) turtle <- saved } else if ( length(expr) == 1 ) { if ( as.name(expr) == "stem" ) turtle <- turtle.move(turtle, 5, "brown") else if ( as.name(expr) == "short") turtle <- turtle.move(turtle, 5, "brown") else if ( as.name(expr) == "leaf" ) { spheres3d(turtle$pos[1],turtle$pos[2],turtle$pos[3],radius=0.1+turtle$level*0.3,color="green") sprites3d(turtle$pos[1],turtle$pos[2],turtle$pos[3],radius=0.5+turtle$level*0.3 ,color="green",texture=system.file("textures/particle.png",package="rgl"),textype="alpha",alpha=0.5) } else if ( as.name(expr) == "roll" ) turtle <- turtle.head(turtle, 60) else if ( as.name(expr) == "down" ) turtle <- turtle.pitch(turtle,10) else if ( as.name(expr) == "up" ) turtle <- turtle.pitch(turtle,-10) else if ( as.name(expr) == "left" ) turtle <- turtle.head(turtle, 1) else if ( as.name(expr) == "right") turtle <- turtle.head(turtle,-1.5) else if ( as.name(expr) == "turnleft") turtle <- turtle.head(turtle,20) else if ( as.name(expr) == "turnright") turtle <- turtle.head(turtle,-20) else if ( as.name(expr) == "turn") turtle <- turtle.roll(turtle,180) } return(turtle) } # # example # simple <- function(level=0) { grammar <- list( stem=lsystem.code( stem-(up-stem-leaf)-stem-(down-stem-leaf)-stem-leaf ) ) plant <- lsystem.gen(lsystem.code(stem), grammar, level ) lsystem.plot(plant,level) } rgl.demo.lsystem <- function(level=0) { gen <- list( stem=lsystem.code( stem-left-stem-branch( turnleft-down-short-turnleft-down-stem-leaf)-right-right-stem--branch( turnright-up-short-turnright-up-short-turnright-short-stem-leaf)-left-left-left-stem-branch( turnleft-down-short-turnright-down-stem-leaf )-branch( up-turnright-short-up-turnleft-up-stem-leaf ) ) ) plant <- lsystem.gen(lsystem.code(stem), gen, level ) lsystem.plot(plant,level) } open3d() rgl.demo.lsystem(level=1) rglwidget() ## ----------------------------------------------------------------------------- # RGL-demo: subdivision surfaces # author: Daniel Adler rgl.demo.subdivision <- function() { # setup environment clear3d("all") view3d() bg3d(color="gray") light3d() # generate basic mesh obj <- oh3d() part <- function( level, tx, ... ) { shade3d( translate3d( obj, tx, 0, 0 ) , color="gray30", front="lines",alpha=0.5,back="lines", override=TRUE ) shade3d( translate3d( subdivision3d( obj, depth=level ), tx, 0, 0 ) , override=TRUE, ... ) } part(0, -5.50, color="blue" ) part(1, -1.75, color="yellow" ) part(2, 1.75, color="red" ) part(3, 5.50, color="green" ) } open3d() rgl.demo.subdivision() ## ----------------------------------------------------------------------------- # RGL-Demo: environment mapping # Author: Daniel Adler rgl.demo.envmap <- function() { open3d() # Clear scene: clear3d("all") light3d() bg3d(sphere=TRUE, color="white", back="filled" , texture=system.file("textures/refmap.png",package="rgl") ) data(volcano) surface3d( 10*seq_len(nrow(volcano)),10*seq_len(ncol(volcano)),5*volcano , texture=system.file("textures/refmap.png",package="rgl") , texenvmap=TRUE , texmode="modulate" , color = "white" ) } rgl.demo.envmap() ## ----------------------------------------------------------------------------- cone3d <- function(base=c(0,0,0),tip=c(0,0,1),rad=1,n=30,draw.base=TRUE,qmesh=FALSE, trans = par3d("userMatrix"), ...) { ax <- tip-base if (missing(trans) && !cur3d()) trans <- diag(4) ### is there a better way? if (ax[1]!=0) { p1 <- c(-ax[2]/ax[1],1,0) p1 <- p1/sqrt(sum(p1^2)) if (p1[1]!=0) { p2 <- c(-p1[2]/p1[1],1,0) p2[3] <- -sum(p2*ax) p2 <- p2/sqrt(sum(p2^2)) } else { p2 <- c(0,0,1) } } else if (ax[2]!=0) { p1 <- c(0,-ax[3]/ax[2],1) p1 <- p1/sqrt(sum(p1^2)) if (p1[1]!=0) { p2 <- c(0,-p1[3]/p1[2],1) p2[3] <- -sum(p2*ax) p2 <- p2/sqrt(sum(p2^2)) } else { p2 <- c(1,0,0) } } else { p1 <- c(0,1,0); p2 <- c(1,0,0) } degvec <- seq(0,2*pi,length=n+1)[-1] ecoord2 <- function(theta) { base+rad*(cos(theta)*p1+sin(theta)*p2) } i <- rbind(1:n,c(2:n,1),rep(n+1,n)) v <- cbind(sapply(degvec,ecoord2),tip) if (qmesh) ## minor kluge for quads -- draw tip twice i <- rbind(i,rep(n+1,n)) if (draw.base) { v <- cbind(v,base) i.x <- rbind(c(2:n,1),1:n,rep(n+2,n)) if (qmesh) ## add base twice i.x <- rbind(i.x,rep(n+2,n)) i <- cbind(i,i.x) } if (qmesh) v <- rbind(v,rep(1,ncol(v))) ## homogeneous if (!qmesh) triangles3d(v[1,i],v[2,i],v[3,i],...) else return(rotate3d(qmesh3d(v,i,material=list(...)), matrix=trans)) } ellipsoid3d <- function(rx=1,ry=1,rz=1,n=30,ctr=c(0,0,0), qmesh=FALSE, trans = par3d("userMatrix"),...) { if (missing(trans) && !cur3d()) trans <- diag(4) degvec <- seq(0,pi,length=n) ecoord2 <- function(p) c(rx*cos(p[1])*sin(p[2]),ry*sin(p[1])*sin(p[2]),rz*cos(p[2])) v <- apply(expand.grid(2*degvec,degvec),1,ecoord2) if (qmesh) v <- rbind(v,rep(1,ncol(v))) ## homogeneous e <- expand.grid(1:(n-1),1:n) i1 <- apply(e,1,function(z)z[1]+n*(z[2]-1)) i2 <- i1+1 i3 <- (i1+n-1) %% n^2 + 1 i4 <- (i2+n-1) %% n^2 + 1 i <- rbind(i1,i2,i4,i3) if (!qmesh) quads3d(v[1,i],v[2,i],v[3,i],...) else return(rotate3d(qmesh3d(v,i,material=list(...)),matrix=trans)) } ############ open3d() ellipsoid3d(ctr=c(2,2,2),rx=3,ry=2,col="red",alpha=0.4) cone3d(base=c(-2,-2,-2),rad=0.5,tip=c(-3,0,-4),col="blue",front="lines",back="lines") shade3d(translate3d(cube3d(),3,-2,3,col="purple")) ### now with qmesh() open3d() q1 <- cone3d(qmesh=TRUE,trans=diag(4)) ## the "unit cone"; ## height=1,radius=1, base at (0,0,0) shade3d(q1) ## various transformations and rotations wire3d(translate3d(q1,3,0,0),col="green") wire3d(translate3d(scale3d(q1,1,1,2),6,0,0),col="green") dot3d(translate3d(q1,0,3,0),col="green") dot3d(translate3d(scale3d(q1,2,1,1),0,6,0),col="green") shade3d(translate3d(q1,0,0,3),col="red") shade3d(translate3d(rotate3d(scale3d(q1,1,1,2),pi/4,0,1,0),0,0,6),col="red") axes3d() open3d() s1 <- ellipsoid3d(qmesh=TRUE,trans=diag(4)) ## the "unit sphere"; ## radius=1, ctr at (0,0,0) shade3d(s1) ## various transformations and rotations wire3d(translate3d(s1,3,0,0),col="green") wire3d(translate3d(scale3d(s1,1,1,2),6,0,0),col="green") dot3d(translate3d(s1,0,3,0),col="green") dot3d(translate3d(scale3d(s1,2,1,1),0,6,0),col="green") shade3d(translate3d(s1,0,0,3),col="red") shade3d(translate3d(rotate3d(scale3d(s1,1,1,2),pi/4,0,1,0),0,0,6),col="red") axes3d() ## ----------------------------------------------------------------------------- cone3d <- function(base,tip,rad,n=30,...) { degvec <- seq(0,2*pi,length=n) ax <- tip-base ## what do if ax[1]==0? if (ax[1]!=0) { p1 <- c(-ax[2]/ax[1],1,0) p1 <- p1/sqrt(sum(p1^2)) if (p1[1]!=0) { p2 <- c(-p1[2]/p1[1],1,0) p2[3] <- -sum(p2*ax) p2 <- p2/sqrt(sum(p2^2)) } else { p2 <- c(0,0,1) } } else if (ax[2]!=0) { p1 <- c(0,-ax[3]/ax[2],1) p1 <- p1/sqrt(sum(p1^2)) if (p1[1]!=0) { p2 <- c(0,-p1[3]/p1[2],1) p2[3] <- -sum(p2*ax) p2 <- p2/sqrt(sum(p2^2)) } else { p2 <- c(1,0,0) } } else { p1 <- c(0,1,0); p2 <- c(1,0,0) } ecoord2 <- function(theta) { base+rad*(cos(theta)*p1+sin(theta)*p2) } for (i in seq_len(n-1)) { li <- ecoord2(degvec[i]) lj <- ecoord2(degvec[i+1]) triangles3d(c(li[1],lj[1],tip[1]),c(li[2],lj[2],tip[2]),c(li[3],lj[3],tip[3]),...) } } lollipop3d <- function(data.x,data.y,data.z,surf.fun,surf.n=50, xlim=range(data.x), ylim=range(data.y), zlim=range(data.z), asp=c(y=1,z=1), xlab=deparse(substitute(x)), ylab=deparse(substitute(y)), zlab=deparse(substitute(z)), alpha.surf=0.4, col.surf=fg,col.stem=c(fg,fg), col.pt="gray",type.surf="line",ptsize, lwd.stem=2,lit=TRUE,bg="white",fg="black", col.axes=fg,col.axlabs=fg, axis.arrow=TRUE,axis.labels=TRUE, box.col=bg, axes=c("lines","box")) { axes <- match.arg(axes) col.stem <- rep(col.stem,length=2) x.ticks <- pretty(xlim) x.ticks <- x.ticks[x.ticks>=min(xlim) & x.ticks<=max(xlim)] x.ticklabs <- if (axis.labels) as.character(x.ticks) else NULL y.ticks <- pretty(ylim) y.ticks <- y.ticks[y.ticks>=min(ylim) & y.ticks<=max(ylim)] y.ticklabs <- if (axis.labels) as.character(y.ticks) else NULL z.ticks <- pretty(zlim) z.ticks <- z.ticks[z.ticks>=min(zlim) & z.ticks<=max(zlim)] z.ticklabs <- if (axis.labels) as.character(z.ticks) else NULL if (!missing(surf.fun)) { surf.x <- seq(xlim[1],xlim[2],length=surf.n) surf.y <- seq(ylim[1],ylim[2],length=surf.n) surf.z <- outer(surf.x,surf.y,surf.fun) ## requires surf.fun be vectorized z.interc <- surf.fun(data.x,data.y) zdiff <- diff(range(c(surf.z,data.z))) } else { z.interc <- rep(min(data.z),length(data.x)) zdiff <- diff(range(data.z)) } xdiff <- diff(xlim) ydiff <- diff(ylim) y.adj <- if (asp[1]<=0) 1 else asp[1]*xdiff/ydiff data.y <- y.adj*data.y y.ticks <- y.adj*y.ticks ylim <- ylim*y.adj ydiff <- diff(ylim) z.adj <- if (asp[2]<=0) 1 else asp[2]*xdiff/zdiff data.z <- z.adj*data.z if (!missing(surf.fun)) { surf.y <- y.adj*surf.y surf.z <- z.adj*surf.z } z.interc <- z.adj*z.interc z.ticks <- z.adj*z.ticks zlim <- z.adj*zlim open3d() clear3d("all") light3d() bg3d(color=c(bg,fg)) if (!missing(surf.fun)) surface3d(surf.x,surf.y,surf.z,alpha=alpha.surf, front=type.surf,back=type.surf, col=col.surf,lit=lit) if (missing(ptsize)) ptsize <- 0.02*xdiff ## draw points spheres3d(data.x,data.y,data.z,r=ptsize,lit=lit,color=col.pt) ## draw lollipops apply(cbind(data.x,data.y,data.z,z.interc),1, function(X) { lines3d(x=rep(X[1],2), y=rep(X[2],2), z=c(X[3],X[4]), col=ifelse(X[3]>X[4],col.stem[1], col.stem[2]),lwd=lwd.stem) }) if (axes=="box") { bbox3d(xat=x.ticks,xlab=x.ticklabs, yat=y.ticks,ylab=y.ticklabs, zat=z.ticks,zlab=z.ticklabs,lit=lit) } else if (axes=="lines") { ## set up axis lines axis3d(edge="x",at=x.ticks,labels=x.ticklabs, col=col.axes,arrow=axis.arrow) axis3d(edge="y",at=y.ticks,labels=y.ticklabs, col=col.axes,arrow=axis.arrow) axis3d(edge="z",at=z.ticks,labels=z.ticklabs, col=col.axes,arrow=axis.arrow) box3d(col=col.axes) } decorate3d(xlab=xlab, ylab=ylab, zlab=zlab, box=FALSE, axes=FALSE, col=col.axlabs) } x <- 1:5 y <- x*10 z <- (x+y)/20 open3d() spheres3d(x,y,z) axes3d() set.seed(1001) x <- runif(30) y <- runif(30,max=2) dfun <- function(x,y) 2*x+3*y+2*x*y+3*y^2 z <- dfun(x,y)+rnorm(30,sd=0.5) ## lollipops only lollipop3d(x,y,z) ## lollipops plus theoretical surface open3d() lollipop3d(x,y,z,dfun,col.pt="red",col.stem=c("red","blue")) ## lollipops plus regression fit linmodel <- lm(z~x+y) dfun <- function(x,y) predict(linmodel,newdata=data.frame(x=x,y=y)) open3d() lollipop3d(x,y,z,dfun,col.pt="red",col.stem=c("red","blue")) #### rgl/inst/doc/WebGL.html0000644000176200001440000300153015026603563014416 0ustar liggesusers User Interaction in WebGL

User Interaction in WebGL

Duncan Murdoch

June 24, 2025

Introduction

This document describes how to embed rgl scenes in HTML documents and use embedded Javascript to control a WebGL display in an HTML document. For more general information about rgl, see rgl Overview.

We assume that the HTML document is produced from R markdown source using knitr or rmarkdown. This format mixes text with Markdown markup with chunks of R code. There is a limited amount of discussion of other methods.

There are two ways to embed an rgl scene in the document. The newest one is recommended: call setupKnitr with argument autoprint = TRUE early in the document. This will set things up to be quite similar to the way standard 2D graphics are included by knitr, i.e. it will detect the fact that you’ve drawn something, and just include it automatically.

If autoprint = FALSE is used or no call is made to setupKnitr(), an explicit call to rglwidget will produce a “widget” which can be embedded into your document by printing it. This document uses that method.

Older methods (e.g. writeWebGL or various hooks) that were used before rgl version 0.102.0 are no longer supported.

Browser support

Most browsers now support WebGL, but in some browsers it may be disabled by default. See https://get.webgl.org for help on a number of different browsers.

Examples

We start with a simple plot of the iris data. We insert a code chunk and call the rglwidget function with optional argument elementId. This allows later Javascript code to refer to the image. We also save the object ids from the plot, so that they can be manipulated later. (The first example in Controls uses tags instead of saving the ids.)

library(rgl)
plotids <- with(iris, plot3d(Sepal.Length, Sepal.Width, Petal.Length, 
                  type="s", col=as.numeric(Species)))
rglwidget(elementId = "plot3drgl")

Next we insert a button to toggle the display of the data.

toggleWidget(sceneId = "plot3drgl", ids = plotids["data"], label = "Data")

The sceneId is the same as the elementId we used in rglwidget(), the ids are the object ids of the objects that we’d like to toggle, and the label is the label shown on the button. To find the names in the plotids variable, apply names() or unclass():

names(plotids)
## [1] "data" "axes" "xlab" "ylab" "zlab"
unclass(plotids)
## data axes xlab ylab zlab 
##   13   14   15   16   17

Using magrittr or base pipes

It can be error-prone to set the elementId in the rglwidget() to match the sceneId in the toggleWidget() (or playwidget(), described below). In the usual case where both are intended to appear together, magrittr-style pipes can be used quite flexibly: the first argument of the control widget accepts the result of rglwidget() (or other control widgets), and the controllers argument of rglwidget() accepts control widgets. In R 4.1.0, the new base pipe operator |> should be usable in the same way.

For example,

rglwidget() %>%
toggleWidget(ids = plotids["data"], label = "Data")

If you have R 4.1.0 or greater, this should do the same:

rglwidget() |>
toggleWidget(ids = plotids["data"], label = "Data")

You can swap the order of button and scene; use the magrittr dot (or the => syntax in base pipes) to pass the toggleWidget to rglwidget in the controllers argument:

toggleWidget(NA, ids = plotids["data"], label = "Data") %>%
rglwidget(controllers = .) 

or using R 4.1.0 or later,

toggleWidget(NA, ids = plotids["data"], label = "Data") |> 
  w => rglwidget(controllers = w) 

Controls

We have seen how to change the contents of the plot using toggleWidget. We can do more elaborate displays. For example, we can redo the previous plot, but with the three species as separate “spheres” objects and buttons to toggle them:

clear3d() # Remove the earlier display

with(subset(iris, Species == "setosa"), 
     spheres3d(Sepal.Length, Sepal.Width, Petal.Length, 
                  col=as.numeric(Species),
                  radius = 0.211,
                  tag = "setosa"))
with(subset(iris, Species == "versicolor"), 
     spheres3d(Sepal.Length, Sepal.Width, Petal.Length, 
               col=as.numeric(Species),
               radius = 0.211, 
               tag = "versicolor"))
with(subset(iris, Species == "virginica"), 
     spheres3d(Sepal.Length, Sepal.Width, Petal.Length, 
               col=as.numeric(Species),
               radius = 0.211,
               tag = "virginica"))
aspect3d(1,1,1)
decorate3d(tag = "axes")
rglwidget() %>%
toggleWidget(tags = "setosa") %>%
toggleWidget(tags = "versicolor") %>%
toggleWidget(tags = "virginica") %>%
toggleWidget(tags = "axes") %>% 
asRow(last = 4)

Since we skipped the label argument, the buttons are labelled with the values of the tags. The asRow function is discussed below.

toggleWidget() is actually a convenient wrapper for two functions: playwidget and subsetControl. playwidget() adds the button to the web page (and can also add sliders, do animations, etc.), while subsetControl() chooses a subset of objects to display.

subsetControl

For a more general example, we could use a slider to select several subsets of the data in the iris display. For example,

rglwidget() %>%
playwidget(start = 0, stop = 3, interval = 1,
       subsetControl(1, subsets = list(
                 Setosa = tagged3d("setosa"),
                 Versicolor = tagged3d("versicolor"),
                 Virginica = tagged3d("virginica"),
                 All = tagged3d(c("setosa", "versicolor", "virginica"))
                 )))

There are several other “control” functions.

par3dinterpControl

par3dinterpControl approximates the result of par3dinterp.

For example, the following code (similar to the play3d example) rotates the scene in a complex way.

M <- r3dDefaults$userMatrix
fn <- par3dinterp(time = (0:2)*0.75, userMatrix = list(M,
                                      rotate3d(M, pi/2, 1, 0, 0),
                                      rotate3d(M, pi/2, 0, 1, 0)) )
rglwidget() %>%
playwidget(par3dinterpControl(fn, 0, 3, steps=15),
       step = 0.01, loop = TRUE, rate = 0.5)

Some things to note: The generated Javascript slider has 300 increments, so that motion appears smooth. However, storing 300 userMatrix values would take up a lot of space, so we use interpolation in the Javascript code. However, the Javascript code can only do linear interpolation, not the more complex spline-based SO(3) interpolation done by par3dinterp. Because of this, we need to output 15 steps from par3dinterpControl so that the distortions of linear interpolation are not visible.

propertyControl

propertyControl is a more general function to set the value of properties of the scene. Currently most properties are supported, but use does require knowledge of the internal implementation.

clipplaneControl

clipplaneControl allows the user to control the location of a clipping plane by moving a slider.

vertexControl

Less general than propertyControl is vertexControl. This function sets attributes of individual vertices in a scene. For example, to set the x-coordinate of the closest point in the setosa group, and modify its colour from black to white,

setosavals <- subset(iris, Species == "setosa")
which <- which.min(setosavals$Sepal.Width)
init <- setosavals$Sepal.Length[which]
rglwidget() %>%
playwidget(
  vertexControl(values = matrix(c(init,   0,   0,   0, 
                                     8,   1,   1,   1), 
                                nrow = 2, byrow = TRUE),
                attributes = c("x", "red", "green", "blue"),
                vertices = which, tag = "setosa"),
    step = 0.01)

ageControl

A related function is ageControl, though it uses a very different specification of the attributes. It is used when the slider controls the “age” of the scene, and attributes of vertices change with their age.

To illustrate we will show a point moving along a curve. We give two ageControl calls in a list; the first one controls the colour of the trail, the second controls the position of the point:

time <- 0:500
xyz <- cbind(cos(time/20), sin(time/10), time)
lineid <- plot3d(xyz, type="l", col = "black")["data"]
sphereid <- spheres3d(xyz[1, , drop=FALSE], radius = 8, col = "red")
rglwidget() %>%
playwidget(list(
  ageControl(births = time, ages = c(0, 0, 50),
        colors = c("gray", "red", "gray"), objids = lineid),
  ageControl(births = 0, ages = time,
        vertices = xyz, objids = sphereid)),
  start = 0, stop = max(time) + 20, rate = 50,
  components = c("Reverse", "Play", "Slower", "Faster",
                 "Reset", "Slider", "Label"),
  loop = TRUE)

rglMouse

While not exactly a control in the sense of the other functions in this section, the rglMouse function is used to add an HTML control to a display to allow the user to select the mouse mode.

For example, the display below initially allows selection of particular points, but the mouse mode may be changed to let the user rotate the display for a another view of the scene.

# This example requires the crosstalk package
# We skip it if crosstalk is not available. 

ids <- with(iris, plot3d(Sepal.Length, Sepal.Width, Petal.Length, 
                  type="s", col=as.numeric(Species)))
par3d(mouseMode = "selecting")
rglwidget(shared = rglShared(ids["data"])) %>% 
rglMouse()

The rglShared() call used here is described below.

Layout of the display

Many rgl displays will contain several elements: one or more rgl scenes and controls. Internally rgl uses the combineWidgets function from the manipulateWidget package.

The rgl package provides 3 convenience functions for arranging displays. We have already met the first: the magrittr pipe, %>%. When the display is constructed as a single object using pipes, the objects in the pipeline will be arranged in a single column.

The second convenience function is asRow. This takes as input a list of objects or a combineWidgets object (perhaps the result of a pipe), and rearranges (some of) them into a horizontal row. As in the toggleWidget example, the last argument can be used to limit the actions of asRow to the specified number of components. (If last = 0, all objects are stacked: this can be useful if some of them are not from the rgl package, so piping doesn’t work for them.)

Finally, getWidgetId can be used to extract the HTML element ID from an HTML widget. This is useful when combining widgets that are not all elements of the same pipe, as in the crosstalk example below.

If these convenience functions are not sufficient, you can call manipulateWidget::combineWidgets or other functions from manipulateWidget for more flexibility in the display arrangements.

Integration with crosstalk

The crosstalk package allows widgets to communicate with each other. Currently it supports selection and filtering of observations.

rgl can send, receive and display these messages. An rgl display may have several subscenes, each displaying different datasets. Each object in the scene is potentially a shared dataset in the crosstalk sense.

The linking depends on the rglShared function. Calling rglShared(id), where id is the rgl id value for an object in the current scene, creates a shared data object containing the coordinates of the vertices of the rgl object. This object is passed to rglwidget in the shared argument. It can also be passed to other widgets that accept shared data, linking the two displays.

If a shared data object has been created in some other way, it can be linked to a particular rgl id value by copying its key and group properties as shown in the example below.

# This example requires the crosstalk package.  
# We skip it if crosstalk is not available. 

library(crosstalk)
sd <- SharedData$new(mtcars)
ids <- plot3d(sd$origData(), col = mtcars$cyl, type = "s")
# Copy the key and group from existing shared data
rglsd <- rglShared(ids["data"], key = sd$key(), group = sd$groupName())
rglwidget(shared = rglsd) %>%
asRow("Mouse mode: ", rglMouse(getWidgetId(.)), 
      "Subset: ", filter_checkbox("cylinderselector", 
                        "Cylinders", sd, ~ cyl, inline = TRUE),
      last = 4, colsize = c(1,2,1,2), height = 60)

If multiple objects in the rgl scene need to be considered as shared data, you can pass the results of several rglShared() calls in a list, i.e. rglwidget(shared = <list>). The key values will be assumed to be shared across datasets; if this is not wanted, use a prefix or some other means to make sure they differ between objects.

If the same rgl id is used in more than one rglShared() object, it will respond to messages from all of them. This may lead to undesirable behaviour as one message cancels the previous one.

Low level controls

We repeat the initial plot from this document:

plotids <- with(iris, plot3d(Sepal.Length, Sepal.Width, Petal.Length, 
                  type="s", col=as.numeric(Species)))
subid <- currentSubscene3d()
rglwidget(elementId="plot3drgl2")

We might like a button on the web page to cause a change to the display, e.g. a rotation of the plot. First we add buttons, with the “onclick” event set to a function described below:

<button type="button" onclick="rotate(10)">Forward</button>
<button type="button" onclick="rotate(-10)">Backward</button>

which produces these buttons:

We stored the subscene number that is currently active in subid in the code chunk above, and use it as `r subid` in the script below. knitr substitutes the value when it processes the document.

The rotate() function uses the Javascript function document.getElementById to retrieve the <div> component of the web page containing the scene. It will have a component named rglinstance which contains information about the scene that we can modify:

<script type="text/javascript">
var rotate = function(angle) {
  var rgl = document.getElementById("plot3drgl2").rglinstance;
  rgl.getObj(`r subid`).par3d.userMatrix.rotate(angle, 0,1,0);
  rgl.drawScene();
};
</script>

If we had used webGL=TRUE in the chunk header, the knitr WebGL support would create a global object with a name of the form <chunkname>rgl. For example, if the code chunk was named plot3d2, the object would be called plot3d2rgl, and this code would work:

<script type="text/javascript">
var rotate = function(angle) {
  plot3d2rgl.getObj(`r subid`).par3d.userMatrix.rotate(angle, 0,1,0);
  plot3d2rgl.drawScene();
};
</script>

Index

The following functions are described in this document:

rgl/inst/doc/pkgdown.html0000644000176200001440000121776215026603571015144 0ustar liggesusers Using RGL in pkgdown web sites

Using RGL in pkgdown web sites

Duncan Murdoch

What is the problem?

pkgdown is an R package that makes it easy to build a web site for your package. However, the previous version 1.6.1 on CRAN didn’t work so well for packages whose examples use RGL or other packages like leaflet that use htmlwidgets. This document described changes that support both of these. The changes are now incorporated into pkgdown 2.0.0, so everything but user instructions has been removed.

Using `RGL in examples.

If you use RGL in example code, they should appear automatically in examples. The RGL output is set up to mimic what would happen in a knitr document that uses

setupKnitr(autoprint = TRUE)

i.e. the output RGL commands will automatically be included in the display. Low-level changes will be collected into a single display:

# Show regression plane with z as dependent variable
library(rgl)
open3d()
## null 
##   47
x <- rnorm(100)
y <- rnorm(100)
z <- 0.2*x - 0.3*y + rnorm(100, sd = 0.3)
fit <- lm(z ~ x + y)

plot3d(x, y, z, type = "s", col = "red", size = 1)

# No plot here, because of the planes3d() call below

coefs <- coef(fit)
a <- coefs["x"]
b <- coefs["y"]
c <- -1
d <- coefs["(Intercept)"]
planes3d(a, b, c, d, alpha = 0.5)

Specifying the size of figures

By default, pkgdown generates standard plots which are wider than they are high (according to the golden ratio). Often RGL plots look better with equal width and height, since the contents may be rotated by the user.

To specify the size of plots in pkgdown, you use the figures entry in _pkgdown.yml. The defaults are similar to

figures:
  dev: ragg::agg_png
  dpi: 96
  dev.args: []
  fig.ext: png
  fig.width: 7
  fig.height: ~
  fig.retina: 2
  fig.asp: 1.618
  bg: NA
  other.parameters: []

By default RGL uses these parameters as well, but allows you to override any of fig.width, fig.height and fig.asp by specifying an rgl entry in other.parameters. For example:

figures:
  fig.width: 5
  other.parameters:
    rgl:
      fig.asp: 1

This will make all plots have a width of 5 inches and will make RGL plots square.

rgl/inst/doc/transparency.Rmd0000644000176200001440000001504015011677075015746 0ustar liggesusers--- title: "A Note on Transparency" author: "Duncan Murdoch" date: "24/10/2020" output: rmarkdown::html_vignette: fig_height: 5 fig_width: 5 toc: true pdf_document: fig_height: 5 fig_width: 5 toc: true html_document: default vignette: > %\VignetteIndexEntry{A Note on Transparency} %\VignetteEngine{knitr::rmarkdown} --- ```{r setup, include=FALSE} if (!requireNamespace("rmarkdown", quietly = TRUE) || !rmarkdown::pandoc_available("1.14")) { warning(call. = FALSE, "These vignettes assume rmarkdown and Pandoc version 1.14. These were not found. Older versions will not work.") knitr::knit_exit() } knitr::opts_chunk$set(echo = TRUE, snapshot = FALSE, screenshot.force = FALSE) library(rgl) options(rgl.useNULL = TRUE) setupKnitr(autoprint = TRUE) M <- structure(c(0.997410774230957, 0.0707177817821503, -0.0130676832050085, 0, -0.0703366547822952, 0.99714070558548, 0.02762770652771, 0, 0.0149840852245688, -0.0266370177268982, 0.999532878398895, 0, 0, 0, 0, 1), .Dim = c(4L, 4L)) ``` ## Introduction When drawing transparent surfaces, `rgl` tries to sort objects from back to front to get better rendering of transparency. However, it doesn't sort each pixel separately, so some pixels end up drawn in the incorrect order. This note describes the consequences of that error, and suggests remedies. ## Correct Drawing We'll assume that the standard `glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)` blending is used. That is, when drawing with transparency $\alpha$, the new colour is mixed at proportion $\alpha$ with the colour previously drawn (which gets weight $1-\alpha$.) This note is concerned with what happens when two transparent objects are drawn at the same location. We suppose the further one has transparency $\alpha_1$, and the closer one has transparency $\alpha_2$. If they are drawn in the correct order (further first), the three colours (background, further object, closer object) should end up mixed in proportions $C = [(1-\alpha_1)(1-\alpha_2), \alpha_1(1-\alpha_2), \alpha_2]$ respectively. ## Incorrect sorting If the objects are drawn in the wrong order, the actual proportions of each colour will be $N = [(1-\alpha_1)(1-\alpha_2),\alpha_1, \alpha_2(1-\alpha_1)]$ if no masking occurs. `rgl` currently defaults to depth masking using `glDepthMask(GL_TRUE)`. This means that depths are saved when the objects are drawn, and if an attempt is made to draw the further object after the closer one (i.e. as here), the further object will be culled, and the proportions will be $M = [(1-\alpha_2), 0, \alpha_2]$. ## Mask or Not? The question is: which is better, `glDepthMask(GL_TRUE)` or `glDepthMask(GL_FALSE)`? One way to measure this is to measure the distance between $C$ and the incorrect proportions. (This is unlikely to match perceptual distance, which will depend on the colours as well, but we need something. Some qualitative comments below.) So we have $$|C-N|^2 = 2\alpha_1^2\alpha_2^2,$$ and $$|C-M|^2 = 2\alpha_1^2(1-\alpha_2)^2.$$ Thus the error is larger with $N$ when $\alpha_2 > 1 / 2$, and larger with $M$ when $\alpha_2 < 1 / 2$. The value of $\alpha_1$ doesn't affect the preference, though small values of $\alpha_1$ will be associated with smaller errors. Depending on the colours of the background and the two objects, this recommendation could be modified. For example, if the two objects are the same colour (or very close), it doesn't really matter how the 2nd and 3rd proportions are divided up, and $N$ will be best because it gets the background proportion exactly right. ## Recommendation Typically in `rgl` we don't know which object will be closer and which one will be further, so we can't base our choice on a single $\alpha_i$. The recommendation would be to use all small levels of `alpha` and disable masking, or use all large values of `alpha` and retain masking. ## Example The classic example of an impossible to sort scene involves three triangles arranged cyclicly so each one is behind one and in front of one of the others (based on https://paroj.github.io/gltut/Positioning/Tut05%20Overlap%20and%20Depth%20Buffering.html). ```{r} theta <- 2*pi*c(0:2, 4:6, 8:10)/12 x <- cos(theta) y <- sin(theta) z <- rep(c(0,0,1), 3) xyz <- cbind(x, y, z) xyz <- xyz[c(1,2,6, 4,5,9, 7,8,3),] open3d() par3d(userMatrix = M) triangles3d(xyz, col = rep(c("red", "green", "blue"), each = 3)) ``` To see the effect of the calculations above, consider the following four displays. ```{r fig.width=8} open3d() par3d(userMatrix = M) layout3d(matrix(1:9, ncol = 3, byrow=TRUE), widths = c(1,2,2), heights = c(1, 3,3), sharedMouse = TRUE) text3d(0,0,0, " ") next3d() text3d(0,0,0, "depth_mask = TRUE") next3d() text3d(0,0,0, "depth_mask = FALSE") next3d() text3d(0,0,0, "alpha = 0.7") next3d() triangles3d(xyz, col = rep(c("red", "green", "blue"), each = 3), alpha = 0.7, depth_mask = TRUE) next3d() triangles3d(xyz, col = rep(c("red", "green", "blue"), each = 3), alpha = 0.7, depth_mask = FALSE) next3d() text3d(0,0,0, "alpha = 0.3") next3d() triangles3d(xyz, col = rep(c("red", "green", "blue"), each = 3), alpha = 0.3, depth_mask = TRUE) next3d() triangles3d(xyz, col = rep(c("red", "green", "blue"), each = 3), alpha = 0.3, depth_mask = FALSE) ``` As you rotate the figures, you can see imperfections in rendering. On the right, the last drawn appears to be on top, while on the left, the first drawn appears more opaque than it should. In the figure below, the three triangles each have different transparency, and each use the recommended setting: ```{r} open3d() par3d(userMatrix = M) triangles3d(xyz[1:3,], col = "red", alpha = 0.3, depth_mask = FALSE) triangles3d(xyz[4:6,], col = "green", alpha = 0.7, depth_mask = TRUE) triangles3d(xyz[7:9,], col = "blue", depth_mask = TRUE) ``` In this figure, all three triangles are the same colour, only lighting affects the display: ```{r fig.width=8} open3d() par3d(userMatrix = M) layout3d(matrix(1:9, ncol = 3, byrow=TRUE), widths = c(1,2,2), heights = c(1, 3,3), sharedMouse = TRUE) text3d(0,0,0, " ") next3d() text3d(0,0,0, "depth_mask = TRUE") next3d() text3d(0,0,0, "depth_mask = FALSE") next3d() text3d(0,0,0, "alpha = 0.7") next3d() triangles3d(xyz, col = "red", alpha = 0.7, depth_mask = TRUE) next3d() triangles3d(xyz, col = "red", alpha = 0.7, depth_mask = FALSE) next3d() text3d(0,0,0, "alpha = 0.3") next3d() triangles3d(xyz, col = "red", alpha = 0.3, depth_mask = TRUE) next3d() triangles3d(xyz, col = "red", alpha = 0.3, depth_mask = FALSE) ``` Here `depth_mask = FALSE` seems to be the right choice in both cases.rgl/inst/doc/transparency.html0000644000176200001440000150451515026603600016170 0ustar liggesusers A Note on Transparency

A Note on Transparency

Duncan Murdoch

24/10/2020

Introduction

When drawing transparent surfaces, rgl tries to sort objects from back to front to get better rendering of transparency. However, it doesn’t sort each pixel separately, so some pixels end up drawn in the incorrect order. This note describes the consequences of that error, and suggests remedies.

Correct Drawing

We’ll assume that the standard glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) blending is used. That is, when drawing with transparency \(\alpha\), the new colour is mixed at proportion \(\alpha\) with the colour previously drawn (which gets weight \(1-\alpha\).)

This note is concerned with what happens when two transparent objects are drawn at the same location. We suppose the further one has transparency \(\alpha_1\), and the closer one has transparency \(\alpha_2\). If they are drawn in the correct order (further first), the three colours (background, further object, closer object) should end up mixed in proportions \(C = [(1-\alpha_1)(1-\alpha_2), \alpha_1(1-\alpha_2), \alpha_2]\) respectively.

Incorrect sorting

If the objects are drawn in the wrong order, the actual proportions of each colour will be \(N = [(1-\alpha_1)(1-\alpha_2),\alpha_1, \alpha_2(1-\alpha_1)]\) if no masking occurs.

rgl currently defaults to depth masking using glDepthMask(GL_TRUE). This means that depths are saved when the objects are drawn, and if an attempt is made to draw the further object after the closer one (i.e. as here), the further object will be culled, and the proportions will be \(M = [(1-\alpha_2), 0, \alpha_2]\).

Mask or Not?

The question is: which is better, glDepthMask(GL_TRUE) or glDepthMask(GL_FALSE)? One way to measure this is to measure the distance between \(C\) and the incorrect proportions. (This is unlikely to match perceptual distance, which will depend on the colours as well, but we need something. Some qualitative comments below.)

So we have

\[|C-N|^2 = 2\alpha_1^2\alpha_2^2,\]

and

\[|C-M|^2 = 2\alpha_1^2(1-\alpha_2)^2.\]

Thus the error is larger with \(N\) when \(\alpha_2 > 1 / 2\), and larger with \(M\) when \(\alpha_2 < 1 / 2\). The value of \(\alpha_1\) doesn’t affect the preference, though small values of \(\alpha_1\) will be associated with smaller errors.

Depending on the colours of the background and the two objects, this recommendation could be modified. For example, if the two objects are the same colour (or very close), it doesn’t really matter how the 2nd and 3rd proportions are divided up, and \(N\) will be best because it gets the background proportion exactly right.

Recommendation

Typically in rgl we don’t know which object will be closer and which one will be further, so we can’t base our choice on a single \(\alpha_i\). The recommendation would be to use all small levels of alpha and disable masking, or use all large values of alpha and retain masking.

Example

The classic example of an impossible to sort scene involves three triangles arranged cyclicly so each one is behind one and in front of one of the others (based on https://paroj.github.io/gltut/Positioning/Tut05%20Overlap%20and%20Depth%20Buffering.html).

theta <- 2*pi*c(0:2, 4:6, 8:10)/12
x <- cos(theta)
y <- sin(theta)
z <- rep(c(0,0,1), 3)
xyz <- cbind(x, y, z)
xyz <- xyz[c(1,2,6, 4,5,9, 7,8,3),]
open3d()
## null 
##   72
par3d(userMatrix = M)
triangles3d(xyz, col = rep(c("red", "green", "blue"), each = 3))

To see the effect of the calculations above, consider the following four displays.

open3d()
## null 
##   74
par3d(userMatrix = M)
layout3d(matrix(1:9, ncol = 3, byrow=TRUE),
         widths = c(1,2,2), heights = c(1, 3,3), 
         sharedMouse = TRUE)
text3d(0,0,0, " ")
next3d()
text3d(0,0,0, "depth_mask = TRUE")
next3d()
text3d(0,0,0, "depth_mask = FALSE")
next3d()
text3d(0,0,0, "alpha = 0.7")
next3d()
triangles3d(xyz, col = rep(c("red", "green", "blue"), each = 3), alpha = 0.7, depth_mask = TRUE)
next3d()
triangles3d(xyz, col = rep(c("red", "green", "blue"), each = 3), alpha = 0.7, depth_mask = FALSE)
next3d()
text3d(0,0,0, "alpha = 0.3")
next3d()
triangles3d(xyz, col = rep(c("red", "green", "blue"), each = 3), alpha = 0.3, depth_mask = TRUE)
next3d()
triangles3d(xyz, col = rep(c("red", "green", "blue"), each = 3), alpha = 0.3, depth_mask = FALSE)

As you rotate the figures, you can see imperfections in rendering. On the right, the last drawn appears to be on top, while on the left, the first drawn appears more opaque than it should.

In the figure below, the three triangles each have different transparency, and each use the recommended setting:

open3d()
## null 
##   76
par3d(userMatrix = M)
triangles3d(xyz[1:3,], col = "red", alpha = 0.3, depth_mask = FALSE)
triangles3d(xyz[4:6,], col = "green", alpha = 0.7, depth_mask = TRUE)
triangles3d(xyz[7:9,], col = "blue", depth_mask = TRUE)

In this figure, all three triangles are the same colour, only lighting affects the display:

open3d()
## null 
##   78
par3d(userMatrix = M)
layout3d(matrix(1:9, ncol = 3, byrow=TRUE),
         widths = c(1,2,2), heights = c(1, 3,3), 
         sharedMouse = TRUE)
text3d(0,0,0, " ")
next3d()
text3d(0,0,0, "depth_mask = TRUE")
next3d()
text3d(0,0,0, "depth_mask = FALSE")
next3d()
text3d(0,0,0, "alpha = 0.7")
next3d()
triangles3d(xyz, col = "red", alpha = 0.7, depth_mask = TRUE)
next3d()
triangles3d(xyz, col = "red", alpha = 0.7, depth_mask = FALSE)
next3d()
text3d(0,0,0, "alpha = 0.3")
next3d()
triangles3d(xyz, col = "red", alpha = 0.3, depth_mask = TRUE)
next3d()
triangles3d(xyz, col = "red", alpha = 0.3, depth_mask = FALSE)

Here depth_mask = FALSE seems to be the right choice in both cases.

rgl/inst/doc/transparency.R0000644000176200001440000000555415026603600015423 0ustar liggesusers## ----setup, include=FALSE----------------------------------------------------- if (!requireNamespace("rmarkdown", quietly = TRUE) || !rmarkdown::pandoc_available("1.14")) { warning(call. = FALSE, "These vignettes assume rmarkdown and Pandoc version 1.14. These were not found. Older versions will not work.") knitr::knit_exit() } knitr::opts_chunk$set(echo = TRUE, snapshot = FALSE, screenshot.force = FALSE) library(rgl) options(rgl.useNULL = TRUE) setupKnitr(autoprint = TRUE) M <- structure(c(0.997410774230957, 0.0707177817821503, -0.0130676832050085, 0, -0.0703366547822952, 0.99714070558548, 0.02762770652771, 0, 0.0149840852245688, -0.0266370177268982, 0.999532878398895, 0, 0, 0, 0, 1), .Dim = c(4L, 4L)) ## ----------------------------------------------------------------------------- theta <- 2*pi*c(0:2, 4:6, 8:10)/12 x <- cos(theta) y <- sin(theta) z <- rep(c(0,0,1), 3) xyz <- cbind(x, y, z) xyz <- xyz[c(1,2,6, 4,5,9, 7,8,3),] open3d() par3d(userMatrix = M) triangles3d(xyz, col = rep(c("red", "green", "blue"), each = 3)) ## ----fig.width=8-------------------------------------------------------------- open3d() par3d(userMatrix = M) layout3d(matrix(1:9, ncol = 3, byrow=TRUE), widths = c(1,2,2), heights = c(1, 3,3), sharedMouse = TRUE) text3d(0,0,0, " ") next3d() text3d(0,0,0, "depth_mask = TRUE") next3d() text3d(0,0,0, "depth_mask = FALSE") next3d() text3d(0,0,0, "alpha = 0.7") next3d() triangles3d(xyz, col = rep(c("red", "green", "blue"), each = 3), alpha = 0.7, depth_mask = TRUE) next3d() triangles3d(xyz, col = rep(c("red", "green", "blue"), each = 3), alpha = 0.7, depth_mask = FALSE) next3d() text3d(0,0,0, "alpha = 0.3") next3d() triangles3d(xyz, col = rep(c("red", "green", "blue"), each = 3), alpha = 0.3, depth_mask = TRUE) next3d() triangles3d(xyz, col = rep(c("red", "green", "blue"), each = 3), alpha = 0.3, depth_mask = FALSE) ## ----------------------------------------------------------------------------- open3d() par3d(userMatrix = M) triangles3d(xyz[1:3,], col = "red", alpha = 0.3, depth_mask = FALSE) triangles3d(xyz[4:6,], col = "green", alpha = 0.7, depth_mask = TRUE) triangles3d(xyz[7:9,], col = "blue", depth_mask = TRUE) ## ----fig.width=8-------------------------------------------------------------- open3d() par3d(userMatrix = M) layout3d(matrix(1:9, ncol = 3, byrow=TRUE), widths = c(1,2,2), heights = c(1, 3,3), sharedMouse = TRUE) text3d(0,0,0, " ") next3d() text3d(0,0,0, "depth_mask = TRUE") next3d() text3d(0,0,0, "depth_mask = FALSE") next3d() text3d(0,0,0, "alpha = 0.7") next3d() triangles3d(xyz, col = "red", alpha = 0.7, depth_mask = TRUE) next3d() triangles3d(xyz, col = "red", alpha = 0.7, depth_mask = FALSE) next3d() text3d(0,0,0, "alpha = 0.3") next3d() triangles3d(xyz, col = "red", alpha = 0.3, depth_mask = TRUE) next3d() triangles3d(xyz, col = "red", alpha = 0.3, depth_mask = FALSE) rgl/inst/doc/pkgdown.R0000644000176200001440000000210415026603571014356 0ustar liggesusers## ----setup, include=FALSE----------------------------------------------------- if (!requireNamespace("rmarkdown", quietly = TRUE) || !rmarkdown::pandoc_available("1.14")) { warning(call. = FALSE, "These vignettes assume rmarkdown and Pandoc version 1.14. These were not found. Older versions will not work.") knitr::knit_exit() } knitr::opts_chunk$set(echo = TRUE, snapshot = FALSE, screenshot.force = FALSE) library(rgl) options(rgl.useNULL = TRUE) setupKnitr(autoprint = TRUE) ## ----eval=FALSE--------------------------------------------------------------- # setupKnitr(autoprint = TRUE) ## ----------------------------------------------------------------------------- # Show regression plane with z as dependent variable library(rgl) open3d() x <- rnorm(100) y <- rnorm(100) z <- 0.2*x - 0.3*y + rnorm(100, sd = 0.3) fit <- lm(z ~ x + y) plot3d(x, y, z, type = "s", col = "red", size = 1) # No plot here, because of the planes3d() call below coefs <- coef(fit) a <- coefs["x"] b <- coefs["y"] c <- -1 d <- coefs["(Intercept)"] planes3d(a, b, c, d, alpha = 0.5) rgl/inst/doc/WebGL.R0000644000176200001440000001303315026603562013650 0ustar liggesusers## ----setup, echo=FALSE, results="asis"---------------------------------------- source("setup.R") setupKnitr(autoprint = FALSE) set.seed(123) ## ----elementId---------------------------------------------------------------- library(rgl) plotids <- with(iris, plot3d(Sepal.Length, Sepal.Width, Petal.Length, type="s", col=as.numeric(Species))) rglwidget(elementId = "plot3drgl") ## ----------------------------------------------------------------------------- toggleWidget(sceneId = "plot3drgl", ids = plotids["data"], label = "Data") ## ----------------------------------------------------------------------------- names(plotids) unclass(plotids) ## ----Pipes-------------------------------------------------------------------- rglwidget() %>% toggleWidget(ids = plotids["data"], label = "Data") ## ----eval=FALSE--------------------------------------------------------------- # rglwidget() |> # toggleWidget(ids = plotids["data"], label = "Data") ## ----"Control before widget"-------------------------------------------------- toggleWidget(NA, ids = plotids["data"], label = "Data") %>% rglwidget(controllers = .) ## ----eval=FALSE--------------------------------------------------------------- # toggleWidget(NA, ids = plotids["data"], label = "Data") |> # w => rglwidget(controllers = w) ## ----"Toggle subsets"--------------------------------------------------------- clear3d() # Remove the earlier display with(subset(iris, Species == "setosa"), spheres3d(Sepal.Length, Sepal.Width, Petal.Length, col=as.numeric(Species), radius = 0.211, tag = "setosa")) with(subset(iris, Species == "versicolor"), spheres3d(Sepal.Length, Sepal.Width, Petal.Length, col=as.numeric(Species), radius = 0.211, tag = "versicolor")) with(subset(iris, Species == "virginica"), spheres3d(Sepal.Length, Sepal.Width, Petal.Length, col=as.numeric(Species), radius = 0.211, tag = "virginica")) aspect3d(1,1,1) decorate3d(tag = "axes") rglwidget() %>% toggleWidget(tags = "setosa") %>% toggleWidget(tags = "versicolor") %>% toggleWidget(tags = "virginica") %>% toggleWidget(tags = "axes") %>% asRow(last = 4) ## ----Slider------------------------------------------------------------------- rglwidget() %>% playwidget(start = 0, stop = 3, interval = 1, subsetControl(1, subsets = list( Setosa = tagged3d("setosa"), Versicolor = tagged3d("versicolor"), Virginica = tagged3d("virginica"), All = tagged3d(c("setosa", "versicolor", "virginica")) ))) ## ----"par3dinterpControl()"--------------------------------------------------- M <- r3dDefaults$userMatrix fn <- par3dinterp(time = (0:2)*0.75, userMatrix = list(M, rotate3d(M, pi/2, 1, 0, 0), rotate3d(M, pi/2, 0, 1, 0)) ) rglwidget() %>% playwidget(par3dinterpControl(fn, 0, 3, steps=15), step = 0.01, loop = TRUE, rate = 0.5) ## ----"vertexControl()"-------------------------------------------------------- setosavals <- subset(iris, Species == "setosa") which <- which.min(setosavals$Sepal.Width) init <- setosavals$Sepal.Length[which] rglwidget() %>% playwidget( vertexControl(values = matrix(c(init, 0, 0, 0, 8, 1, 1, 1), nrow = 2, byrow = TRUE), attributes = c("x", "red", "green", "blue"), vertices = which, tag = "setosa"), step = 0.01) ## ----"ageControl()"----------------------------------------------------------- time <- 0:500 xyz <- cbind(cos(time/20), sin(time/10), time) lineid <- plot3d(xyz, type="l", col = "black")["data"] sphereid <- spheres3d(xyz[1, , drop=FALSE], radius = 8, col = "red") rglwidget() %>% playwidget(list( ageControl(births = time, ages = c(0, 0, 50), colors = c("gray", "red", "gray"), objids = lineid), ageControl(births = 0, ages = time, vertices = xyz, objids = sphereid)), start = 0, stop = max(time) + 20, rate = 50, components = c("Reverse", "Play", "Slower", "Faster", "Reset", "Slider", "Label"), loop = TRUE) ## ----crosstalk,eval = requireNamespace("crosstalk", quietly=TRUE)------------- # This example requires the crosstalk package # We skip it if crosstalk is not available. ids <- with(iris, plot3d(Sepal.Length, Sepal.Width, Petal.Length, type="s", col=as.numeric(Species))) par3d(mouseMode = "selecting") rglwidget(shared = rglShared(ids["data"])) %>% rglMouse() ## ----"rglShared()",eval=requireNamespace("crosstalk", quietly = TRUE)--------- # This example requires the crosstalk package. # We skip it if crosstalk is not available. library(crosstalk) sd <- SharedData$new(mtcars) ids <- plot3d(sd$origData(), col = mtcars$cyl, type = "s") # Copy the key and group from existing shared data rglsd <- rglShared(ids["data"], key = sd$key(), group = sd$groupName()) rglwidget(shared = rglsd) %>% asRow("Mouse mode: ", rglMouse(getWidgetId(.)), "Subset: ", filter_checkbox("cylinderselector", "Cylinders", sd, ~ cyl, inline = TRUE), last = 4, colsize = c(1,2,1,2), height = 60) ## ----plot3d2------------------------------------------------------------------ plotids <- with(iris, plot3d(Sepal.Length, Sepal.Width, Petal.Length, type="s", col=as.numeric(Species))) subid <- currentSubscene3d() rglwidget(elementId="plot3drgl2") ## ----echo=FALSE, results="asis"----------------------------------------------- writeIndex(cols = 5) rgl/inst/doc/deprecation.R0000644000176200001440000000021715026603570015204 0ustar liggesusers## ----setup, include = FALSE--------------------------------------------------- knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) rgl/inst/doc/pkgdown.Rmd0000644000176200001440000000571315011677075014714 0ustar liggesusers--- title: "Using RGL in pkgdown web sites" author: "Duncan Murdoch" output: rmarkdown::html_vignette: fig_height: 5 fig_width: 5 toc: true pdf_document: fig_height: 5 fig_width: 5 toc: true html_document: default vignette: > %\VignetteIndexEntry{Using RGL in pkgdown web sites} %\VignetteEngine{knitr::rmarkdown} --- ```{r setup, include=FALSE} if (!requireNamespace("rmarkdown", quietly = TRUE) || !rmarkdown::pandoc_available("1.14")) { warning(call. = FALSE, "These vignettes assume rmarkdown and Pandoc version 1.14. These were not found. Older versions will not work.") knitr::knit_exit() } knitr::opts_chunk$set(echo = TRUE, snapshot = FALSE, screenshot.force = FALSE) library(rgl) options(rgl.useNULL = TRUE) setupKnitr(autoprint = TRUE) ``` ## What is the problem? [pkgdown](https://pkgdown.r-lib.org/) is an R package that makes it easy to build a web site for your package. However, the previous version 1.6.1 on CRAN didn't work so well for packages whose examples use RGL or other packages like [leaflet](http://rstudio.github.io/leaflet/) that use [htmlwidgets](http://www.htmlwidgets.org). This document described changes that support both of these. The changes are now incorporated into `pkgdown` 2.0.0, so everything but user instructions has been removed. ## Using `RGL in examples. If you use RGL in example code, they should appear automatically in examples. The RGL output is set up to mimic what would happen in a `knitr` document that uses ```{r eval=FALSE} setupKnitr(autoprint = TRUE) ``` i.e. the output RGL commands will automatically be included in the display. Low-level changes will be collected into a single display: ```{r} # Show regression plane with z as dependent variable library(rgl) open3d() x <- rnorm(100) y <- rnorm(100) z <- 0.2*x - 0.3*y + rnorm(100, sd = 0.3) fit <- lm(z ~ x + y) plot3d(x, y, z, type = "s", col = "red", size = 1) # No plot here, because of the planes3d() call below coefs <- coef(fit) a <- coefs["x"] b <- coefs["y"] c <- -1 d <- coefs["(Intercept)"] planes3d(a, b, c, d, alpha = 0.5) ``` ## Specifying the size of figures By default, pkgdown generates standard plots which are wider than they are high (according to the golden ratio). Often RGL plots look better with equal width and height, since the contents may be rotated by the user. To specify the size of plots in pkgdown, you use the `figures` entry in `_pkgdown.yml`. The defaults are similar to ``` figures: dev: ragg::agg_png dpi: 96 dev.args: [] fig.ext: png fig.width: 7 fig.height: ~ fig.retina: 2 fig.asp: 1.618 bg: NA other.parameters: [] ``` By default RGL uses these parameters as well, but allows you to override any of `fig.width`, `fig.height` and `fig.asp` by specifying an `rgl` entry in `other.parameters`. For example: ``` figures: fig.width: 5 other.parameters: rgl: fig.asp: 1 ``` This will make all plots have a width of 5 inches and will make RGL plots square. rgl/inst/doc/rgl.Rmd0000644000176200001440000013563015011677075014031 0ustar liggesusers--- title: "rgl Overview" author: "Duncan Murdoch" date: "`r format(Sys.time(), '%B %d, %Y')`" output: rmarkdown::html_vignette: fig_height: 5 fig_width: 5 toc: true html_document: df_print: paged toc: true pdf_document: fig_height: 5 fig_width: 5 toc: true vignette: > %\VignetteIndexEntry{rgl Overview} %\VignetteEngine{knitr::rmarkdown} --- ```{r setup, echo=FALSE, results="asis"} source("setup.R") setupKnitr(autoprint = TRUE) set.seed(123) ``` ## Introduction The `rgl` package is used to produce interactive 3-D plots. It contains high-level graphics commands modelled loosely after classic R graphics, but working in three dimensions. It also contains low level structure inspired by (but incompatible with) the `grid` package. This document gives an overview. See the help pages for details. For installation instructions, see the `README` file in the top level directory of the source tarball `r paste0("rgl_", packageVersion("rgl"), ".tar.gz")` (or a later version). ### About this document This document was written in R Markdown, using the `knitr` package for production. It corresponds to `rgl` version `r packageVersion("rgl")`. Most of the highlighted function names are HTML links. The internal links should work in any browser; the links to help topics should work if you view the vignette from within the R help system. The document includes WebGL figures. To view these, you must have Javascript and WebGL enabled in your browser. Some older browsers may not support this -- see https://get.webgl.org for tests and links to a discussion. ## Basics and High Level Functions The `r indexfns("plot3d")` function plots points within an RGL window. It is similar to the classic `r linkfn("plot", pkg="graphics")` function, but works in 3 dimensions. For example ```{r "plot3d()"} with(iris, plot3d(Sepal.Length, Sepal.Width, Petal.Length, type="s", col=as.numeric(Species))) ``` can be used to plot three columns of the `iris` data. Allowed plot types include `"p", "l", "h", "s"`, meaning points, lines, segments from z=0, and spheres. There's a lot of flexibility in specifying the coordinates; the `r linkfn("xyz.coords", pkg = "grDevices")` function from the `grDevices` package is used for this. You can use your mouse to manipulate the plot. The default is that if you click and hold with the left mouse button, you can rotate the plot by dragging it. The right mouse button is used to resize it, and the middle button changes the perspective in the point of view. If you call `r linkfn("plot3d")` again, it will overwrite the current plot. To open a new graphics window, use `r linkfn("open3d")`. The other high level function is `r indexfns("persp3d")` to draw surfaces. It is similar to the classic `r linkfn("persp", pkg = "graphics")` function, but with greater flexibility. First, any of `x`, `y` or `z` can be specified using matrices, not just `z`. This allows parametric surfaces to be plotted. An even simpler specification is possible: `x` may be a function, in which case `persp3d` will work out the grid itself. See `r linkfn("persp3d.function", text="?persp3d.function", pkg="rgl")` for details. For example, the `MASS` package estimates Gamma parameters using maximum likelihood in a `r linkfn("fitdistr", text="?MASS::fitdistr", pkg="MASS")` example. Here we show the log likelihood surface. ```{r "persp3d()", fig.height=3, fig.width=6, fig.keep="last", eval=requireNamespace("MASS",quietly=TRUE)} # This example requires the MASS package library(MASS) # from the fitdistr example set.seed(123) x <- rgamma(100, shape = 5, rate = 0.1) fit <- fitdistr(x, dgamma, list(shape = 1, rate = 0.1), lower = 0.001) loglik <- function(shape, rate) sum(dgamma(x, shape=shape, rate=rate, log=TRUE)) loglik <- Vectorize(loglik) xlim <- fit$estimate[1]+4*fit$sd[1]*c(-1,1) ylim <- fit$estimate[2]+4*fit$sd[2]*c(-1,1) mfrow3d(1, 2, sharedMouse = TRUE) persp3d(loglik, xlim = xlim, ylim = ylim, n = 30) zlim <- fit$loglik + c(-qchisq(0.99, 2)/2, 0) next3d() persp3d(loglik, xlim = xlim, ylim = ylim, zlim = zlim, n = 30) ``` On the left, the whole surface over a range of the parameters; on the right, only the parts of the surface with log likelihood values near the maximum. Note: this example used the `knitr` hook functions (see `r linkfn("setupKnitr")`) to insert the scene into this vignette; the previous example used the `rglwidget` function. We generally recommend the newer `r linkfn("rglwidget")` approach. Note that both `plot3d` and `persp3d` are generic functions, with the following methods defined: ```{r} methods(plot3d) methods(persp3d) ``` ## Adding Graphical Elements ### Primitive shapes Just as we have `r linkfn("points", pkg="graphics")` and `r linkfn("lines", pkg="graphics")` in classic graphics, there are a number of low level functions in `rgl` to add graphical elements to the currently active plot. The "primitive" shapes are those that are native to OpenGL: Function | Description ----------------------------- | ----------- `r indexfns("points3d")`: | adds points `r indexfns("lines3d")`: | adds lines `r indexfns("segments3d")`: | adds line segments `r indexfns("triangles3d")`: | adds triangles `r indexfns("quads3d")`: | adds quadrilaterals Each of the above functions takes arguments `x`, `y` and `z`, again using `r linkfn("xyz.coords", pkg="grDevices")` for flexibility. They group successive entries as necessary. For example, the `r linkfn("triangles3d")` function takes each successive triple of points as the vertices of a triangle. You can use these functions to annotate the current graph, or to construct a figure from scratch. ### Constructed shapes `rgl` also has a number of objects which it constructs from the primitives. Function | Description ----------------------------- | ----------- `r indexfns(c("text3d", "texts3d"))`: | adds text `r indexfns("abclines3d")`: | adds straight lines to plot (like `abline`) `r indexfns("arc3d")`: | adds spherical arcs or spirals to plot `r indexfns("planes3d")`: | adds planes to plot `r indexfns("clipplanes3d")`: | add clipping planes to plot `r indexfns(c("sprites3d", "particles3d"))`: | add sprites (fixed shapes or images) to plot `r indexfns("spheres3d")`: | adds spheres `r indexfns(c("surface3d", "terrain3d"))`: | a surface (as used in `r linkfn("persp3d")`) `r indexfns("drape3d")`: | drapes lines on a surface or object(s) `r indexfns("shadow3d")`: | projects mesh onto a surface `r indexfns("arrow3d")`: | add an arrow to a scene `r indexfns("pch3d")`: | draw base-style plotting symbols `r indexfns("plotmath3d")`: | used by `r linkfn("text3d")` for math text ### Axes and other "decorations" The following low-level functions control the look of the graph: Function | Description ------------------------------------ | ----------- `r indexfns(c("axes3d", "axis3d"))`: | add axes to plot `r indexfns(c("box3d", "bbox3d"))`: | add box around plot `r indexfns("title3d")`: | add title to plot `r indexfns("mtext3d")`: | add marginal text to plot `r indexfns("decorate3d")`: | add multiple "decorations" (scales, etc.) to plot `r indexfns("aspect3d")`: | set the aspect ratios for the plot `r indexfns(c("bg3d", "bgplot3d"))`: | set the background of the scene `r indexfns("show2d")`: | show a 2D plot or image in a 3D scene `r indexfns("legend3d")`: | set a legend for the scene `r indexfns("grid3d")`: | add a reference grid to a graph `r indexfns("thigmophobe3d")`: | choose label positions to avoid overlap `r indexfns("setAxisCallbacks")`: | set user-defined axis annotations For example, to plot three random triangles, one could use ```{r "triangles3d()", fig.width=3, fig.height=3} triangles3d(cbind(x=rnorm(9), y=rnorm(9), z=rnorm(9)), col = "green") decorate3d() bg3d("lightgray") aspect3d(1,1,1) ``` Besides the `*3d` functions mentioned above, there are deprecated functions `r deprecated(c("rgl.abclines", "rgl.bbox", "rgl.bg", "rgl.clipplanes", "rgl.lines", "rgl.linestrips", "rgl.planes", "rgl.points", "rgl.primitive", "rgl.quads", "rgl.setAxisCallback", "rgl.spheres", "rgl.sprites", "rgl.surface", "rgl.texts", "rgl.triangles"))`. You should avoid using all of these functions, which do not work properly with the `*3d` functions and will soon be removed from `rgl`. See the `r linkfn("r3d", text="?r3d", pkg="rgl")` help topic for details. The function `r indexfns(c("rgl.getAxisCallback"))` provides low-level support for `r linkfn("setAxisCallbacks")`. ## Controlling the Look of the Scene ### Camera angle By default when you open a new plot with `r linkfn("open3d")`: * The x axis goes from left to right. * The y axis goes from near the camera to far away. * The z axis goes from down to up. You can change the camera angle simply by dragging the picture with the mouse. To set the camera angle programmatically, use `r indexfns("view3d")`. This uses polar coordinates: * `theta` sets the rotation around the vertical axis, in degrees. * `phi` sets the "vertical" rotation around the horizontal axis, from -90 to 90 degrees. The default angle is roughly `theta = 0, phi = -70`. Starting from this position: * As you increase `theta`, the graph will spin anticlockwise from your point of view. * As you increase `phi` to 0, you start to look down at the scene from the top. If you increase `phi` above 0, you continue over and start to see the graph from the "back" (and upside down). You can also use `r indexfns("observer3d")` to change the camera location using `x,y,z` coordinates. In particular, increasing the `z` coordinate lets you zoom out, and decreasing it zooms you in. One useful approach is to use the mouse to find a nice viewing angle. You can then save it using `par3d("userMatrix")` and restore the same view later: ```{r, eval = FALSE} myview <- par3d("userMatrix") # ... later ... par3d(userMatrix = myview) ``` ### Lighting In most scenes, objects are "lit", meaning that their appearance depends on their position and orientation relative to lights in the scene. The lights themselves don't normally show up, but their effect on the objects does. Use the `r indexfns("light3d")` function to specify the position and characteristics of a light. Lights may be infinitely distant, or may be embedded within the scene. Their characteristics include `ambient`, `diffuse`, and `specular` components, all defaulting to white. The `ambient` component appears the same from any direction. The `diffuse` component depends on the angle between the surface and the light, while the `specular` component also takes the viewer's position into account. The deprecated `r deprecated("rgl.light")` function should no longer be used; use `r linkfn("light3d")` instead. ### Materials The mental model used in `rgl` is that the objects being shown in scenes are physical objects in space, with material properties that affect how light reflects from them (or is emitted by them). These are mainly controlled by the `r indexfns("material3d")` function, or by arguments to other functions that are passed to it. The material properties that are recognized in calls to `material3d` are described in detail in the `r linkfn("material3d", text="?material3d", pkg="rgl")` help page, and listed in the `r indexfns("rgl.material.names")` variable. All of them can be set except the ones in `r indexfns("rgl.material.readonly")`. Here we give an overview. Property | Default | Meaning --------- | ------- | ------------------ color | white | vector of surface colors to apply to successive vertices for diffuse light alpha | 1 | transparency: 0 is invisible, 1 is opaque lit | TRUE | whether lighting calculations should be done ambient | black | color in ambient light specular | white | color in specular light emission | black | color emitted by the surface shininess | 50 | controls the specular lighting: high values look shiny smooth | TRUE | whether shading should be interpolated between vertices texture | NULL | optional path to a "texture" bitmap to be displayed on the surface front, back | fill | should polygons be filled, or outlined? size | 3 | size of points in pixels lwd | 1 | width of lines in pixels Other properties include "texmipmap", "texmagfilter", "texminfilter", "texenvmap", "fog", "point\_antialias", "line\_antialias", "depth\_mask", "depth\_test", "polygon_offset", "margin", "floating", "tag" and "blend"; see `r linkfn("material3d", "the help page", pkg = "rgl")` for details. There is also a deprecated `r deprecated("rgl.material")` function that works at a lower level; users should avoid it. ### Textures As described in the previous section, one of the material properties is `texture`, the name of a bitmap file (in `.png` format) containing an image to be displayed on the surface. This section gives more details about textures. In `OpenGL`, each vertex in a polygon may be associated with a particular location in the bitmap. The interior of the polygon interpolates within the bitmap. There are two conventions in `rgl` functions for specifying these coordinates. Functions which specify primitives (`r linkfn("triangles3d")`, etc.) accept an optional matrix argument `texcoords` which gives `s` (horizontal) and `t` (vertical) locations within the bitmap in columns with one row per vertex. The coordinates are `(0,0)` for the lower left, and `(1,1)` for the upper right. If values outside this range are given, the image repeats, i.e. `(1.1, 1.2)` would specify the same point in the image as `(0.1, 0.2)`. Other functions such as `r linkfn("surface3d")` that take matrices for each vertex coordinate accept texture coordinates as matrices as well, in arguments `texture_s` and `texture_t`. For example, the following code displays four copies of a 2D plot on a quad, because the texture coordinates run from 0 to 2 in both `s` and `t`: ```{r Texture} filename <- tempfile(fileext = ".png") png(filename = filename) plot(rnorm(1000), rnorm(1000)) safe.dev.off() open3d() xyz <- cbind(c(0,1,1,0), 0, c(0,0,1,1)) quads3d(xyz, texture = filename, texcoords = xyz[,c(1, 3)]*2, col = "white", specular = "black") ``` Some other notes: - The color in `quads3d()` above was specified to be white. By default, the colors in the bitmap will modify the color of the surface. If `col` is black (a common default), you won't see anything, so a warning may be issued. - You usually don't want specular reflections (which show up as glare). Setting `specular` to black prevents those. - The material property `"texmode"` allows texture colors to be used differently. The default is `"modulate"`, where the texture values combine multiplicatively with the underlying values. - Another aspect of how the bitmap is handled is controlled by the material property `"textype"`. The default is `"rgb"`, which takes the red-green-blue colors from the bitmap and uses them to modify the corresponding colors in the polygon. - Other possibilities for `"textype"` and `"texmode"` are described in `r linkfn("material3d", "the material3d help page", pkg = "rgl")`. - The other `"tex*"` material properties control how the interpolation within the image is done. - Modern `OpenGL` supports 1- and 3-dimensional textures; these are not currently supported in `rgl`. ### Fonts `rgl` uses the same ideas as base graphics for drawing text: there are font families named `"sans"`, `"serif"`, and `"mono"` for drawing text of those types. In `rgl`, the `"symbol"` family is not supported. New font families can be defined using the low-level function `r indexfns("rglFonts")`, or more simply using the higher level function `r indexfns("rglExtrafonts")`. The latter function requires the `extrafont` package to be installed. ### par3d: Miscellaneous graphical parameters The `r indexfns("par3d")` function, modelled after the classic graphics `r linkfn("par", pkg="graphics")` function, sets or reads a variety of different `rgl` internal parameters, listed in the `r indexfns("rgl.par3d.names")` variable. All of them can be set except the ones in `r indexfns("rgl.par3d.readonly")`. Some parameters are completely read-only; others are fixed at the time the window is opened, and others may be changed at any time. Name | Changeable? | Description ----------- | ----- | ----------- antialias | fixed | Amount of hardware antialiasing cex | | Default size for text family | | Device-independent font family name; see `r linkfn("text3d", text="?text3d", pkg="rgl")` font | | Integer font number useFreeType | | Should FreeType fonts be used if available? fontname | read-only | System-dependent font name set by `r linkfn("rglFonts")` FOV | | Field of view, in degrees. Zero means isometric perspective ignoreExtent | | Should `rgl` ignore the size of new objects when computing the bounding box? skipRedraw | | Should `rgl` suppress updates to the display? maxClipPlanes | read-only | How many clip planes can be defined? modelMatrix | read-only | The OpenGL ModelView matrix; partly set by `r indexfns("view3d")` projMatrix | read-only | The OpenGL Projection matrix bbox | read-only | Current bounding-box of the scene viewport | | Dimensions in pixels of the scene within the window windowRect | | Dimensions in pixels of the window on the whole screen listeners | | Which subscenes respond to mouse actions in the current one mouseMode | | What the mouse buttons do. See `r linkfn("mouseMode", '"mouseMode"')` observer | read-only | The position of the observer; set by `r indexfns("observer3d")` scale | | Rescaling for each coordinate; see `r linkfn("aspect3d")` zoom | | Magnification of the scene The deprecated `r deprecated("rgl.viewpoint")` function should not be used. ### Default settings The `r indexfns("r3dDefaults")` list and the `r indexfns("getr3dDefaults")` function control defaults in new windows opened by `r linkfn("open3d")`. The function looks for the variable in the user's global environment, and if not found there, finds the one in the `rgl` namespace. This allows the user to override the default settings for new windows. Once found, the `r3dDefaults` list provides initial values for `r linkfn("par3d")` parameters, as well as defaults for `r linkfn("material3d")` and `r linkfn("bg3d")` in components `"material"` and `"bg"` respectively. ## Meshes: Constructing Shapes `rgl` includes a number of functions to construct and display various solid shapes. These generate objects of class `"shape3d"`, `"mesh3d"` or `"shapelist3d"`. The details of the classes are described below. We start with functions to generate them. ### Specific solids These functions generate specific shapes. Optional arguments allow attributes such as color or transformations to be specified. Function | Description ------------------------------------ | ----------- `r indexfns(c("tetrahedron3d", "cube3d", "octahedron3d", "dodecahedron3d", "icosahedron3d"))`: | Platonic solids `r indexfns(c("cuboctahedron3d", "oh3d"))`: | other solids ```{r Solids} cols <- rainbow(7) layout3d(matrix(1:16, 4,4), heights=c(1,3,1,3)) text3d(0,0,0,"tetrahedron3d"); next3d() shade3d(tetrahedron3d(col=cols[1])); next3d() text3d(0,0,0,"cube3d"); next3d() shade3d(cube3d(col=cols[2])); next3d() text3d(0,0,0,"octahedron3d"); next3d() shade3d(octahedron3d(col=cols[3])); next3d() text3d(0,0,0,"dodecahedron3d"); next3d() shade3d(dodecahedron3d(col=cols[4])); next3d() text3d(0,0,0,"icosahedron3d"); next3d() shade3d(icosahedron3d(col=cols[5])); next3d() text3d(0,0,0,"cuboctahedron3d"); next3d() shade3d(cuboctahedron3d(col=cols[6])); next3d() text3d(0,0,0,"oh3d"); next3d() shade3d(oh3d(col=cols[7])) ``` A very large collection of polyhedra is contained in the `r linkfn("Rpolyhedra-package", text = "Rpolyhedra", pkg = "Rpolyhedra")` package. ### Generating new shapes These functions generate new shapes: Function | Description ------------------------------------ | ----------- `r indexfns("cylinder3d")`: | generate a tube or cylinder `r indexfns("polygon3d")`: | generate a flat polygon by triangulation `r indexfns("extrude3d")`: | generate an "extrusion" of a polygon `r indexfns("turn3d")`: | generate a solid of rotation `r indexfns("ellipse3d")`: | generate an ellipsoid in various ways `r indexfns("mesh3d")`: | generate a shape from indexed vertices `r indexfns("shapelist3d")`: | generate a shape by combining other shapes `r linkfn("as.mesh3d")`: | a generic function; see below A related function is `r indexfns("triangulate")`, which takes a two dimensional polygon and divides it up into triangles using the "ear-clipping" algorithm. The generic function `r indexfns("as.mesh3d")` is provided to allow data structures produced by other code to be converted to mesh structures. Currently the following classes are supported: Class | Package | Description ----- | ------- | ----------- `r indexfns("deldir", pkg = "deldir")` | `deldir` | Delaunay triangulations of irregular point clouds `r indexfns("triSht", pkg = "interp")` | `interp` | Also Delaunay triangulations `r indexfns("tri", pkg = "tripack")` | `tripack` | Generalized Delaunay triangulations `r indexfns("ashape3d", pkg = "alphashape3d")` | `alphashape3d` | Alpha-shapes `r linkfn("rglId")` | `rgl` | `rgl` object identifiers The `r indexfns("checkDeldir")` function checks that a compatible version of the `deldir` package is installed. The default `r indexfns("as.mesh3d.default")` method is a simple way to construct a mesh from a matrix of vertices; it can use `r indexfns("mergeVertices")` (which can also be used on its own) to merge repeated vertices within the matrix, allowing `r linkfn("addNormals")` to be used to give a smooth appearance. The `r indexfns("as.tmesh3d")` generic is a variation that guarantees the resulting object will have no quad entries. Functions `r indexfns(c("tmesh3d","qmesh3d"))` are now obsolete; use `r linkfn("mesh3d")` instead. ### The underlying class structure for shapes `"shape3d"` is the basic abstract type. Objects of this class can be displayed by `r indexfns("shade3d")` (which shades faces), `r indexfns("wire3d")` (which draws edges), or `r indexfns("dot3d")` (which draws points at each vertex.) `"mesh3d"` is a descendant type. Objects of this type contain the following fields: Field | Meaning ------------ | --------------- vb | A 4 by n matrix of vertices in homogeneous coordinates. Each column is a point. ip | (optional) A vector of vertex indices for points. is | (optional) A 2 by s matrix of vertex indices. Each column is a line segment. it | (optional) A 3 by t matrix of vertex indices. Each column is a triangle. ib | (optional) A 4 by q matrix of vertex indices. Each column is a quadrilateral. material | (optional) A list of material properties. normals | (optional) A matrix of the same shape as vb, containing normal vectors at each vertex. texcoords | (optional) A 2 by n matrix of texture coordinates corresponding to each vertex. values | (optional) A vector of length n holding values at each vertex meshColor | (optional) A text value indicating how colors and texture coordinates should be interpreted. tags | (optional) A vector added by some functions (e.g. `r linkfn("clipMesh3d")`) to relate output parts to input parts. ### Contouring and clipping shapes These functions compute and plot contours of functions on surfaces, or clip objects along a contour of a function. Function | Description -------------------------------- | ----------- `r indexfns("contourLines3d")`: | draw contour lines on surface `r indexfns("filledContour3d")`: | fill between contours on surface `r indexfns("clipMesh3d")`: | clip mesh object using curved boundary `r indexfns("clipObj3d")`: | clip general object using curved boundary ### Manipulating shapes These functions manipulate and modify mesh objects: Function | Description ------------------------------------ | ----------- `r indexfns("addNormals")`: | add normal vectors to make a shape look smooth `r indexfns("subdivision3d")`: | add extra vertices to make it look even smoother `r indexfns("merge.mesh3d", backticked("merge"))`: | merge mesh objects `r indexfns("facing3d")`: | subset of mesh facing "up" `r indexfns("getBoundary3d")`: | get the boundary of a mesh object The individual steps in `r linkfn("subdivision3d")` are also available: `r indexfns(c("deform.mesh3d", "divide.mesh3d", "normalize.mesh3d"))`. These are mainly intended for internal use. ## Multi-figure Layouts `rgl` has several functions to support displaying multiple different "subscenes" in the same window. The high level functions are Function | Description ------------------------- | ----------- `r indexfns("mfrow3d")`: | Multiple figures (like `r linkfn("par", text = 'par("mfrow")', pkg="graphics")` `r indexfns("layout3d")`: | Multiple figures (like `r linkfn("layout", pkg="graphics")`) `r indexfns("next3d")`: | Move to the next figure (like `r linkfn("plot.new", pkg="graphics")` or `r linkfn("frame", pkg="graphics")`) `r indexfns("subsceneList")`: | List all the subscenes in the current layout `r indexfns("clearSubsceneList")`: | Clear the current list and revert to the previous one There are also lower level functions. Function | Description ---------------------------------- | ----------- `r indexfns("newSubscene3d")`: | Create a new subscene, with fine control over what is inherited from the parent `r indexfns("currentSubscene3d")`: | Report on the active subscene `r indexfns("subsceneInfo")`: | Get information on current subscene `r indexfns("useSubscene3d")`: | Make a different subscene active `r indexfns(c("addToSubscene3d", "delFromSubscene3d"))`: | Add objects to a subscene, or delete them `r indexfns("gc3d")`: | Do "garbage collection": delete objects that are not displayed in any subscene ## Documents with `rgl` Scenes The `rgl` package can produce output that can be embedded in other documents. The recommended way to do this has changed several times over the years. We will start with the current recommendation, then list older methods. ### The recommended method Currently the best way to embed an `rgl` scene in a document is to produce the document in HTML using R Markdown. Early in the document, you should have code like this in one of the setup code chunks: ````markdown `r ''````{r echo=FALSE, include=FALSE} library(rgl) setupKnitr(autoprint = TRUE) ``` ```` The call to `setupKnitr()` will install a number of hooks and set options in `knitr` so that `rgl` code is handled properly. The `autoprint = TRUE` argument makes `rgl` act in the document almost the same way it would act in the console, or the way base graphics are handled by `knitr`: If you print the value of high level `rgl` functions, a plot will be inserted into the output, but maybe only after low level modifications to it are complete. For example, this code block prints both triangles and spheres in a single plot at the end: ```{r Autoprint} xyz <- matrix(rnorm(27), ncol = 3) triangles3d(xyz, col = rainbow(9)) spheres3d(xyz, col = rainbow(9), radius = 0.1) ``` There are a few differences if you have a complicated situation: - The mechanism depends on the result of the `rgl` function calls being automatically printed. If the calls are in a loop or other code block where automatic printing doesn't happen, you'll need some trickery to get things to print. For example, this will print three plots: ```{r eval = FALSE} plots <- NULL for (i in 1:3) { plot3d(rnorm(10), rnorm(10), rnorm(10)) plots <- htmltools::tagList(plots, rglwidget()) close3d() } plots ``` - It also depends on the fact that `rgl` functions return results using `lowlevel()` or `highlevel()` to mark which kind of plot they are. If you are using a function from another package to produce the plot, you may need to insert an explicit call to one of those to get it to print. Use `lowlevel()` if the function just modifies an existing plot, `highlevel()` if it starts a new one. For example, ```{r eval = FALSE} foreignHigh() # Produces a high level plot, but doesn't return # an appropriate value highlevel() foreignLow() # Modifies the previous plot lowlevel() ``` This should display the output at the end of the code chunk, when modifications are assumed complete. ### Producing PDF output While some PDF previewers support interactive 3D graphics, most don't. To produce a screenshot of an `rgl` scene in an R Markdown document with PDF output, simply follow the directions given above. The auto-printing will detect PDF output and use `snapshot3d` to produce a PNG file to insert. (See below if you want to insert a different format of graphic.) If you really need interactive output, see the `r linkfn("writeASY")` function. ### Manual insertion of plots You may not want to use the `setupKnitr(autoprint = TRUE)` method described above. It is very new, and may still have bugs; you may have an older document and not want to edit it to work that way. In this case, you can insert plots manually. Use setup code ````markdown `r ''````{r echo=FALSE, include=FALSE} library(rgl) setupKnitr() ``` ```` and call `rglwidget()` at top level whenever you want to insert a plot. There are a couple of other differences in default behaviour if you are not using `autoprint`: - By default, each code chunk continues the `rgl` scene from earlier chunks. You'll need an explicit `r linkfn("open3d")` call to get a clean window. - Also by default, the `rgl` window is not closed at the end of the chunk. This probably doesn't matter, but you may find you run out of memory if your scenes are really big. ### Older methods The original way to insert an `rgl` scene in a document was to use the deprecated `r deprecated("writeWebGL")` function to write HTML code to insert in a document. Later, `Sweave` and `knitr` hooks were added. These are no longer supported, and you should update old documents to use the newer methods. If you are reading documents that suggest using those methods, let the author know they need updating! ## Utility Functions ### User interaction By default, `rgl` detects and handles mouse clicks within your scene, and uses these to control its appearance. You can find out the current handlers using the following code: ```{r} par3d("mouseMode") ``` The labels `c("left", "right", "middle")` refer to the buttons on a three button mouse, or simulations of them on other mice. `"wheel"` refers to the mouse wheel, and `"none"` refers to actions that take place when the mouse is moved without pressing any button. The button actions generally correspond to click and drag operations. Possible values for `r indexfns("mouseMode", '"mouseMode"')` for the mouse pointer or wheel are as follows: Mode | Description -------------- | --------- `"none"` | No action `"trackball"` | The mouse acts as a virtual trackball. Clicking and dragging rotates the scene `"xAxis"`, `"yAxis"`, `"zAxis"` | Like `"trackball"`, but restricted to rotation about one axis `"polar"` | The mouse affects rotations by controlling polar coordinates directly `"selecting"` | The mouse is being used by the `r linkfn("select3d")` function `"zoom"` | The mouse zooms the display `"fov"` | The mouse affects perspective by changing the field of view `"pull"` | Rotating the mouse wheel towards the user "pulls the scene closer" `"push"` | The same rotation "pushes the scene away" `"user"` | A user action set by `r indexfns(c("setUserCallbacks", "rgl.setMouseCallbacks", "rgl.setWheelCallback"))`. Use `r indexfns("rgl.getMouseCallbacks")` and `r indexfns("rgl.getWheelCallback")` to retrieve. The following functions make use of the mouse for selection within a scene. Function | Description ---------------------------- | ----------- `r indexfns("identify3d")`: | like the classic graphics `r linkfn("identify", pkg="graphics")` function `r indexfns("select3d")`: | returns a function that tests whether a coordinate was selected `r indexfns("selectpoints3d")`: | selects from specific objects `r indexfns("hover3d")`: | displays "hover" info about points `r indexfns("selectionFunction3d")` produces the selection function from information about the projection and mouse selection region; it is used internally in the functions above. The deprecated `r deprecated("rgl.select3d")` function is an obsolete version of `select3d`, and `r indexfns("rgl.select")` is a low-level support function. ### Animations `rgl` has several functions that can be used to construct animations. These are based on functions that update the scene according to the current real-world time, and repeated calls to those. The functions are: Function | Description ---------------------- | ------------- `r indexfns("play3d")`: | Repeatedly call the update function `r indexfns("spin3d")`: | Update the display by rotating at a constant rate `r indexfns("par3dinterp")`: | Compute new values of some `r linkfn("par3d")` parameters by interpolation over time See the `r linkfn("movie3d")` function for a way to output an animation to a file on disk. Animations are not currently supported in the HTML written by `r linkfn("rglwidget")`, though the `playwidget` function provides equivalent functionality. ### Integration with TCL/TK There are three functions in `rgl` that support control of an `rgl` scene using the TCL/TK framework. Function | Description ---------------------- | ------------- `r indexfns("tkspin3d")`: | Set up buttons in a window to control a scene `r indexfns("tkspinControl")`: | Embed the control buttons in a separate TCL/TK frame `r indexfns("tkpar3dsave")`: | Create a dialog to interactively save mouse actions These functions were formerly contained (without the `tk` prefixes on their names) in the `tkrgl` package. That package is now deprecated. ### Exporting and importing scenes `rgl` contains several functions to write scenes to disk for use by other software, or to read them in. In order from highest fidelity to lowest, the functions are: Function | Description ----------- | ------------- `r indexfns("scene3d")`: | Save a scene to an R variable, which can be saved and reloaded `r indexfns("rglwidget")`: | Prints as HTML and Javascript to display a scene in a web browser. (See also [User Interaction in WebGL](WebGL.html).) `r indexfns("writeASY")`: | Write files for Asymptote `r indexfns("writePLY")`: | Write PLY files (commonly used in 3D printing) `r indexfns(c("readOBJ", "writeOBJ"))`: | Read or write OBJ files (commonly used in 3D graphics) `r indexfns(c("readSTL", "writeSTL"))`: | Read or write STL files (also common in 3D printing) `r indexfns("as.rglscene")`: | Generic function, no methods in `rgl` The [`rgl2gltf`](https://dmurdoch.github.io/rgl2gltf/dev/) package can read or write GLTF and GLB files. It includes an `as.rglscene` method to convert GLTF objects to `rgl` scenes. The code in `rgl`'s `r indexfns("Buffer")` R6 class is based on the GLTF format. It is used by `r linkfn("rglwidget")` to make output webpages somewhat smaller than they were previously. There are also functions to save snapshots or other recordings of a scene, without any 3D information being saved: Function | Description ------------ | ------------- `r indexfns("snapshot3d")`: | Save a PNG file bitmap of the scene `r indexfns("rgl.postscript")`: | Save a Postscript, LaTeX, PDF, SVG or PGF vector rendering of the scene `r indexfns("movie3d")`: | Save a series of bitmaps to be assembled into a movie `r indexfns("rgl.pixels")`: | Obtain pixel-level information about the scene in an R variable `r indexfns("rgl.Sweave")`: | Driver function for inserting a snapshot into a Sweave document. `r indexfns(c("hook_rgl", "hook_webgl"))`: | `knitr` hook functions for inserting images into a document. `r indexfns("setupKnitr")`: | Function to set up `knitr` hooks The `r indexfns("rgl.snapshot")` function is a low level version of `snapshot3d()`; it requires that the `rgl` display be onscreen and copies from there. `snapshot3d()` tries to use the `webshot2` package so it will work even with no display. The functions `r indexfns(c("rgl.Sweave.off", "Sweave.snapshot"))` are involved in Sweave processing and not normally called by users. ### Default display There are two ways in which `rgl` scenes are normally displayed within R. The older one is in a dedicated window. In Unix-alikes this is an X11 window; it is a native window in Microsoft Windows. On macOS, the XQuartz system (see https://www.xquartz.org) needs to be installed to support this. To suppress this display, set `options(rgl.useNULL = TRUE)` before opening a new `rgl` window. See the help page for the `r indexfns("rgl.useNULL")` function for how to set this before starting R. The newer way to display a scene is by using WebGL in a browser window or in the Viewer pane in RStudio. To select this, set `options(rgl.printRglwidget = TRUE)`. Each operation that would change the scene will return a value which triggers a new WebGL display when printed. ### Working with WebGL scenes You should use the following scheme for exporting a scene to a web page. There's also an older scheme, which is no longer supported. The recommended approach works with the `htmlwidgets` framework (see http://www.htmlwidgets.org/). In an R Markdown document in `knitr`, use the `r linkfn("rglwidget")` function. (You can also use chunk option `webgl=TRUE`; we recommend the explicit use of `rglwidget`.) This approach also allows display of `rgl` scenes in [RStudio](https://posit.co/). Besides `rgl` scenes, various controls for them can be displayed, and there are a few utility functions that can be useful: Function | Description ------------------------------------ | ------------- `r indexfns("propertyControl")`: | set individual properties `r indexfns("clipplaneControl")`: | control a clipping plane `r indexfns("subsetControl")`: | control which objects are displayed `r indexfns("ageControl")`: | "age" vertices of an object `r indexfns("vertexControl")`: | control properties of vertices `r indexfns("par3dinterpControl")`: | WebGL control like `r linkfn("par3dinterp")` `r indexfns("playwidget")`: | display and automate controls `r indexfns("toggleWidget")`: | display a button to toggle some items `r documentedfns <- c(documentedfns, "%>%");indexfns("pipe", text="%>%")`: | `magrittr` pipe `r indexfns(c("figHeight", "figWidth"))`: | Dimensions of figures in R Markdown document `r indexfns("rglShared")`: | share data using `crosstalk` package `r indexfns("rglMouse")`: | change mouse mode in RGL scene `r indexfns("asRow")`: | arrange multiple objects in an HTML display `r indexfns("getWidgetId")`: | get the `elementId` from a widget These functions work with the above scheme in Shiny apps: Function | Description ------------------------------------ | ------------- `r indexfns("sceneChange")`: | used in `Shiny` for large scene changes `r indexfns(c("shinyGetPar3d", "shinySetPar3d"))`: | get or set `r linkfn("par3d")` values from Shiny `r indexfns("shinyResetBrush")`: | reset the mouse brush in Shiny The `r linkfn("selectionFunction3d")` function is also likely to be involved in mouse interactions when using Shiny. Some functions are mainly for internal use: `r indexfns(c("elementId2Prefix", "playwidgetOutput", "renderPlaywidget", "rglwidgetOutput", "renderRglwidget", "registerSceneChange"))`. More details are given in the vignette [User Interaction in WebGL](WebGL.html). The functions `r indexfns(c("lowlevel", "highlevel", "rglId"))` are also for internal use, marking function results for automatic printing. Finally, the function `r indexfns("setUserShaders")` allows you to use hand-written shaders in WebGL, and `r indexfns("getShaders")` allows you to see what shader would be used. ### Working with the scene `rgl` maintains internal structures for all the scenes it displays. The following functions allow users to find information about them and manipulate them. In cases where there are both `*3d` and `rgl.*` versions of functions, most users should use the `*3d` version: the `rgl.*` functions are more primitive and are mainly intended for internal use. Function | Description ------------------------------------ | ----------- `r indexfns("open3d")`: | open a new window `r indexfns("close3d")`: | close the current window `r indexfns("cur3d")`: | id of the active device `r indexfns("set3d")`: | set a particular device to be active `r indexfns("pop3d")`: | delete objects from the scene `r indexfns(c("clear3d"))`: | delete all objects of certain classes `r indexfns("ids3d")`: | ids, types and tags of current objects `r indexfns("tagged3d")`: | find tags or objects with tags Some of these functions have alternate names for back compatibility: `r deprecated(c("rgl.cur", "rgl.ids", "rgl.pop"))`. Either name will work, but the `*3d` version is recommended for new code. Some have deprecated versions: `r deprecated(c("rgl.clear", "rgl.set"))`. Those should not be called. These functions are mainly intended for programming, and have no corresponding `*3d` counterparts: Function | Description ------------- | ----------- `r indexfns("rgl.bringtotop")`: | bring the current window to the top `r indexfns("rgl.dev.list")`: | ids of all active devices `r indexfns(c("rgl.attrib", "rgl.attrib.info", "rgl.attrib.count"))`: | attributes of objects in the scene `r indexfns("rgl.projection")`: | return information about the current projection `r indexfns(c("rgl.user2window", "rgl.window2user"))`: | convert between coordinates in the current projection The `r indexfns("as.triangles3d")` generic function is intended to extract coordinates in a form suitable for passing to `r linkfn("triangles3d")`. Currently a method is provided for `r linkfn("rglId")` objects. In addition to these, there are some deprecated functions which should not be called: `r deprecated(c("rgl.init", "rgl.open", "rgl.close", "rgl.quit"))`. ### Working with 3-D vectors Most `rgl` functions work internally with "homogeneous" coordinates. In this system, 3-D points are represented with 4 coordinates, generally called (x, y, z, w). The corresponding Euclidean point is (x/w, y/w, z/w), if w is nonzero; zero values of w correspond to "points at infinity". The advantage of this system is that affine transformations including translations and perspective shifts become linear transformations, with multiplication by a 4 by 4 matrix. `rgl` has the following functions to work with homogeneous coordinates: Function | Description ------------------------------------ | ----------- `r indexfns(c("asEuclidean", "asHomogeneous"))`: | convert between homogeneous and Euclidean coordinates when x, y and z are columns `r indexfns(c("asEuclidean2", "asHomogeneous2"))`: | convert when x, y and z are rows `r indexfns(c("rotate3d", "scale3d", "translate3d"))`: | apply a transformation `r indexfns("transform3d")`: | apply a general transformation `r indexfns(c("rotationMatrix", "scaleMatrix", "translationMatrix"))`: | compute the transformation matrix `r indexfns("identityMatrix")`: | return a 4 x 4 identity matrix `r indexfns("projectDown")`: | a 3D to 2D projection down a vector There is also a function `r indexfns("GramSchmidt")`, mainly for internal use: it does a Gram-Schmidt orthogonalization of a 3x3 matrix, with some specializations for its use in `r linkfn("cylinder3d")`. ### Working with other packages Sometimes it may be convenient to interactively rotate a scene to a particular view, then display it in `lattice` or base graphics. The `r indexfns("rglToLattice")` and `r indexfns("rglToBase")` functions support this. For example, we first display the volcano data in `rgl`: ```{r fig.alt="Volcano in rgl", echo = 2:3} close3d() persp3d(volcano, col = "green") ``` This display is interactive, but we can reproduce the initial view using the `lattice` `r linkfn("wireframe", pkg = "lattice")` or base graphics `r linkfn("persp", pkg = "graphics")` functions: ```{r eval=requireNamespace("orientlib", quietly = TRUE) && requireNamespace("lattice", quietly = TRUE), fig.alt=paste0("Volcano in ", c("lattice", "base"), "graphics.")} # Only evaluated if the lattice & orientlib packages are installed lattice::wireframe(volcano, col = "green", screen = rglToLattice()) angles <- rglToBase() persp(volcano, col = "green", shade = TRUE, theta = angles$theta, phi = angles$phi) ``` Note that the `orientlib` package must be available for these functions to work. ### Creating `pkgdown` websites The ["Using RGL in pkgdown web sites"](pkgdown.html) vignette describes how to use `rgl` in a `pkgdown` web site. The utility function `r indexfns("in_pkgdown_example")` can be used to detect that `pkgdown` is being used. ### Working with `testthat` The `testthat` package is widely used for unit tests in packages. Such tests are hard to write with `rgl`, because the output is visual and interactive rather than a simple value. The `r indexfns("expect_known_scene")`, `r indexfns("compare_proxy.mesh3d")` and `r indexfns("all.equal.mesh3d")` functions help with this by removing system-dependent features of `rgl` output. ### Working with Javascript The WebGL displays created using `r linkfn("rglwidget")` rely on a large body of Javascript code included in this package. To help in development of this code, the `r indexfns("makeDependency")` function was written. It may be useful in other packages that include Javascript. ### Other functions and objects This section is for miscellaneous functions and objects that don't fall in any of the other categories in this document. The `r indexfns("setGraphicsDelay")` function is designed to work around what appears to be a bug on macOS: if a standard plot window is opened too quickly after an `rgl` window, R can crash. This function inserts a one second delay when it appears to be needed. The `r indexfns("gltfTypes")` vector contains constants used in OpenGL and glTF. ## Warning: Work in Progress! This vignette is always a work in progress. Some aspects of the `rgl` package are not described, or do not have examples. There may even be functions that are missed completely, if the following list is not empty: ```{r echo=FALSE} setdiff(ls("package:rgl"), c(documentedfns, deprecatedfns)) ``` ## Index of Functions The following functions and constants are described in this document:
```{r echo=FALSE, results="asis"} writeIndex(cols = if (knitr::is_html_output()) 5 else 4) ``` rgl/inst/doc/deprecation.Rmd0000644000176200001440000001756215000743766015544 0ustar liggesusers--- title: "Deprecating the `rgl.*` interface" author: "Duncan Murdoch" date: "`r Sys.Date()`" output: rmarkdown::html_vignette: toc: true vignette: > %\VignetteIndexEntry{Deprecating the `rgl.*` interface} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` # Introduction Since at least 2004, `rgl` has had two interfaces for many of the primitive functions: `rgl.*` and `*3d`. For example, to draw points you could use `rgl.points()` or `points3d()`. With the upcoming version 1.0.0 release of `rgl`, most of the duplication will be removed. The first step will be to deprecate a large number of `rgl.*` functions so they give warnings when they are called, and a few months later they will be removed from the package exports. This document describes the differences and changes needed by users of the `rgl.*` interface. # Differences between the interfaces ## Opening a window The `rgl.open()` function has a single argument, `useNULL`. If set to `TRUE`, the NULL `rgl` device will be used. The `par3d()` settings will be set to their defaults. The `open3d()` function has arguments ```r function(..., params = getr3dDefaults(), useNULL = rgl.useNULL(), silent = FALSE ) ``` and allows `par3d()` values to be specified, and uses the `r3dDefaults` variable to set default values for `par3d()`, `material3d()`, and `bg3d()`. Initially `r3dDefaults` is defined as ```r list(userMatrix = rotationMatrix(290*pi/180, 1, 0, 0), mouseMode = c("none", "trackball", "zoom", "fov", "pull"), FOV = 30, family = "sans", bg = list(color="white", fogtype = "none"), material = list(color="black", fog = TRUE) ) ``` Users can create their own default lists; e.g. to get the same result as `rgl.open()` would give, use ```r open3d(params = list()) ``` or ```r r3dDefaults <- list() open3d() ``` ## Material properties The `rgl.material()` function has a large number of parameters. The pre-deprecation arguments were: ```r function( color = "white", alpha = 1.0, lit = TRUE, ambient = "black", specular = "white", emission = "black", shininess = 50.0, smooth = TRUE, texture = NULL, textype = "rgb", texmipmap = FALSE, texminfilter = "linear", texmagfilter = "linear", texenvmap = FALSE, front = "filled", back = "filled", size = 3.0, lwd = 1.0, fog = TRUE, point_antialias = FALSE, line_antialias = FALSE, depth_mask = TRUE, depth_test = "less", polygon_offset = c(0.0, 0.0), margin = "", floating = FALSE, tag = "", blend = c("src_alpha", "one_minus_src_alpha"), col, ... ) ``` Thus a call like `rgl.material(color = "black")` will set the color to black, and will also set all of the other parameters to the default values listed above. On the other hand, the arguments to `material3d()` are ```r function (..., id = NULL) ``` Calling `material3d(color = "black")` will set the color to black and leave all other parameters unchanged. ## Primitive shapes The primitive shapes (points etc.) can be set using calls like `rgl.points(x, y, z, color = "black")` or `points3d(x, y, z, color = "black")`. The first difference is that `rgl.*` primitives will call `rgl.material()` to set the material properties: in this example `color` will be set to `black`, and all other parameters will be set to their defaults. The `*3d` versions of the primitives use `material3d()` to set material properties, so only those that were specified will be changed, and the original values will be restored afterwards. The second difference is what happens if there is no window already open. The `rgl.*` functions will call `rgl.open()` (ignoring `r3dDefaults`), whereas the `*3d` functions will call `open3d()`. # Why deprecate `rgl.*`? Both of the systems worked, but they do not work together. For example, calling `rgl.points()` will have carry-on effects on later `points3d()` calls, whereas each `points3d()` call will just draw the points, it won't affect future calls. Users have found this confusing, and it makes their code hard to debug, and the `rgl` package hard to maintain. The `*3d` interface is more flexible, and more similar to the base graphics interface in R, so I've decided it will be the only one available going forward. ## Some `rgl.*` functions are not deprecated There will still be some `rgl.*` functions in the package. These are functions that are mainly intended for programming, such as `rgl.attrib()` and `rgl.user2window()`, and a few legacy functions like `rgl.Sweave()` supporting older approaches of using `rgl`. In a few cases both function versions are identical (`rgl.cur`, `rgl.ids`, and `rgl.pop` are identical to `cur3d`, `ids3d` and `pop3d` respectively), and for those the `rgl.*` versions will be kept, but the documentation will concentrate on the `*3d` functions. # My package uses `rgl.*`. What do I need to do? If your package is using `rgl.*` functions, the first step is to just make the substitutions suggested by the deprecation warning message. For example, if you use `rgl.points(rnorm(10), rnorm(10), rnorm(10))` try using `points3d(rnorm(10), rnorm(10), rnorm(10))` instead. In most cases this will give you what you want. In some cases more changes will be needed. ## `rgl.open` and `rgl.material` See above if you were using these. ## Textures The default color after `rgl.open()` was white, whereas with `open3d()` the default color is black, with a white background. Textures multiplicatively modify the color of the object, so after `open3d()`, a texture on an object will still appear black. Explicitly specifying `color = "white"` when a texture is used will fix this. ## `rgl.surface()` The arguments to `rgl.surface()` and `surface3d()` functions are different. The argument lists are ```r rgl.surface( x, z, y, coords = 1:3, ..., normal_x = NULL, normal_y = NULL, normal_z = NULL, texture_s = NULL, texture_t = NULL) surface3d(x, y = NULL, z = NULL, ..., normal_x = NULL, normal_y = NULL, normal_z = NULL, texture_s = NULL, texture_t=NULL) ``` Notice that the arguments are in a different order. Another difference is that `rgl.surface()` expects the surface to be defined in the `y` coordinate and viewed in the orientation produced by `rgl.open()`, not the one produced by `open3d()`. Up until very recently, `surface3d()` didn't allow both `x` and `z` to be vectors. The excellent [`rayshader` package](https://www.rayshader.com) used the convention that the `y` argument held the surface, so the `y` direction should point up. Using `view3d(theta = 45, phi = 45)` (which it was already doing) gives a reasonable view. ## Lists of material names and par3d properties Many functions in `rgl` and other packages use `...` to set material or `par3d` properties in a call, and for some, `...` will contain other optional arguments. Some packages used the argument list of `rgl.material()` to identify the material property names. Going forward, packages should use the variables ```r rgl.material.names rgl.material.readonly ``` These are character variables holding all the material property names. (`rgl.material.names` contains all names; `rgl.material.readonly` is the read-only subset of that list.) There are also variables ```r rgl.par3d.names rgl.par3d.readonly ``` which give the same information for `par3d`. Since these variables are recently added, you will need to add a dependence on `rgl (>= 0.111.5)` if you use them. ## Others If you have particular problems adapting other `rgl.*` to the `*3d` interface, please post them as issues on https://github.com/dmurdoch/rgl/issues . I'll explain how to get what you want or fix things in `rgl` so you can do it. rgl/inst/doc/WebGL.Rmd0000644000176200001440000004035715013106241014166 0ustar liggesusers--- title: "User Interaction in WebGL" author: "Duncan Murdoch" date: "`r format(Sys.time(), '%B %d, %Y')`" output: rmarkdown::html_vignette: toc: true fig_width: 5 fig_height: 5 vignette: > %\VignetteIndexEntry{User Interaction in WebGL} %\VignetteEngine{knitr::rmarkdown} %\VignetteDepends{crosstalk} --- ```{r setup, echo=FALSE, results="asis"} source("setup.R") setupKnitr(autoprint = FALSE) set.seed(123) ``` ## Introduction This document describes how to embed `rgl` scenes in HTML documents and use embedded Javascript to control a WebGL display in an HTML document. For more general information about `rgl`, see [rgl Overview](rgl.html). We assume that the HTML document is produced from R markdown source using `knitr` or `rmarkdown`. This format mixes text with Markdown markup with chunks of R code. There is a limited amount of discussion of other methods. There are two ways to embed an `rgl` scene in the document. The newest one is recommended: call `r linkfn("setupKnitr")` with argument `autoprint = TRUE` early in the document. This will set things up to be quite similar to the way standard 2D graphics are included by `knitr`, i.e. it will detect the fact that you've drawn something, and just include it automatically. If `autoprint = FALSE` is used or no call is made to `setupKnitr()`, an explicit call to `r linkfn("rglwidget")` will produce a "widget" which can be embedded into your document by printing it. This document uses that method. Older methods (e.g. `writeWebGL` or various hooks) that were used before `rgl` version 0.102.0 are no longer supported. ## Browser support Most browsers now support WebGL, but in some browsers it may be disabled by default. See https://get.webgl.org for help on a number of different browsers. ## Examples We start with a simple plot of the iris data. We insert a code chunk and call the `r linkfn("rglwidget")` function with optional argument `elementId`. This allows later Javascript code to refer to the image. We also save the object ids from the plot, so that they can be manipulated later. (The first example in [Controls](#controls) uses tags instead of saving the ids.) ```{r elementId} library(rgl) plotids <- with(iris, plot3d(Sepal.Length, Sepal.Width, Petal.Length, type="s", col=as.numeric(Species))) rglwidget(elementId = "plot3drgl") ``` Next we insert a button to toggle the display of the data. ```{r} toggleWidget(sceneId = "plot3drgl", ids = plotids["data"], label = "Data") ``` The `sceneId` is the same as the `elementId` we used in `rglwidget()`, the `ids` are the object ids of the objects that we'd like to toggle, and the `label` is the label shown on the button. To find the names in the `plotids` variable, apply `names()` or `unclass()`: ```{r} names(plotids) unclass(plotids) ``` ## Using `magrittr` or base pipes It can be error-prone to set the `elementId` in the `rglwidget()` to match the `sceneId` in the `toggleWidget()` (or `playwidget()`, described below). In the usual case where both are intended to appear together, [`magrittr`](https://CRAN.R-project.org/package=magrittr)-style pipes can be used quite flexibly: the first argument of the control widget accepts the result of `rglwidget()` (or other control widgets), and the `controllers` argument of `rglwidget()` accepts control widgets. In R 4.1.0, the new base pipe operator `|>` should be usable in the same way. For example, ```{r Pipes} rglwidget() %>% toggleWidget(ids = plotids["data"], label = "Data") ``` If you have R 4.1.0 or greater, this should do the same: ```{r eval=FALSE} rglwidget() |> toggleWidget(ids = plotids["data"], label = "Data") ``` You can swap the order of button and scene; use the `magrittr` dot (or the `=>` syntax in base pipes) to pass the `toggleWidget` to `rglwidget` in the `controllers` argument: ```{r "Control before widget"} toggleWidget(NA, ids = plotids["data"], label = "Data") %>% rglwidget(controllers = .) ``` or using R 4.1.0 or later, ```{r eval=FALSE} toggleWidget(NA, ids = plotids["data"], label = "Data") |> w => rglwidget(controllers = w) ``` ## Controls We have seen how to change the contents of the plot using `r indexfns("toggleWidget")`. We can do more elaborate displays. For example, we can redo the previous plot, but with the three species as separate "spheres" objects and buttons to toggle them: ```{r "Toggle subsets"} clear3d() # Remove the earlier display with(subset(iris, Species == "setosa"), spheres3d(Sepal.Length, Sepal.Width, Petal.Length, col=as.numeric(Species), radius = 0.211, tag = "setosa")) with(subset(iris, Species == "versicolor"), spheres3d(Sepal.Length, Sepal.Width, Petal.Length, col=as.numeric(Species), radius = 0.211, tag = "versicolor")) with(subset(iris, Species == "virginica"), spheres3d(Sepal.Length, Sepal.Width, Petal.Length, col=as.numeric(Species), radius = 0.211, tag = "virginica")) aspect3d(1,1,1) decorate3d(tag = "axes") rglwidget() %>% toggleWidget(tags = "setosa") %>% toggleWidget(tags = "versicolor") %>% toggleWidget(tags = "virginica") %>% toggleWidget(tags = "axes") %>% asRow(last = 4) ``` Since we skipped the `label` argument, the buttons are labelled with the values of the tags. The `asRow` function is discussed `r linkfn("asRow", "below")`. `toggleWidget()` is actually a convenient wrapper for two functions: `r indexfns("playwidget")` and `r indexfns("subsetControl")`. `playwidget()` adds the button to the web page (and can also add sliders, do animations, etc.), while `subsetControl()` chooses a subset of objects to display. ### `subsetControl` For a more general example, we could use a slider to select several subsets of the data in the iris display. For example, ```{r Slider} rglwidget() %>% playwidget(start = 0, stop = 3, interval = 1, subsetControl(1, subsets = list( Setosa = tagged3d("setosa"), Versicolor = tagged3d("versicolor"), Virginica = tagged3d("virginica"), All = tagged3d(c("setosa", "versicolor", "virginica")) ))) ``` There are several other "control" functions. ### `par3dinterpControl` `r indexfns("par3dinterpControl")` approximates the result of `r linkfn("par3dinterp")`. For example, the following code (similar to the `r linkfn("play3d")` example) rotates the scene in a complex way. ```{r "par3dinterpControl()"} M <- r3dDefaults$userMatrix fn <- par3dinterp(time = (0:2)*0.75, userMatrix = list(M, rotate3d(M, pi/2, 1, 0, 0), rotate3d(M, pi/2, 0, 1, 0)) ) rglwidget() %>% playwidget(par3dinterpControl(fn, 0, 3, steps=15), step = 0.01, loop = TRUE, rate = 0.5) ``` Some things to note: The generated Javascript slider has 300 increments, so that motion appears smooth. However, storing 300 `userMatrix` values would take up a lot of space, so we use interpolation in the Javascript code. However, the Javascript code can only do linear interpolation, not the more complex spline-based SO(3) interpolation done by `r linkfn("par3dinterp")`. Because of this, we need to output 15 steps from `r linkfn("par3dinterpControl")` so that the distortions of linear interpolation are not visible. ### `propertyControl` `r indexfns("propertyControl")` is a more general function to set the value of properties of the scene. Currently most properties are supported, but use does require knowledge of the internal implementation. ### `clipplaneControl` `r indexfns("clipplaneControl")` allows the user to control the location of a clipping plane by moving a slider. ### `vertexControl` Less general than `r linkfn("propertyControl")` is `r indexfns("vertexControl")`. This function sets attributes of individual vertices in a scene. For example, to set the x-coordinate of the closest point in the setosa group, and modify its colour from black to white, ```{r "vertexControl()"} setosavals <- subset(iris, Species == "setosa") which <- which.min(setosavals$Sepal.Width) init <- setosavals$Sepal.Length[which] rglwidget() %>% playwidget( vertexControl(values = matrix(c(init, 0, 0, 0, 8, 1, 1, 1), nrow = 2, byrow = TRUE), attributes = c("x", "red", "green", "blue"), vertices = which, tag = "setosa"), step = 0.01) ``` ### `ageControl` A related function is `r indexfns("ageControl")`, though it uses a very different specification of the attributes. It is used when the slider controls the "age" of the scene, and attributes of vertices change with their age. To illustrate we will show a point moving along a curve. We give two `ageControl` calls in a list; the first one controls the colour of the trail, the second controls the position of the point: ```{r "ageControl()"} time <- 0:500 xyz <- cbind(cos(time/20), sin(time/10), time) lineid <- plot3d(xyz, type="l", col = "black")["data"] sphereid <- spheres3d(xyz[1, , drop=FALSE], radius = 8, col = "red") rglwidget() %>% playwidget(list( ageControl(births = time, ages = c(0, 0, 50), colors = c("gray", "red", "gray"), objids = lineid), ageControl(births = 0, ages = time, vertices = xyz, objids = sphereid)), start = 0, stop = max(time) + 20, rate = 50, components = c("Reverse", "Play", "Slower", "Faster", "Reset", "Slider", "Label"), loop = TRUE) ``` ### `rglMouse` While not exactly a control in the sense of the other functions in this section, the `r indexfns("rglMouse")` function is used to add an HTML control to a display to allow the user to select the mouse mode. For example, the display below initially allows selection of particular points, but the mouse mode may be changed to let the user rotate the display for a another view of the scene. ```{r crosstalk,eval = requireNamespace("crosstalk", quietly=TRUE)} # This example requires the crosstalk package # We skip it if crosstalk is not available. ids <- with(iris, plot3d(Sepal.Length, Sepal.Width, Petal.Length, type="s", col=as.numeric(Species))) par3d(mouseMode = "selecting") rglwidget(shared = rglShared(ids["data"])) %>% rglMouse() ``` The `rglShared()` call used here is described `r linkfn("rglShared", "below")`. ## Layout of the display Many `rgl` displays will contain several elements: one or more `rgl` scenes and controls. Internally `rgl` uses the `combineWidgets` function from the [`manipulateWidget`](https://github.com/rte-antares-rpackage/manipulateWidget) package. The `rgl` package provides 3 convenience functions for arranging displays. We have already met the first: the `magrittr` pipe, `%>%`. When the display is constructed as a single object using pipes, the objects in the pipeline will be arranged in a single column. The second convenience function is `r indexfns("asRow")`. This takes as input a list of objects or a `combineWidgets` object (perhaps the result of a pipe), and rearranges (some of) them into a horizontal row. As in the `r linkfn("toggleWidget", "toggleWidget example")`, the `last` argument can be used to limit the actions of `asRow` to the specified number of components. (If `last = 0`, all objects are stacked: this can be useful if some of them are not from the `rgl` package, so piping doesn't work for them.) Finally, `r indexfns("getWidgetId")` can be used to extract the HTML element ID from an HTML widget. This is useful when combining widgets that are not all elements of the same pipe, as in the `crosstalk` example below. If these convenience functions are not sufficient, you can call `r linkfn("combineWidgets", text = "manipulateWidget::combineWidgets", pkg = "manipulateWidget")` or other functions from `manipulateWidget` for more flexibility in the display arrangements. ## Integration with `crosstalk` The [`crosstalk`](https://rstudio.github.io/crosstalk/) package allows widgets to communicate with each other. Currently it supports selection and filtering of observations. `rgl` can send, receive and display these messages. An `rgl` display may have several subscenes, each displaying different datasets. Each object in the scene is potentially a shared dataset in the `crosstalk` sense. The linking depends on the `r indexfns("rglShared")` function. Calling `rglShared(id)`, where `id` is the `rgl` id value for an object in the current scene, creates a shared data object containing the coordinates of the vertices of the `rgl` object. This object is passed to `r linkfn("rglwidget")` in the `shared` argument. It can also be passed to other widgets that accept shared data, linking the two displays. If a shared data object has been created in some other way, it can be linked to a particular `rgl` `id` value by copying its `key` and `group` properties as shown in the example below. ```{r "rglShared()",eval=requireNamespace("crosstalk", quietly = TRUE)} # This example requires the crosstalk package. # We skip it if crosstalk is not available. library(crosstalk) sd <- SharedData$new(mtcars) ids <- plot3d(sd$origData(), col = mtcars$cyl, type = "s") # Copy the key and group from existing shared data rglsd <- rglShared(ids["data"], key = sd$key(), group = sd$groupName()) rglwidget(shared = rglsd) %>% asRow("Mouse mode: ", rglMouse(getWidgetId(.)), "Subset: ", filter_checkbox("cylinderselector", "Cylinders", sd, ~ cyl, inline = TRUE), last = 4, colsize = c(1,2,1,2), height = 60) ``` If multiple objects in the `rgl` scene need to be considered as shared data, you can pass the results of several `rglShared()` calls in a list, i.e. `rglwidget(shared = )`. The key values will be assumed to be shared across datasets; if this is not wanted, use a prefix or some other means to make sure they differ between objects. If the same `rgl` id is used in more than one `rglShared()` object, it will respond to messages from all of them. This may lead to undesirable behaviour as one message cancels the previous one. ## Low level controls We repeat the initial plot from this document: ```{r plot3d2} plotids <- with(iris, plot3d(Sepal.Length, Sepal.Width, Petal.Length, type="s", col=as.numeric(Species))) subid <- currentSubscene3d() rglwidget(elementId="plot3drgl2") ``` We might like a button on the web page to cause a change to the display, e.g. a rotation of the plot. First we add buttons, with the "onclick" event set to a function described below: which produces these buttons: We stored the subscene number that is currently active in `subid` in the code chunk above, and use it as `r rinline("subid")` in the script below. `knitr` substitutes the value when it processes the document. The `rotate()` function uses the Javascript function `document.getElementById` to retrieve the `
` component of the web page containing the scene. It will have a component named `rglinstance` which contains information about the scene that we can modify: If we had used `webGL=TRUE` in the chunk header, the `knitr` WebGL support would create a global object with a name of the form `rgl`. For example, if the code chunk was named `plot3d2`, the object would be called `plot3d2rgl`, and this code would work: ## Index The following functions are described in this document:
```{r echo=FALSE, results="asis"} writeIndex(cols = 5) ``` rgl/inst/doc/rgl.html0000644000176200001440000454551715026603600014255 0ustar liggesusers rgl Overview

rgl Overview

Duncan Murdoch

June 24, 2025

Introduction

The rgl package is used to produce interactive 3-D plots. It contains high-level graphics commands modelled loosely after classic R graphics, but working in three dimensions. It also contains low level structure inspired by (but incompatible with) the grid package.

This document gives an overview. See the help pages for details.

For installation instructions, see the README file in the top level directory of the source tarball rgl_1.3.24.tar.gz (or a later version).

About this document

This document was written in R Markdown, using the knitr package for production. It corresponds to rgl version 1.3.24.

Most of the highlighted function names are HTML links. The internal links should work in any browser; the links to help topics should work if you view the vignette from within the R help system.

The document includes WebGL figures. To view these, you must have Javascript and WebGL enabled in your browser. Some older browsers may not support this – see https://get.webgl.org for tests and links to a discussion.

Basics and High Level Functions

The plot3d function plots points within an RGL window. It is similar to the classic plot function, but works in 3 dimensions.

For example

with(iris, plot3d(Sepal.Length, Sepal.Width, Petal.Length, 
                  type="s", col=as.numeric(Species)))

can be used to plot three columns of the iris data. Allowed plot types include "p", "l", "h", "s", meaning points, lines, segments from z=0, and spheres. There’s a lot of flexibility in specifying the coordinates; the xyz.coords function from the grDevices package is used for this.

You can use your mouse to manipulate the plot. The default is that if you click and hold with the left mouse button, you can rotate the plot by dragging it. The right mouse button is used to resize it, and the middle button changes the perspective in the point of view.

If you call plot3d again, it will overwrite the current plot. To open a new graphics window, use open3d.

The other high level function is persp3d to draw surfaces. It is similar to the classic persp function, but with greater flexibility. First, any of x, y or z can be specified using matrices, not just z. This allows parametric surfaces to be plotted. An even simpler specification is possible: x may be a function, in which case persp3d will work out the grid itself. See ?persp3d.function for details. For example, the MASS package estimates Gamma parameters using maximum likelihood in a ?MASS::fitdistr example. Here we show the log likelihood surface.

# This example requires the MASS package
library(MASS)
# from the fitdistr example
set.seed(123)
x <- rgamma(100, shape = 5, rate = 0.1)
fit <- fitdistr(x, dgamma, list(shape = 1, rate = 0.1), lower = 0.001)
loglik <- function(shape, rate) sum(dgamma(x, shape=shape, rate=rate, 
                                           log=TRUE))
loglik <- Vectorize(loglik)
xlim <- fit$estimate[1]+4*fit$sd[1]*c(-1,1)
ylim <- fit$estimate[2]+4*fit$sd[2]*c(-1,1)

mfrow3d(1, 2, sharedMouse = TRUE)
persp3d(loglik, 
        xlim = xlim, ylim = ylim,
        n = 30)
zlim <- fit$loglik + c(-qchisq(0.99, 2)/2, 0)
next3d()
persp3d(loglik, 
        xlim = xlim, ylim = ylim, zlim = zlim,
        n = 30)

On the left, the whole surface over a range of the parameters; on the right, only the parts of the surface with log likelihood values near the maximum.

Note: this example used the knitr hook functions (see setupKnitr) to insert the scene into this vignette; the previous example used the rglwidget function. We generally recommend the newer rglwidget approach.

Note that both plot3d and persp3d are generic functions, with the following methods defined:

methods(plot3d)
##  [1] plot3d.ashape3d*      plot3d.default*       plot3d.deldir*       
##  [4] plot3d.formula*       plot3d.function*      plot3d.lm*           
##  [7] plot3d.mesh3d*        plot3d.rglWebGL*      plot3d.rglbackground*
## [10] plot3d.rglbboxdeco*   plot3d.rglobject*     plot3d.rglscene*     
## [13] plot3d.rglsubscene*   plot3d.tri*           plot3d.triSht*       
## see '?methods' for accessing help and source code
methods(persp3d)
## [1] persp3d.ashape3d* persp3d.default*  persp3d.deldir*   persp3d.formula* 
## [5] persp3d.function* persp3d.tri*      persp3d.triSht*  
## see '?methods' for accessing help and source code

Adding Graphical Elements

Primitive shapes

Just as we have points and lines in classic graphics, there are a number of low level functions in rgl to add graphical elements to the currently active plot. The “primitive” shapes are those that are native to OpenGL:

Function Description
points3d: adds points
lines3d: adds lines
segments3d: adds line segments
triangles3d: adds triangles
quads3d: adds quadrilaterals

Each of the above functions takes arguments x, y and z, again using xyz.coords for flexibility. They group successive entries as necessary. For example, the triangles3d function takes each successive triple of points as the vertices of a triangle.

You can use these functions to annotate the current graph, or to construct a figure from scratch.

Constructed shapes

rgl also has a number of objects which it constructs from the primitives.

Function Description
text3d, texts3d: adds text
abclines3d: adds straight lines to plot (like abline)
arc3d: adds spherical arcs or spirals to plot
planes3d: adds planes to plot
clipplanes3d: add clipping planes to plot
sprites3d, particles3d: add sprites (fixed shapes or images) to plot
spheres3d: adds spheres
surface3d, terrain3d: a surface (as used in persp3d)
drape3d: drapes lines on a surface or object(s)
shadow3d: projects mesh onto a surface
arrow3d: add an arrow to a scene
pch3d: draw base-style plotting symbols
plotmath3d: used by text3d for math text

Axes and other “decorations”

The following low-level functions control the look of the graph:

Function Description
axes3d, axis3d: add axes to plot
box3d, bbox3d: add box around plot
title3d: add title to plot
mtext3d: add marginal text to plot
decorate3d: add multiple “decorations” (scales, etc.) to plot
aspect3d: set the aspect ratios for the plot
bg3d, bgplot3d: set the background of the scene
show2d: show a 2D plot or image in a 3D scene
legend3d: set a legend for the scene
grid3d: add a reference grid to a graph
thigmophobe3d: choose label positions to avoid overlap
setAxisCallbacks: set user-defined axis annotations

For example, to plot three random triangles, one could use

triangles3d(cbind(x=rnorm(9), y=rnorm(9), z=rnorm(9)), col = "green")
decorate3d()
bg3d("lightgray")
aspect3d(1,1,1)

Besides the *3d functions mentioned above, there are deprecated functions rgl.abclines, rgl.bbox, rgl.bg, rgl.clipplanes, rgl.lines, rgl.linestrips, rgl.planes, rgl.points, rgl.primitive, rgl.quads, rgl.setAxisCallback, rgl.spheres, rgl.sprites, rgl.surface, rgl.texts, rgl.triangles. You should avoid using all of these functions, which do not work properly with the *3d functions and will soon be removed from rgl. See the ?r3d help topic for details.

The function rgl.getAxisCallback provides low-level support for setAxisCallbacks.

Controlling the Look of the Scene

Camera angle

By default when you open a new plot with open3d:

  • The x axis goes from left to right.
  • The y axis goes from near the camera to far away.
  • The z axis goes from down to up.

You can change the camera angle simply by dragging the picture with the mouse.

To set the camera angle programmatically, use view3d. This uses polar coordinates:

  • theta sets the rotation around the vertical axis, in degrees.
  • phi sets the “vertical” rotation around the horizontal axis, from -90 to 90 degrees.

The default angle is roughly theta = 0, phi = -70. Starting from this position:

  • As you increase theta, the graph will spin anticlockwise from your point of view.
  • As you increase phi to 0, you start to look down at the scene from the top. If you increase phi above 0, you continue over and start to see the graph from the “back” (and upside down).

You can also use observer3d to change the camera location using x,y,z coordinates. In particular, increasing the z coordinate lets you zoom out, and decreasing it zooms you in.

One useful approach is to use the mouse to find a nice viewing angle. You can then save it using par3d("userMatrix") and restore the same view later:

myview <- par3d("userMatrix")
# ... later ...
par3d(userMatrix = myview)

Lighting

In most scenes, objects are “lit”, meaning that their appearance depends on their position and orientation relative to lights in the scene. The lights themselves don’t normally show up, but their effect on the objects does.

Use the light3d function to specify the position and characteristics of a light. Lights may be infinitely distant, or may be embedded within the scene. Their characteristics include ambient, diffuse, and specular components, all defaulting to white. The ambient component appears the same from any direction. The diffuse component depends on the angle between the surface and the light, while the specular component also takes the viewer’s position into account.

The deprecated rgl.light function should no longer be used; use light3d instead.

Materials

The mental model used in rgl is that the objects being shown in scenes are physical objects in space, with material properties that affect how light reflects from them (or is emitted by them). These are mainly controlled by the material3d function, or by arguments to other functions that are passed to it.

The material properties that are recognized in calls to material3d are described in detail in the ?material3d help page, and listed in the rgl.material.names variable. All of them can be set except the ones in rgl.material.readonly. Here we give an overview.

Property Default Meaning
color white vector of surface colors to apply to successive vertices for diffuse light
alpha 1 transparency: 0 is invisible, 1 is opaque
lit TRUE whether lighting calculations should be done
ambient black color in ambient light
specular white color in specular light
emission black color emitted by the surface
shininess 50 controls the specular lighting: high values look shiny
smooth TRUE whether shading should be interpolated between vertices
texture NULL optional path to a “texture” bitmap to be displayed on the surface
front, back fill should polygons be filled, or outlined?
size 3 size of points in pixels
lwd 1 width of lines in pixels

Other properties include “texmipmap”, “texmagfilter”, “texminfilter”, “texenvmap”, “fog”, “point_antialias”, “line_antialias”, “depth_mask”, “depth_test”, “polygon_offset”, “margin”, “floating”, “tag” and “blend”; see the help page for details.

There is also a deprecated rgl.material function that works at a lower level; users should avoid it.

Textures

As described in the previous section, one of the material properties is texture, the name of a bitmap file (in .png format) containing an image to be displayed on the surface. This section gives more details about textures.

In OpenGL, each vertex in a polygon may be associated with a particular location in the bitmap. The interior of the polygon interpolates within the bitmap. There are two conventions in rgl functions for specifying these coordinates.

Functions which specify primitives (triangles3d, etc.) accept an optional matrix argument texcoords which gives s (horizontal) and t (vertical) locations within the bitmap in columns with one row per vertex. The coordinates are (0,0) for the lower left, and (1,1) for the upper right. If values outside this range are given, the image repeats, i.e. (1.1, 1.2) would specify the same point in the image as (0.1, 0.2).

Other functions such as surface3d that take matrices for each vertex coordinate accept texture coordinates as matrices as well, in arguments texture_s and texture_t.

For example, the following code displays four copies of a 2D plot on a quad, because the texture coordinates run from 0 to 2 in both s and t:

filename <- tempfile(fileext = ".png")
png(filename = filename)
plot(rnorm(1000), rnorm(1000))
safe.dev.off()
## quartz_off_screen 
##                 2
open3d()
## null 
##   59
xyz <- cbind(c(0,1,1,0), 0, c(0,0,1,1))
quads3d(xyz, texture = filename, texcoords = xyz[,c(1, 3)]*2, 
        col = "white", specular = "black")

Some other notes:

  • The color in quads3d() above was specified to be white. By default, the colors in the bitmap will modify the color of the surface. If col is black (a common default), you won’t see anything, so a warning may be issued.
  • You usually don’t want specular reflections (which show up as glare). Setting specular to black prevents those.
  • The material property "texmode" allows texture colors to be used differently. The default is "modulate", where the texture values combine multiplicatively with the underlying values.
  • Another aspect of how the bitmap is handled is controlled by the material property "textype". The default is "rgb", which takes the red-green-blue colors from the bitmap and uses them to modify the corresponding colors in the polygon.
  • Other possibilities for "textype" and "texmode" are described in the material3d help page.
  • The other "tex*" material properties control how the interpolation within the image is done.
  • Modern OpenGL supports 1- and 3-dimensional textures; these are not currently supported in rgl.

Fonts

rgl uses the same ideas as base graphics for drawing text: there are font families named "sans", "serif", and "mono" for drawing text of those types. In rgl, the "symbol" family is not supported.

New font families can be defined using the low-level function rglFonts, or more simply using the higher level function rglExtrafonts. The latter function requires the extrafont package to be installed.

par3d: Miscellaneous graphical parameters

The par3d function, modelled after the classic graphics par function, sets or reads a variety of different rgl internal parameters, listed in the rgl.par3d.names variable. All of them can be set except the ones in rgl.par3d.readonly. Some parameters are completely read-only; others are fixed at the time the window is opened, and others may be changed at any time.

Name Changeable? Description
antialias fixed Amount of hardware antialiasing
cex Default size for text
family Device-independent font family name; see ?text3d
font Integer font number
useFreeType Should FreeType fonts be used if available?
fontname read-only System-dependent font name set by rglFonts
FOV Field of view, in degrees. Zero means isometric perspective
ignoreExtent Should rgl ignore the size of new objects when computing the bounding box?
skipRedraw Should rgl suppress updates to the display?
maxClipPlanes read-only How many clip planes can be defined?
modelMatrix read-only The OpenGL ModelView matrix; partly set by view3d
projMatrix read-only The OpenGL Projection matrix
bbox read-only Current bounding-box of the scene
viewport Dimensions in pixels of the scene within the window
windowRect Dimensions in pixels of the window on the whole screen
listeners Which subscenes respond to mouse actions in the current one
mouseMode What the mouse buttons do. See “mouseMode”
observer read-only The position of the observer; set by observer3d
scale Rescaling for each coordinate; see aspect3d
zoom Magnification of the scene

The deprecated rgl.viewpoint function should not be used.

Default settings

The r3dDefaults list and the getr3dDefaults function control defaults in new windows opened by open3d.
The function looks for the variable in the user’s global environment, and if not found there, finds the one in the rgl namespace. This allows the user to override the default settings for new windows.

Once found, the r3dDefaults list provides initial values for par3d parameters, as well as defaults for material3d and bg3d in components "material" and "bg" respectively.

Meshes: Constructing Shapes

rgl includes a number of functions to construct and display various solid shapes. These generate objects of class "shape3d", "mesh3d" or "shapelist3d". The details of the classes are described below. We start with functions to generate them.

Specific solids

These functions generate specific shapes. Optional arguments allow attributes such as color or transformations to be specified.

Function Description
tetrahedron3d, cube3d, octahedron3d, dodecahedron3d, icosahedron3d: Platonic solids
cuboctahedron3d, oh3d: other solids
cols <- rainbow(7)
layout3d(matrix(1:16, 4,4), heights=c(1,3,1,3))
text3d(0,0,0,"tetrahedron3d"); next3d()
shade3d(tetrahedron3d(col=cols[1])); next3d()
text3d(0,0,0,"cube3d"); next3d()
shade3d(cube3d(col=cols[2])); next3d()
text3d(0,0,0,"octahedron3d"); next3d()
shade3d(octahedron3d(col=cols[3])); next3d()
text3d(0,0,0,"dodecahedron3d"); next3d()
shade3d(dodecahedron3d(col=cols[4])); next3d()
text3d(0,0,0,"icosahedron3d"); next3d()
shade3d(icosahedron3d(col=cols[5])); next3d()
text3d(0,0,0,"cuboctahedron3d"); next3d()
shade3d(cuboctahedron3d(col=cols[6])); next3d()
text3d(0,0,0,"oh3d"); next3d()
shade3d(oh3d(col=cols[7]))

A very large collection of polyhedra is contained in the Rpolyhedra package.

Generating new shapes

These functions generate new shapes:

Function Description
cylinder3d: generate a tube or cylinder
polygon3d: generate a flat polygon by triangulation
extrude3d: generate an “extrusion” of a polygon
turn3d: generate a solid of rotation
ellipse3d: generate an ellipsoid in various ways
mesh3d: generate a shape from indexed vertices
shapelist3d: generate a shape by combining other shapes
as.mesh3d: a generic function; see below

A related function is triangulate, which takes a two dimensional polygon and divides it up into triangles using the “ear-clipping” algorithm.

The generic function as.mesh3d is provided to allow data structures produced by other code to be converted to mesh structures. Currently the following classes are supported:

Class Package Description
deldir deldir Delaunay triangulations of irregular point clouds
triSht interp Also Delaunay triangulations
tri tripack Generalized Delaunay triangulations
ashape3d alphashape3d Alpha-shapes
rglId rgl rgl object identifiers

The checkDeldir function checks that a compatible version of the deldir package is installed.

The default as.mesh3d.default method is a simple way to construct a mesh from a matrix of vertices; it can use mergeVertices (which can also be used on its own) to merge repeated vertices within the matrix, allowing addNormals to be used to give a smooth appearance.

The as.tmesh3d generic is a variation that guarantees the resulting object will have no quad entries.

Functions tmesh3d, qmesh3d are now obsolete; use mesh3d instead.

The underlying class structure for shapes

"shape3d" is the basic abstract type. Objects of this class can be displayed by shade3d (which shades faces), wire3d (which draws edges), or dot3d (which draws points at each vertex.)

"mesh3d" is a descendant type. Objects of this type contain the following fields:

Field Meaning
vb A 4 by n matrix of vertices in homogeneous coordinates. Each column is a point.
ip (optional) A vector of vertex indices for points.
is (optional) A 2 by s matrix of vertex indices. Each column is a line segment.
it (optional) A 3 by t matrix of vertex indices. Each column is a triangle.
ib (optional) A 4 by q matrix of vertex indices. Each column is a quadrilateral.
material (optional) A list of material properties.
normals (optional) A matrix of the same shape as vb, containing normal vectors at each vertex.
texcoords (optional) A 2 by n matrix of texture coordinates corresponding to each vertex.
values (optional) A vector of length n holding values at each vertex
meshColor (optional) A text value indicating how colors and texture coordinates should be interpreted.
tags (optional) A vector added by some functions (e.g. clipMesh3d) to relate output parts to input parts.

Contouring and clipping shapes

These functions compute and plot contours of functions on surfaces, or clip objects along a contour of a function.

Function Description
contourLines3d: draw contour lines on surface
filledContour3d: fill between contours on surface
clipMesh3d: clip mesh object using curved boundary
clipObj3d: clip general object using curved boundary

Manipulating shapes

These functions manipulate and modify mesh objects:

Function Description
addNormals: add normal vectors to make a shape look smooth
subdivision3d: add extra vertices to make it look even smoother
merge: merge mesh objects
facing3d: subset of mesh facing “up”
getBoundary3d: get the boundary of a mesh object

The individual steps in subdivision3d are also available: deform.mesh3d, divide.mesh3d, normalize.mesh3d. These are mainly intended for internal use.

Multi-figure Layouts

rgl has several functions to support displaying multiple different “subscenes” in the same window. The high level functions are

Function Description
mfrow3d: Multiple figures (like par(“mfrow”)
layout3d: Multiple figures (like layout)
next3d: Move to the next figure (like plot.new or frame)
subsceneList: List all the subscenes in the current layout
clearSubsceneList: Clear the current list and revert to the previous one

There are also lower level functions.

Function Description
newSubscene3d: Create a new subscene, with fine control over what is inherited from the parent
currentSubscene3d: Report on the active subscene
subsceneInfo: Get information on current subscene
useSubscene3d: Make a different subscene active
addToSubscene3d, delFromSubscene3d: Add objects to a subscene, or delete them
gc3d: Do “garbage collection”: delete objects that are not displayed in any subscene

Documents with rgl Scenes

The rgl package can produce output that can be embedded in other documents. The recommended way to do this has changed several times over the years. We will start with the current recommendation, then list older methods.

Producing PDF output

While some PDF previewers support interactive 3D graphics, most don’t. To produce a screenshot of an rgl scene in an R Markdown document with PDF output, simply follow the directions given above. The auto-printing will detect PDF output and use snapshot3d to produce a PNG file to insert. (See below if you want to insert a different format of graphic.)

If you really need interactive output, see the writeASY function.

Manual insertion of plots

You may not want to use the setupKnitr(autoprint = TRUE) method described above. It is very new, and may still have bugs; you may have an older document and not want to edit it to work that way.

In this case, you can insert plots manually. Use setup code

```{r echo=FALSE, include=FALSE}
library(rgl)
setupKnitr()
```

and call rglwidget() at top level whenever you want to insert a plot.

There are a couple of other differences in default behaviour if you are not using autoprint:

  • By default, each code chunk continues the rgl scene from earlier chunks. You’ll need an explicit open3d call to get a clean window.

  • Also by default, the rgl window is not closed at the end of the chunk. This probably doesn’t matter, but you may find you run out of memory if your scenes are really big.

Older methods

The original way to insert an rgl scene in a document was to use the deprecated writeWebGL function to write HTML code to insert in a document. Later, Sweave and knitr hooks were added. These are no longer supported, and you should update old documents to use the newer methods. If you are reading documents that suggest using those methods, let the author know they need updating!

Utility Functions

User interaction

By default, rgl detects and handles mouse clicks within your scene, and uses these to control its appearance. You can find out the current handlers using the following code:

par3d("mouseMode")
##        none        left       right      middle       wheel 
##      "none" "trackball"      "zoom"       "fov"      "pull"

The labels c("left", "right", "middle") refer to the buttons on a three button mouse, or simulations of them on other mice. "wheel" refers to the mouse wheel, and "none" refers to actions that take place when the mouse is moved without pressing any button.

The button actions generally correspond to click and drag operations. Possible values for “mouseMode” for the mouse pointer or wheel are as follows:

Mode Description
"none" No action
"trackball" The mouse acts as a virtual trackball. Clicking and dragging rotates the scene
"xAxis", "yAxis", "zAxis" Like "trackball", but restricted to rotation about one axis
"polar" The mouse affects rotations by controlling polar coordinates directly
"selecting" The mouse is being used by the select3d function
"zoom" The mouse zooms the display
"fov" The mouse affects perspective by changing the field of view
"pull" Rotating the mouse wheel towards the user “pulls the scene closer”
"push" The same rotation “pushes the scene away”
"user" A user action set by setUserCallbacks, rgl.setMouseCallbacks, rgl.setWheelCallback. Use rgl.getMouseCallbacks and rgl.getWheelCallback to retrieve.

The following functions make use of the mouse for selection within a scene.

Function Description
identify3d: like the classic graphics identify function
select3d: returns a function that tests whether a coordinate was selected
selectpoints3d: selects from specific objects
hover3d: displays “hover” info about points

selectionFunction3d produces the selection function from information about the projection and mouse selection region; it is used internally in the functions above.

The deprecated rgl.select3d function is an obsolete version of select3d, and rgl.select is a low-level support function.

Animations

rgl has several functions that can be used to construct animations. These are based on functions that update the scene according to the current real-world time, and repeated calls to those. The functions are:

Function Description
play3d: Repeatedly call the update function
spin3d: Update the display by rotating at a constant rate
par3dinterp: Compute new values of some par3d parameters by interpolation over time

See the movie3d function for a way to output an animation to a file on disk.
Animations are not currently supported in the HTML written by rglwidget, though the playwidget function provides equivalent functionality.

Integration with TCL/TK

There are three functions in rgl that support control of an rgl scene using the TCL/TK framework.

Function Description
tkspin3d: Set up buttons in a window to control a scene
tkspinControl: Embed the control buttons in a separate TCL/TK frame
tkpar3dsave: Create a dialog to interactively save mouse actions

These functions were formerly contained (without the tk prefixes on their names) in the tkrgl package. That package is now deprecated.

Exporting and importing scenes

rgl contains several functions to write scenes to disk for use by other software, or to read them in.

In order from highest fidelity to lowest, the functions are:

Function Description
scene3d: Save a scene to an R variable, which can be saved and reloaded
rglwidget: Prints as HTML and Javascript to display a scene in a web browser. (See also User Interaction in WebGL.)
writeASY: Write files for Asymptote
writePLY: Write PLY files (commonly used in 3D printing)
readOBJ, writeOBJ: Read or write OBJ files (commonly used in 3D graphics)
readSTL, writeSTL: Read or write STL files (also common in 3D printing)
as.rglscene: Generic function, no methods in rgl

The rgl2gltf package can read or write GLTF and GLB files. It includes an as.rglscene method to convert GLTF objects to rgl scenes. The code in rgl’s Buffer R6 class is based on the GLTF format. It is used by rglwidget to make output webpages somewhat smaller than they were previously.

There are also functions to save snapshots or other recordings of a scene, without any 3D information being saved:

Function Description
snapshot3d: Save a PNG file bitmap of the scene
rgl.postscript: Save a Postscript, LaTeX, PDF, SVG or PGF vector rendering of the scene
movie3d: Save a series of bitmaps to be assembled into a movie
rgl.pixels: Obtain pixel-level information about the scene in an R variable
rgl.Sweave: Driver function for inserting a snapshot into a Sweave document.
hook_rgl, hook_webgl: knitr hook functions for inserting images into a document.
setupKnitr: Function to set up knitr hooks

The rgl.snapshot function is a low level version of snapshot3d(); it requires that the rgl display be onscreen and copies from there. snapshot3d() tries to use the webshot2 package so it will work even with no display. The functions rgl.Sweave.off, Sweave.snapshot are involved in Sweave processing and not normally called by users.

Default display

There are two ways in which rgl scenes are normally displayed within R. The older one is in a dedicated window. In Unix-alikes this is an X11 window; it is a native window in Microsoft Windows. On macOS, the XQuartz system (see https://www.xquartz.org) needs to be installed to support this.

To suppress this display, set options(rgl.useNULL = TRUE) before opening a new rgl window. See the help page for the rgl.useNULL function for how to set this before starting R.

The newer way to display a scene is by using WebGL in a browser window or in the Viewer pane in RStudio. To select this, set options(rgl.printRglwidget = TRUE). Each operation that would change the scene will return a value which triggers a new WebGL display when printed.

Working with WebGL scenes

You should use the following scheme for exporting a scene to a web page. There’s also an older scheme, which is no longer supported.

The recommended approach works with the htmlwidgets framework (see http://www.htmlwidgets.org/). In an R Markdown document in knitr, use the rglwidget function. (You can also use chunk option webgl=TRUE; we recommend the explicit use of rglwidget.) This approach also allows display of rgl scenes in RStudio. Besides rgl scenes, various controls for them can be displayed, and there are a few utility functions that can be useful:

Function Description
propertyControl: set individual properties
clipplaneControl: control a clipping plane
subsetControl: control which objects are displayed
ageControl: “age” vertices of an object
vertexControl: control properties of vertices
par3dinterpControl: WebGL control like par3dinterp
playwidget: display and automate controls
toggleWidget: display a button to toggle some items
%>%: magrittr pipe
figHeight, figWidth: Dimensions of figures in R Markdown document
rglShared: share data using crosstalk package
rglMouse: change mouse mode in RGL scene
asRow: arrange multiple objects in an HTML display
getWidgetId: get the elementId from a widget

These functions work with the above scheme in Shiny apps:

Function Description
sceneChange: used in Shiny for large scene changes
shinyGetPar3d, shinySetPar3d: get or set par3d values from Shiny
shinyResetBrush: reset the mouse brush in Shiny

The selectionFunction3d function is also likely to be involved in mouse interactions when using Shiny.

Some functions are mainly for internal use: elementId2Prefix, playwidgetOutput, renderPlaywidget, rglwidgetOutput, renderRglwidget, registerSceneChange. More details are given in the vignette User Interaction in WebGL. The functions lowlevel, highlevel, rglId are also for internal use, marking function results for automatic printing. Finally, the function setUserShaders allows you to use hand-written shaders in WebGL, and getShaders allows you to see what shader would be used.

Working with the scene

rgl maintains internal structures for all the scenes it displays. The following functions allow users to find information about them and manipulate them. In cases where there are both *3d and rgl.* versions of functions, most users should use the *3d version: the rgl.* functions are more primitive and are mainly intended for internal use.

Function Description
open3d: open a new window
close3d: close the current window
cur3d: id of the active device
set3d: set a particular device to be active
pop3d: delete objects from the scene
clear3d: delete all objects of certain classes
ids3d: ids, types and tags of current objects
tagged3d: find tags or objects with tags

Some of these functions have alternate names for back compatibility:
rgl.cur, rgl.ids, rgl.pop. Either name will work, but the *3d version is recommended for new code. Some have deprecated versions: rgl.clear, rgl.set. Those should not be called.

These functions are mainly intended for programming, and have no corresponding *3d counterparts:

Function Description
rgl.bringtotop: bring the current window to the top
rgl.dev.list: ids of all active devices
rgl.attrib, rgl.attrib.info, rgl.attrib.count: attributes of objects in the scene
rgl.projection: return information about the current projection
rgl.user2window, rgl.window2user: convert between coordinates in the current projection

The as.triangles3d generic function is intended to extract coordinates in a form suitable for passing to triangles3d. Currently a method is provided for rglId objects.

In addition to these, there are some deprecated functions which should not be called: rgl.init, rgl.open, rgl.close, rgl.quit.

Working with 3-D vectors

Most rgl functions work internally with “homogeneous” coordinates. In this system, 3-D points are represented with 4 coordinates, generally called (x, y, z, w). The corresponding Euclidean point is (x/w, y/w, z/w), if w is nonzero; zero values of w correspond to “points at infinity”. The advantage of this system is that affine transformations including translations and perspective shifts become linear transformations, with multiplication by a 4 by 4 matrix.

rgl has the following functions to work with homogeneous coordinates:

Function Description
asEuclidean, asHomogeneous: convert between homogeneous and Euclidean coordinates when x, y and z are columns
asEuclidean2, asHomogeneous2: convert when x, y and z are rows
rotate3d, scale3d, translate3d: apply a transformation
transform3d: apply a general transformation
rotationMatrix, scaleMatrix, translationMatrix: compute the transformation matrix
identityMatrix: return a 4 x 4 identity matrix
projectDown: a 3D to 2D projection down a vector

There is also a function GramSchmidt, mainly for internal use: it does a Gram-Schmidt orthogonalization of a 3x3 matrix, with some specializations for its use in cylinder3d.

Working with other packages

Sometimes it may be convenient to interactively rotate a scene to a particular view, then display it in lattice or base graphics. The rglToLattice and rglToBase functions support this.

For example, we first display the volcano data in rgl:

persp3d(volcano, col = "green")

This display is interactive, but we can reproduce the initial view using the lattice wireframe or base graphics persp functions:

# Only evaluated if the lattice & orientlib packages are installed
lattice::wireframe(volcano, col = "green", 
           screen = rglToLattice())

Volcano in latticegraphics.

angles <- rglToBase()
persp(volcano, col = "green", shade = TRUE,
      theta = angles$theta, phi = angles$phi)

Volcano in basegraphics.

Note that the orientlib package must be available for these functions to work.

Creating pkgdown websites

The “Using RGL in pkgdown web sites” vignette describes how to use rgl in a pkgdown web site. The utility function in_pkgdown_example can be used to detect that pkgdown is being used.

Working with testthat

The testthat package is widely used for unit tests in packages. Such tests are hard to write with rgl, because the output is visual and interactive rather than a simple value. The expect_known_scene, compare_proxy.mesh3d and all.equal.mesh3d functions help with this by removing system-dependent features of rgl output.

Working with Javascript

The WebGL displays created using rglwidget rely on a large body of Javascript code included in this package. To help in development of this code, the makeDependency function was written. It may be useful in other packages that include Javascript.

Other functions and objects

This section is for miscellaneous functions and objects that don’t fall in any of the other categories in this document.

The setGraphicsDelay function is designed to work around what appears to be a bug on macOS: if a standard plot window is opened too quickly after an rgl window, R can crash. This function inserts a one second delay when it appears to be needed.

The gltfTypes vector contains constants used in OpenGL and glTF.

Warning: Work in Progress!

This vignette is always a work in progress. Some aspects of the rgl package are not described, or do not have examples. There may even be functions that are missed completely, if the following list is not empty:

## [1] "in_pkgdown"      "rgl.incrementID" "safe.dev.off"    "textureSource"

Index of Functions

The following functions and constants are described in this document:

%>%   decorate3d   movie3d   rgl.getMouseCallbacks   shinyGetPar3d  
Buffer   deform.mesh3d   mtext3d   rgl.getWheelCallback   shinyResetBrush  
GramSchmidt   delFromSubscene3d   newSubscene3d   rgl.material.names   shinySetPar3d  
Sweave.snapshot   deldir   next3d   rgl.material.readonly   show2d  
abclines3d   divide.mesh3d   normalize.mesh3d   rgl.par3d.names   snapshot3d  
addNormals   dodecahedron3d   observer3d   rgl.par3d.readonly   spheres3d  
addToSubscene3d   dot3d   observer3d   rgl.pixels   spin3d  
ageControl   drape3d   octahedron3d   rgl.postscript   sprites3d  
all.equal.mesh3d   elementId2Prefix   oh3d   rgl.projection   subdivision3d  
arc3d   ellipse3d   open3d   rgl.select   subsceneInfo  
arrow3d   expect_known_scene   par3d   rgl.setMouseCallbacks   subsceneList  
as.mesh3d   extrude3d   par3dinterp   rgl.setWheelCallback   subsetControl  
as.mesh3d.default   facing3d   par3dinterpControl   rgl.snapshot   surface3d  
as.rglscene   figHeight   particles3d   rgl.useNULL   tagged3d  
as.tmesh3d   figWidth   pch3d   rgl.user2window   terrain3d  
as.triangles3d   filledContour3d   persp3d   rgl.window2user   tetrahedron3d  
asEuclidean   gc3d   pipe   rglExtrafonts   text3d  
asEuclidean2   getBoundary3d   planes3d   rglFonts   texts3d  
asHomogeneous   getShaders   play3d   rglId   thigmophobe3d  
asHomogeneous2   getWidgetId   playwidget   rglMouse   title3d  
asRow   getr3dDefaults   playwidgetOutput   rglShared   tkpar3dsave  
ashape3d   gltfTypes   plot3d   rglToBase   tkspin3d  
aspect3d   grid3d   plotmath3d   rglToLattice   tkspinControl  
axes3d   highlevel   points3d   rglwidget   tmesh3d  
axis3d   hook_rgl   polygon3d   rglwidgetOutput   toggleWidget  
bbox3d   hook_webgl   pop3d   rotate3d   transform3d  
bg3d   hover3d   projectDown   rotationMatrix   translate3d  
bgplot3d   icosahedron3d   propertyControl   scale3d   translationMatrix  
box3d   identify3d   qmesh3d   scaleMatrix   tri  
checkDeldir   identityMatrix   quads3d   scene3d   triSht  
clear3d   ids3d   r3dDefaults   sceneChange   triangles3d  
clearSubsceneList   in_pkgdown_example   readOBJ   segments3d   triangulate  
clipMesh3d   layout3d   readSTL   select3d   turn3d  
clipObj3d   legend3d   registerSceneChange   selectionFunction3d   useSubscene3d  
clipplaneControl   light3d   renderPlaywidget   selectpoints3d   vertexControl  
clipplanes3d   lines3d   renderRglwidget   set3d   view3d  
close3d   lowlevel   rgl.Sweave   setAxisCallbacks   view3d  
compare_proxy.mesh3d   makeDependency   rgl.Sweave.off   setGraphicsDelay   wire3d  
contourLines3d   material3d   rgl.attrib   setUserCallbacks   writeASY  
cube3d   merge.mesh3d   rgl.attrib.count   setUserShaders   writeOBJ  
cuboctahedron3d   mergeVertices   rgl.attrib.info   setupKnitr   writePLY  
cur3d   mesh3d   rgl.bringtotop   shade3d   writeSTL  
currentSubscene3d   mfrow3d   rgl.dev.list   shadow3d  
cylinder3d   mouseMode   rgl.getAxisCallback   shapelist3d  
rgl/inst/doc/deprecation.html0000644000176200001440000006655115026603570015764 0ustar liggesusers Deprecating the rgl.* interface

Deprecating the rgl.* interface

Duncan Murdoch

2025-06-24

Introduction

Since at least 2004, rgl has had two interfaces for many of the primitive functions: rgl.* and *3d. For example, to draw points you could use rgl.points() or points3d(). With the upcoming version 1.0.0 release of rgl, most of the duplication will be removed. The first step will be to deprecate a large number of rgl.* functions so they give warnings when they are called, and a few months later they will be removed from the package exports.

This document describes the differences and changes needed by users of the rgl.* interface.

Differences between the interfaces

Opening a window

The rgl.open() function has a single argument, useNULL. If set to TRUE, the NULL rgl device will be used. The par3d() settings will be set to their defaults.

The open3d() function has arguments

function(..., 
         params = getr3dDefaults(), 
         useNULL = rgl.useNULL(), 
         silent = FALSE )

and allows par3d() values to be specified, and uses the r3dDefaults variable to set default values for par3d(), material3d(), and bg3d(). Initially r3dDefaults is defined as

list(userMatrix = rotationMatrix(290*pi/180, 1, 0, 0),
     mouseMode = c("none", "trackball", "zoom", "fov", "pull"),
     FOV = 30,
     family = "sans",
     bg = list(color="white",
               fogtype = "none"),
     material = list(color="black", fog = TRUE)
)

Users can create their own default lists; e.g. to get the same result as rgl.open() would give, use

open3d(params = list())

or

r3dDefaults <- list()
open3d()

Material properties

The rgl.material() function has a large number of parameters. The pre-deprecation arguments were:

function(
  color        = "white",
  alpha        = 1.0,
  lit          = TRUE, 
  ambient      = "black",
  specular     = "white", 
  emission     = "black", 
  shininess    = 50.0, 
  smooth       = TRUE,
  texture      = NULL, 
  textype      = "rgb", 
  texmipmap    = FALSE, 
  texminfilter = "linear", 
  texmagfilter = "linear",
  texenvmap    = FALSE,
  front        = "filled", 
  back         = "filled",
  size         = 3.0,
  lwd          = 1.0, 
  fog          = TRUE,
  point_antialias = FALSE,
  line_antialias = FALSE,
  depth_mask   = TRUE,
  depth_test   = "less",
  polygon_offset = c(0.0, 0.0),
  margin = "",
  floating = FALSE,
  tag = "",
  blend = c("src_alpha", "one_minus_src_alpha"),
  col,
  ...
)

Thus a call like rgl.material(color = "black") will set the color to black, and will also set all of the other parameters to the default values listed above.

On the other hand, the arguments to material3d() are

function (..., id = NULL)  

Calling material3d(color = "black") will set the color to black and leave all other parameters unchanged.

Primitive shapes

The primitive shapes (points etc.) can be set using calls like rgl.points(x, y, z, color = "black") or points3d(x, y, z, color = "black").

The first difference is that rgl.* primitives will call rgl.material() to set the material properties: in this example color will be set to black, and all other parameters will be set to their defaults. The *3d versions of the primitives use material3d() to set material properties, so only those that were specified will be changed, and the original values will be restored afterwards.

The second difference is what happens if there is no window already open. The rgl.* functions will call rgl.open() (ignoring r3dDefaults), whereas the *3d functions will call open3d().

Why deprecate rgl.*?

Both of the systems worked, but they do not work together. For example, calling rgl.points() will have carry-on effects on later points3d() calls, whereas each points3d() call will just draw the points, it won’t affect future calls.

Users have found this confusing, and it makes their code hard to debug, and the rgl package hard to maintain. The *3d interface is more flexible, and more similar to the base graphics interface in R, so I’ve decided it will be the only one available going forward.

Some rgl.* functions are not deprecated

There will still be some rgl.* functions in the package. These are functions that are mainly intended for programming, such as rgl.attrib() and rgl.user2window(), and a few legacy functions like rgl.Sweave() supporting older approaches of using rgl.

In a few cases both function versions are identical (rgl.cur, rgl.ids, and rgl.pop are identical to cur3d, ids3d and pop3d respectively), and for those the rgl.* versions will be kept, but the documentation will concentrate on the *3d functions.

My package uses rgl.*. What do I need to do?

If your package is using rgl.* functions, the first step is to just make the substitutions suggested by the deprecation warning message. For example, if you use rgl.points(rnorm(10), rnorm(10), rnorm(10)) try using points3d(rnorm(10), rnorm(10), rnorm(10)) instead. In most cases this will give you what you want. In some cases more changes will be needed.

rgl.open and rgl.material

See above if you were using these.

Textures

The default color after rgl.open() was white, whereas with open3d() the default color is black, with a white background. Textures multiplicatively modify the color of the object, so after open3d(), a texture on an object will still appear black. Explicitly specifying color = "white" when a texture is used will fix this.

rgl.surface()

The arguments to rgl.surface() and surface3d() functions are different. The argument lists are

rgl.surface( x, z, y, 
             coords = 1:3,  ..., 
             normal_x = NULL, normal_y = NULL, normal_z = NULL,
             texture_s = NULL, texture_t = NULL)
surface3d(x, y = NULL, z = NULL,
          ...,
          normal_x = NULL, normal_y = NULL,
          normal_z = NULL,
          texture_s = NULL, texture_t=NULL)

Notice that the arguments are in a different order. Another difference is that rgl.surface() expects the surface to be defined in the y coordinate and viewed in the orientation produced by rgl.open(), not the one produced by open3d(). Up until very recently, surface3d() didn’t allow both x and z to be vectors.

The excellent rayshader package used the convention that the y argument held the surface, so the y direction should point up. Using view3d(theta = 45, phi = 45) (which it was already doing) gives a reasonable view.

Lists of material names and par3d properties

Many functions in rgl and other packages use ... to set material or par3d properties in a call, and for some, ... will contain other optional arguments. Some packages used the argument list of rgl.material() to identify the material property names. Going forward, packages should use the variables

rgl.material.names
rgl.material.readonly

These are character variables holding all the material property names. (rgl.material.names contains all names; rgl.material.readonly is the read-only subset of that list.) There are also variables

rgl.par3d.names
rgl.par3d.readonly

which give the same information for par3d.

Since these variables are recently added, you will need to add a dependence on rgl (>= 0.111.5) if you use them.

Others

If you have particular problems adapting other rgl.* to the *3d interface, please post them as issues on https://github.com/dmurdoch/rgl/issues . I’ll explain how to get what you want or fix things in rgl so you can do it.

rgl/inst/doc/demos.html0000644000176200001440002140115715026603570014574 0ustar liggesusers rgl Demos

rgl Demos

2025-06-24

Introduction

This vignette holds code that was previously included as “demos” in rgl. Some of the demos require R to be running; those remain available via demo(package = "rgl").

hist3d: 3D histogram using basic building blocks

##########
### 3D HIST EXAMPLE:
##########

################################################################################

##### Required functions 'binplot' and 'hist3d':

binplot.3d<-function(x,y,z,alpha=1,topcol="#ff0000",sidecol="#aaaaaa") {
  save <- par3d(skipRedraw=TRUE)
  on.exit(par3d(save))
    
  x1<-c(rep(c(x[1],x[2],x[2],x[1]),3),rep(x[1],4),rep(x[2],4))
  z1<-c(rep(0,4),rep(c(0,0,z,z),4))
  y1<-c(y[1],y[1],y[2],y[2],rep(y[1],4),rep(y[2],4),rep(c(y[1],y[2],y[2],y[1]),2))
  x2<-c(rep(c(x[1],x[1],x[2],x[2]),2),rep(c(x[1],x[2],rep(x[1],3),rep(x[2],3)),2))
  z2<-c(rep(c(0,z),4),rep(0,8),rep(z,8) )
  y2<-c(rep(y[1],4),rep(y[2],4),rep(c(rep(y[1],3),rep(y[2],3),y[1],y[2]),2) )
  quads3d(x1,z1,y1,col=rep(sidecol,each=4),alpha=alpha)
  quads3d(c(x[1],x[2],x[2],x[1]),rep(z,4),c(y[1],y[1],y[2],y[2]),
              col=rep(topcol,each=4),alpha=1) 
  segments3d(x2,z2,y2,col="#000000")
}

hist3d<-function(x,y=NULL,nclass="auto",alpha=1,col="#ff0000",scale=10) {
  save <- par3d(skipRedraw=TRUE)
  on.exit(par3d(save))
  xy <- xy.coords(x,y)
  x <- xy$x
  y <- xy$y
  n<-length(x)
  if (nclass == "auto") nclass<-ceiling(sqrt(nclass.Sturges(x)))
  breaks.x <- seq(min(x),max(x),length=(nclass+1))
  breaks.y <- seq(min(y),max(y),length=(nclass+1))
  z<-matrix(0,(nclass),(nclass))
  for (i in seq_len(nclass)) {
    for (j in seq_len(nclass)) {
      z[i, j] <- (1/n)*sum(x < breaks.x[i+1] & y < breaks.y[j+1] & 
                            x >= breaks.x[i] & y >= breaks.y[j])
      binplot.3d(c(breaks.x[i],breaks.x[i+1]),c(breaks.y[j],breaks.y[j+1]),
                 scale*z[i,j],alpha=alpha,topcol=col)
    }
  }
}
################################################################################

open3d()
#> null 
#>   16
bg3d(color="gray")
light3d(0, 0)

# Drawing a 'bin' for given coordinates:
binplot.3d(c(-0.5,0.5),c(4.5,5.5),2,alpha=0.6)

# Setting the viewpoint ('theta' and 'phi' have the same meaning as in persp):
view3d(theta=40,phi=40)
##### QUADS FORMING BIN

open3d()
#> null 
#>   17
# Defining transparency and colors:
alpha<-0.7; topcol<-"#ff0000"; sidecol<-"#aaaaaa"

# Setting up coordinates for the quads and adding them to the scene:
y<-x<-c(-1,1) ; z<-4; of<-0.3
x12<-c(x[1],x[2],x[2],x[1]); x11<-rep(x[1],4); x22<-rep(x[2],4)
z00<-rep(0,4); z0z<-c(0,0,z,z); zzz<-rep(z,4); y11<-rep(y[1],4)
y1122<-c(y[1],y[1],y[2],y[2]); y12<-c(y[1],y[2],y[2],y[1]); y22<-rep(y[2],4)

quads3d(c(x12,x12,x11-of,x12,x22+of,x12),
          c(z00-of,rep(z0z,4),zzz+of),
          c(y1122,y11-of,y12,y22+of,y12,y1122),
          col=rep(c(rep(sidecol,5),topcol),each=4),alpha=c(rep(alpha,5),1))

# Setting up coordinates for the border-lines of the quads and drawing them:
yl1<-c(y[1],y[2],y[1],y[2]); yl2<-c(y[1]-of,y[1]-of)
xl<-c(rep(x[1],8),rep(x[1]-of,8),rep(c(x[1],x[2]),8),rep(x[2],8),rep(x[2]+of,8))
zl<-c(0,z,0,z,z+of,z+of,-of,-of,0,0,z,z,0,z,0,z,rep(0,4),rep(z,4),rep(-of,4),
      rep(z+of,4),z+of,z+of,-of,-of,rep(c(0,z),4),0,0,z,z)
yl<-c(yl2,y[2]+of,y[2]+of,rep(c(y[1],y[2]),4),y[1],y[1],y[2],y[2],yl2,
      rep(y[2]+of,4),yl2,y[2],y[2],rep(y[1],4),y[2],y[2],yl1,yl2,y[2]+of,
      y[2]+of,y[1],y[1],y[2],y[2],yl1)

lines3d(xl,zl,yl,col="#000000")
view3d(theta=40,phi=40)
##### COMPLETE HISTOGRAM:

open3d()
#> null 
#>   18
# Setting the rng to a fixed value:
set.seed(1000)

# Drawing a 3d histogramm of 2500 normaly distributed observations:
hist3d(rnorm(2500),rnorm(2500),alpha=0.4,nclass=7,scale=30)
# Choosing a lightgrey background:
bg3d(col="#cccccc")
view3d(theta=40,phi=40)

bivar: Bivariate densities: kernel smoothing using surface3d and alpha-channel (requires MASS package)

# rgl demo: rgl-bivar.r
# author: Daniel Adler

rgl.demo.bivar <- function() {
  if (!requireNamespace("MASS", quietly = TRUE))
    stop("This demo requires MASS")
  
  # parameters:
  n<-50; ngrid<-40
  
  # generate samples:
  set.seed(31415)
  x<-rnorm(n); y<-rnorm(n)
  
  # estimate non-parameteric density surface via kernel smoothing
  denobj <- MASS::kde2d(x, y, n=ngrid)
  den.z <-denobj$z
  
  # generate parametric density surface of a bivariate normal distribution
  xgrid <- denobj$x
  ygrid <- denobj$y
  bi.z <- dnorm(xgrid)%*%t(dnorm(ygrid))
  
  # visualize:
  zscale<-20
  
  # New window
  open3d()
  
  # clear scene:
  clear3d("all")
  
  # setup env:
  bg3d(color="#887777")
  light3d()
  
  # Draws the simulated data as spheres on the baseline
  spheres3d(x,y,rep(0,n),radius=0.1,color="#CCCCFF")
  
  # Draws non-parametric density
  surface3d(xgrid,ygrid,den.z*zscale,color="#FF2222",alpha=0.5)
  
  # Draws parametric density
  surface3d(xgrid,ygrid,bi.z*zscale,color="#CCCCFF",front="lines") 
}

rgl.demo.bivar()

Abundance: Animal abundance, visualization of multi-dimension data using multiple techniques

# RGL-Demo: animal abundance
# Authors: Oleg Nenadic, Daniel Adler

rgl.demo.abundance <- function() {
  open3d()
  clear3d("all")               # remove all shapes, lights, bounding-box, and restore viewpoint
  
  # Setup environment:
  bg3d(col="#cccccc")     # setup background
  light3d()               # setup head-light
  
  # Importing animal data (created with wisp)
  terrain<-dget(system.file("demodata/region.dat",package="rgl"))
  pop<-dget(system.file("demodata/population.dat",package="rgl"))
  
  # Define colors for terrain
  zlim <- range(terrain)
  colorlut <- terrain.colors(82) 
  col1 <- colorlut[9*sqrt(3.6*(terrain-zlim[1])+2)]
  
  # Set color to (water-)blue for regions with zero 'altitude' 
  col1[terrain==0]<-"#0000FF"
  
  # Add terrain surface shape (i.e. population density):
  surface3d( 
      1:100,seq(1,60,length=100),terrain,
      col=col1,spec="#000000", ambient="#333333", back="lines"
  )
  
  # Define colors for simulated populations (males:blue, females:red):
  col2<-pop[,4]
  col2[col2==0]<-"#3333ff"
  col2[col2==1]<-"#ff3333"
  
  # Add simulated populations as sphere-set shape
  spheres3d(
    pop[,1],
    pop[,2],
    terrain[cbind( ceiling(pop[,1]),ceiling(pop[,2]*10/6) )]+0.5,
    radius=0.2*pop[,3], col=col2, alpha=(1-(pop[,5])/10 )
  )

}
rgl.demo.abundance()

lsystem: Plant modelling using a turtle and L-system

# demo: lsystem.r
# author: Daniel Adler

#
# geometry 
#

deg2rad <- function( degree ) {
  return( degree*pi/180 )
}

rotZ.m3x3 <- function( degree ) {
  kc <- cos(deg2rad(degree))
  ks <- sin(deg2rad(degree))
  return( 
    matrix(
      c(
        kc, -ks,   0, 
        ks,  kc,   0,
         0,   0,   1
      ),ncol=3,byrow=TRUE
    ) 
  )
}

rotX.m3x3 <- function( degree ) {
  kc <- cos(deg2rad(degree))
  ks <- sin(deg2rad(degree))
  return(
    matrix(
      c(
         1,   0,   0,
         0,  kc, -ks,
         0,  ks,  kc
      ),ncol=3,byrow=TRUE
    )
  )
}

rotY.m3x3 <- function( degree ) {
  kc <- cos(deg2rad(degree))
  ks <- sin(deg2rad(degree))
  return(
    matrix(
      c(
        kc,   0,   ks,
         0,   1,    0,
       -ks,   0,   kc
      ),ncol=3,byrow=TRUE
    )
  )
}

rotZ <- function( v, degree ) {
  return( rotZ.m3x3(degree) %*% v)
}

rotX <- function( v, degree ) {
  return( rotX.m3x3(degree) %*% v)
}

rotY <- function( v, degree ) {
  return( rotY.m3x3(degree) %*% v)
}


#
# turtle graphics, rgl implementation:
#

turtle.init <- function(pos=c(0,0,0),head=0,pitch=90,roll=0,level=0) {
  clear3d("all")
  bg3d(color="gray")
  light3d()
  return( list(pos=pos,head=head,pitch=pitch,roll=roll,level=level) )
}


turtle.move <- function(turtle, steps, color) {
  
  rm <- rotX.m3x3(turtle$pitch) %*% rotY.m3x3(turtle$head) %*% rotZ.m3x3(turtle$roll)
  
  from <- as.vector( turtle$pos )  
  dir  <- rm %*% c(0,0,-1)
  to   <- from + dir * steps
    
  x <- c( from[1], to[1] )
  y <- c( from[2], to[2] )
  z <- c( from[3], to[3] )
  lines3d(x,y,z,col=color,size=1.5,alpha=0.5)
  turtle$pos <- to
  return(turtle)
}

turtle.pitch <- function(turtle, degree) {
  turtle$pitch <- turtle$pitch + degree
  return(turtle)
}

turtle.head <- function(turtle, degree) {
  turtle$head <- turtle$head + degree
  return(turtle)
}

turtle.roll <- function(turtle, degree) {
  turtle$roll <- turtle$roll + degree
  return(turtle)
}

#
# l-system general
#


lsystem.code <- function( x )
  substitute( x )

lsystem.gen <- function( x, grammar, levels=0 ) {
  code <- eval( substitute( substitute( REPLACE , grammar ), list(REPLACE=x) ) )
  if (levels)
    return( lsystem.gen( code , grammar , levels-1 ) )
  else
    return( code )
}

#
# l-system plot
#

lsystem.plot <- function( expr, level ) {
  turtle <- turtle.init(level=level)
  lsystem.eval( expr, turtle )
}

lsystem.eval <- function( expr, turtle ) {
  if ( length(expr) == 3 ) {
    turtle <- lsystem.eval( expr[[2]], turtle )
    turtle <- lsystem.eval( expr[[3]], turtle )
    turtle <- lsystem.eval( expr[[1]], turtle )
  } else if ( length(expr) == 2 ) {
    saved <- turtle
    turtle <- lsystem.eval( expr[[1]], turtle )
    turtle <- lsystem.eval( expr[[2]], turtle )
    turtle <- saved
  } else if ( length(expr) == 1 ) {
    if ( as.name(expr) == "stem" )      turtle <- turtle.move(turtle, 5, "brown")
    else if ( as.name(expr) == "short") turtle <- turtle.move(turtle, 5, "brown")
    else if ( as.name(expr) == "leaf" ) {
      spheres3d(turtle$pos[1],turtle$pos[2],turtle$pos[3],radius=0.1+turtle$level*0.3,color="green")
      sprites3d(turtle$pos[1],turtle$pos[2],turtle$pos[3],radius=0.5+turtle$level*0.3 ,color="green",texture=system.file("textures/particle.png",package="rgl"),textype="alpha",alpha=0.5)     
    }
    else if ( as.name(expr) == "roll" ) turtle <- turtle.head(turtle, 60)
    else if ( as.name(expr) == "down" ) turtle <- turtle.pitch(turtle,10)
    else if ( as.name(expr) == "up" )   turtle <- turtle.pitch(turtle,-10)
    else if ( as.name(expr) == "left" ) turtle <- turtle.head(turtle, 1)
    else if ( as.name(expr) == "right") turtle <- turtle.head(turtle,-1.5)
    else if ( as.name(expr) == "turnleft") turtle <- turtle.head(turtle,20)
    else if ( as.name(expr) == "turnright") turtle <- turtle.head(turtle,-20)
    else if ( as.name(expr) == "turn") turtle <- turtle.roll(turtle,180)
  }
  return(turtle)
}


#
# example
#

simple <- function(level=0) {
  grammar <- list(
    stem=lsystem.code(
      stem-(up-stem-leaf)-stem-(down-stem-leaf)-stem-leaf
    )
  )
  plant <- lsystem.gen(lsystem.code(stem), grammar, level )
  lsystem.plot(plant,level)
}

rgl.demo.lsystem <- function(level=0) {
  gen   <- list(
    stem=lsystem.code( 
      stem-left-stem-branch( turnleft-down-short-turnleft-down-stem-leaf)-right-right-stem--branch( turnright-up-short-turnright-up-short-turnright-short-stem-leaf)-left-left-left-stem-branch( turnleft-down-short-turnright-down-stem-leaf )-branch( up-turnright-short-up-turnleft-up-stem-leaf ) 
    )
  )    
  plant <- lsystem.gen(lsystem.code(stem), gen, level )
  lsystem.plot(plant,level)  
}

open3d()
#> null 
#>   24
rgl.demo.lsystem(level=1)
#> $pos
#>               [,1]
#> [1,] -2.092747e+00
#> [2,]  7.992083e+01
#> [3,] -4.893740e-15
#> 
#> $head
#> [1] 5
#> 
#> $pitch
#> [1] 90
#> 
#> $roll
#> [1] 0
#> 
#> $level
#> [1] 1
rglwidget()

subdivision: Subdivision surfaces using generic meshes (preview of generic 3D interface)

# RGL-demo: subdivision surfaces
# author: Daniel Adler

rgl.demo.subdivision <- function() {
  # setup environment
  clear3d("all")
  view3d()
  bg3d(color="gray")
  light3d()

  # generate basic mesh
  obj <- oh3d()

  part <- function( level, tx, ... ) {
    shade3d( translate3d( obj, tx, 0, 0 )
    , color="gray30", front="lines",alpha=0.5,back="lines", override=TRUE
    )
    shade3d( translate3d( subdivision3d( obj, depth=level ), tx, 0, 0 )
    , override=TRUE, ... )
  }
  
  part(0, -5.50, color="blue"   )
  part(1, -1.75, color="yellow" )
  part(2,  1.75, color="red"    )
  part(3,  5.50, color="green"  )

}

open3d()
#> null 
#>   26
rgl.demo.subdivision()

envmap: Environment mapping

# RGL-Demo: environment mapping
# Author: Daniel Adler

rgl.demo.envmap <- function() {
  open3d()
  # Clear scene:
  clear3d("all")
  light3d()
  bg3d(sphere=TRUE, color="white", back="filled"
  , texture=system.file("textures/refmap.png",package="rgl")
  )
  data(volcano)

  surface3d( 10*seq_len(nrow(volcano)),10*seq_len(ncol(volcano)),5*volcano
  , texture=system.file("textures/refmap.png",package="rgl")
  , texenvmap=TRUE
  , texmode="modulate"
  , color = "white"
  )
}
rgl.demo.envmap()

shapes3d: 3D shape primitives (cones, ellipsoids, cubes), some taken from qmesh3d

cone3d <- function(base=c(0,0,0),tip=c(0,0,1),rad=1,n=30,draw.base=TRUE,qmesh=FALSE,
                   trans = par3d("userMatrix"), ...) {
  ax <- tip-base
  if (missing(trans) && !cur3d()) trans <- diag(4)
  ### is there a better way?
  if (ax[1]!=0) {
    p1 <- c(-ax[2]/ax[1],1,0)
    p1 <- p1/sqrt(sum(p1^2))
    if (p1[1]!=0) {
      p2 <- c(-p1[2]/p1[1],1,0)
      p2[3] <- -sum(p2*ax)
      p2 <- p2/sqrt(sum(p2^2))
    } else {
      p2 <- c(0,0,1)
    }
  } else if (ax[2]!=0) {
    p1 <- c(0,-ax[3]/ax[2],1)
    p1 <- p1/sqrt(sum(p1^2))
    if (p1[1]!=0) {
      p2 <- c(0,-p1[3]/p1[2],1)
      p2[3] <- -sum(p2*ax)
      p2 <- p2/sqrt(sum(p2^2))
    } else {
      p2 <- c(1,0,0)
    }
  } else {
    p1 <- c(0,1,0); p2 <- c(1,0,0)
  }
  degvec <- seq(0,2*pi,length=n+1)[-1]
  ecoord2 <- function(theta) {
    base+rad*(cos(theta)*p1+sin(theta)*p2)
  }
  i <- rbind(1:n,c(2:n,1),rep(n+1,n))
  v <- cbind(sapply(degvec,ecoord2),tip)
  if (qmesh) 
    ## minor kluge for quads -- draw tip twice
    i <- rbind(i,rep(n+1,n))
  if (draw.base) {
    v <- cbind(v,base)
    i.x <- rbind(c(2:n,1),1:n,rep(n+2,n))
    if (qmesh)  ## add base twice
      i.x <-  rbind(i.x,rep(n+2,n))
    i <- cbind(i,i.x)
  }
  if (qmesh) v <- rbind(v,rep(1,ncol(v))) ## homogeneous
  if (!qmesh)
    triangles3d(v[1,i],v[2,i],v[3,i],...)
  else
    return(rotate3d(qmesh3d(v,i,material=list(...)), matrix=trans))
}     


ellipsoid3d <- function(rx=1,ry=1,rz=1,n=30,ctr=c(0,0,0),
                        qmesh=FALSE,
                        trans = par3d("userMatrix"),...) {
  if (missing(trans) && !cur3d()) trans <- diag(4)
  degvec <- seq(0,pi,length=n)
  ecoord2 <- function(p)
    c(rx*cos(p[1])*sin(p[2]),ry*sin(p[1])*sin(p[2]),rz*cos(p[2]))
  v <- apply(expand.grid(2*degvec,degvec),1,ecoord2)
  if (qmesh) v <- rbind(v,rep(1,ncol(v))) ## homogeneous
  e <- expand.grid(1:(n-1),1:n)
  i1 <- apply(e,1,function(z)z[1]+n*(z[2]-1))
  i2 <- i1+1
  i3 <- (i1+n-1) %% n^2 + 1
  i4 <- (i2+n-1) %% n^2 + 1
  i <- rbind(i1,i2,i4,i3)
  if (!qmesh)
    quads3d(v[1,i],v[2,i],v[3,i],...)
  else return(rotate3d(qmesh3d(v,i,material=list(...)),matrix=trans))
}

############
open3d()
#> null 
#>   30
ellipsoid3d(ctr=c(2,2,2),rx=3,ry=2,col="red",alpha=0.4)
cone3d(base=c(-2,-2,-2),rad=0.5,tip=c(-3,0,-4),col="blue",front="lines",back="lines")
shade3d(translate3d(cube3d(),3,-2,3,col="purple"))
### now with qmesh()
open3d()
#> null 
#>   31
q1 <- cone3d(qmesh=TRUE,trans=diag(4))  ## the "unit cone";
                                        ## height=1,radius=1, base at (0,0,0)
shade3d(q1)
## various transformations and rotations
wire3d(translate3d(q1,3,0,0),col="green")
wire3d(translate3d(scale3d(q1,1,1,2),6,0,0),col="green")
dot3d(translate3d(q1,0,3,0),col="green")
dot3d(translate3d(scale3d(q1,2,1,1),0,6,0),col="green")
shade3d(translate3d(q1,0,0,3),col="red")
shade3d(translate3d(rotate3d(scale3d(q1,1,1,2),pi/4,0,1,0),0,0,6),col="red")

axes3d()
open3d()
#> null 
#>   32
s1 <- ellipsoid3d(qmesh=TRUE,trans=diag(4))  ## the "unit sphere";
                                        ## radius=1, ctr at (0,0,0)
shade3d(s1)
## various transformations and rotations
wire3d(translate3d(s1,3,0,0),col="green")
wire3d(translate3d(scale3d(s1,1,1,2),6,0,0),col="green")
dot3d(translate3d(s1,0,3,0),col="green")
dot3d(translate3d(scale3d(s1,2,1,1),0,6,0),col="green")
shade3d(translate3d(s1,0,0,3),col="red")
shade3d(translate3d(rotate3d(scale3d(s1,1,1,2),pi/4,0,1,0),0,0,6),col="red")

axes3d()

lollipop3d: “Lollipop” plots (3D scatterplot with lines between points and a surface)

cone3d <- function(base,tip,rad,n=30,...) {
  degvec <- seq(0,2*pi,length=n)
  ax <- tip-base
  ## what do if ax[1]==0?
  if (ax[1]!=0) {
    p1 <- c(-ax[2]/ax[1],1,0)
    p1 <- p1/sqrt(sum(p1^2))
    if (p1[1]!=0) {
      p2 <- c(-p1[2]/p1[1],1,0)
      p2[3] <- -sum(p2*ax)
      p2 <- p2/sqrt(sum(p2^2))
    } else {
      p2 <- c(0,0,1)
    }
  } else if (ax[2]!=0) {
    p1 <- c(0,-ax[3]/ax[2],1)
    p1 <- p1/sqrt(sum(p1^2))
    if (p1[1]!=0) {
      p2 <- c(0,-p1[3]/p1[2],1)
      p2[3] <- -sum(p2*ax)
      p2 <- p2/sqrt(sum(p2^2))
    } else {
      p2 <- c(1,0,0)
    }
  } else {
    p1 <- c(0,1,0); p2 <- c(1,0,0)
  }
  ecoord2 <- function(theta) {
    base+rad*(cos(theta)*p1+sin(theta)*p2)
  }
    for (i in seq_len(n-1)) {
      li <- ecoord2(degvec[i])
      lj <- ecoord2(degvec[i+1])
      triangles3d(c(li[1],lj[1],tip[1]),c(li[2],lj[2],tip[2]),c(li[3],lj[3],tip[3]),...)
    }   
}

lollipop3d <- function(data.x,data.y,data.z,surf.fun,surf.n=50,
                         xlim=range(data.x),
             ylim=range(data.y),
             zlim=range(data.z),
                         asp=c(y=1,z=1),
             xlab=deparse(substitute(x)),
             ylab=deparse(substitute(y)),
             zlab=deparse(substitute(z)),
             alpha.surf=0.4,
                         col.surf=fg,col.stem=c(fg,fg),
                         col.pt="gray",type.surf="line",ptsize,
                         lwd.stem=2,lit=TRUE,bg="white",fg="black",
                         col.axes=fg,col.axlabs=fg,
                         axis.arrow=TRUE,axis.labels=TRUE,
                         box.col=bg,
                         axes=c("lines","box")) {
  axes <- match.arg(axes)
  col.stem <- rep(col.stem,length=2)
  x.ticks <- pretty(xlim)
  x.ticks <- x.ticks[x.ticks>=min(xlim) & x.ticks<=max(xlim)]
  x.ticklabs <- if (axis.labels) as.character(x.ticks) else NULL
  y.ticks <- pretty(ylim)
  y.ticks <- y.ticks[y.ticks>=min(ylim) & y.ticks<=max(ylim)]
  y.ticklabs <- if (axis.labels) as.character(y.ticks) else NULL
  z.ticks <- pretty(zlim)
  z.ticks <- z.ticks[z.ticks>=min(zlim) & z.ticks<=max(zlim)]
  z.ticklabs <- if (axis.labels) as.character(z.ticks) else NULL
  if (!missing(surf.fun)) {
    surf.x <- seq(xlim[1],xlim[2],length=surf.n)
    surf.y <- seq(ylim[1],ylim[2],length=surf.n)
    surf.z <- outer(surf.x,surf.y,surf.fun)  ## requires surf.fun be vectorized
    z.interc <- surf.fun(data.x,data.y)
    zdiff <- diff(range(c(surf.z,data.z)))
  } else {
    z.interc <- rep(min(data.z),length(data.x))
    zdiff <- diff(range(data.z))
  }
  xdiff <- diff(xlim)
  ydiff <- diff(ylim)
  y.adj <- if (asp[1]<=0) 1 else asp[1]*xdiff/ydiff
  data.y <- y.adj*data.y
  y.ticks <- y.adj*y.ticks
  ylim <- ylim*y.adj
  ydiff <- diff(ylim)
  z.adj <- if (asp[2]<=0) 1 else asp[2]*xdiff/zdiff
  data.z <- z.adj*data.z
  if (!missing(surf.fun)) {
    surf.y <- y.adj*surf.y
    surf.z <- z.adj*surf.z
  }
  z.interc <- z.adj*z.interc
  z.ticks <- z.adj*z.ticks
  zlim <- z.adj*zlim
  open3d()
  clear3d("all")
  light3d()
  bg3d(color=c(bg,fg))
  if (!missing(surf.fun)) 
    surface3d(surf.x,surf.y,surf.z,alpha=alpha.surf,
                front=type.surf,back=type.surf,
                col=col.surf,lit=lit)
  if (missing(ptsize)) ptsize <- 0.02*xdiff
  ## draw points
  spheres3d(data.x,data.y,data.z,r=ptsize,lit=lit,color=col.pt)
  ## draw lollipops
  apply(cbind(data.x,data.y,data.z,z.interc),1,
        function(X) {
          lines3d(x=rep(X[1],2),
                  y=rep(X[2],2),
                  z=c(X[3],X[4]),
                  col=ifelse(X[3]>X[4],col.stem[1],
                    col.stem[2]),lwd=lwd.stem)
        })
  if (axes=="box") {
    bbox3d(xat=x.ticks,xlab=x.ticklabs,
             yat=y.ticks,ylab=y.ticklabs,
             zat=z.ticks,zlab=z.ticklabs,lit=lit)
  } else if (axes=="lines") { ## set up axis lines
    axis3d(edge="x",at=x.ticks,labels=x.ticklabs,
           col=col.axes,arrow=axis.arrow)
    axis3d(edge="y",at=y.ticks,labels=y.ticklabs,
           col=col.axes,arrow=axis.arrow)
    axis3d(edge="z",at=z.ticks,labels=z.ticklabs,
           col=col.axes,arrow=axis.arrow)
    box3d(col=col.axes)
  }
  decorate3d(xlab=xlab, ylab=ylab, zlab=zlab, box=FALSE, axes=FALSE, col=col.axlabs)
}

x <- 1:5
y <- x*10
z <- (x+y)/20
open3d()
#> null 
#>   36
spheres3d(x,y,z)
axes3d()
set.seed(1001)
x <- runif(30)
y <- runif(30,max=2)
dfun <- function(x,y)  2*x+3*y+2*x*y+3*y^2 
z <- dfun(x,y)+rnorm(30,sd=0.5)
## lollipops only
lollipop3d(x,y,z)
## lollipops plus theoretical surface

open3d()
#> null 
#>   38
lollipop3d(x,y,z,dfun,col.pt="red",col.stem=c("red","blue"))
## lollipops plus regression fit

linmodel <- lm(z~x+y)
dfun <- function(x,y) predict(linmodel,newdata=data.frame(x=x,y=y))
open3d()
#> null 
#>   40
lollipop3d(x,y,z,dfun,col.pt="red",col.stem=c("red","blue"))
####
rgl/inst/doc/demos.Rmd0000644000176200001440000005142415011677075014352 0ustar liggesusers--- title: "rgl Demos" date: "`r Sys.Date()`" output: rmarkdown::html_vignette: toc: true fig_height: 5 fig_width: 5 vignette: > %\VignetteIndexEntry{rgl Demos} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r setup, include = FALSE} knitr::opts_chunk$set( collapse = FALSE, # Bug in knitr 1.42 requires FALSE here comment = "#>", snapshot = FALSE, screenshot.force = FALSE) library(rgl) setupKnitr(autoprint = TRUE) ``` ## Introduction This vignette holds code that was previously included as "demos" in `rgl`. Some of the demos require R to be running; those remain available via `demo(package = "rgl")`. ## hist3d: 3D histogram using basic building blocks ```{r} ########## ### 3D HIST EXAMPLE: ########## ################################################################################ ##### Required functions 'binplot' and 'hist3d': binplot.3d<-function(x,y,z,alpha=1,topcol="#ff0000",sidecol="#aaaaaa") { save <- par3d(skipRedraw=TRUE) on.exit(par3d(save)) x1<-c(rep(c(x[1],x[2],x[2],x[1]),3),rep(x[1],4),rep(x[2],4)) z1<-c(rep(0,4),rep(c(0,0,z,z),4)) y1<-c(y[1],y[1],y[2],y[2],rep(y[1],4),rep(y[2],4),rep(c(y[1],y[2],y[2],y[1]),2)) x2<-c(rep(c(x[1],x[1],x[2],x[2]),2),rep(c(x[1],x[2],rep(x[1],3),rep(x[2],3)),2)) z2<-c(rep(c(0,z),4),rep(0,8),rep(z,8) ) y2<-c(rep(y[1],4),rep(y[2],4),rep(c(rep(y[1],3),rep(y[2],3),y[1],y[2]),2) ) quads3d(x1,z1,y1,col=rep(sidecol,each=4),alpha=alpha) quads3d(c(x[1],x[2],x[2],x[1]),rep(z,4),c(y[1],y[1],y[2],y[2]), col=rep(topcol,each=4),alpha=1) segments3d(x2,z2,y2,col="#000000") } hist3d<-function(x,y=NULL,nclass="auto",alpha=1,col="#ff0000",scale=10) { save <- par3d(skipRedraw=TRUE) on.exit(par3d(save)) xy <- xy.coords(x,y) x <- xy$x y <- xy$y n<-length(x) if (nclass == "auto") nclass<-ceiling(sqrt(nclass.Sturges(x))) breaks.x <- seq(min(x),max(x),length=(nclass+1)) breaks.y <- seq(min(y),max(y),length=(nclass+1)) z<-matrix(0,(nclass),(nclass)) for (i in seq_len(nclass)) { for (j in seq_len(nclass)) { z[i, j] <- (1/n)*sum(x < breaks.x[i+1] & y < breaks.y[j+1] & x >= breaks.x[i] & y >= breaks.y[j]) binplot.3d(c(breaks.x[i],breaks.x[i+1]),c(breaks.y[j],breaks.y[j+1]), scale*z[i,j],alpha=alpha,topcol=col) } } } ################################################################################ open3d() bg3d(color="gray") light3d(0, 0) # Drawing a 'bin' for given coordinates: binplot.3d(c(-0.5,0.5),c(4.5,5.5),2,alpha=0.6) # Setting the viewpoint ('theta' and 'phi' have the same meaning as in persp): view3d(theta=40,phi=40) ##### QUADS FORMING BIN open3d() # Defining transparency and colors: alpha<-0.7; topcol<-"#ff0000"; sidecol<-"#aaaaaa" # Setting up coordinates for the quads and adding them to the scene: y<-x<-c(-1,1) ; z<-4; of<-0.3 x12<-c(x[1],x[2],x[2],x[1]); x11<-rep(x[1],4); x22<-rep(x[2],4) z00<-rep(0,4); z0z<-c(0,0,z,z); zzz<-rep(z,4); y11<-rep(y[1],4) y1122<-c(y[1],y[1],y[2],y[2]); y12<-c(y[1],y[2],y[2],y[1]); y22<-rep(y[2],4) quads3d(c(x12,x12,x11-of,x12,x22+of,x12), c(z00-of,rep(z0z,4),zzz+of), c(y1122,y11-of,y12,y22+of,y12,y1122), col=rep(c(rep(sidecol,5),topcol),each=4),alpha=c(rep(alpha,5),1)) # Setting up coordinates for the border-lines of the quads and drawing them: yl1<-c(y[1],y[2],y[1],y[2]); yl2<-c(y[1]-of,y[1]-of) xl<-c(rep(x[1],8),rep(x[1]-of,8),rep(c(x[1],x[2]),8),rep(x[2],8),rep(x[2]+of,8)) zl<-c(0,z,0,z,z+of,z+of,-of,-of,0,0,z,z,0,z,0,z,rep(0,4),rep(z,4),rep(-of,4), rep(z+of,4),z+of,z+of,-of,-of,rep(c(0,z),4),0,0,z,z) yl<-c(yl2,y[2]+of,y[2]+of,rep(c(y[1],y[2]),4),y[1],y[1],y[2],y[2],yl2, rep(y[2]+of,4),yl2,y[2],y[2],rep(y[1],4),y[2],y[2],yl1,yl2,y[2]+of, y[2]+of,y[1],y[1],y[2],y[2],yl1) lines3d(xl,zl,yl,col="#000000") view3d(theta=40,phi=40) ##### COMPLETE HISTOGRAM: open3d() # Setting the rng to a fixed value: set.seed(1000) # Drawing a 3d histogramm of 2500 normaly distributed observations: hist3d(rnorm(2500),rnorm(2500),alpha=0.4,nclass=7,scale=30) # Choosing a lightgrey background: bg3d(col="#cccccc") view3d(theta=40,phi=40) ``` ## bivar: Bivariate densities: kernel smoothing using surface3d and alpha-channel (requires MASS package) ```{r} # rgl demo: rgl-bivar.r # author: Daniel Adler rgl.demo.bivar <- function() { if (!requireNamespace("MASS", quietly = TRUE)) stop("This demo requires MASS") # parameters: n<-50; ngrid<-40 # generate samples: set.seed(31415) x<-rnorm(n); y<-rnorm(n) # estimate non-parameteric density surface via kernel smoothing denobj <- MASS::kde2d(x, y, n=ngrid) den.z <-denobj$z # generate parametric density surface of a bivariate normal distribution xgrid <- denobj$x ygrid <- denobj$y bi.z <- dnorm(xgrid)%*%t(dnorm(ygrid)) # visualize: zscale<-20 # New window open3d() # clear scene: clear3d("all") # setup env: bg3d(color="#887777") light3d() # Draws the simulated data as spheres on the baseline spheres3d(x,y,rep(0,n),radius=0.1,color="#CCCCFF") # Draws non-parametric density surface3d(xgrid,ygrid,den.z*zscale,color="#FF2222",alpha=0.5) # Draws parametric density surface3d(xgrid,ygrid,bi.z*zscale,color="#CCCCFF",front="lines") } rgl.demo.bivar() ``` ## Abundance: Animal abundance, visualization of multi-dimension data using multiple techniques ```{r} # RGL-Demo: animal abundance # Authors: Oleg Nenadic, Daniel Adler rgl.demo.abundance <- function() { open3d() clear3d("all") # remove all shapes, lights, bounding-box, and restore viewpoint # Setup environment: bg3d(col="#cccccc") # setup background light3d() # setup head-light # Importing animal data (created with wisp) terrain<-dget(system.file("demodata/region.dat",package="rgl")) pop<-dget(system.file("demodata/population.dat",package="rgl")) # Define colors for terrain zlim <- range(terrain) colorlut <- terrain.colors(82) col1 <- colorlut[9*sqrt(3.6*(terrain-zlim[1])+2)] # Set color to (water-)blue for regions with zero 'altitude' col1[terrain==0]<-"#0000FF" # Add terrain surface shape (i.e. population density): surface3d( 1:100,seq(1,60,length=100),terrain, col=col1,spec="#000000", ambient="#333333", back="lines" ) # Define colors for simulated populations (males:blue, females:red): col2<-pop[,4] col2[col2==0]<-"#3333ff" col2[col2==1]<-"#ff3333" # Add simulated populations as sphere-set shape spheres3d( pop[,1], pop[,2], terrain[cbind( ceiling(pop[,1]),ceiling(pop[,2]*10/6) )]+0.5, radius=0.2*pop[,3], col=col2, alpha=(1-(pop[,5])/10 ) ) } rgl.demo.abundance() ``` ## lsystem: Plant modelling using a turtle and L-system ```{r} # demo: lsystem.r # author: Daniel Adler # # geometry # deg2rad <- function( degree ) { return( degree*pi/180 ) } rotZ.m3x3 <- function( degree ) { kc <- cos(deg2rad(degree)) ks <- sin(deg2rad(degree)) return( matrix( c( kc, -ks, 0, ks, kc, 0, 0, 0, 1 ),ncol=3,byrow=TRUE ) ) } rotX.m3x3 <- function( degree ) { kc <- cos(deg2rad(degree)) ks <- sin(deg2rad(degree)) return( matrix( c( 1, 0, 0, 0, kc, -ks, 0, ks, kc ),ncol=3,byrow=TRUE ) ) } rotY.m3x3 <- function( degree ) { kc <- cos(deg2rad(degree)) ks <- sin(deg2rad(degree)) return( matrix( c( kc, 0, ks, 0, 1, 0, -ks, 0, kc ),ncol=3,byrow=TRUE ) ) } rotZ <- function( v, degree ) { return( rotZ.m3x3(degree) %*% v) } rotX <- function( v, degree ) { return( rotX.m3x3(degree) %*% v) } rotY <- function( v, degree ) { return( rotY.m3x3(degree) %*% v) } # # turtle graphics, rgl implementation: # turtle.init <- function(pos=c(0,0,0),head=0,pitch=90,roll=0,level=0) { clear3d("all") bg3d(color="gray") light3d() return( list(pos=pos,head=head,pitch=pitch,roll=roll,level=level) ) } turtle.move <- function(turtle, steps, color) { rm <- rotX.m3x3(turtle$pitch) %*% rotY.m3x3(turtle$head) %*% rotZ.m3x3(turtle$roll) from <- as.vector( turtle$pos ) dir <- rm %*% c(0,0,-1) to <- from + dir * steps x <- c( from[1], to[1] ) y <- c( from[2], to[2] ) z <- c( from[3], to[3] ) lines3d(x,y,z,col=color,size=1.5,alpha=0.5) turtle$pos <- to return(turtle) } turtle.pitch <- function(turtle, degree) { turtle$pitch <- turtle$pitch + degree return(turtle) } turtle.head <- function(turtle, degree) { turtle$head <- turtle$head + degree return(turtle) } turtle.roll <- function(turtle, degree) { turtle$roll <- turtle$roll + degree return(turtle) } # # l-system general # lsystem.code <- function( x ) substitute( x ) lsystem.gen <- function( x, grammar, levels=0 ) { code <- eval( substitute( substitute( REPLACE , grammar ), list(REPLACE=x) ) ) if (levels) return( lsystem.gen( code , grammar , levels-1 ) ) else return( code ) } # # l-system plot # lsystem.plot <- function( expr, level ) { turtle <- turtle.init(level=level) lsystem.eval( expr, turtle ) } lsystem.eval <- function( expr, turtle ) { if ( length(expr) == 3 ) { turtle <- lsystem.eval( expr[[2]], turtle ) turtle <- lsystem.eval( expr[[3]], turtle ) turtle <- lsystem.eval( expr[[1]], turtle ) } else if ( length(expr) == 2 ) { saved <- turtle turtle <- lsystem.eval( expr[[1]], turtle ) turtle <- lsystem.eval( expr[[2]], turtle ) turtle <- saved } else if ( length(expr) == 1 ) { if ( as.name(expr) == "stem" ) turtle <- turtle.move(turtle, 5, "brown") else if ( as.name(expr) == "short") turtle <- turtle.move(turtle, 5, "brown") else if ( as.name(expr) == "leaf" ) { spheres3d(turtle$pos[1],turtle$pos[2],turtle$pos[3],radius=0.1+turtle$level*0.3,color="green") sprites3d(turtle$pos[1],turtle$pos[2],turtle$pos[3],radius=0.5+turtle$level*0.3 ,color="green",texture=system.file("textures/particle.png",package="rgl"),textype="alpha",alpha=0.5) } else if ( as.name(expr) == "roll" ) turtle <- turtle.head(turtle, 60) else if ( as.name(expr) == "down" ) turtle <- turtle.pitch(turtle,10) else if ( as.name(expr) == "up" ) turtle <- turtle.pitch(turtle,-10) else if ( as.name(expr) == "left" ) turtle <- turtle.head(turtle, 1) else if ( as.name(expr) == "right") turtle <- turtle.head(turtle,-1.5) else if ( as.name(expr) == "turnleft") turtle <- turtle.head(turtle,20) else if ( as.name(expr) == "turnright") turtle <- turtle.head(turtle,-20) else if ( as.name(expr) == "turn") turtle <- turtle.roll(turtle,180) } return(turtle) } # # example # simple <- function(level=0) { grammar <- list( stem=lsystem.code( stem-(up-stem-leaf)-stem-(down-stem-leaf)-stem-leaf ) ) plant <- lsystem.gen(lsystem.code(stem), grammar, level ) lsystem.plot(plant,level) } rgl.demo.lsystem <- function(level=0) { gen <- list( stem=lsystem.code( stem-left-stem-branch( turnleft-down-short-turnleft-down-stem-leaf)-right-right-stem--branch( turnright-up-short-turnright-up-short-turnright-short-stem-leaf)-left-left-left-stem-branch( turnleft-down-short-turnright-down-stem-leaf )-branch( up-turnright-short-up-turnleft-up-stem-leaf ) ) ) plant <- lsystem.gen(lsystem.code(stem), gen, level ) lsystem.plot(plant,level) } open3d() rgl.demo.lsystem(level=1) rglwidget() ``` ## subdivision: Subdivision surfaces using generic meshes (preview of generic 3D interface) ```{r} # RGL-demo: subdivision surfaces # author: Daniel Adler rgl.demo.subdivision <- function() { # setup environment clear3d("all") view3d() bg3d(color="gray") light3d() # generate basic mesh obj <- oh3d() part <- function( level, tx, ... ) { shade3d( translate3d( obj, tx, 0, 0 ) , color="gray30", front="lines",alpha=0.5,back="lines", override=TRUE ) shade3d( translate3d( subdivision3d( obj, depth=level ), tx, 0, 0 ) , override=TRUE, ... ) } part(0, -5.50, color="blue" ) part(1, -1.75, color="yellow" ) part(2, 1.75, color="red" ) part(3, 5.50, color="green" ) } open3d() rgl.demo.subdivision() ``` ## envmap: Environment mapping ```{r} # RGL-Demo: environment mapping # Author: Daniel Adler rgl.demo.envmap <- function() { open3d() # Clear scene: clear3d("all") light3d() bg3d(sphere=TRUE, color="white", back="filled" , texture=system.file("textures/refmap.png",package="rgl") ) data(volcano) surface3d( 10*seq_len(nrow(volcano)),10*seq_len(ncol(volcano)),5*volcano , texture=system.file("textures/refmap.png",package="rgl") , texenvmap=TRUE , texmode="modulate" , color = "white" ) } rgl.demo.envmap() ``` ## shapes3d: 3D shape primitives (cones, ellipsoids, cubes), some taken from qmesh3d ```{r} cone3d <- function(base=c(0,0,0),tip=c(0,0,1),rad=1,n=30,draw.base=TRUE,qmesh=FALSE, trans = par3d("userMatrix"), ...) { ax <- tip-base if (missing(trans) && !cur3d()) trans <- diag(4) ### is there a better way? if (ax[1]!=0) { p1 <- c(-ax[2]/ax[1],1,0) p1 <- p1/sqrt(sum(p1^2)) if (p1[1]!=0) { p2 <- c(-p1[2]/p1[1],1,0) p2[3] <- -sum(p2*ax) p2 <- p2/sqrt(sum(p2^2)) } else { p2 <- c(0,0,1) } } else if (ax[2]!=0) { p1 <- c(0,-ax[3]/ax[2],1) p1 <- p1/sqrt(sum(p1^2)) if (p1[1]!=0) { p2 <- c(0,-p1[3]/p1[2],1) p2[3] <- -sum(p2*ax) p2 <- p2/sqrt(sum(p2^2)) } else { p2 <- c(1,0,0) } } else { p1 <- c(0,1,0); p2 <- c(1,0,0) } degvec <- seq(0,2*pi,length=n+1)[-1] ecoord2 <- function(theta) { base+rad*(cos(theta)*p1+sin(theta)*p2) } i <- rbind(1:n,c(2:n,1),rep(n+1,n)) v <- cbind(sapply(degvec,ecoord2),tip) if (qmesh) ## minor kluge for quads -- draw tip twice i <- rbind(i,rep(n+1,n)) if (draw.base) { v <- cbind(v,base) i.x <- rbind(c(2:n,1),1:n,rep(n+2,n)) if (qmesh) ## add base twice i.x <- rbind(i.x,rep(n+2,n)) i <- cbind(i,i.x) } if (qmesh) v <- rbind(v,rep(1,ncol(v))) ## homogeneous if (!qmesh) triangles3d(v[1,i],v[2,i],v[3,i],...) else return(rotate3d(qmesh3d(v,i,material=list(...)), matrix=trans)) } ellipsoid3d <- function(rx=1,ry=1,rz=1,n=30,ctr=c(0,0,0), qmesh=FALSE, trans = par3d("userMatrix"),...) { if (missing(trans) && !cur3d()) trans <- diag(4) degvec <- seq(0,pi,length=n) ecoord2 <- function(p) c(rx*cos(p[1])*sin(p[2]),ry*sin(p[1])*sin(p[2]),rz*cos(p[2])) v <- apply(expand.grid(2*degvec,degvec),1,ecoord2) if (qmesh) v <- rbind(v,rep(1,ncol(v))) ## homogeneous e <- expand.grid(1:(n-1),1:n) i1 <- apply(e,1,function(z)z[1]+n*(z[2]-1)) i2 <- i1+1 i3 <- (i1+n-1) %% n^2 + 1 i4 <- (i2+n-1) %% n^2 + 1 i <- rbind(i1,i2,i4,i3) if (!qmesh) quads3d(v[1,i],v[2,i],v[3,i],...) else return(rotate3d(qmesh3d(v,i,material=list(...)),matrix=trans)) } ############ open3d() ellipsoid3d(ctr=c(2,2,2),rx=3,ry=2,col="red",alpha=0.4) cone3d(base=c(-2,-2,-2),rad=0.5,tip=c(-3,0,-4),col="blue",front="lines",back="lines") shade3d(translate3d(cube3d(),3,-2,3,col="purple")) ### now with qmesh() open3d() q1 <- cone3d(qmesh=TRUE,trans=diag(4)) ## the "unit cone"; ## height=1,radius=1, base at (0,0,0) shade3d(q1) ## various transformations and rotations wire3d(translate3d(q1,3,0,0),col="green") wire3d(translate3d(scale3d(q1,1,1,2),6,0,0),col="green") dot3d(translate3d(q1,0,3,0),col="green") dot3d(translate3d(scale3d(q1,2,1,1),0,6,0),col="green") shade3d(translate3d(q1,0,0,3),col="red") shade3d(translate3d(rotate3d(scale3d(q1,1,1,2),pi/4,0,1,0),0,0,6),col="red") axes3d() open3d() s1 <- ellipsoid3d(qmesh=TRUE,trans=diag(4)) ## the "unit sphere"; ## radius=1, ctr at (0,0,0) shade3d(s1) ## various transformations and rotations wire3d(translate3d(s1,3,0,0),col="green") wire3d(translate3d(scale3d(s1,1,1,2),6,0,0),col="green") dot3d(translate3d(s1,0,3,0),col="green") dot3d(translate3d(scale3d(s1,2,1,1),0,6,0),col="green") shade3d(translate3d(s1,0,0,3),col="red") shade3d(translate3d(rotate3d(scale3d(s1,1,1,2),pi/4,0,1,0),0,0,6),col="red") axes3d() ``` ## lollipop3d: "Lollipop" plots (3D scatterplot with lines between points and a surface) ```{r} cone3d <- function(base,tip,rad,n=30,...) { degvec <- seq(0,2*pi,length=n) ax <- tip-base ## what do if ax[1]==0? if (ax[1]!=0) { p1 <- c(-ax[2]/ax[1],1,0) p1 <- p1/sqrt(sum(p1^2)) if (p1[1]!=0) { p2 <- c(-p1[2]/p1[1],1,0) p2[3] <- -sum(p2*ax) p2 <- p2/sqrt(sum(p2^2)) } else { p2 <- c(0,0,1) } } else if (ax[2]!=0) { p1 <- c(0,-ax[3]/ax[2],1) p1 <- p1/sqrt(sum(p1^2)) if (p1[1]!=0) { p2 <- c(0,-p1[3]/p1[2],1) p2[3] <- -sum(p2*ax) p2 <- p2/sqrt(sum(p2^2)) } else { p2 <- c(1,0,0) } } else { p1 <- c(0,1,0); p2 <- c(1,0,0) } ecoord2 <- function(theta) { base+rad*(cos(theta)*p1+sin(theta)*p2) } for (i in seq_len(n-1)) { li <- ecoord2(degvec[i]) lj <- ecoord2(degvec[i+1]) triangles3d(c(li[1],lj[1],tip[1]),c(li[2],lj[2],tip[2]),c(li[3],lj[3],tip[3]),...) } } lollipop3d <- function(data.x,data.y,data.z,surf.fun,surf.n=50, xlim=range(data.x), ylim=range(data.y), zlim=range(data.z), asp=c(y=1,z=1), xlab=deparse(substitute(x)), ylab=deparse(substitute(y)), zlab=deparse(substitute(z)), alpha.surf=0.4, col.surf=fg,col.stem=c(fg,fg), col.pt="gray",type.surf="line",ptsize, lwd.stem=2,lit=TRUE,bg="white",fg="black", col.axes=fg,col.axlabs=fg, axis.arrow=TRUE,axis.labels=TRUE, box.col=bg, axes=c("lines","box")) { axes <- match.arg(axes) col.stem <- rep(col.stem,length=2) x.ticks <- pretty(xlim) x.ticks <- x.ticks[x.ticks>=min(xlim) & x.ticks<=max(xlim)] x.ticklabs <- if (axis.labels) as.character(x.ticks) else NULL y.ticks <- pretty(ylim) y.ticks <- y.ticks[y.ticks>=min(ylim) & y.ticks<=max(ylim)] y.ticklabs <- if (axis.labels) as.character(y.ticks) else NULL z.ticks <- pretty(zlim) z.ticks <- z.ticks[z.ticks>=min(zlim) & z.ticks<=max(zlim)] z.ticklabs <- if (axis.labels) as.character(z.ticks) else NULL if (!missing(surf.fun)) { surf.x <- seq(xlim[1],xlim[2],length=surf.n) surf.y <- seq(ylim[1],ylim[2],length=surf.n) surf.z <- outer(surf.x,surf.y,surf.fun) ## requires surf.fun be vectorized z.interc <- surf.fun(data.x,data.y) zdiff <- diff(range(c(surf.z,data.z))) } else { z.interc <- rep(min(data.z),length(data.x)) zdiff <- diff(range(data.z)) } xdiff <- diff(xlim) ydiff <- diff(ylim) y.adj <- if (asp[1]<=0) 1 else asp[1]*xdiff/ydiff data.y <- y.adj*data.y y.ticks <- y.adj*y.ticks ylim <- ylim*y.adj ydiff <- diff(ylim) z.adj <- if (asp[2]<=0) 1 else asp[2]*xdiff/zdiff data.z <- z.adj*data.z if (!missing(surf.fun)) { surf.y <- y.adj*surf.y surf.z <- z.adj*surf.z } z.interc <- z.adj*z.interc z.ticks <- z.adj*z.ticks zlim <- z.adj*zlim open3d() clear3d("all") light3d() bg3d(color=c(bg,fg)) if (!missing(surf.fun)) surface3d(surf.x,surf.y,surf.z,alpha=alpha.surf, front=type.surf,back=type.surf, col=col.surf,lit=lit) if (missing(ptsize)) ptsize <- 0.02*xdiff ## draw points spheres3d(data.x,data.y,data.z,r=ptsize,lit=lit,color=col.pt) ## draw lollipops apply(cbind(data.x,data.y,data.z,z.interc),1, function(X) { lines3d(x=rep(X[1],2), y=rep(X[2],2), z=c(X[3],X[4]), col=ifelse(X[3]>X[4],col.stem[1], col.stem[2]),lwd=lwd.stem) }) if (axes=="box") { bbox3d(xat=x.ticks,xlab=x.ticklabs, yat=y.ticks,ylab=y.ticklabs, zat=z.ticks,zlab=z.ticklabs,lit=lit) } else if (axes=="lines") { ## set up axis lines axis3d(edge="x",at=x.ticks,labels=x.ticklabs, col=col.axes,arrow=axis.arrow) axis3d(edge="y",at=y.ticks,labels=y.ticklabs, col=col.axes,arrow=axis.arrow) axis3d(edge="z",at=z.ticks,labels=z.ticklabs, col=col.axes,arrow=axis.arrow) box3d(col=col.axes) } decorate3d(xlab=xlab, ylab=ylab, zlab=zlab, box=FALSE, axes=FALSE, col=col.axlabs) } x <- 1:5 y <- x*10 z <- (x+y)/20 open3d() spheres3d(x,y,z) axes3d() set.seed(1001) x <- runif(30) y <- runif(30,max=2) dfun <- function(x,y) 2*x+3*y+2*x*y+3*y^2 z <- dfun(x,y)+rnorm(30,sd=0.5) ## lollipops only lollipop3d(x,y,z) ## lollipops plus theoretical surface open3d() lollipop3d(x,y,z,dfun,col.pt="red",col.stem=c("red","blue")) ## lollipops plus regression fit linmodel <- lm(z~x+y) dfun <- function(x,y) predict(linmodel,newdata=data.frame(x=x,y=y)) open3d() lollipop3d(x,y,z,dfun,col.pt="red",col.stem=c("red","blue")) #### ```rgl/inst/useNULL/0000755000176200001440000000000015026603601013301 5ustar liggesusersrgl/inst/useNULL/README.txt0000644000176200001440000000011714771520323015003 0ustar liggesusersThis directory will contain a version of the rgl DLL that doesn't use OpenGL. rgl/inst/textures/0000755000176200001440000000000014555455305013711 5ustar liggesusersrgl/inst/textures/worldsmall.png0000644000176200001440000001607714555455305016612 0ustar liggesusersPNG  IHDRQ"gAMA ahPLTEv|̯|}ȟ}}~ػɵρقۂنΉɊȞ݋ތׯގѵөǙĐ߾ϩ˓جӞēڬ˒қ꼴ޫݣ¿ܞјҝӢ͓ǖηӴԴ׬ǘٵØܷȕբ߯߷Ȝ˩ꭼ즾챿ﴼﺲȨ̬˦÷ՙIDATx흋{u_[Ԉ7B) iǷa@CGH;'I,OosΜ,amj+V,W,jm+ecKg'OfӕtlCNNzf, ;h񽈙r :R0ljQdo;9A. bw>`- UC y 񰰔OqioߞCc@n5 ̌umOm~',9ZQF3Dro[R_u΄mqDQ3^:gP ?MmQۑA.0 1̾0P󳭪!:`ĈH.'2R7.oZu63cҝ+3w:Bfsqng|v۠Zطf|l =|z<;OF^rLƖ{<hr8+Pғ%G`>r7z(%e=1lF'j:Er?2sD|]i!P9?갱|4$6$!BLve85(gXhen/ r 屆 I$_GX7X5?v~tCYp饊~_I;Y)S 0U59-k͚74 6Z*ɠQT"YÃK)L'&~#nfԄBldϔrA6sckq_㙌~ߨ72YfǙ*[| %.kj%\W}5xOi;n83ҙZf}ox*t mT  Y:Ƨ;*3)c]֭9+gA2( av= $(dFAE"`$?nvŒ Y$(UĄU0,D(L&+V^rY# (+VͅK 2rD(QWҏML2tG_H Z0|HB+Sef5F.N]A8[:ìA^S~I S%RQF$=gxSUkrJrK䥌@I9Qg<~Z+ lH%d.5jx xCf`GĴ4֤,!_%reo L+oaa(D`P<"p}mB8Y(e7jkO2짎IriFae9ō^+TZA :X2w-of|;fRUhN)J~M !dVhzECԜɀ4IfmYOỹ(>Z6KhmjOٌŒ#5&;b'Zq2ga 24io"}i?j;ț$0N/AYs/ GwD7a|5- mQ@!Y.jyfl] c(o]'G&|_OFm*?˟T<%Q =`(`H `<-ɭc=F~okŐ6cf\6dyd,]$E79z@ä$9LB;T4j1G.JYJҨ" e3K/͵bF[x44#[͌2@+ yQvJߌ,o3V;鴇ͤ`~GJr&B3J򀕆TE s,o&⪞CXRK^ٜq(KeNrLUBv77AOã_7j&>64,-bXvsdg` ͒ Ƭ"L(w0ؠ(KnEYbԛ"OAz*ol>`Y)KƒtIp֠xv'eiC"^J&m6 XA:<9CglCΞ=ĉ?an{,; g O؞f%辠W &׬ST]xRJS,%M%bVUO3j&F=]EeY-gB,LdqXҟ<4P2Ž1X>L1:3֯EXH4aXz0A6̍ӼP"܄?k/kDwm˳a &(m؟|`D3Af-Hy\֕`Z"f_Ja,C;<rЯKiOOveԎ¹/4"_rc] iX6U'W_zI{1IR{ ꔡ@J~W t,6*e#=8 Y[ݻ㮙(sXR%bɯ큄Y:7쪏51w#0Ke^ Xƞ1=ǎhR^NM ݐ|IBZ+ZqXS: v!w}Ɍ,;%yd9”,tYv$mJh{X~R^RҜڸI%AIyN}(~2}*#AH^\1 n|bܞڿ`RX8:\hӥXڵ<.%M<_,XdPbc$LdK ޘ3urX1?dRcO>oxN(9Ka'cpsQ?Y.y$`Z@a6 ZRV T`@Y0aR XvCS[$d z-:m,N5&E0( &F02YX <:߯U[ :N$,!Y'[=k k=5%4aE^۵k{K,Dw8Lju7hJe]%8-Yc>ȳfBd% %GW%J" 0&3j&۳t/(Y) ]BjeiLϫQ̲a,^F(Ydy[[!Y 1=|YgG.*9L%bT;ʀ%"Yw3KHa 1 <[4)#o2^2b(2*,*C|Eì{z'RR"ޅV#(H[2Q&XZsሏ),Okwh)Jy@k]TIJNV|lfU!S#cQjL7aN|1e<1vYM4A#b!KL&,aV(h0N&KBs:%䱃P&J I̲s1&˿- jb=et>«AG,YSd)Nv{Oq-aZb}*chq01,M_0h9 z<8&̉Ϥ6{_[Y$щ!L͒1Ȝ ]6jІK֌t,EȄ`) 2NHKԺ^Y>N Q,45K}Mk[㧯-ay0k5Sb5 0ξ(; L\a¬̹67-f"mnL,tЬpJnX,ٛߚe- JaZԹpeنK,* m#Y$=~nE "L [0suu1i9$28ޕ2X´P6fi0a̼\ b 5Q"Y0y gylQPFE"hXKiQ[Dz ҥȆJLv-%H2nQfsڰ\EiWy/Bg>`&O>"l ˕27Z\a<.,M#JfJS\Q!XBR>+ʡ(Rr(yUX:eF"NHqX`灥gYe]l* c:#&X. &˒%ُ[mblt=%%%;Va.MptwXn}e+Ǯ,W[YVn4˵,{X .<$,W,̮(7%àI3옣nkE:W`\(g| 6%̬glI2$ᥙfr[O)-mvbYR #s, = Z} Yc9ǐ Oh XHPMR4YNK2)QL[3aC2ai ;FĜg%7jtrꌛ#s$+Pl=WҥpDP>/t$U=$XZ*Y1s\;eXT/]YfVC&ɬW9f)tٴ hb2V`4qѶ:^e!u ` (>m@nltυv:4m6=<g4xF~KS `sϼ(s~A `3 |x i j O3W1Ы3 Q^YMt7?1n=hEl$~pxFHuF7t=?5 pmUu}̀Η[A2mmq;ϗ;>.x!X޺=m}~׆]#rr ȣEl8wl׆3c}ƶ'֝F2~Iw!??1x}ʠF6*żv?]l=/o6+m>}o{~ghtҦ{+x؜yla`yН7*㥊`bC篲)^^,3tA}3sxڀvVѫݗs1=usc~bW&\6paR'/ g ֣v7M/;#S] aUV=:4 n-jvh]̒]lݭ^6}~xlU `pl>30v"n-yu*7r|}ьLwYAG}l3U,LvF}T'f=+'1@V r]%O#.3@.9Pm) 9?b6%f?l1RGF'Obt9i>s> ׶CDHdeFl˂V@SwB]i0He}p7C=+۾4`7XrOmD13]D~? c P*"d"]d%"-nP!?C I?S* 8Y*C'j0Xb2Y B)g3˪PYjV)Y*Țwϊ2Nm\=<}T̊; ư+`Ϙ}fV/340..}4LL:Aٶ~mgوt[hs=a-GmG&&cݹii CgO=ױno᧯8c "1ޜ'[FDe 韈y}Y"houwFyU>2 tOb}'[dcJəʅ .?F",",VHtyؿ^̔`O5 v5mtrϯ)ۍO֘hy+>ܼ3e(hϳlpoYaiclIO >Ƴ8$fS'4~^a%00,֟K+2@wæywptVgleDZ+=9;yb-Xы:9{uh4Xiv@%ψAU@;An"nbQinjҴv`Hda<:OO0ҳcvB휘t_m=3z1K(_{4"(fcb`A$Ssۉ`M?M#̰o.0Ndz击`%frPqTkDkޣ[O74@eV:3 rs5O[vqDQn /<Q}T0"1-9 j1h+fSػF8Z)qFYGvrkt٥J { nWiwʸus]Hd (fo y|'H9=aKn iɨ$шi'ڿn&117$.Ћ6{W O'7!B6 ޽֊ R0Yha_˗'ʼ_b"XHCx9W(0O~\1wpBN`Sx|f *_O3 ?Jr r/<1 #yL+Bps hVA *wAWLpc$!"!$G(H19&!t^ 9F/ٙ^ߙ#LG蘸Q& o7w!x';`(aIy/ۯ{pld's7#K{!݌{I&Χ\h/T`| ef}Yq&~w;{;3WzP]bfgW\]'O#@7K5q:!гב(@txz8a؆b*m4ܯC}_~ lq`/{fI@ ^/ ~ޔHlXA[ٷy0݁iGiLh$;3HI`9C?V>#)Q9xywBlskIJS^hOUa Wy!+G_-%2!23}2cy\ 5CV552ӜS9!cs !j)r} Y9eS.ms.x?MMM,R{|fS_C>kig hbZƍN+:ؐL= H/p-ݬ| XJ&P'Za`%PmoO`x=nR׀Cjx}q?]BйRº~\SHcD"wPHXgG5+ z RKe B,`8cUkǝ^.x 4DSEB~rp5aG˻مsCym_ 7oypBF[ !eT Ν\#GL b1!D1Ebg =!e [/6a[?s.__aA'V6I>q2:Du[ @Dd>/]xᯎ?gjtO;SLġ'ڣ|OB4s`4tlo  A=#̎ɋW.(:B/ 1#ea _PdU}3+ٴPߋΥX*CqHzJa[//-uFpǾwZN%<9Tn>ОuDJB` ֆ3X`䧁/ \$? /\)u?;d[0B Tأ[v:HHJn@a†S8BO\F">,37?/}֡ ^l`P׵K]B\}J# P5IʅIE=z&g{!zyyrks],@E]%jsjcv8uy'mkm]>? A3yANڰ_/OlO,f+;!O؂,/x#:?o}1/= f6A2'EIOP .=B9aoL$+Kn N'B-Y*O},\/7A%ȝ9&32#WBDK$VPђ*hr#fff"LspB@d`ƅwD`/% ^xzV[Ox簞'/1gl\2v u.ﶷZV=?bl7=_8c3p/ea*w왮4Y0yFWYhC&ϟضaDlk4Y)A|B) k({&E>ʕ"uMxB6S z ^ 'V}Mڋ >{??dA{ hWt[~?Lt`Ktwpk˽i ^(4^3ώ;uZi+=L#Dn+?Q ڞ\vp ly ZzIcAB)#ByG;]P$JPQ&6Ul;O+7T +` 6&a5 S+<-fAA"O@i?.Ujb#GPl4g5@/ E{5(zl9\ X\'=!nɃ v/5O2]ZvՓϷ<OL4^l-C2fZ|`K ;5LFJ +=o-c~~ O>? x;/6̲Fy, d[[O̞T4؟LqwMB*LO=yp =n FLK틉^)l"a/2˟{{`h++7hÞGMEKitg00 t!GEܚ7%\6{>Em3t*"*bcF6mz9 JRxB @ETCITȪjNF"@cCy bw"210jLq@6-+X.̖2HJFQI 0PK1A0յݬ v^(]L7aחx3)\M>m% {Dd8^h3.=iy^B hxq 3a.Dhm2"PmdZ =2!24"afy0B7  LEqI.]񄳦o !z%CB/f]zmr%|DRm(Cا`/L{NF`HfA'0d$r ɈijO+| ǛD!za)c"Еo >[K%`N @sAsz\BRpyz^0?<'Z`=IyW | {1Ĭ&ʏex@J$ q/`E[D꣱>C~`\ak le _ s C0EyNE1i})@;*Ї1f*qI׻mH{z\O{FE.uɛXV\]dx1Pu5~. K!qS)Jl1<1P&VסC|yV{"޲ gE>OL4?+N%ɡ7BŸF/ȃXPm MDh:4,#S?H 9uS ?)RD? mp6<] 8L#ROR ?MCD L٧mja} b@ pn*\*J>I}OO_SF x8+̬]m,ID\zj1 @?)Hve?bg ~ KfŋTPWm ؂v{j3%9 r6;vT\!0 з󃃖D}B`ZKLF,ƬI ; QAJ @75Pl | P^eTjL *b{h"0FR #t@1ZB{v \ZzPf A3侔`_Qb ޷RJ X2-/O5 L$$2Қ@ӷ+T8фH3%DX4EJC x l^@؆}C8 yS,8b3:2-TA4z@ UMiVdu! j.$90*.O'LCw Ƕ|.fZTBKO6a~[[v]n}l (uM5CDLCJ%|)\ ?bg4d *ABTʘaU aMJj i;rd`w뿱D+͘;^Ⱦ8Le|dp`wĝ}JPeU5׶EIFuZG[ii8ݷ~t~-?A@c?2PQ JanPF@046b b d?Xť<@iv>z&!REwR҆~+,DwŮ r[K-@AkeRD^0!"(Cgm >}n5[KqZG"޸ z)PAi]K13sOmA%/'} ?JFxlhy.^;XO=hDxngA_uo"y۹N j3 G`/0S 0nC˸[š?@Ç|/ Es'CfTāOzJru6Ɂ]CK^-#'Df"Pք튎)[?f@Yg?ݞa2q#5k, -BgTm} ׿qG{\S2"6d4Y±rz ,h]/wK[c̈^Oj}[aUUo"#* ?f;rmZ^RRKð;a脜 0"{aV35VTrQE$|U)!lBlLU>mvO/x0meuL}OlV/ٶAT~RƥQw|)Z^c6]%04lP8ZWn%ʿl-V^|n?Yp'uK}A ׺6ȴ-R40=s'A{}k˘07" T kߵr#%h4Ht#\v/7Bi`#@AZ\Q ?Ƥw*"sp>]2CDM/;ۭ,ܿz/ )ɟn 2#a>#,řU'Amx%OM}͡"2U6שS=FHEBGZ|_B3ZǦ?]HZ?K/Jn˳m @*_.Ydi%GFϺ傋@_ol}n@GV] [r(@QtC NlF}_ߣj'(oMo6:•/4&iݽ?6$G CKx l ?/WL\M9-ov?oO03ɳn\7Bu,1 Azџ z3  #dŒC[Ɂ/3z` {:L #Pe?ڇfmZͲZ6fI-LVKfi8T_#t'8 k% ( z m9*d\Ft_5yEF!.^f= H 8"q#9ES z)<" ^9 +kp y"G(LHq. Pg!x CP1&}+x?)g V:Z[T+098xvBޱ^̋82F&lqr=Cs*ա jC3bF4IG*B&W &D$-l#`J7++cj/t`ebzIVY`kTP'~`3yAHgtI8 g*=cҢ<#sl9TG0;:f0E'JpB&TFF!qਓ%Jd?]^l

"YzAZ'\lMW/fu4£%$A"qDP8cp<(̓SSApz{GIN,UiVNW^̳:Rt{J+(jPd^©64* lOϤ'`*ZrE ӾGuJcl2r@YPā0:GepG`Éc9^(8A 3;suU*x*@pTΜEeDE Mr!UYe+d@S0!g+)sJ)嬪Z_ ^/L|V(3'T=<<9h{F ZAL,Ȍ,DPܴA* X Wg ABuCe!`Q.0M#{k11 V$|,J.8E܊dh9[Κl94lW4is5GeG;Xm]zm:A5⥹?FmxGn`k`yM`,&hf}J#T3 a8(^mTB:`=3Px1c9xJآb[JR0{;ĂX`SM<̱2u6CAz륪ŬT=~ܓg5 Q1uѰeR"Od:(j.cYzR 0f AQi5~*q } :FdExz)B ADF D*l&E+2"`. 'LM cb}qD$^H+GD遃Cϳ@ʻʇ( ]Aw. ;q$DBV9Dk/Vfz%%5a iKH1R%4 rh@ڣwJ4VhI:1Lܦ&j-kQWfB^%UEFiaHȋȫHM23sO.EècUr L).MW "- 5A}sa_|~]tlPObKik0]X`<%G })zJJAm#1ʨ0yTG <BVHYA ƨwVN+jZ@"["K0R`hE! \qLW(frp2(eLmƘ)ZVU#PeM1}b{}ƒV_$9~z0Ԗ" Ъi}N:tσT={KOzk9)r@N9v"$BQ/XrZV6s]d@)'ҙtPhFNI_⃅@UE"q1*66ZuVm MrM&""**YMv ]]1iLZBBr𜟁 !{>8GCL{3T<)dKb{gh6Q#/=yOޑ<{Kp.8N*//셄:w,,zJr<\N2`2@9 Mu\ED8tYīW-/hʼsNwxYgg&muYۨ]֤6&6Z|z /\RZx=Gٴ̑%8ˮ qmcq BK{'´azi5ZH0kQ؅bںLks< >cb䄜/?{JTUC*P\l xIT9z!_j\Dh}Ņ"a*ǵ_1ǀDm輥O;8ll٥&YcSƛ֪F5rL)gwУYiWw:?jc OS`0NZU7{P=g1{f'Oz>ԞuӤ:9Rpx8HDB}o{.)3Ui%Q5mH(Q0&"$Z@28d=Sp @ta9a/"U-#g!c4!{Pأ j!2`ޅ~x̸csƯ. k[Ҙ9Eҙ-%'?tҗݕY[;ka$Ѓz(ʅB \U\WU`;Ip DB ԒAR0 O.r1!,%J!f@ r@$F f}lD$"j $ YVL9A:F9hsAӘܳ񕱜O*TUCF!(A Puxa_Ͱ۶u {`a5f'HMH*Tğ,*6x=B(1صCe,Yg_JE9˞|s :&AB,#;EH9*`Q^v);5WRr9 *H+}F'EL̙zo *I Y[:<<Zy@C",13^B?4wg4B#rUUBj{B[hE(ڗ|ñ~gͶU m :r;G{5ۍ#x~V6z/POIzA/̂,eFBwF?8vBBĈղA̖rQ bWW:4YI4[hʲq]FR\q5Hq(@Hƒ}Pt³&MkM\U iV,,A got" JDbi|"`;IAc|v8 C|PL_t 5 F 5wne( q0FZrD\hƌ=Xx -,%K}{clu2k:Xulirŋ[.er*m5k+M3MSM3M0 j831vݵcw|7o 9>pl2\jw 'bLN48%ɍlɠ&FD%A4T[@EmfAK\3PSĖP#iGڑ&3YjZ\ l]&md\KG'9zسO`aEaF" ʤ9P)!YQ' Bb%JDiА"@UǰI 1":3+ KࣹBU ղΟwr!d"P],[j[$Au4?_V+iK1eˊ 9Ŧ)%tlIڥlA\Ws\ul@ #iePUmZ_{jUg]=Co~}I{깢ia1u+/B9*/H`r^s 11YuPD#A]hw*,DsclW1vRnsMb6]qߺ&U1ڂXK-̴ɄS˓.Rl:5\m&#cV0NfTSgyO&ztpY% ˘X*ĕTIJYM|"Fۮ$ǚs]?/ Mͷ0[u&sf*⺮-a apR`Iĕi*Sdf0pgf..ONu*TM&jy7n߹};!O焗1Okz#fDGg"I>@ۥfz233V &`ST蒪aqu̲XV&Ƙb3S&iӥ]̊˘-G]&U4EI'(ٴ .΢q8i1ekeN_y]u1Ok?ap|'gdrPxQkJ1jN,E+,R &3֕#49vPjvN1ND/5LCtG>,?yՕtQb[dhQu0Zutv ZuY(gJbrìQa.GVKNU60?K dٲdyrqt57sStP?|PU^|?|wޯo><]\cs0@ƶYsr0"BZV,<Μc4C"^s.'?ѻ֍;f:?;?=y$׎_k_Wܘ9'ز=;'fS[{q^yD_M39ΥIN m ]B^SGjl6fCbʀM ۶K1QM[Bhc7 (+6FvbٚiS5ǔR@.i59u)Ͽz͛|ae5wڿҞ~?DBK02@ЉWϤc*3GȄZUjᔈкbbB9EĔQ; P"h!㉳9p*ieӐ1;'&uVnj7-/l$3[]iUBobw>IgtZN#~|ii~|];'G0?;}ѱN<}QaZ=:;{?\,pv1///x:I&^50{G;rvӣGkǎmVR]W׎kvN kfXLdc'YZ3TD.v>bV@n$hSI]M.V5[fK IMkʨm\SGj3еФ6[v5Ӄ,˦UMj4?[N޿d>sbg rNl6};]-sLm2S׵)'c&]fֶfԢKE`m8@J9WuC]*d"K7Xhtykj upyvZ;̴\*рb}]$sJM>EAnQ Mc>RGw3ѣNfpzrK) @ c'[_z t?gx}%̮o}p D$_,ɼiOcgeNb~6߹}λjϼ_}V%?˚-g|~vՓ]l{1M  ,[,1vZ,UU]-BPMQ5m^ !L&C QfX<≋2W[N[.r)MS~uAMӝ~6o"Faץt/竸X@\VawJ7n&sy 6NfYw9t'o~Q߾w,wMJ֡D-^~^\NM&Wx5D:?_ T~7yW{zvaU׋"u-3j=Au9r4k対+m}_=?_=|$(ApjҤ)um]ji9]~ڡ ̮LҭnNp=Y/~~{8/7wޚL&_|XVk;^=Ixy (>~|rXܼyALYszz޺}{2=Hj)e,@^BS?>1dy>{ݻw.ccǿ,+uG]l?z\g~g?o퍛oubVˮ|QnZU7m7O?1Nz{;iWy9'jrMUfj R51v9DYqV 1;|bn^>N?~|~v/E)8t_+_v5w]\@o;5UӦI\ڍOG?zч@;'J4)Lo}LJ7^OϺg.૯L2?'-Y|e]-.v*qg~Ù-ȵɚlq5H )f&!mU_׾޸qG??чYbSbhլI'䮫+ojB.Xw|p up/ݹW|;kgo_ Iu5BPe M'ipn@n߹ύ?xګ?k/>.G+;={kvƭoV"჏?o~K/ʺLn^;<:G&w~^::1e$;?_/}7Õqݏms[&ͦ1Wnk>xۿdr8?]V3"*V7o|/|կ|ڵo}[GJ-'c޻ã;fum׮ g$˱[5s)!C^8LsK}ᅲSFēmbSؾ_jʫh-'&ٲi *￳ae1.?|&kodv<<{o}|ԶW|?>?;}ǾrTT2E)}k_ɚ>a\"!i媀^]szv"M4ͪmmTsr4}r$F3K),弚?O}qWv1)EpӢ'K|xtzу;__oʯƯߺw8tǏO2>;ȩջw?~w~·~E7Eg&!*5lg4w??_+7~o}w~ww޿㓳UJ*w??:h*Jٵk@Yr&L&vs6f8wbNXONN>|t?f:?={G?{|Z-?}uMcrL#BF!$H J eTИUinvM1dvxy~+<~f-woyN;px~ޣG}xnlN5gtc /K|@nY\}ovP{OwHr]E51/Vm%j d29<.eaR9E ܹş}?}_?xl(]c[`53 !XV9aabIs֔DL9!⽏6-H4  c͌YK1d͛oZ ~?o}|޶鷿[nM?<;; 7r4I=y8?ͦӃF>ʝ?/ݾyݗ??|o޹6=ko/~{?Og_q{?јTW.,W^bϭrLO_)O= !0>uٙjNGG/t~ҭ)自v0;|Z!t:cӪ6trj@פ&ᬪmˉ9Zy_o||h{w_/엿{7?qx4Yb';<8:]~7?.VVӷ~R׿GY.d2CUF.Ǭmc`Ū1f66 s1f]Wk|{; .. ,R:@Js=ES,#2gHBXHsbifq!xc??wAT>' m3YK@sd6[(G/ko?x7+v+ׯ|s B_ҍof^]ڝ&?z睷f\$n~[Tq?|wǏ;}g'];ϵkrJ޿q0xݮKu=&]׭Ejl2bƺr9ϱS͋9MbDԶᒨf>WomWb\D[-QQ2)Ĕ36s#`Z.~kyk>x=k?GǏƍYexh@zxx>x<魙_zZn̮ÏO~7x~ئ^/6J)mEвM&TUs9K`bfSM) a׵9FDfo߾urzwSL)F@E06,\ EѐEUc :Xbbׯ76QJ DشIs؉s9޹~ _{s܊on$-iS -8k:9?cqUԳٜµÃ˷} ?_{{oVݍ}~O|;onx6{w_E=;㬏?/n~~pbj,I֛k/=~QO 8Yϝg9).f躦r||Եӳżeۮ%*ԹڴܵU ZMԂu]O)*3xĔn߸qhvGv@F`咳NšaJI͐5"Hd*t/_qKMW6{׆s3|=XNkp*ɹf`vxy>|%C::::F>k_'_'Q&"F$Bժ뺮$c|3 bӬRhmׯ;r֓r)Ĥ tUդ8?jՖ!)1"13 ̝f^9B`% cNd&)FДs֜05LDĔUcN"'j~pޟw b9)N.*s~\KLWa^5sӼjN̨9mgٱ-ޜخ rpޱva͉,km!'cB2K)dGGu]!AJ r%Bhu۪ Rז <+'rvh2&k/ 7P$;_ 56-쐂ͪYUADRfUldW糙K1Uzr|0lj#\jRy`R9'f|խrjӥ~d:/_DW'q&'lcj^,ifu-2Ř)s<9a1rfPI)gI\BQ;빥H9?'kچE$9&mׂjB3Ԅf)%C`qLTG\M\5Yj9w iL\ d5Et"kĤ\*^,TE$f= ru.s͑Jr ܄YrrF*9]+ɤU3.c&ZDT3"Htf5Ř̀)u(aRV)+Nb NڸD|֔rWl̄S5f6z,;, R25ȚUs&Вs<;H.fjir50K/rfT2<m#"eoЄ=~믓Du,LIL e,diė@Sض)']2!Rfb!,`CD9.6`"9a1#,he]Wv) W+DdHC4rLI4Zux>Ĭu4f2ZLWI0lJ,BƺcȪH!b9˄{srF ]@j&45Ƞ$ /B2mLBM8h!*clFGXU^s2S&Z.ctMJ=c!a@$U%l(uT0#!+ -@[:D,"sjj]E7eRxIn)Ij!&*Bvངʥ1*31jBij!8_K'-U 8f$'D J)ʚsY\Lss)E4Fh'*YR3qMӘդH(ℽdjŜR0"005-2z8f4ŦʄQsJ Ҝє5v: 6`S'"L^m;f1c=qK,93K2 !SMմARlFPu 5΀#@gj5sNPE$= iz޿ )@Z6kɤiV`) PT*f1$5ŝ삛8qٮy8?X# LL^i0Z'SRJޑ`̘DU>[ʠTcNm՜B\J\*s MU%콋1( !*9%f 1Sy!ǒblV&jXNf“}=1掦 -F$*^NSb4100t!z6 uBW0E j"p3m6*u]`JDUpxq9y|4OfMt1有h20;SaqNmղ].IʳU>zUU AsΉp4ٔEr.9"Ҕaz2U3}u]YLdf0kn\d2]v!Z>;;0&)Inc'ټi;f7͒r:qp~zc;Lizl\B]ةvIU#bj[3cUMm眬Vu躖ۦ5S'H)c^ a Tөwl퐹>5MS klWsLۮ‡]ĶSKއvB٬ݢY :"&ϪfL1HQAf-W]rfPB9OٖF m㫲msppЙdc9އ]+}? @CN @ί"ZQ)bJ|%0Uuy>_f:3U꺶^w)n)mTW]VUU ir'))=z*Smv:v]Dd2~X,WUy\8P.N9Y4]-T;w}2NCmY. nf6yuĩ89_s$|ꉪx b,`fNDIUժa7麦5Vֈ}c@D]ױlB](-3sKhcL9 MS'y6L+c];_vW5L,MM2tZXxϝs4lBDFmL9[ ak0J)ainEfӪVժȥlAħs9^5+",h)f(ptvclsΓi-u5]jbjSf.UV3S̚-'-r0$d31mvms<"\FI7յTUU@9jZU뺞rѝD#bge3 ӏ>~xdEP;]N]mMu]UU5dr|uΪ鬞 [!P4sRu]5f\V0$qA|@*\$Tu]O9?N3dC_zD(˂AO#XV8]o^,%2و8bUU]e9r"pt(餞TU<#1R7 aRIUU{'K]Uu몚Vts^E;N&UC"H\Fc"qԒB6K%6.fHIRbrbReӭHM.[4er@YQNֺ&h*/uE qݟ~/RPYSJyꪚ8 7^{Ͽ_{lYoܸϿִ͗6e$ =x|9_6uخfՔ{(tG=xid\=Yvw'4PLe2fl6Ln޼yppPdMY;_}R!  ?3# ]PJU>=!r,C%]l[wfV2 "@1l}XY1HeJRL9 NrZ-]lRgD0S2.,,L΋# #V>T{JhViwuG LEǒi2KV AVC5b韗Sm۵mR(}E&Cʀ@rDJUF&>0;$.v9őgeEc1w]|'W@ jU66m<8>,Ǔ[ãlw^ڶd]&7ݸ~LJ s^.kxkrP/W'F&Ƙz:fu=qѵGd2ɓxvWj2Pa% dfV)etO)-K:P9!_9 el;E\W"c%޻ Γxd$ $!x} {/*8G$_afvE#@UKMRTDgÃ+ X!+d--򭥘6ŮeT#3&T"m] 3b\3U^c'F%(- ZH q,B"tqFGãpzp4=8x7~_K/߼}ƭ.T7o߹~v'eCTz9`2i=d2OӺzrxp$>PgL1 WEs7gYUUyEtPMgcbV9A2X Jؕ/2VD|%"L,EV1Ye"k!T֫ߖ7"/5MwDL1Aւ3b1:I]c L8Ti= !8vQSԴK] #zGZ;vBh*%8VX/]ĄI 31#JmNOPWj`avfLB7D쐝F3DrUUD 2>1;ƪɉ)E8D$1FSu:?<<,vժP)|5'S1M0ysN&E9תncwj>CTԾrm޹}],)%@-ԬVx0}GmN?*z%O&1r9/>xp2I5βG?/uNo߾<*RMӈ5͊眂O5nݺD26ɀ 1D޻;"ؚu[B!gqLSJiVWZ9Amk\F ]L*ڔ Ms-8!;xX (#ALؕ?]fZumKB=ARl@HժZyfu6HoŜcrNjOSagmҔ!)\TQ$^p팒H BU.h,W9N0be5899aD*Ycgu]7n>ۧggHj_~׾?͗޸VΤRソu֝;w^}7xW_NUjլV>L;T+hpuggg]9玎JX̀h=TU]5"e3@ޕ xnpE[u20;:o\ifB|.F N9?|G۷r΀x/~Km۲cm/\~}\>z􈙽=>x^>{?hz03WeTBĽ+G9S2r| ,kIHמPa2J/V⺈Ȥ*OR(m0b۶1%AY֬QUcb)%~th/:~sܻ!43?~ U=ErVU5"]Lgmb]MU 2iQlÓ.m[زK>x_ (q.Řf{4VDJw?ŔĘc]e 3YH*ژ|1 {L}m,|&eB-k"NgaݵWm+2l6~vL{.K"޾s'xp}VWU#"N:SҔ7sgggyPϛyK)wjfDqXڵkUUy?xޣsU9w{|rB\+GG> sBrs^ĉNNf_Nf՞,BUŔ@!gbdDdqYڒ 9禓1 Q4IU i$sUÂ)EPSK`99?!hZߺ~pt0}YF |v~>jX. 0u rV'uE$ỲMsy| |ڤ7n`}ÇDeQ.'@ĔS)gEqU-j5fz~~&5i^&{~K養]sGsדJ;Y}ڵdY,97:;lR];:q۷J> 4Mu)%",Bh9E4e4Fdm۶e$f̬֘*NzN<fUդd2cvccLAt2D}K9 Eb{qN&EKF3J{vA.d6:BժmN`69:L*8aKlz8N0 !8_d9 #0z"B]|jknܸzQF#MFB.j6=d1ڮicŦK1#WƤ X~= )E5cc"V53Vb899Y,岸ݲU>˖e\j\.OOOݻӓYj3?ϱRlfu/cy4igIc?G?|Ïg')Ŷmyf"$2.ui&n2O& zb 9+1F/;PW`6[G;Tt2uŹwWU]HqNXT-} U+|'M)I/]`f0s~eo. =ҵvz#)kuj1_H}]z&0B\(UJ4jնmYg1v_~+T͈X86wf|F MM.7isFi6m7jBBUރ݃ykCoϒ*Lץe3S]Wya^_s>B瑼ŨjPlpGn0(LOrvM:9‹*)2]/!"UC%?_U(#R]O`~~w\.߸n٬ յà EW.(jJ9mRJhڶ:)({1`_{#IYY}.9Ņ$.܋Iz= Whf2#cfzYUU==tٙn}9wo~w8iUEf0 c.HT(g%fpss3 qf?Oץ~PrqHm'WL̲SU-v1%/k50cHb*yCL4.iJȩÁvl>l]R$h9qx=S7Mik"B"q10U#b`h!r zF@0LH083V[ȩcğ)wȎTqeGDMU⼃+ uݦ0C)Q;eЎáeSWWWR6&&0c4iEtav7#r]] ݍeru uwSSXEyscq޼SΡ#O`o<c,SRew ΗibS~$}KxK1v]aߠ._]__X*) 3\_0dea8);SWM!ġ["zqz}0Xjwf:xTbnKR2C1ʘۛc2|C`Kal8< iBǡa\4Ʈ}Sxww0 äi*"abR6qT*ۄ/n_ٸmD}7إ__t}c41v\)WJ]m0dDX25b]LK]Sô?a49J @*Im{i!ɛHZAlTp8<%soon6WW;f.hDRqHd!~smvi_+٬P 5ƸR(2GDh ƨ;l68[Zkŋ)L "H)"bAD 5T?TJժu%m&H (jQ cHæC&CMQkrqɢ*(0[ ʔ}6rlm{tF01buɹ(s`&3^wu}}LqF7*Ql%6k"/_~̪RJI (p\r)UŘbXF%qJWVJ1pxx49g?K]mnfUrM U s-L\Ax3KqNUM`)d曛jۇjJ)&"L.-NaLSqy2!r 1QcP4nzcyy!nwz%YU]JU \X-jXUADEmDT">z53=f$~Y)Z p`16HR4B,yQ& !̨>]4?fC"Z J H =t̽fR G1FW_3Ni{7v]g3f)F}1\qUfM KQ3 ]ݾȵLLH.8\v-]K9OyEa1L)MhümȞr0>U&3"_-oiHã\v{cRsjf*eӇ.وa< c69áD!0Y>!0ntk̬8Ly}3B)T÷UDQTM^,#Ů|Ʊ/`mb"uR/& px/@|,ϖm_TT^D"1 xqfO-~a-OU!yf 9ze& ۆ@n]_m1)0A*eZKuZJ"*b͋jz680⋒ۤ}3[X @0Qk.'fUu/W3ӕ\[\l)ÅӑRME@C),Yizu hP#7E,/QR-]K2b R2B7_詶љL6ZOT9Wd&uԪdAt1Q Sy A5 leҨrR"3b)>"n9D&Iuחӥ rԈz^b)q8 1@Z Tk-E 0r/_L}WMcL[BJhtdSq8xsvf .-V+\E/>q^7ۧQTEeaXϲZ(!B dfR2"v)"n>溯`怤V]ZhaCb.c !y@DPdTc& iٖNe6f  ۼhՒ%Ў)@da9yZ}T0L&3s0*mZT.tnA+G90ꚸ TS[yuz4WUeʭFR A\:frٟZk Q91ln!޾xЕ7%9`3M1Ĩ  `mիWklš3N,3 T@tv=;~Xu!T)5g"Ѷۍ`Y)܉vJy$oV[ļORLrLH)ZF"s`1FgЀL TYoMQtCwninwwγ3»w4\L;]'9Jveq?obL]9LfPH?"n$sa"0_:&qЄx#sm3$!—?ϕc @fI%V zDy;14kT,V)ZX=0 AАc1ԹJ]]_2T4M52J10A1_Wۭ+8m]۫/_682-pX˔r<@EG普bCr0gXRfR 1Ͷwi>6V˨xPS@3_<`` fi.^:&_ڠm9q4kPZ520Zo BB#m]i1iʇÈ~ 4 .ubb0gXзo~"H!1 bl т6 b߼砖fflhPkurU*^vbk,%9F df%!&Be<_ݗ)Ɨ|':2f:P 1DB7Bꪥ["^}poooOQR\s]3ϖKDzuD5]BiGJ M]JU#)Ef]K=?C%طZ粗DGopzfT"yhhFI]dT+3AV010`"1;0 Cg!HM0牻Za~ȬfUM,3Fc~ "gXD8X$PlJi2#m{ j.Hu@ "CJFRoYa"0CZ ݦG\H{{h䌈}_mwQ8YSFM3aWW~_Q5t4M_|Q10 |}mTTY@9;^k͵u\@ ͬauLBZ@^v=k@ 2nnb[i]&b"w)gU L.m xƉkA"U0T#43EcL>F#/kI#)MJ6WSáJ̆ Vj-@lV1}?jBp!DTjX9ήWuˀuZ `=ybMs!k@ f'\u8P[I RJ)4?m 1D@?0H`Rg"W_waRfiqaPGWJxdt*VBST03rLQ4h(j5=՜R0R !< ُ*" Vk3Gݩ1 V UjPc@#8RL!6aG8á Ϙւj6q 2+@5ht]Ps9!k# !ԩH5z^Qx8ɊG൯fCD4/(L)H!q>pnRuݯWw~|/5@wjFU"2 0 EmmKc(#}-#"s)`nj5# P&V2n)I-yifDz֙K."S"j&K7^TD$ZKL !Ű!H.96QG(p RAS5D 51GHABf8V-ی_ntXx? :QZe0W^Ɏ!F؂ϻ; 2ϋ|2xZʹz,I=)+VGj6qε L @'e*HŔA1LC`)K1FUs8 jTi@G,3"L!``".r<h} !1#CHb*  HU0XZ LTVVif 11x6ޜ 5Gתh5 M;tT ąq"/wJM%^< `"" XjAMԷ~}HDd`uR`0W|Wfc|p/.RJ-#7|p8YM&4 0|ss f&"71O9W(yUH]jt4kXzx dz i:"HZXFh}G uv SIKSuMM10a*2N\aFscBM8an1rH1OIqCy 1 aIX|3`&bFH(UC΢cR@ASfZsY" RMvH?狚ښPHb*Vgb5+QD<Ο;A}[אR M3[wG:'mWS#8b/*EUJ>ZsEd^ 믾?~YH}s@- 1#v";27ZTj H= U$Թbp_jR4R4,CGbk!n:&RLM,XPkIZ9(5k"j.9anDI .UЦc"a͉$"MLkpԀYaQT%14VlT^Puj.!ǔ5d"&VZ_zB_cW q ᕅh=!P3j Wk×*by}RBMg̬ևR3m K ˗^c uv۴Iű?C?ۗjP10 #IPemJE4MVUݏBc50 f{4M"vL_~ nVEܖb":̨1oP qH];ɤTFM7} ğD}vn{fF#- %t6'ɲ@c2BEU&%fF1( ˯^g\A"8_󊈐>V i; P2M@TN _!?[5pM_NCd s~s OcRVv6ϫcd@h3ok Y? *O 1ZsqUֻol6/إPesQUaG!0W}u.%u0֔zdA~_o61Ԫ Q8oVk1*i IUPM"QBdT"KQR ."[-!v#V0oK*Z-V֎m`. jEJLAJ* (fjի} 5_xqu}/CCQt|֐j(mF<6Q}#ޙ/,"#4A9Y`Zyao8pT$lZWWWsӍ8czwbn3sґ*Qn1~>QH ~8oo^wvB7=x3r~ODl][q Z#JmTdDZV5LnG(%/4!K 4 h~K DlUT%L]cֱjb >m4hEd՗__ 8qa0%>O] .(1,"HU-1`IA5>v]7~! 3jSծ.i<1u)~sXšm(ƕ,Cv@ pfRBg>X暛)XtrX;2ZIw-a]GG8LcSB4Q4~7J?cl6VVrbZUTEʔlPt)mMJW^ϹZxx}ߙYoTdV0lf-(uJJu]sڸ8 MLݦCVi :d]4My0KL Lh} },Rѵׯ}_9,R;5t12'6U-J8ebc"RAԠs﹐(jV b0j`@Q9~HETP#\j^Jn?Y7bTdi7]+ӛe$_U)ǙO_nza}hp|`,۸nb3ng@p$,˗Q4g*ÿ7_}}ugei*%p< O3@>sww5u9p/|vaiiRn3fj@@k-^;woTmM߻q3&$]ݎ9LI* > 1MR2r .e\dץK!2;DaT6aHUX5<*g11)((A1 P|Cqʥ(O]NEqT-R'YVǕ~46 ō`KK1D/ !739ZӇorq'Efu͋num 6Pyz1rnUտ8O?~@ W%0B"py2)%&򪠔bUtޭ77|suu= X23;~a8lwSnfPJ\JA 40~_6vb.cƇ%>]u:pʓv7RVQAh )@J\7Z`h#o}OMC͙FZ^qO>Z&Y*!0u ZT H!V$EU58 fUC1ł!! kRj0,Ns6$cVo䴁#Ϟ1˛/DZOF2" +i>n(P5Y'm <5 >,/EUi`&h.d ĨBUHE&3&gf(M7ؘy] xjPAŅż6OiGBMc0bkq6C.C真2`KQi=3k /^LӔs!O,yƼmo^lb+vO>)Zjɷ0 D|ε*ZŪ)H  f(!b:EUM!J#GM͗bOlU0c)"9fhVDeTˑ18A&@ !2&8E0T^P,l.7 &`(,XUsu@ԕ|NF톆ϑUlC0*K_k'UZ<m0Qd^yњu|G@ h a,thds\o~z햦)؅c߅1LLߤ/^7A%Y:3viaYނu*bZU\ nYU+TUu>fRELUS]H6KX,ĚseJL4f,!r0U&MJ)hc4"b@ ,&`h-R zߖ*f'%L9!@ECO] (\)E6RBZzhضSoFgى +u֬DNj_ПBYGú  Csm\.nn$Nri60\G>,V ;:BJA\z(Zj0b.Ť AU}r;Dv}$,ʈ¢"*̓^yƔ(.zV8s[[@UZ-ׇs+4eEGZיuُ;jWFaZ8j? , |)FSlxFSP0s0 C* 8^Ip;bgJB-\Wlƙ} ` BHmC6DK0K]r&D cERO7F6ElStvΕ/@g~|q]KzR\C``b%!vBrTRcp(b,ELmkxKHkVURE;8<қ,GLa=jݼW89` sZEQ!P\,،! W'x]rzF%= ?/^Qa8m43fNXzLJBCbd2&J6o9ϒ}6 (`V3AS)u\ yFL hUKյFW9krj '֟%;'͂fԂ Zl4u$% 68S?4Yyx`w;{#3bs`' ъ:xx=Mhp4"s o70yM lwAĀ̀$jd.a2%m9"5F]1s.7ܐ#Xz>ۻ @ڠH}$;.|hgeV fr!R{G֌Xz ТX dܺ?FN7g2pMf)*>)EH4 Q0 m!b{DO{FGê4GT?ɾ̍t- zCۑ9D@l%hժ_m _g~΢moI.8VcY3G14Q0@4CPORH [L4GUs9gVBd/.^ @fWሹ^8 NXp1`v,$@sFy#8Ub7+`Bb&JoSbHxwynj"_θG=9Xo;8yQj16Qㆽ< sZFn*21DN89?=SKX=l>iwފ 7B'tX&-GG8żW/sDtd26nfvM])0tIR@q}ŮyF)x I yZڣp<%J4@|<;P0scQ3^ʠADtTd-|#b/ 3zO~.{%:GߌgsDV"pU4E0'֢\$O z<F ]_z!,$(Ծ"XL@-9ch uxEy5p3laCռrbE_lXgŏ370T ւL#3m61u3ƼDDkupsO8DdzRr'zD'}/" #,l;S]5ڋ?#'oy/&*>`> DT `u9ma'X6 ڒcXn03pl""` \oCF1K@˲=*4Ěܭ^nܼܥuq)>fуyf1Hsfs7MLCUEU]G;]rGTF}??뜄12R"p%.ߏt:IQc +i8IW5%ߍN̅j-[Zܷ6C~ 6%? OCcj<-zNDR%zSƷ\Sv>$,^D]0 9H&!dLPIEUʅFQۄF}Ws!hG-Ժ)!P jG{D|~jxL⤯Գ2"2ZS#FB{@U)ZhϢΘG5+Et}[dQMBo,2fTZj '+n}әGEi7ˊZiEժULQCCP/yA^K5|o-"=|VHY<ƚ.x<W3 ߹NnDcG$>IQ,Ǻ4/1z[@ff}~E91k\g%9pͳ"2j&ҙƜx = [ (N5ʄ:rnM0C 7FAu. gj6.+H935 ,RfRjzx`6qq!sE\\Y@r\#}-|ӳ[w"Hڏqu+ 1fY$WJb(JMUTu6XLD=:~[|Fw \j;ۮxݠ'^oiy?ֲȎz>/cdgL@*P,@Gx: qKC< :w[ 'Ybr7n+yLOU-5qV[VS1ԛ&Db:Ɏn}͎ Eg,rvñE9yh+t]\<ዠ9T\~v߶cǝlyD oEu.La!>;s]Ҡp.GX9q/y~<.MUG7YK9Ew?T#]l pQeB zlA҅>gG?6'C!Ip*>vq.Tލ2G"~sLx68, 5;<3:<J}aG7Ƕߣz6[S<Z ?fӣJxEDڄ@ATu~G>2R!e^vωv/>y/Ӵ&޽Dy[oƚSsS(98^=]b!U뜄_?|G<3-=pG;S+W|ջ!wg{NݟkE{u={x~"Y}?}Dwo]_s<5wAU' sE0AdO~|i(sx݉lBcߞf×Gm?o/\xtz=ߊr C=z>t pђ|vQ=rيr*P|#?9<_Z!՞#sx.~9}!ug#cDg$Oh5!eTv; mnQ*K/QvBhXlϸNN͟9Zn?98|! Aqrhgym_0¨w?{6 ~O898Nq9E;ʉ1{CPCRl2{3?/ iH 鄆Xյ9[ǯxA#CqRH4rs.v zcJ>NYR-c I]ܴ}S< .c79vq}a{}ƿ|r'tX̜E#aR5m3uweQq-'4_q׷1~;2?n/Qi-Vlrʠo}^R^PHtqPdv;+?og_=pQQ^d/I=Y|oaNW5gN7-2E#{15W2A3=>--3『$jPɝ'ixJ5A1;$q>4'1;9r߂|e?i6>T%4C8C奖'w96mYkj-VoYFo;~8xor ww[n8YNh7?Xoinh{5㌭><7Π8;X>t]R?j}3箋9Vݪm3/ߜm4'c[ ŝ f<7)Ӯ3V<>j4fRtz cDq2+Ή29X4mVψxXV>pg%(~B~t]:6zܗ k҇cw#g'W;r. 94r7he' G`[P>9>0y$r#0xmxO&WxQѝx߱Ϲߡ!wG׌Gj|O &{ϧ ԺyJt|Kz4#nAS aרQe۫QgqYM>YLiu\,r$On@/ F_uPu8yCh/$x$rq߇ZZQ qCt _Ipt-amJa1cg,{oyFϪ˳ė?{|u,/_fE,V/e&3n ɭ[h\;Kǐ˵dLO{zJnñFnT7oKnPӜ8W{YlF)m_=׏1m^?i2@s%<1fYW?,-?fWf[a'P^ċr4zRR_ |caVZC ,#"~,h텝9z@ }yWny#kWv SoݯZswB/KzķÃz9٦%笸Y;x|Kߛxm_3X㘌x-?p?8l(ʤIhܶ]siZe~Mno;(-ScNkoPc9K^dwڧQ}\`ډ-}dg޶*`Τxgա+33n&s%cӡڦRh=}l۹mXn 6}"Xnͬ E8὏qys;N\[Gݭ%FW^Q~AqbvY Ix# u/sfՙ;hYnVgeٞ?eɌĭ^9-- ]Sa o8z\sew?~}';3dpcux4{߱O'U췧gS2apq=o쒣wxi~] #<ϱtbkp˷צ-;w=Q<9⁎kp|̙3;+ौq5~}ee߶b|eBKx_wzҩV*f? Eqf+i ?zĈ{]ہg_|(mqse(be+>0WBkr "cþ~X|V4=cu 2)ҵ8$~ϽvlW=etB(frވtZ_GkgvPSO B)NDOi'uN4x1 O颶AEuOC36kz`;trXmJ}lQ~EwdIlu杕!Uc⿛(VGq.[v.cDm/퇬+W-07Ixu-e{z/J"3lGq7(=B k?{67tddM¨[c+ʦExukbt8fdҖb*b ^,(>w|rɇK7eW_]^+ ^ŭ&|We>|Pex4ŵxX|8ؗ ?ڒGoQ;7~I_XϞ J5(:َgt*伭`zYG׋9{5_t|p2M\(N/({Z-Ϊr|\h2-e4-[/OEn.v_,|vSϤr>޹irNosK ٦,4=d K-ד6T܎,uXdza<8,IS|3{Sv{]˸="/y@Ͼu) gn^׬x #O&e,ӳ!eR2Er/{F|E=4_~|CQ?OPAaюi?Dч*f`_~ۜ'/M_\n h3[Ȟdp;O(~<ggyiWBi^G7K/!N_VVri 7BBEn39; qvTz|r˶FW!4`Ɵhdžȟu'ˣjk^ͯ\r^c:A+[/?5'N%D~e/tɇ͊v@z'*;կ:EG|4=+WѺƸ 6snmjz_ojo_bt%jܷPdZ0H}gF[jhn*wxo#5YgVw6dx ev{x8ӷmtuVΆxCmq>vTgBw?白?n6N273.>ۜŘBcaɊmlN?;n/1&}VCNK[7k`Mx.OS|#'eVhm]I_ !?[vn/{dhxK_=Ӯ/Ƚl %*>,-^/( {OÊnKvϽ[OE%.ћf{nJ yz嶝E*rz/:#I{cSf\V;t|0B‡O(Veh~̃ ,e[?'鍀{~Qx] oU<}L3pt#ۀ;}L2.o}WU|zttRe؞*lܖeIXyܣۺpI}u\-#>hH-[_㩲j}_쮶3.Ik>籝|-.a~&wP=\5MݬW^OR]Hk,̶I{GW\^o)z }:[3̐Tݜ2o\v3=AfCe8Ŋ,ųiyﻱ&/ՖDzP'oFNO֦ZPğ(|Mhz]B6]Ĵg=~eçO|W}1/[o%jLV;VLĜ8`9GTDw- #,Nq "(Wo+>dv$'m촲ٻ#`ƗgŃvoiD5k{68Ԋo?Y@KT<`Qh1oȷ(~ǢQ9qFLWf#܊PgȭZܱj6nբ]uWm{ w+")n{4{^N.xwMì̹m"mnM4߸ꀕJǓW ލOwiʸd^a2LpɱA;AWqszXhiMa7H畯}=X'Fumt>Ÿ|ИQ0N OV|{Z o7sYȂu{v`l!t[n9G9. tD% XCS\KXê:XhJ@}Ƿ>Gꯦ>=+ m)9'x2iS\gH;Lv69{|*ǷTӣ-5x_G܍U{ů6ɸ&O/ 4Xoew8HN֌@Is_fV ?6L_1=n}r<3f ;"m*=w\7C 9EA5j^rZr8!inGqF|Pz;mln{cH}q3W|*vC вj\9WOw]Y '(nוz)ٕ(nuCenelp6Il&S:ŧ_f6 ҅w) ף2|n=sl=x8]]=pX=xVѱ5wDqBfi,b|J|<>^&vI~-0[.9Mϊ[F4M ]Tdc8^=_tϫfR8Ned Y(Qj\ps'+ۼ4n6S'8^kN^胼fi@+oZ0"^`DoI14W<^hdx8ߡ!o]Pg 狸cTܽtV󲏅E.lk yLA/,p33'd46.OQ<lVmv7Q,s ߋC y|2`ܘ&dnx.v[ay Ookﴲ%s?}j}U1/z^>!IN_ڶlo>XKw)̴B\Xp鱄yQ^&3܇roBLúMlۮ:jqacύkÞm;.Ken;5p ":qꍂI/ rG7\}zC *mϣA3i(Yqk+v]]g) Y75E_8/-fbዖ;u'aq0U4W<2V㄄+5>++ODoNon_BYY=[0qZ{?_ϾkUEYoc]X%!K]8N*7W>' K16Xen?kx _VVB8H*\egnnζ垮?T֝f"@ܦˎ(xt}1V-N}N`(>-?\[:VS >@_)^89qvo!yѮRޗerBrvlkv!ɅY'R6ʜ܊J6\⃐b)ƽd:|GW>˾7h7۰k+[V[kqP9. C^Γp f1;0PH9~Zy9w1]7@@/#i>#6qsM1xyT1"ޭmjIYޖB9e{Q'5]&<TWyV<S/( %' >lW7aMP_˗ gCˇts>8h<}vy).q9$Wç{J!xU?-C<.͊G\ X}l :Rɱ$kVćGKE;Gx^ۻ*}?^V5CCluvm*dxh-Um=-R ~)TE8"Q]e.v 03GkMr9,!_ݴM֊f8R ͷ*^[+msxӈXn2˾xuS|)DBrA|4ފT-OG>>5ã^Fq 9v!ƽ {=M67+BNQ ɲ~m2⍣Kklse2Y+ 6&mK;ayˍLۿ\qioz.?ww09_Kty N{}&@XV}쾊5Xx74m k/EnrMGQ3':=@= 7e^(4?(Oq|3kۖhd=1of'>3'1ۛf}Ԏ'E|N/O;'UK򁴊bjlj#}?>^Yƴxs?Sl3ݏ,zce-ûU8#`+&'//@Ͷ[pUǎ0 o;3R&ۛ#+pj/`cLCdÍq?n[Ю/Rڥc1W6۴j~b<~A>Esrѻa>ev_(|+C]۔nHzPv=aZuSQeyRm$G!81)yfҍQuR/my)ޏ+zgsfu7ŵD >ЬS\NqL"no{LZgx'}Wœ;[_6kq%19ڤ+.9fHP%Uod99-6M9r !"z<owM33hl~PR]ⲟ<+'L973M1%w*0~< oV7>"\"?b\f.k֏` 9C7AlW7S%hV[}܎/Tt+mk+?p ]3ˁxf@u0ݳmgxͭ%G.Px*sdk.[5ӳM 9o!~<˵Q.k333B1HWqk9n I q*ni~|59^To`ϔ6B/=[T|bnC߼ljlU(چc,1B% q~5yL{w-L_εTd~F)xx͔#|Σq2i>LT] f\m˥ oB\#{'0si[A~fgVu+ܮ?[ZY޶7wnf-P\ ֧x\-ڇǻیg߻?y wDB,.6:-r99(WI#[P#fjzl]P:vrB<ᷜRخ:} -rBne#$pzS\z5}{B<(R?~9;wT3^4Ϗ?{vAǽFKvҠe g61ޖz@^mQ\6|q;j2jzK⾜=+Sx J[7#ԸB: 87)c Pa,کҪ΁ooZHs?]#0>;I5bUKylYz2޿p/T6č{xP$>Rjt5/D$~k:^>0 w|uG9T_MݫN8nQ?f'rɸ߿>PC޽j8 ^)>纊Q&s^Eon(nǼx57^!@vHS iWnr[WQK ~xd?l_ŭ)?H=a8)lrP-.;07;DkڲV\s 7t•jS#WH4^6qV+n,w#ݿ(4\_ދf_Dqg=[PeoVs`2Jr%0ۙ )W)K~7ل0ʶC}BoWz܀nElv$62]Jlx2}3<ʶ(ds(ވGFDϨz9nӁ[ oWWOhxfEgle8Tj:QvV]tʿz-\\Vvj<jw@} ~Bi`xWOdx/;ByZnuƻ%TEqcp\x3:q?`zOb<ݓompѮ[!;%c|(⹬l:\2|x-S^vF<43ޖ& -yyǕoY* Xm8cCSoř^J.oaxHƓvK0o=MCG⟪c<]1!=zsí6qo[n +ۤ^;2A<.G{H|+-z'2$kqd[G%yqoūJT ŏ[6[XGԍGWɂ[:Etue=~Z ʼnB[.ǽb$q?Uk(xDu) :e],~OVr!x$bx ^3ᣥkcq6 Q<p_V|ԲL;cP|qTxЈv\}yl] ~T>y>54;.<x6tG;xrƋ<[4O=-2nGol dy_by7R<N0 o8y\?~'w>?Y8:>_cje~oGcܦjq 7n3C&g.<Ϻ>] ]9Pӭ32nPT .o8o0} ceBsXqNP3f[3iNgQPw3ܷ_exV3S/DY.s5khC3G`_֯yC} |9UٺF~2M3^jhnvSy!MO ^Xn{;{Y1^[GmCI HОߪ/&\x?}&u"aq ޹BW]87;rS\ݴӌ8u:=9HJYmw}Fƥjcn@|#e.")]M•:iq#቟; n.vF2ִ) #״xlW-Y7g^v8_VKsW|?%FWUFc<}~$]ƫB| Kqs!Qw5%JU]sVwv9TjKt;>~iy mOǵEo&[_ZH9|",̤iQit)٪ωii׼LoXc΍ !7~(=-qq'F^ĸUrf,Sa?O?v#<ՒG? m`<:+⸌nӇ[ϲˡ\ _WFC(gۣm"ոocmkڬVmOiɶ0฼˧c6xyO;V{{S%tGˁxiZr5 tg-ݪYFb4dž'W ZCqy)LFgSf`o,d 0wPOmΫ tK3|FgH7<mU0me_@Ÿ< ν-bufϸC|6P\4rIkZƇ?WH[5U_i~|x;>7'ڈKqP+5p!tyXOB%7x<ۯԿW ^k[cZ{"Lfd6tϡjEٚb5~o-O Q\瑒*#궉|"x?]P|rJwⱆԭ%_<2uגö7x[p*>iOoN{^Hqp%7)9W7c{wƍp7tc/+'mQ㩸jx~Y񛚛1xwXʇoVSܽ쐾OϘ=p`msflxbn2겅QGzV͑W(Y;l] vzTP̱ܺdTϴ,-8k/XqEܡb\Ax1exbe<~֗AU\gUbM`R/|ϸ EZg)b)|Wj"μ8DzvVWVJ0%/~<I/oIe w).v>)k^[q Ԫ[ :xC곈_/"3ޞu6x[=t²9 8Ppě]^Y>n^ Vx+:+`zR\➊{3^InI-jG[V[βkȶ0+N:};rd8_\q^&{6Lxi2vx|= )u}O*g/Dvgs2(^3^#kܖ,uD :,-a|q5Q2;"zKsk#n!<W >G?φp\ JS^с^Tx9t0g3Adܺmh>A츶}]_Z{"k.o;Ni;<4!:KW~nو8OYgwWO@+Ojz߱ތ7mlYk@14r_vƵqS㏼!#e@RwLO |'H qǓۆ݆[%S?_sB$?4PYMc-OJ'ۜiq~Sތ oւz;I*[d!uC8'Gg ~<|iG[7h5ilVyq=֩?bkԭ{)v ŝe$tv3hE]}Bt#Rmd|s Ѧ1QBkWknW^)ψ{ۍ;6}}RucfW#(lTхxKϢSqt?%oJZ93( qu72oKhhQKqtχ2C\M_ՕqauE\? a"Q@ٱwӋJ^ Ig%Q=-dxu0^Ɛ|QH[FxWwe㺞cWǩ'S@6|9&Qv};ӳz EEMo/ߧXO7y~{t[Y(gP|ۇkC (_BKK; WF75~aWNC8Hqc~qW b=䋥[&~L/W(.ρQi-c2EG)B9OaFgh5ܱ:>/E7@ш}X}'kǦ>QE|s^oZBٕ>*~fH\(~,98Xk, n|ˆ /~lz/V1xk[qs˓PuaSþsmePbYӸPG4)>(fk{?ŕ-Y(^mF}>1 t}S9n VGqCNix=ln+:^+`IqMwuOajeB1Ñ<hgs\?F9{0rALJ_4|;dţB2Pp*VCͼQߧYv֭y\1I:t]JZcx(NPKVT\7>_Q<;}BY7Y1;n*nl,HƷ:uJwFM!h Gq+hH▇n3OKq_a|Mf'bO$w\Atc-Y?>ȃ(N`osֶ팸&Ӆ\#잊׌MOچ/;ōAE.q^VW_mq?6VZz,H Swߘ0kv߿o??}10m?w2X6x҅m-o)ۺ<ΫΊ7Q܋xXWZ8?|c\#J#& rWf\7'ەעY^Iw\ϡhbM}gZq r+)ewK(4BX~xȸ٨?_1 lD|U{ 1G+Y%Y&oon9E3;y1SM~?G1>b[?#@ѮW^Aq2]|}xol4fx`bM>Tސ撇V7t^CvWP:- IenRQ+n=&۶|7;aK.pSǯV;{Ε!O "N7 ۖQHWl?hv {#[1QƏۆOvGMKq_?g78{1.\8A)ᴞ<_"xgQ\+^, OߏqoxVw"NUqi:%1όN 99a6baܫ8rttәsI Q/\}^Gql'8-Vt<_[PGQ m]>8wxp)>|N8}0oex (2~cRTOI)^?nop| 6npq:a߂8 ^9~O +q14[xvG\4[/Gq0)nDk O4>?NGӟq;bsTt0ʶ!p<|Ī b&+ ΧM%9ux;ݯ;G?k d,Ƨ1}4\Kцrj\ދepi[9=a=H&GQ\]_.UaD9ɢƀ7?R3lB2@|zΈ7hx/+:MoV(NԄhϦqⳆ_woYU?G=c#|+uu6S}Ǘw `x-kj}\UW,2葓P(d5`VWk^dE(?)|Ba˗m13Z8ӑ~$EJN)M񺘋pĸYƭeKA~O .K!+Omg\qOQ ƍ4i"E!r!\?6U\/9~+Ȕx7oRQ(5/qVqE0Si,akoŭGxnƜxw (1^?%1\׀Z G).n5w!W5.\/=D*Ym<./C9މ-7Px.g x:k/:"cގS\cA3]gxS+0N)]ֳn ﵿ1jq^mry~W>kZ(~ ¾8  EmֵV1nN;p|_ gu xBqxO7??%9oJycxؖnr!iARJ$?ŏU6||w4{k?,.)ʶ g.X(^ Wg\Gm}֥k1x+)~SөhoPs+]nU;bnFw* +>)ƫn B6-ŷ2HSųSG+gˢ[8m69*R`Vq]b15Ox?VwS+~|a\O5N]1,{yPV7ZiC_/܌k-(^$Ax+z(0M,Ǩ9 6~0I.'f\q01g =~[5K/r|n_To0S5|g6l-[qc/AZG4&]cBQ;q퀸 q˂nu&qwďV.nLJy{;?qa4bYxi,Ɠ*{< /Z57oE:xl|-!zfB]:3罺k[jv^c,sCfhz@:f_tP{^fx P<]1.QqQOxUfjx֥DgEq5nVkȕxH]类w3 ߬x\5ߌۓ㜅,AbRZx4ӼP?XɂwsƕK-nL]sE^{=) @P #罏xmtտC _vvD|YD4i1f& 1ws U|TAoVO|oH|Y(|OU S|ʸM-33>6jA4D)y9G،ơ Kܴ3Ÿ2{V|2u? ՏSfP3'dܖ;Ygm~(5<̦xϝi07~4d+/VWb<9З|켺wE./Iq>kfF|I;a)xr1/c.T+%qMK}n:{r|a#{6D\K[]MIqc\!j[{(nc#7?me\*]C~#xDS2k'u?2[gmOxI=0B9kV\RGGc w0xI* s|▦{,?NH߿{q8#?FÚhG;+G* ;{C_F2슯Ua#628~0ޏ7c+47㊀G'yn(JťI7>\r0~Wת-XȤz~]gx帷x(0Hg)ץPMFo5SawR| 3SlV"^< j VMQƓ(n>W8yLqS=_'{l*yZ|"x"5kqpk=n~[8|֊G4Yw_|*3|Se)iJޫo=۫.ƃO:Ăg5UDV_/Z'_R|%GܢKouoO8)G]j܊WCN9)NoQuGf/Z^-#W/nW|ɳʾ7IqPs*? ;' (.DzBnz<8nFZD!;lGq\>AW%#}/?˸!ȼ)7g#?{~ySPrpuN7lj{(>x V&Qc<*^uWg@m`>Bܭ0^F]Ggswǫ)Ň_əv[~w߁7!~su-= Uxdœ1vKBնB#hz=q_ZqĊ/2oqO)'b {0nw<)]_3gɮ/b4UqmRoUU|W [x"kugW)`Z{njڀM ȞXq>H{jl)>?GXKxx@5>E|2n?K(ø"=j>ܙP|nX]/+>q W􁌇)nw\+Rsܾ[ţ3.^ؖNqϋmaVՆ?T|?>+ׯ߃q%ٺUApcxx3.[bm?ԩe݊Ǔ6_%(1_By})c_UνJý/@q9$TV FSu.O0?CWcTT;^^;ǚߤtGaEx*y n-gipEGQg҈kTzS1!_x5 R[S*qxrLOa\)0+m+Ǔ3=N42Χ)hG.x_/-s㎵mz3$_~ǖ(%+Y*_MIq:u/ſ׾M{aۯ Y#ro\W|G+<Cqj䅸}fGgzqvw}Eqqϩo W<]ވ׃ֽ^|2hqz:n{DR(x:yԬ]6fI ގR/[Ѧq3_ԍd+7nڨ^Pz|EUK渑⶛nom;U| slJ]Kԫ af.?ůb~7V7^"nƛԷ)xlW21x qc[ ū8SkEqG;]񏖫uJg-?]Moz]{gDQ=R[+~x QKo1u+Sƕc1.Y~)ј:8/<GmZŕK`D܊+o0~ZorKo}M~t\ƩQ"^+>7D1]q1GSi3׊v]<89qmŕ]CVf\5x]o}95o7s +r<8o|ixM4'r쭸ΦxkiEf\x Y)Έ:9N>aܢ8 !}Swx(7Teh2!cɆxxco Os5 ➈GWcifTm-Ǡ>b@t0Agxϸ!܇7D6?Seǥt" a/ xfX즸o;xwWs##e aφqm6<"Rw+Ga\3SWRN>8^udE+>1<"9 k1> 1jCE2R>j-;}=*Ep#ٯR\7f4}ANCIŨɊ8G|&oZ%p[7ӓq6^?^fxø ,ƣ*%ƫx,Ż>K-W?AgG}Y5:?OWZ\5~/1(NhpG6)y2 f|okUK@c]FP/ǵ]ܯ/yt^ux^ CH=o֯F1/p1=7+Qxs=Omt3~w{xPY30MZk9!~'#}pkt)I`xnlG*>WA<>Z0פF^3\(d R$ěml%a75o6Rm!37^P<R;>Qj2m4cI0tqZR7 o[6( G9qR\!=dD~1-^/x(.Ͷ{U[i[N^ǟ¡K%Ն[9ܫqxՅhj ߦ|QZGkMq-uj_V|xD E1d-#B7uUjJ%W+~būj\ 7xNxs6[R|u⯙w:MɥךV~Gc^9/.?ָ-#nQ|f=z?Mk_Hk?TqBOs,imx;3oזo/1)Et_lp7ۇJRN{P6[[兩B[ԯMsⶪ0ūsf/lm̰nO9N$\GPxg'w"qAkkJ|-➊Kg63k[MykS2pU-}5 n1|x󜸘Gq]PĿ<@1q̜K-cb\s; ?(/wPavCZfsL["uJH 7fgWto'ኇ0>DU6eZI{ U;;^vI_x5[CSkFG]^\{fG",+ӵK+궲??@ /(15:5sȸM;("~g|Gaѥa۪R u>| 1FGd+_hн + _V|gx&ƕPcBWO˅xM7(EqqW?^tޜsˊg=^2EvC`<&[!+ԭ+jYۗץ^JP^^}92){T(ƛ +xz#x^Mͦ>#Sʹ*S I]9qI*ny q srSo{&Vb|u@ŃoON"R KK]e|ݟqLbe\3Mf{*1Zdx׊um .Xzw}W 8=__PtXm$-W1_6)b\<+. *^Vv#/*ZDDk@ W ܳՑf0>n@Qlm2cjl)~G5QעϽ4fԊϯlk~mtBqXR<01]1ZNux32ZVxb\󿧈k4($eE)N*-7nq#HLHJS|u]ozPߠJez'KBV\ofEZ[k~i^B_1;Uq:1^R V<8 W;DiP?SzktawR߅mڍ|Oi)6~u'dA;D<4(ƕSf~.ۚŸ^[.=-~r\ m!N->~o׌˗q҂gGznFU|Odw~ HcL]GsH:{3 ُ`<ə <'})8>)w(#N4.Hn;⡻m=% ]v}<x'Qdxb7ߢI˞2r_Q|mDq!b߮nŸUq98z:QJ{|0m_Uq I{]kۄ6?@k(PςEq梅 9C;A;"Qu_ŗP1l?'Lpc1>!SI8)TmZT\^rͷw\C1>Ww1'5T< #?rRZ(N2ScBw2 7uoP\A3|?۽+^&yNP쭸zK2.sy+%}&9q7zݱzuV1@eA _EsP?EyK0[_Lx7,5g#ފ/OzUB37QH*t0) cs}ӋތoQj]~uD2gؖ$|r-ΊVk_} s?uj[q-"O6GͬB烹,b|dÉߥU[k d,Ƈw~+W }d\NoZO 6M4A<@WE*>`?ϐr՘*F-nCqH%'P6~{_J̸n?8UVr-u^|2פ%\мW$C-Ϛ(>˟_|.Q^x-3)u<}4rO"KDOqR#w^E|!,:!1q8!HxiU&+ V]^\$μdR\f|<xBu>o>Hqy X0[8Ws /9y1٣I5OG#؊B,?|$qCH_?qo= .:uYCw")n)Ƿ)\/(nu_A?M] ז'P܊m MjoR!=ãvoABsv5vO+w(uk [jsTO)ϸF߃KGɑ' %Ɠ(n >P|cKq47ոTz.I8u+~KE0:*ϙEܪ8Mab6,voOS.˺u&.")B*qx( ?C%GAgk)\r3 uxϸnqޣ (mTI/~9ObS<ʁfm ^rkE cۦAi&W>evY׏s{!^'xT]_<1 g#Jq12l њܖJuܯ8$jx8R|| T BsЃߞ(~'8qW[Vq>H CA'Q%_uJx3{rγ&cWU 3U/ʵ+څtl)^%~C ŸV >i _^YqYۀ+oMxV.ҕBqb^ KosƲA8J$f53(yOů9KЬ x>DqtAt%nf{a1.}hc?ZՆ܊]}Cs>e-GPu> }C# ܚ"ؒ}abw oeXuJxuu-\GR|sv^60߬ߍ79BqRC܎GE<ƛ)l9{ 1?xu T:ǹ]n7,iV v;9h(NF,wSQQ?N=(!F]85h^_G PfCsRӓ~^;E,ylƕ }Z[!_]^1bngR˽^ANq/xiB9ӫq)^!>ICxSߋq>tk_ q(nQG:hd=NƕoSӭ)z*y+`2_|לV31n9ubO6(n"Son/Nګ{*NJ7y=̾8Y"ŬVⴡjD5<5F߶I4ŭkGś7S"nW\_;vHԌٿ7o&eM-NΧ0nd۴5߹;ُ xxd#J5-jeSoeuVO'kQH/q[e݃*4{+;=kf`xx86ĝzf*x^N뺾 ~YcPp|wŗ6j||}_Y-3'Wu+!gZ?-.~NX6{5W}w2V+sr<EpóS|lSbe`lGƵk7kQn"\ƭ4_++f5 lxx(JY n{҃ڰn~;eY QP縼 o'YWxuP|_#+nOF~Ьϛ/+- P=ΨMȦ" CS@|W +cG(f)C{%?qpvZ#^+a^qO*~[um*nYR_kqrq>_p4Dd|D}OU#Gb~yN?e(l: sՇx$_e<zUqh(yr1)(NNYGJWx!,(>X~9[<¦+^V+5z)S3!Ί Xq]F^^v4|kvaQWO7{gѪx΢G})mdBw/Ո(>VSߏ/gi'(8*޾.K;EKϓgH׹)meGޱd!/8-+uؐ oKg'Gù {288_ew?5\a@_ϽG\#RhX<88wDnx[|bg^q"Z)s"kb̏yɵ幓ܫU֭G<4)( _Ss4顒;7LEOU⏗c0Z6i[LGs_KǛP\(^"ijrۍ.!=صi۠$u5F1^d)ku3f7?6}tk y_^poёjViq+ؤg@}_#LslnyjN5MF潄Lŭw[|SjqB13.o)P? u;GWN7[>o؜_{_ћ>zzbנWmtBuwrq/FVr?]9%yu KشM?l'XvPxL#p{~O|# n3q5W~z&998x=AMqje j}ӌAgN8lQ܋qغ,˝հ܊ݏ@#x+8T˸1x>qh[Sz\:\i8*ٟ88rGw%p ځl'u7&,y=3Iq/.ȭn&;KǼ#2^(xB1ΧT 6uf䛾io>߿?n: IYhw3H֮ns<3pZ8.Z1>Fbܢ8[<5o`g#wn qGV5Wո97q3(~9ğ4l /#W?CK(A<{xW}DC5=Nrƣ!' _cwuF7_ >JdqClTifMw՚oH;+Q#GMSNMgOR[x3Dbw^ِqٟߦ ůWem^Pb_-dS%⑊p?o%^+rjq5Ć $m-~n47ŗvoWE*UL~h$1'(/3Fq/A9-O13ţaSė@QO5?-F1./uBOtbkq}ɅGK"VҶQ|2q\*~xA AqGJC(^OdV-_ʴfBGm|QqRT3op4[Q帲RQ2XI({)>Yx.ۯoQ?Vx4fqGoU|d8g&wZ}0eQHӘknp8PBAǒfQץ*N#'Q}..˧}Q$Xr|(Ǹ~~h/Ŀe?.t 9"^$A=9k8BoCs4ǵS—vfm[q?Ic﹦s^tQMCqe$wcx-7P\kkCJfT]O΢x3B6PqʸT4//мy f"{F|Aq(^ )qbm(sFq2?ߨ>V0zo Pܳq_=^X)ϋ'!^.E/wKVKIGq?M-A$ (ƹ0U5^AqGYǣ$iikŅR] ݿ3 q^hu!I\Qgs& '+N)~"}Gq⛾fW^/sOxGĩ HM} ?('ڂ|(+c^6W.ů~kՃ(98] %5XvJ3*Ÿ(MoX7z{qJ_P\a١r7i;Bq?>k;*NP}x-FHGi%Ӏx/(V\ugJx\_[x/!6!ʡ?nQ?m5N&).ėǭiY)F|VQӸ^{w\AQauQq M^CܦPa-0lV]u/WNJ(H[졸V(v\^O)S+N[۔2(q1-㋊/z+Z_ Q< (NP<(⿨MoW)8Cq1Ǟ(xsy@`]j#gU<&BVܲ xߙ25F!WGqyiչ(~{*KW:NP -WQ<[ }joS?*ETpc 89Uf⁈?;c8c*bIvWAۖx?FԵx8?T_J(Jq3?aD)HWwh}ֲ)GXrx(NΦ)~!ϓq5+qE X8_՟^؈xo+88RJxW)80(NNR,7nyf2UraG+)N{)YހQ|~0$ŵ(~$(NPŹ9TҬGqrnƱP'.Q|r\ DqGqrRp߱9'b 'Gw,䚆R8S)g+t ß88➈Ίb8x??88Vq㫷i?2WR\qWq?cPRZ䣸#f(^`QRq? (${ğ888++0Q!*S@PAQZ\q黿{qe/Nq888WqE2_/>1|z((NNw2EGq8!y")~w|nDcaQ\q{A^͊88+p>N;.Zq>>Gs+ ~6PũE.sc4tP:9+~D[!)>rKgoQgRH2şR|8MpQ]r'+S)n̎ӂ gŃ?F\*IR)ޗCq~B(NH"ş'Te\2i@q#Th#(pW9.'$oŅe+gQ 6W.$Pk82my=ʕD"]u (Wq>:feH]7=R8EڅvRIϺr1%37mT1B߫; {C+# f FAxwxyK 9;77.d]WOB+,CNI.) !:{ta߭[LScfBqr$(N9p㑶_`8!L\?GqBQQ BqRp)ㄐսRٛHb\(Nv/6'xIRmoqBGQ8}#qBg{Cq8AP!Wދ9N7A⵴d-Ź> 9l?=vbEqg%6BHT{{$(N|oOy#_qZ)!d[^*^;>:#d8\EރW~D{4^ՐB8>=LYKgr+MNӷrJ}iP8BJQ]q Gq5AqBA=i3DS-QR*y!ŗCOJ""$V{qes_8}(xx8-y)jCILW'xkPs)Lf !$Əl׭;Ѭ'%1n,5wBJ% WEQ?wB#' 8x}Vo.!8I[_ǹf{W=!8I\7f\+ëW~ !I6Όw+W3^$}1-O2h:!8٫UsGΚZF$JS+RF7|D9!ėΕjm-n+ig$f1Ŝ7B2 c~yMRs$B^BPx3^ޏ5s" ; 淮GqBAq5ެrn~.߆$sq57^o$oś_ߓ !I抷ʜ/qn'8n{jnԇxx}!E!qu8nz:VL.بV{_' *=IѨ Fo=AT:*W=> BҒ!IIEq6)qBBrB!(NtF!(NJioBAqB! R"B!8!\L:B!8!羜!(N!'BPB!(N!B!(N!' BCW!B!(N!'Bu!'p-By!BAqB! !BAqB|9BAqBVբB2BB!(N!'B5v9!' Hy! B N!(NhBImQSBiu:c0wBP%QZ !I~W5nDBܛbwe8s$n -!'y6B5^feo!8ɏǿ{86Q''yx= !'~, !HNʪ'0 {%toI8F.8}%Gq BG{3sA'9ژ'KP(NȾ) Gq>bRRvJZ(mT@̅ (&7E$a?wVUOƽnTGDu"n{k<$$i@ic\>NћMS煗LJf 'ٽ O-#dH^vc Y1{EG/ JߔNڐ͋!tw욜?% +ho;|+Cn*K9UCJvjޭtrHB":W?y$%;}f8ϕs̛ӓ}:QdOcwr(Qۏv²6kgLW%5w(ɩ mlqӝw(N\'E1%yyt3f%xvzRs;Yކ%<녠II1_8gNyv]=(9D~#&4Iҗ>3/?h }{~e&W &ܹ#;>4zPp|SEǻ?DS$.Μ3*2sXѴ״uۺ0#'%ve Լ ='I8ڳ]YiT62ZGy:r( },w(ooH<~br'Gwܬg-3NS8ߞIm2ߪ(N ~CM=]xa{^#xًI)%9&Wob3D'h3 `pH??<׃†*t>E~&8r=,Ǻ?=eyL _F 8!i <pka鳝:qSMXO]Y,mH=Cc#RO]kﻗkr4JIN_y|)R^Bub p?OD^`_P30:x K/gVWg.!@]\ձWH[J~`lu6G>BHNYBtW)S ۄcQEjBr.5g\?/N iCBٺKB_MoB8;~BLɻrju^ !PϖB?e-BQOB l/yq>GB!TFB)Ru ;uB!'SB!^yXq !\P7BH1Ϣ:!R;|BP|}g!1 !B'BB!(N!'BB! !'BB! !'BB! !BB! !BB! !BAqB! !BAqB! !RF%5liIENDB`rgl/inst/textures/bump_dust.png0000644000176200001440000012244214555455305016426 0ustar liggesusersPNG  IHDR,JIDATxdײmM& S,>DdDf,Um` ` \4eps nJR[/51sQU;bo[ۗO1>5?;sn!3" `.P vh4Jhj~ȩYB1'yo滠v?Fj e+zOo8鯛w+rW > \鋟˫fw\B&34S3vS%gkY(^}L %,%KtEHmzE}½1sP~#??S- o5J} !Uj%?ɿWo9Kzܛ+f`/fc i|>m]/LIP6= !@|=Tl~hm4US3c% Q*4&1Q$3CDDb&b)2g)FR;&M`T5mG󞦅aDD{\-D05*JE:_TU Jjzv<N03bd.#XLM ͤR<#=3׈Ԝ7nKRd:T{ 5>aL h޳"#0i}u1/\\VNcq#ITG~)}1u euey͎E/D0U1P:vޭ/=@Q݈u, h f"(2 ?nS1RTѳ "f=ŘTRUǐ%>GRDMmDh4qszzQ8 e8Ǚ% a:;LSq6h0| X9Tu?Z˝?ND'(_~$|zZ!*JR]1LΓؘώ V&Ed:>!RтùH#Dɂ`"  $[ˋ|.M_9> kO<(fFutfoX~.="M;k +\.g?^4_(4UWTM2:Z}_=ɏC?$A|3'yYUT,ff c ?4ED53{ZYtFaiOLΜ}\J)>Ȓ;]ydSaqZ.ÇGbW2i K}yۿ!]Wn}| n:_LB1f' o)/+ Ħ@1Zgs5[01q|޻@t%j `LC4BA2-`Tnvn:WzhKix8aQ`T(Y?/1p&Jl9^l3⋻>_Uw'`ϩ:heЖPoSvk7,lP'ګ* !Mw( iEϤy^teʘ=Yd Њ2,FļG~}Uvǧ4EZ *#9ECcwӋ_恙̐T:|>(nw_7?Yŋ?< *z10`\.ƍ"3舜Gd&뽰C$*ʠәŇڍh:t կ/?{NJT\sߺv}=ig3FZ} f(f533j)ӗUSl҉T$XX1lh-Ӵ*Y. `Jc@$W P>JY%3bDv]^ϛ]~)L α;HT矟>?3001@n1wR5d fZb6ҐyRTcsӣY?T7 DD`f6-$4D$XCS#w($m!g;|m/D(bj&bU@?o ա*;r { ueޏPAT!sGtzxo2~gĄi}f#lhLjU@mQ-1JQW5M6fϗTT%3/`ȎL-1>3dROA*g}hN}<W>mQ @r?A@z6G_QS.> 6"jQcF]]I1>j~zQZ=|xHL inOeUXQ J1&򔒕~TRr@tHq;9iۍN{bvhlw wү.󍻷C|L=\ÿ{)mSH 7,1Zm|/'@U|P*>ſޟ|Ah%f_َ(}k~"Tmq}ڷdo;RJE$ۅtrvܞYB!*rȑfer=XA屗*ot}gwo`UPT$F1JSo`Hhx|].*Uw\rb+VrN\݄u}khv M:fK0u 0PRO;\b5s舘KTpv{K润7WI@p+ >g)̀& LQsQ|xٮZeZ-BOXbwX|nnݏ~~Hngl) WV6+1ЀuϻmIYAc:=~-ww< pv4R(6woʋ,hY"$=@nd4sc/βWVGm,C#J".F]V`CɥX^a{Ӌ!]#SG~U/5ŦhՕc"䪒.c>"*lo=o3h1j#UQ5"x!$WvZ;:ӟOU!(2{DXD񵷬i;83°ڡ 2٬2Fu cCYR?t]AhypA lN~þJh^9Ԃe(%=2DUێ`3Ԙ1)R*N =ť̒bh"I3Tӻ˓,}$5hۊIa9|j0 *%|:k'Dqlb7QUyP,-d21p`a3@w$S3CpN0 g7R\\ӗw.Ofq+ʤEr5hNPd{T\X&;&BZAPxJ2$8ۑ6_shpl&ɰB!$'(g$G>)}ꮞ;~]=I& !!D}V %V7JDLH"zܧ"9Q9̞raqzx2`wy{~ڣs祔ȝ$APo IJΊgS. 4`*ƞB. V QI0"wyL` ©;T#-.P{h4Xx }}}qxlFq3Ӌm0A;S2@`fr"s F#&L^\6%Zv=~]9m 7N6XR-Ei.<#Lx;& -D$P AAʾ:wډvouٺ2`VF%=)g+]j1{#*hZ\=wWE@ݬ8jx81<U)ETR@!lKJcTv( Ddב2A:=h&gN$1 Un x`j9<_~.w!]I6?YXo+#bY#'/=X.": Aȣ!P3:kN^.7mꬖnL%г0p~2o+bdLȬŷͼ)9!GuH)wxXc? ~\nB;0@ qJ4AjZ|4wZN*Q_o:Ts46C9G3'9Wv">U-CKfd<5TTLyJbb ON+`7/^.b@v "Dix憝Ξw]{&6C%5ޑ$dђb fF<60`f&Iwup^Xy3?NYrQ@ܮV؎`\U7}ԍ<_'Wa;>.\wU5BD0Q v y֬\Dx_˧G@bfb7XsiP/ uɘ TJ[C.I U>x#_^|qP ]%9]"`RJN!M*ۭ[ͻ+2lj]M2W8 V!180r(>͛}\zb a @ 9FUMUHk(fιhbI?-0w@XJŊŪAunV|/V7+Tr9 ;lD !ЁVO)" pmIp&UKVW;"5MДb|)7_~Zb GHSII1- U|`)Cr5#++ݹ&4XlkDgwָg?o_SNuqUDqQz TsIg`F7z6<)>@ -=!&`Q̟`q/q]슑sd*fZr!- žhvTU Rݞ3,wdyHStMc<ԕ+c}Dj}I>b^.&e1 ו*RrJL( d܇͂9TrC05Q;Ks`E0Jl\I9I r@I=\Ȯjx? Q͂Ga^w]߶TmywS >c#3@ӓ@Gw /D%#[4_:gъ$8U{'4eҦ)"1T -._k<`JEc6qQt_uG7oKj* i%W?Y@)#2E'XPb5'Y7o]].~tۇGt'P1es#OBnlG[ǿ&\BudwČ*L'I08nG)˳ʟ>?u՘ 8cR`YEH9S)\7#8܆N9T^52BYAVC{Ţi*02c_aH(ECS ƪ)O~xJ<{I`*>~pW L6#Ne?b٬`niQ`"=MLT(JCS+w7ER\`ǾP3+y*r& *fgIG$$R˹Zk?}~CͩX@{-+V|*L C;ѱDT-@saGd|N+&A&5M;5ɀFdr(YT يR'4n[ZU(d!<VGy"Vs#ZTqyFQDfӂ*aְ0f+Se{)ϵvA?/ͨj98>]<9m6q{~Ah@|Y <40C20S1*VT;BDƨrZ Y&;r1V6EmeD*2߳˪!"1+F`FyPvs۫⹼0fdf+Up5UZUD"QC0C6qlsk[Q:C""I7 48 j)Fd[kA4PӤÔ$vG< ! ,ٜU\B&EWϟ9\8(+@h TJ)E*G~`\N2ؠ᳏.=`;Pc0> 3B()-KK(8g , MYcœ!KyreHO^5H>?5a8IɲX}u=/n )æe1c5{E79qwݜhF \ uzCpĭz-:Y&fxF`X9q<25D):`>T{GyY^buE s)<ȿo2dRr R@~~;2d6vj.]nd_ |L%g%F=P8PY>i B0FJF4-%~:r~jՀߍ{,>čpRzxIy *FbퟑP !;_,qx 9 ~k_{yRc*:&?n^t0"3H&EX5KCfI]}@s X"S"E a0}'g$1"A,S ,9`uf@PϮ܏#e$Frޓ3Cj;`Zk n/g;W悎&p0S03B3D+q,޶z}=%4)aYr(KU̎Lȩj΢f|h-1$sZ4A5CTdZah* :6CrExWfLF,Od9&scUWʡm?RTE ۶:f)~ˋ`؍uSGu:`jDhdƬJ&jЀ!EB3Mb"R3zE;ئDZVȦ"f& ;^GvȠj}'$"fnhgYm8Sd"D8v:* F #@j2u@5$>0V.g2B\@Kk 1t@eģsGSA}M7XS;;Fɐ- p6p_tfȁL)2 wjP$!veMo]jΒ"10Oȁ`R7z {Fd$Nje01[b&E'{ujXV%Ͼ&vI(2>@JM|zT_5wd~{o%qlC3t׊XӬ[Tg}98d8/bH>f1bfc(Gi5 >MKsH2W'|<*  xBw|vcaBH:R9ͳ"!LA7=D?ۉiws5U[.oA9iINp6R5nj':Iʇ"$D3:j,}!TRRX 2ɚ9iUT9rˮG@E'.\| $8$K)jVRqb9C WylKSKu}R[mqԑ^<0aURげ:ql?D*qp.*HNwNt^)"JJU  L 0ObM:H `Mk&69dtb0 T~{vd5`bwR  64{'5]:r o|`/jd:;I]{8MsAsp9#NPLAc!"6~mz3L-Z* j$qt'Gdx i~yT=-o|fiH~J]Mbk{jnC.LZUd&9eLj`Zh*u #Ta5:YDM E>+Eb*xRPrl$LGFdJ_~S^`R (8RqPJR/~ϻ@*)b8iȍU,}&7yqZ=1mD͐+"@ * H\:ebw{ɇݓLhl$ 6l}4{8E>mO}#wP3ٹ,"XC!QDDEmJ.1Tr>>CR3OMC6M ^Ssl;~@ĄEP3y+AʵV7WՓ|(Q @#F1RNu^r%@`m{qg5gs#\JI=3Y LLV/=5i=+wdڗ>MptT_')D1n$`VǮ۴@d!Ǡu*_ $IF6) $av>}V>yP׬(dbi-nl <Ǔs@}yG1rM%Bzi?~<;*WD9|h>FyHHj5&*fv"%~z .TI=Yۖ8zB 2) UUǘ& #MP)) }bzAJf2z˷0vow{6N\8ɩ{r)JiP .ʮc|Os̚ i,ɪɓn/˓NȝR!PQYbHYP۵ nyôVIzS92QȌc}T f1~ ,xY rlJ@}|\®)XϝRU9~(>~,rQC9$öfXG.蛵NŖ$.Q! ul#ECF;lh" pɝ̯v9}7pL*D:c0D#3#HN:s].vzYς)9 XDv;߇قZjHc6@DZ7\7W5RI y~Pݯ޽h>^̛۬쐭ͼ69#bI_·9a<%XUWL\;6"`uXm]%5vׄ'Mpࠦ\<TPp`0+Tm:fBzU~d0<C)ig!+0cb_>[ 挱v]w'=!" cm U!>逵P13-WS@~A=PɊtL* w%3dvLN<WjV{+QRi^\]3?٠fq{W'3Ւ]hf=}bzӺ|SяP'}5)2;9"D_?ކ Ⱦ0S"XVI+a0 9P{?XMz5v?o#-1褝5Dd@< Dt.n5<̈Ĉ{: 04a+X4g8%7vdH*u߽^jW,-Ҭq\u-O~}5ev?~U#7pj)g5z})?&M0HvR RigaLTDT y^FbL|85n.)CA=Ffв->_C0#v5AL4,& JҵTFl7?Q?\;{+'o闋0$GP5-jԑO="Bn0&rP'JT=aUĐ[.RC֊lw1(uoԿm]aXb]CIO1G_Aթ,TT>_?|fۡdBgaO/{W߻N\oǧG/'a>kZԎ@3[$:4 Ot rFASD`vdRrU@3oٗ;C`3_1c_c=t{ xa:;7sNĤ`:5ˎ~<_B1Ry:?~ZyOYin:hF\7Rʃ ϫu7+cgN%6-54K9nXUv{^:=7L ]_}]^^놌޳MbȢe%Cr''O.|Z.В"JQ î4%reTU>Gvn컄QLEIfxl|ݔ.0 =6r/"8_ 7@mvMfŢΪ?۝/׫#f}a]~0\Tfm??D`?JIE"fQn;MрPԹ_˷KiCW</mZh)ƌ& FbkP.PhÇg_ڮ濄/o4U6b݈YPԕU}Ka*_?tcszޔ;ۻU_u{;ׇR"b3ak}8ޑ[3YIG=T+iɩ0ܳy?&i'B\MUBSb4uzb7u~2|?=GMۻ9٩Q>]ؕQ/qCguF?7tr֗pՈ"h7pzYq 9%,:~Y5GfɱT*R}QۇcEO| ftXlQ${tu Aه¯˛ώ23!!3 p]v9 ΪŬFjW.& ~~6[>TTg%^˳_ξ>^)9+pv7O&QsKT9\rC (:t1kePSߜ{%Pq<& T鏿8\7[$GUQRu8,ZE{Ǡ{|\[+QA}\@G]^'+q:C)2 ՘]u6X\or6 ;T /=@^~ͺ7][Sb^t;npxA^utoٯWU:HA:y3fq69vm|<}ߎJ\!RgmFf*p=Ts!T)0lm3'8 Sb"mǗmUu7#c.1ٮ,^컄'wyBBĚsY݄? ?ۮ fu:F{T MFN2b*<۰rSd.~dnL O.X}M%ɞ;Q>B҂ {ӔN}ͪw~~Bpep!JꝊGZ8C]=|kJdjZ[88o:*O} iǤڈR01bV ?t|%Oy1:OBs_?>U5L"ҏ??~hTNJ nƒ[hfS>lcl1{=zW+:G*!  \:OcOc?7㚄4OfSKe3{5夐4Jw҂ :&<§#ANfƏS箻L|~T﷧7o?8d鏖Wڐ cf.3zb_ZQS VA@-ʹAp;`rJͬgɈ6}F@Tm<AȅzrG=1R #0fe3Zw.1HT#Je3DdL:6DͩbfdQu벨/dYSF`1Wt](9oQ'U1eI \Kʒ24t,.2 :,R/C[.Uޮ>ukDKj:飌tfvЇU-Y)r*,vy~ZAm\?9ig룻jf'RR8'KfPsFttCf`Q̀CHXژZ2m߷ yE\- {_ c=qLS!yD& %!#dAeYy#>`P~O5 .|iP~;pX֫@)5dOi4[ڻɊ*-ޡC"ˀDw'8DCbL`΢" @iS Hb9X xf tV=}/L ^U+F IΙS1P u.y9'CcL`FW?}=p gi$冱t}R"dT'](c2 /\!T"3X4S+]#r "YYOx?f-q\$>T[?lCpG ؑ<r)+I+P$f͊dpEؔ@7!jJ]bk "FSD/#(YTu4g z*uf*@[Y-9O䬎SΣQt\* S$c ah=8r hqpt 6ft[w{g-E H D7ϻuf #ǡr]C;xS5vNLEMٲ gAUڭzdoWr!S/0$LERȱ{6\.}py:DUuaԢC ekG6/6@xg?ͶC\`sw*7w [gT\jO SD*O wz*csR n1#1^J ;U)dR Aj"ԯ{iSn=b=?;Ic83Cyߙrȱj.9K}PkloDJ*C7r;/6}N/^^+Zڶs7~2ӡs)R~1WdzܕMlRC&C4O3ku20碖cf )f3iWvXNͷEPE&!c;f*-m,Q$EIC&EdlY˷LJLaUu܄Dܶv[򛿾eL]x"""(Zw>"ȏ; mLW6.ǘA %#ɔ @˪ԚzoNgGhNI#(ey3gvVN3?:Rx~yoœ Y={5mUSvA.m݋RUN`A6yMt:Ȉ($,:h:ja2dൃ>˸ f C-kmUXAmݜ1iRH%fDpQ s`fT1,m'rs1ܾ?[8fnQ*"dZF:= Ucڔ/Q~'SCɦŐ6U'?W+ڱkN+G 9)R%YԌI2`I.lL_hhPU(;H+q|`@&jAYQr?ɥ $F#V7xȢ{m 2> GdR/. >|x.[z *LɪŞCb"-vv{6K66Wn_j&EKC㮺t4y#C6oBP_uzj×rPf*REH ʙ|]"UCb:7,t6o__?kL &ןN%fc˜GXңxң mۇ9.D3n3p5OÂ_WgM6-BXujMQW6׵3C::9;<Mha:Ū96XTҽ~=]sm\ӘNxTi>60b{ڣs.%Rp>z_B`w'Wk *F0>~ӘCU}.ysJZݲcNmC:ΞŔ:r=fjySj=J ̠I[?+dU0TX}M;H1DŽ.Q`qgcw~ovUo_-Ǒ3"USqmWi˿k].=w?|0ٱ$C oa1(:o9`Y"62/V9DZrn]k]wq w_Ͽ=~mk6s$cQPeLfjt- p]M(}B^2[h;swW9?w{vIuzrXLX.\4-d E$!"k7ΚέӢnǦQ$B;?[V};^NYPy'*'Kc'4Or%"3U>HıqXg~D%a$5om=. rzy燸&ݰ=1uW)Hx1BS/࠘ c&C!GUCeX4߹،$~zJ\A%Rmp?oY{X.]D \)XhX/6[yLpuf*SA^Zgb S,Co=c0{ \fs~ J`t'%s ~Aw{ ᜒ'ն~T]< [L!|lPE##ώWW/. kl--?!i=GQ:=Z[QH(xG`:< X6j3H4>JF_WDn :Wh²킆Pǽ[1+N8R3q\*x$7!i14Ҵ'̛~7~{>\l#"USG]iCcq.Gww 3 8`V%CAR?BPS X 2S,39394e"Lk@PA$΀lClBaj љ> 䔜CU#)i0lB[bZa~P7s8'ٝrH42Me&^'aaߔ1Tг ְ>)Pk ZuC/m*bN6`n?Y}qYJYӔG8ȉh[#G8xRĚ"6޷+^^]^1,?J盒P.0h`)XaT.n;+/nNM#T}%#1#^zLȖ  \MҘ*U5`矴L~-Rm b.ƞA +߽[=o޼n$;w LXȧ%y6ojRig??^%_gbBlͽ6)#ز 0l0_1Wi]t>zn~cLy*uٯlɒމkqǞΔ'pG@6YdM / У1  @ht(tuYUgcfkɬyvf;?0HkTrR9tAS7ZC+NvjUrAQCQ"O_VϾ]{J㑶Sx=Bi:Ю A$ymGV*;,C$ s͡ۏHٸ#GƗOhRm7.9nexɩR&,j&B0⪿|&Ӏ"@}$釆˘2>f=|g&~}SOK+9P_6 {0,~Kwp]./R [rJT`bSl" M%! "-u]I]U!`!(WB͂dIo{7rs o쫏]S s5@rN@(mw۫fsL:73rZN62*t m=z./ ]5,5Y|~sO.MT#f<({pZ^C{e*;#Ԇ2 %RFM$k9ȱ!%wt̩Ick:+O͊:Wm<$* |l?z \-mߦ-5x?}ZֻP;k>^v}I}rͮ{5*!XPҤP77)*utiH n:&s@.8Tf_MDCHuŔrMR6 ryGA=Dw~wMqQ717DE8t ;ҁ=pƊ.qu}+Tc AmĪ&A1sfb| &$HԱd2Cr9vΉ ,3#vE]]^=g?8;wCjuCnf3gPa(Yy]c@Xs~+زl2̧gZG9'1N_ק Ⱥt_lӉ=:qn04C{,; N>m* \ ŪҲ{lZ,-I-|gG9Z wew_4]ٴ?/}*wL-t?\a(J4NȀILìȐ;^$FErw번'2jzx曹spLC,L9dID|ɩgoZ1T)+Pou|jR2\݆|wZ]|G%^趫O꣹|RCbDy}_wo6aIo“]onqU]@ν A:lW"!;F( b M.HR`}4鶼 7OL'FͤtBYeck|f3o^WN&'0r}L./]Be_ ӹь !DSDRVS@ȗ\T gojѼCb{m>| il>`2 ;-=:KB 4Ǯg@A-E?ʝ#h"+WW`r7My1#l1D15Q3p{/ÅctP]u.+Nȧ.f5Ng:o[F\[}HMDU"@*@3fKD)%CR5͜/NVV{,~_y}>t&ۻZU]CLwWW)Rrp-6(1>koEE$I Ț}'7@!KIGt #:s`"XA]]b6w\,imp\`KǍ{\Ͼx52{ܗ,(wQ4V͈MбfEF3W֓{P)#˄H.]׾{H/O޺L5/7_jK t7+V9Y1jY \1iCYPOE,LD>QO+cTz墔8ƭL_2Ǝ$/i?#va @DW;A- MMM $2lv~Y(dI;[F$ܞO7_}|'K#FIHeiӰN>His} 탇$Ȧjh@{ ( %XPr1cѺ)TWڏzoTM_Tbg>̵eU:Ҙ@pecw>=-CˈD #QsgȄs,2}~rCBG:va9q&3,kK ]WOORW&Y$e!ȱ&KrY(@Eˊn?bW"WA\VW?Z8+ S7!-)G !%v `i7[<c?9$H7ղ:]o .cIūǵOMl[ @Ƅ4h iS6o[s6%K\ɬ.U"#sX/_Y:МhR3zkQ]-9g!l2Թ6'aӜh5}rئ;,FG0=]̳/ )`e>Wga]A$2! q &4 +k{tqs2t3#aW`IB_o&ޝaL-MDA!=++<"rOo>,ʆ >%Nv/JGHfmivw:McJUE5dyQe B# #qrNT6J~d^,ݡ(4 WE4YDd-*td }ܖ$ǘŠ B|yѻ4- ۮOK"ː!pҺM߾xXK~iqw#*`#h ZV@"r)uR˖ڏaCYe"FE. zg˨},1kT[.^oG̃WiXP$,nٹIb? qNB~'!tiw>8 V_O~Ó )6Ǽ8bـ砩&BmEIѨֱ?~na\0yV\>7CMvm'CH*0W]{;wski1tm9dB<*p~\]ۃ(F1 ڏHч4:܁a’=?|<66^l~!IgM :N7W\z` %_Y @n[@}B/9kɇR༈MK=`}oyOiI|v>NU;ނ鮑ͳ30ITT 1#X4n2y}-We1 $ΨWޭO{0ŘRYtbr@S:N.ŚC>N}C C^.C->u63ש~fÔHp%XcT9~YtL*IXNNZoM>83 wGbw8VXX^ W ,~S0B~:e|՟/^xo>fKVwmCƸ):LSx#7WY'}IEX8[nBUYp6wo9eki7);CT3n{%2UsouƓs~vo1ZU9K6M3EU \~j˟+&ӱ4Xvhlck^Y3.LH ;ř_4=!w1mj@9A _U4@!HƮS{v06ر;=%Qv;ʽ>OnADJK<5cրX.v.!lQ6Ыfa0+ɶtbjגN?o( ADXSV'Svx ڶ6})uYU d)P(ԼvD+#WpY8D:?{ ϞM|>oonn^ 5WES+YsLDH%*?߽j*_lʘDEjD)eAvĴzB=t'FQCVa@CR` &}|Ճih {th5k@Y{E( rxzwƁ954!?+}QԪ[jtYo&;ŠJ[36˅^#C|qxQN# P΢cERQ0e&&}Erq8lilYo8z#errX5UZ(a۸9w]lc]Qx4|B$K=o:nE MI߉J]wV?~!ϾZ]ǗkZfI-w18SSUq f͝O%)eDL jCcf/OS6OqWo?\_,9O&obudQiƔ}gM :gB>&@i !fÓ-;ˊ~"?!YuY-~_|VIwy~ҕ~76Iqj1XgAv9b1ě )GkAqF1*ׅlϽӿ X1iC eٵ5oܘ2LΧ(8O8tٿUKAClŞ 3H v!sQy9j[ð?j~A}Cy,>ꊦlyCgJdQͦ\_Is%tԦ;cT9ENs;&?z ,A8JC18XFy],76=ED>yV')3mjRY[0Z0{N}L{]ȋ딹d"twO pΣh?bH{]R{#|ljU,:Ngo*|nVo~يQ%Ǿ떏۽;4 Յ"oE$*1ɐ7P'"L0cҟ,֕BvopкQ\>^b&7o~$g}2$Bb}F˿4Xw) 9xl! C I?7-ROiΊٓi(L9. G Vf5r~'RF&q?DsiMClvn>wV"fĐa߁EاRo>Vcq}XVUi_3oQ~9f}y ~Q>?TC/'p}o ΍]E| 5dD9I, LEhۖgwu4t;†6 `} 1A"Ҝ%af5:2R1wͽ$c4r1 >/c: ue/dbTS9laoawϦ}c>D,O1`Ej'܍eĎO?Ū-zf126jm2 7$Әޝ<{ NAL\l;4M1#an.;!"P3QDSatNX"j&f2z$uTibA뵫؜cCxCDE[Duݮ 'Ssh̋Q.7;NlQd[HsU͞543]h]Fu14<(Xnt={;IFf 1ҀZNU)ۧ3mZzEM <E{?[.?˥Zz}D KI9b3P!"sUL]S¾rddf)}d#TTMGB0hpcnǀD'dΙذ(=ܓ$n-RgB3dvL>S`4%?q7FIFz0ƣ0kK#ixC#Ki*tcLUr?׃0r2iibHhTִ_7Y>b9imi >vٌHNZp%}F*r}2B cМ4f-HpRӨlY}r;cY6fU ue"#eIy?tht11]cypC G тlgCZu 6iߛ/q?-ز<$-2:C_`Vs*"NcWve hBT%ikT*@D}< C_R z)͒WSt+|~Zו/|LC,ŘvZ=qjH[>q`yh;ܲ,@or=G4P04~ v̓8x iq^iO֕;̂(N"t ^JC(-LzzRUBF* :L\\=8<[;mӠ}\qj#Vs h C&i5 910iߥlĄpH(L}qk&T1$x[̆CCAEw[UL9A>%*FβZ&4O5 M*+JTq8HL,K5Ί 9%S Sաv±'Ij nyR qC܅723kSxvl9):6d4Z RX}8y]>}~9Iĵ&qmGJ9Lvڈo]hF9 3Li`{#eFqC6cP(w|Yx29'#֑8ZFP:Vr8ęιsE?V1nWYKrg"kDM#zLұ  NS)*;H$޼ؽW &koN&o>W'K`Lҥhivyo!EJ`%cafsoxˁHSl崊Gs|ߐ4U|{D}¨-W1T\NStݙu߅7eKn_e"ezɧ5tc9cᇽ(e{Of(`G-\3FEЇ7c%0\Z)+cyn&O~b~r)Fv V՜m@A`*Sxs{??W=f 7K\&ps]yvh:L[.s6`&Yx_YddI#A(,\`V1Q46Ak4# f#hs΃i(_IA nĨ~ JtVLwp(d)׾9=~^ow/֗SxNs=PgK܅|0=I~x@q6GV-O{ȮNrTh}/9q$.~wevuܿZC Pt޻"nkyg^hkק}ҭ;iҐb*r~umw}\ѡ9`bǹҺrK_\~E-\Ss?t)>e'N\= dZ6>6?y߾ټBEgV:DK?>C)870Y?mY6zIc]vU\ͱ( Qq]yPWtZ?+Yp6߻ 39M$Lށd~zZ޼< sC\e:@g /̺äs{J8PH4&ue{γ~*ӏdHOoIpE>uUbѝmS߾#UcLm!,~<اi&bQY/nMfYfNz֛R_"v 壓Xu6N.tYfy3ˎubugǧ5cJU|{ݽ~t7n?;f˻yѐ6 Duv|RP~;#;_?wF]ErBgo{sUxϫyQQIJċ]W]qO- !>ST^yrTK 5T7/ү^.զyl6{u,.@Agݍ-:zɦ5NlHք4j-ҥ5v9 }_;UJ}`-9GHаT|fwyA8<9K7/%?(s,*n%pì@y5+@u*ˋlynWjoɼ>lMNhRCwϧ]96gxh,ge~ {0GAWYnNt;oͣk7X6 4k>O< NldOys7PVr"1c4@Э`fwۧČ&)BR0&bD١'h J*Ͽ}Q4 >|2`'ǃx}tUY? BQ} pOxb&vWRa=pˎ09^s5嬐*1W[U)I,}UlNwm۰ku+X]Ul0Y\}2u˧MW0?]mn'\NX\|G.e#1EY﾿^SzNៜ|V:S#~yT)i5AR.]/O\prqg{G<ҏHv̩;YI &W0vr9dQ>-!UT4á%rvckhl:RbG8sMOC69Yګ!3 2 w5ɴi̚j}WUrR ь<(#%D:&J U,frRXDe~F3Pݺ[~~ɤբ"X𾋑D}À"ݤr1fRSЅ 4fԔ!C ssg+ĽC a0PC*l_o6]?z<_ ~az6/QPjׯb. Č  Lz5O/^,i%6;3Ž*1C, b 15uYA1 CU/.wЭ7OmZ>GdÒG nx^.G};횓l;9&. ,etl(*75Ak8CT`v|~Xٮwg!v݉!*vRL(F\BÇDF1G'Жa|hmF!d %fԺ4QsuTl%~]^_I_Wj.8ZS#SOfm'VЅQ A,C>'p퇷/ ~PU]v)({4)hB3ՀC3@(Jf]3Mnޖ.W-|mp'!@ 'pLA8jkFHVirM=[Nܻ U;MLoѷ} k ұ-/O+GdQ*,ӏA`yA{]LhE1SR{!PCXf'.L9w!>Ω:8j?}:Z  PӜÞgQDCއY\DSE,:_Mё,5+t+LahC7_}'i?G?^\nHPve:EȊޡh溛S}fﰂLCۋro` A$醧 = `Opͤ폟PLsʇ|w5Etf 鴚Ok즧W^]םs#d^CkGPveAfC1iPD%c&BU9t?Hg&lp!T '/UjF0W{Hm e6~{ 2!+em8h猝CӜr"'B?RT-j-'dY 1M 1pLIENDB`rgl/inst/textures/refmap.png0000644000176200001440000004162614555455305015702 0ustar liggesusersPNG  IHDR,brgAMA aCMIDATx}l[v~kSa2 6 q$"@ C@"EQAHAPPI(Blj(VHH; |x͛#Ev3wk}ΩSU{WUv==uO޿YJD`k<+@UqAHb|q>Rp8 p8a9p8a9^D/8,kө8̿Y[<f=ֺr pJp8NX p8 p8a9 Ao||N8V㰪HBun<."L߼%,*g&NXmXp8 p8CCHpp8NX p8 p8a9ǛAXr`?/~A5`G8~Q:'T[/+!X!ǺEpp8Jp8NXp8 p8n_‹3pˋ#T-.R`]Wָ$uu]r8NXto/|ycp8.ap,tN%"8?> GOo*1 ѫP-~uLřX!HI>#8Η>>Vώa_?h+8;P'D@\ 3WC-frG_|-ftwpp %,%,8cⳆ54$sdOQ׷U/R9skJp8oJ("pp8.aUª*>VS+i&68CN~\r8OAk^B;W}ӎ__j`¿COo6 8z"F)$@.w]O~vQAz !TtrDɅnyND4_&P\ŸBXuu)*p:F8_4N\ºD b\a ӑO5${_=KX.a]u)vړa9K=G.^F&aYݽ)yKR/1=5+yɫI'ˑ/~QctlڦP#d*PsO-AD"6<ߋGU 8zeurub2d\|j#F{qx\5C_~jZ}qR jT`c"X{k3<o);ȗ4FR0EQ#BGe.theڋ+mJC|ruRYSVnd36R`h6?3nxmNZ?Gx#و 2ܿYPfx8U"lwH6˟a1I XǺF 2U k~ KUTaM%S\uZ²198UzG?l_3a /O\o"320Om_Gm뇎C RK[y/| U/)]*ќZ:/ AF'&,=~W|$Rk2/o|2a#>u,=4rhx|4iUB[mX>óչ]~?9kGyZW`\6ļ~L7_*F1J52" X{OӪuKVsǪ VDcO ս0xxJ_ZGDxБt)WqGyjwt<9! ISmvٳ9N۽(\"K5IdQi4/.AOx%[[ yVU/u UцbwOnsyX%J9aYU#qʩ#?JX{k>a6 >爫ѼGe+Wj5%$ֆc i+aO3 ]6Z#M 6aډxGJ`F]FXS%, U7ԎN#ax֩7^se>>DX'O1&8)M-?aQ Uڰjkm*mJd(a BSKXu"ӣ\JX$u < ˬ;UסQ":=ltx_~ ذiP XJ>n2DzQpvyV0KX6 Af94oG(wS!\MX=+ϟP%:]SXī*(LfaPbѝ%o50 RM"PA z ͬWŪDӂ:%YmQA`ԲH(Fk,7UwY+sTHx/ *eU=SW,j_}Ds0i"UQBAP&}l$mPlX2?L-)%P(J( )&T0Vru+ 1v b7zeِ0S\ҩWY J& e-~x"D)(2IHq3aa*abM枞o| $̖7x8yF-nM pHL?"-F²Y$>=lX'ן36DN aI"ſb[2\ z슻?WbIEӬ}kۖ2 jn墐YvP;0G[C .-mSQ)$D[+a6R BwU:i[6q¶ƫT)SHX[7T[OP˙m[P-"HU :<@fe[٣^3y9Ee>@h# |X&UF4U?!ao׾" V3JcdhSNSb{ [com6>O@ %vXWa$dJ- kq^?#*ՓA  @f/E?$XU2/*A@LBO|/J %MUxAUG%1Ӗ&v$,Wec,HB7!e2*Zh&9Ϋb-DDe>Gb$i`CmkfARN~>9g$ͼ7kDd:&`lh'ן&)TZ SDE'"" C3 >֌F#Xmm͆XBUBk%Yzl.KL"@jd_%*%8տԙyCIW#avtU&RJH!HP"VVF> %0>4`U@`VTS ŭmj3 ':U9>;ڍhs<$_GZk"m~>T7ٔ,RX .2UV2i@A YSL'FU6]?2_SYROb!$ϵp4ë*E)K^٬'8zs5pNNGrg79(j41c˭a #0'o>\S9kjdE0ٰU{M.[fdx9HiBpDk[2IRvU1dԷ4ILE|`vl=ܰR{wz{|z4HK=Kݪ.@9?ITbhu E@Z~5.L6J7bju]p nT9H&,HJ+tm#I],hcqLag%,H@-%J ɿ)fIERyA/;C! sda)hH?FNoAr\[mǰNƥm۞Z([%3_7b3QxOBX"v>5J njOЩIWd% ':5J)EePc=JQ%. 8)n0*8YꗡO+q !LAZɍJXGY[oehͫLIݮq V˄U#s{hXNq[yJޒ)}ߤ-8Ar>F/K2R)~>$Rsl5(`iSq5|$2 QsW j0*Q CXб#XUbJ#BVI+-jYz$5e[Z-fۻQ {X*^uk]+gj u/Tlt%1wHߣO2"i "r:^|I(ve.heωl62%BU40&qy=z֚.UmL&+~s&PVgcҌ*2/,:R[*T; ![J*'{ 8$.gm=8s^}z0~~n2-EV_15c. ܘLqEcPc7g+_褵]vU)Q$a| 9Y8u\UT_ll_Mʭ(zU͝Q3M[?S}h0DliRIdJg=bD2M0.fQCNޮ<\/ªF.ؒ6blRjS /IrСü ng\R.I)XV0ZM |~[EV|g~v!jVlL?o$,1JHղIX 1BUȬEm-]754Ud9Y (kչXm[ JQքg]>j0Bk*ΗUpbVF1SbkQ.\Y)2C=fn*BR[N ԟSU9Swغd?m(,'Đ ܮMf H٨-G`Æ"dd2st-wVLMwFCe݄ e+%E{|ETf'c[1 Q'6ӄ9?mt8\G5*Q(z=D2sYhN.D1"%0%bU&qRgWQ+8\1PmWa2sBaOsק5/6S2,ľ 1EՓYOVt"I6x275c_ q{k̝ry_{cKri7gydWԆKDLɮ6u Vk9)Ђ˫()%KBSráGr29?ܿoUK]1y;~+)hݮo(߷2ћ۸ %,K/Kr_*"b&Ad|\p~%񵪒G$~ކl{ mִVauft)ViH*O-f UlqFrcZjs]霬L%&1R1VΪƐ!*Ĕ\m@PtO v@rJ$I˙!U'[͆U\@qlՕ(6jIU7@6 TcvN(خ<5}KJB<ۍ-\#qFo"% ŬY:ˇ[/jĭjuv Flqc D1-̮6Q$=wR΍썃(rXq iK旛Ф,:1O{ȫ+t)sU#T+?_k*- uHwmg,m4~6„|bĥ[Pxc597 +`Z=Z}+ku7"jl7E[8j(n ʱsOT$*v4튴 IH!qu/IxgDųeٞ/P X(:4nצCm(8#ϰ17(UV J@/dD! Yܶ7模UPcA>4'kUZB(!MXϾo5^]sR`} K5aSbW *#a89NezQ[QkA Vy"D*08fܞM @ am@oi }썤VF}G/"I sksg(6*%w&դk4rwl?Іc=pu[!]p761YkQ3CsM^-*F-;{-Ye|S7? T+O$c;XuM]h$JBc6\-HGRh"TQ!r?uXViu+$D2B|{qD蝄mX?nnv~|կ%&iR}Cż鄻'Xؖ*D$}Ff!0Gfk7YV&Rܘvv9^ݵ(m[vCRb^tmoiU1ԤQE4lpQq6oW)E4&9JDjd S[AšʛTle^+R#IB7QSk ҶAvP9`$[r~Q_ѵZ_%gO<0Xmq-3eƳma,L_j5 6F:\!'Vr cW'\+o_kVPTuM3v'2Ć UBW)X3TreQ}]kQ "zꔰ2:oRR%dX+_T!iI>oY%}bFe[Hn8ǭ5" `B[Z 3aYB2O J:MNEN:M!Hjc A;(B`AR9@iw (m2y̢4+9%Wp3uDs$jM9l8Amw?4?gbaDtww3bپЮҪ_{y_xŋj媂:&phhB !ǛHWMhBj?{MwYN$R꺮fK3‹ӊchÂ$ZjRQ{/LZ,_ QFsOCDsL5:!!M ,C\*7w?xm M*DHITH FktKQcEXŒ&p,BDL*{nH,D:P40&a憛H"Vu2holQaDwUq$-%KBt۶[hYr~-u]i@9=XVmá! ]2r#n% k3XAԶPb e[a4? y|>&1>q,>q<˖S[" 4]{'H`l9kH]yʏ\,=(4I'I~$M!韴w]gJ}jS'َ&IZ*G7"Uo7WW&I)e(Sz#+kG((k'& a%VO/t2Zz /YO}[Rt)%f~yLTk>STSRQ]޷W_}ywKѫ&)ּp AAB%3Q F wUFh!1:hKڑ$M-@LH XkQUI"҉#oa4M3;o{~$,9BD}N+BLYgJ)w⣻ܾ_uJn1} WG9 H !2#0HX Ƕ5zgiZ&]')% w0RP#Dd\nPV/%Ș,BfAyRۭVTx)i6w]v*W͢S1VK_} 0[ҢFЈ&Ĺfhl26Mj&8 r4 e.nlAlD[oqQUw.&r$`Z41ZZ5q@qÒZB*\4qb94]EL!zm%GeF 룓vmvtUmBZ6Sm-YijMR@$&%Q+ Ϥ$-" x;%UgVEI$$BD'5, !>WŌ4ܮ~[IJҊ:a #:Ekٳg7˫26 D! !a D uz{_~qUloǦ̠}2醦dt U/|0塞rJHSj>~k>gE4#ܶv}DPץU'(g4!f<[?{m|j|gϟ<{z4?É+ Q{ۭVJۄJmNԶr䎸"1r,J+*Ƙyޥ@X.0YjPHu"%;rϞ_,1mI+́lIE$, (߾l%iJڶ)VJ I^JۭRI'4,~Y8K9')t`i. ].@hnާIr=RU%վڎWWW"C zGm~t""KP4"D))+:j?ZF4Mc %Lj2Uu Z޾|}buKĸCGA䥞m{g-C"n48մSE~WשkS{6Q=o=[\_;o? [[S鄿v%um! X/ll(^Q~iЊGMbZ4Ml>؈l"ink$L S ~5. +r3l P"U$]GfNU%SmYzg٤XTw6[%lueM$UMIS)pqJUWo"T4Qno)Ƹ}8 Iu${cܚ[͍VBAD]kFAJYM"Z>Ģ^MQQ*lD]K+ LM;o?h{N/C4hTݶVM!4J; N^ ʍ7kfi8EٲXH) %ٝOViJu6o?f&FfeѤZەDMIA0!0Ge 23i[0O_t7~WH"{V^:RR 6QzbͭTYg)%&J 3t xt}e;mjEH wДz:-Mp V,zp 9./tVHIgu>8Ʊ;*qP%Zf C\)D5 cX<5RE&Ka̠nqF&ҥ)ZPTJ$ s@BJ9dpdi'ѮU ȎA$n`!蘈8$`fRUT ԀD)Q+mfG3zHd'1f\ٿc r*p2ޜOIUY)u ξ\n*R#}ƬVbDLx$\i:~藊 +u25=ٲ!юʂd]m"pJzз3RAq<][D|)DD1~bm1/!G6ի\n lAAY'cl5Q`j5Y6eH:JH48QH(TylHn*ɶzZ.SAY;iɰLӎQEXP ӮZ}-] k1Q檚S֔ڔ$$iZ1JS/I13 ,DHC ]'wf\.VLҵcɐyRRy6U j*$(^bJ`e&v*믪 :15b4;$~!AV Z0Iwp11{ZԹBv*TNpTd՟7?FݛSDDԪeN`VtPFT4Ꮈ"hV" C`hz T;F%@m"LhNt_C᭙ 47CύfA(LhKʨB7˖_O_A/0J~뇖Z&թz7MC Qfs٘I=C2o|A4MZ]4~p~A.{s>%fe޻*z Gyl;>qF,s Kamx Mm> r:'Sùm_61>L#E+4`5֒Of88k+Yզ'+#?. ΍@+݆67FX5xF_J?GE[uBeg} Q)aA|ޞxn*U- %a#mMr0s"կkbG֫yq}RŹcms8'a";_h[U:&DzUmX~[a..p<ֱٶ׿xͱNȣI dz1% &Aurfp4cI^t/'`Wzc;;a{rG_ss#8ӏ}ٟ?M[~3wm{S;:lmi3fNxy$_,t>x1wٞ`勰F.'~?{Nm%0@гJ=k HsG$x 5a^JX.a9WRx }w_a=FKX.ַޙ]+aYmwu,r q 1>"Q% 'G&{/o]wU0'om}R2}'.a9 /^_:alue&oorUBW ]%7}?pº oS[mX=*۰NJXc0SGxV.a5Wy$ .a}oNMZK4N-a.dcDs߃}O~wuDr qօ7|otrr8a]a}⓿UBW ^aCNXNX' ׻J*UB',[w E+w8#QkgUB:aJpb띏Z.a9\rr p 먄% ,l3YO7e$&!裏D9~+񙌬L(iFMdOx?>xc@,}N4wjT""sv8lgO7=)RU',T3'#KXjs8N&a! EX'~6di,apX:%a={.a9Z|K²D_zKOqU$ƅHX7o}%"^$> y]UBW MX.x}8a9ax$ [EXr\)KXra)_d\N::S$#ݼ0|1M_`D.~n\LIM_;y{j<<]Yn=+/ 딄'ݏO캺ے6p~4zSOH',KX?5r 0q\Mgur:Du>%$߀u p8p8a9',pr8#dHth+>>ešDsnyFf`acDMJN}=ƢP'eJR݆p8p8NX p8 p<5 ZܖB֠Z -p8\r8NXp8vl[(A3IENDB`rgl/inst/textures/sunsleep.png0000644000176200001440000024061314555455305016263 0ustar liggesusersPNG  IHDR?1ARIDATxၮe[eU>칗JT"ßݳoPTĦT6p3=ik$T6clH0xNf02b{qS9ıN$GKudFO8S쎸FN;G{(> 01i}f'UC<э+Tժj4;JD&DNHL ҳt"J&cbdݐvd=ё br33};Dn,xݤ Sƚ$`3DضT1 Ln\LTcB𶕎*Jhd421: <I; =0LӑɝeP7IFӌ#ڡdǍ t'd=nt4*Tj >L'`9rT+;8ѣaaCeFOFJԨ$7hb`THiGc#Ѥ)щv ҈>agDm:r f;1!;kL#Dj'F&]^-X6^}hz IxيT  'fSFH 8$@֠) DLbnj;lcNf&Im'4TmQf$#'я~'Iz3'9l2)D!<&N-܄IgzPN2'Bbvi&1SplF4""Bt`DIXi&';y;=AvbNLp"hp 76YX@cO9LBwf=V*;舔@!B ;v+&AT: Qzf!hhC;&F6=rts|dٽ$MF*ckQt92rh F)#Qg04rƄiV;0a;r=C M:I pj'Fd&&kJ7id2` $55iQ]-ڮlh$I{h؏=:\C wRQL2 ;hb*$PU)8JvcV-qs0ŎҍjMMf*кL )z jZUlʀ:VP)Ƥ&bk:Lj6lظض H6s܁,|jh i'I$3< tfwR@3A "CcO8d$%=AD8ch'' r;%%܄HɌv.݃ӝ}Gw$-?;d}$WI`\[)n٤l'ڕk<ػ%6p5%C=N22z! jC2I6hS:3鞈]P'Q)6E#B&w&P-lrӛb'G3C$Iʚ550 V 7m]%JK .Hf-`Gce@)SMz葈r )~+MÍ (Wߓ[{O7.D#Jc#N34a[Av[hWImi$ 3OV0!j;]BLuۚ'khsn3G<񘓜v&NFwГnpr6FMr ̠fa}؎uc;FzɁqDYhR0F7RJ݀TKiK%$$A1t I$b-DNR e0+DiI8Cթd *iLUGūxS~<&扇UHiN""MB ' R1C7e ]{S-ڙ I#N40rvo*؅ȠHJL0:h\@bpHw̌bKȨ+k{B 5dLȄ3GFΌC>3smF%sDaCm&2R(48LI۝sd⁣ĮN2&@M"*h[i.T6HvaJ4GD@#IJ'h'G3= #G8əOذ'}LJ128eڸq -D,LҮ!PiPM6M6AW׬-%iTml^m51'cN.V{& Ķa#(6`*RY]#Ns`ȸNT9]m cNPdmldQڑSb`3JNc+ƪXBR'$x,a-ٮ' ЉQa&IaUXmSBD6!ZumVq$D5Q&$q>nƎ>g9a̐ى J$ 0pbQ!mș;n1XX4h(%چ$]ڶHYSp¤v*J 6q&qթ !tƕb'd&QC;:Jz☡ءc'MvZ{喵T7 mv1ݖ-A*i D%k* 55AT"buan)8iI33M4BՓ72vh s&v2&a≓9'GgLNcS}b '>18ό=O8$&vgVO0rMn7!)?&IJ$*-6LT TeFu2p TK )]dL<$D'& k{mʤD:0+&Q[]VUm)EmK7 B@a V3dD846mɡNh jH:晤}LH5tL20`LP!!Ӟ<ȡxx9r|~'I?{&Ɨ]qB vb Zir H2VZ%D)RPpEvcmhdDv6n{woe/m6M_-\ 5^R+Rt lB[ĔM"Zm+(Ji \! P@Yu ݠa@Gpk{=0rdܣL g6|'Mjw`FYHh CeSbgHҰ>'+dn:--5Ԋ+&~ӁIlthATI8JND2RłVH:IY -niӥX˶ z//v- r[Vm{^ϻ{_KnBu` vhB75Hi1M5 UFN&R(`4fj@ (Fv7vfaG7;>ñGg&HGP֮tbYLT)61P6Qwd3>_ɇ#% I[gRd&`!DtR68=ǧ ( DZ춋ԓSvLQ06zM5-LmKk{o Hn,v]$JE8ҥ^dY`{V6f@l+ml#mHa=^@@)@XӑuSN㞘դtmP1Q3PÐD&pN&|{c<1SNz&G>'D}ʉc?I+|]\1l F:G"LR#'NΓg1V{b 2=lb{̀-SRN:a>ynzR۲gsw ܥm{?]zm ־l/,lhP|%b\YE9Fm@-2G#'92*:&Cwư$m+d K[K^XCrA qLw%B$ THpZ,)^}jHKj3j:Rؓ`ɘ0uj ʜTߤs&| &a3} :hvp>B4fr  vljHbB,!OI'7s/~{oo?^{͗n)Sc5QoY +t֕nz鳾cԮĻƒa[U %j&Z1MTi{Sp%-юrYΤ쫩}%Zd aBNSPuA܃WC/@6L@ހwх et3ӭ@Qd;F_A^TwcL%{@2I ¶ԆBGfxojBMҷd 5XV8B+-@f[v lЅ-K)K].p{Cw6k݀9MpܽJޟ{^z%vEnӛ6u1]TwWM HIւFUc¥j(l[!WSʽZh/,[QaޫUpmilem$B P.\KR{xn +i HEȌjJC1c<1~q*}0iR$H4 (vB.ܺ{??_;;?ן;=s??>o{~vnܼM}~tGϽ }~gn:O"F31-xZD"&i$Rv)X: JbۅK[&F`un J䦑emC n[PAC5 -"E+JiA1UZJj Q ږV!dBB3}t܁C:i 0M6މBĽmc۶6Җ" F-]n~?/?~wi}ޟ]߽k[ݽ,~6nmecS"CͻSw͟{jʐiU`媥5g&:mnLhʈ2V*iF` IFӫi}̄P-]f% V*Šhb&5Y&BJBN&c&ڎ ~bל}'1nN3N90zHHzJH016ɈWDD]-ݟݟ[~o} @2]"^)5.[@w-/~/r{N˿n)v{M4ɣ'd:mG;8:Q B iU I,r?UbP,(mlhL$fDhT꣊Pcy FS@qj'2co0D<0#CgigIMđN(ڙ\\-] H 11Peff&-{i('-m-X vUluajEA =pB70[(]wܽ]-[wsaw[6{˟\~׿랟{CT]-EAAUUDZ-еH}aa6E(Yld6Zi\ۤE(]xuiۅ --`&.Ji4jP@dB шLt'MlK@3.nYon*lt햷mKIVI[(05h"@M< MkMdIG9ٜhdlǘ,Dm-tl w{nݬ.]]~?}]YTqM< jh2&dL`BPLDumD(m vl -\ z4Q"Vȅ($M:TE 3f숬($]XliBX%6Q-޽t Q ,ܶJZvE'#1Lm0dFwdfif9zxNg'O+8;~{9~&?'ɉ9q$hAۀmDl|Y--ifB|;g~Dk X,53AJfXt8~XES6.7L!q7']z+椉+KsC2 XFouPJ:Am-wVJ[XzUiq FzT3hc۶-DKR#HnXGHN46eS X*U-U !VRj6K 춑[Ľf[n inn ޥʖ 0 .mn wn*ŶmwK{{mKWO] liA;IKeR ,) .H,^-Rc2M1x%@$ JoH_yKn cYevҲ n Z+)Ψ%5rD"ܰrMw`(4-4tTl[14$ ]pJb 5m/ U-`kZ .eSlmɀuKbooꅊ t'$C:/de{xҏo$};ۮ}ۅuk/oRo2l BaˢRʕqe[ήt*mo`ҴFv#D(@Avpp'ng[[EvSZAiFUjrqAMRuŶ Zy3ޱ'E2X nThI  + [@PU3&1$)i] !iVж TPk7 O0$~N~/'}rO'c?:w-n- O}/^n}[w%{6+֐5oXsm/yBfDwn.{{KIVpLZw1I(hٻQM"&j&#A!x3]P3&LL0q4Fq'yab" 1 F 'Q$xgFŠBpG1Q Xfc(!Q%IiQN21 aM4sə8q3gK>s35%IjFŶL wI̓9iIf?ҭGޔt -۲\i}[% ` vvx9/,`҄pIi *&m&.hKo\ ҍءIM&•*m[A-fMacO`^* *! Mm/-m [ar bzmL\,Ԣe \@h- Z34DH!';ig0'~3|g5|'{@BCmW 3<3!gTx1޺-ܲe+"F/̻lޥwm^{[.vnw˽RnRtÔ r8(Pb** uŁ`#PoeP- -] &Y5ҕ4>ܖkAˤv['I*媐0ЩKULءUM`m]ZIt^C6Z @ZTm-t-`hۦݢ  '-6}_Q}mw {nVHn]^ʖmBwgּli۩[ л5 k -KѶv{Y_MzȝFZ6.L,`E+(1#Հ wPvU\E( )+̥l1q/3}ݰAfM\a^jRu bu&\LJޮIw3RBj-D,Q–^ϑj  JitELRlF(K#]x^\_w>sd?-8[~ߟ+ݽ?kנ_|a˿v.uJ mu; VW*{fjzoN[ ޽,M]GJԐ*P5;DҒpBj()Z [ S¦Y!RʆdR QM\"2Vpkh-V}O6)WOڄ(6ud &eP-f#ϑȶ]Pv L; R5;ݶҊZ ?(ܷ<4-fXRZq}!mlj_9{grvgݘmٶ;Й} '}]Bڥt-֥Ur%ҭQBBu7i ӒBfԲRrN`ځgobY 5A9lsJB*njw~4745L񦧠Ljjc @Lip"\glcƠ[$n+*BɥOI?!w}۞nݓ4B!om̡ex7m_FXm~'Ȫ˦]m2{ez=~_/v5sgenݛ??/O}R?\|\ v\ݻmwo6\o{BMU@ V[9fp*tJ6TOKXc N Q MwWլk[,Fw<7I ŲWTDRU++l10.[Nl'ƅH{RA\mط"0w{3v=Wi;˽zNGe>gqΌ,[,k}mx%dwwI-ss'oU^.~e2Lt6טys6̴~Ϸnf }t)o[Hel@0,0uնA9&cZ(TA)`ژ]b1 RM d-kA#BVݚ,f,T&$@'aKlKZuDiX){5(ʉGnw23t?jƕmN{#>噗8c[ZnP4}MEpg '+?4oqdza0K]å[d߻3# |"vϸx-?})˻smF@>ٔ,|.<:?}>Kw[Ld&.A#u1; hʦ$xAtq[be[(cJJh,uWR$Hw|qfn :j =U {/GhmG'l7cKw䡝XݗMfJb,l]wͺuuvoc% E'b;QÒ]l%8MiCMoc*!*H/\gs_!zk"m[<[ sq3ּ-ɏe~_?n6jZu)mzS@O~{W[;# Gܛw/@i%(*9V Q0*HPY*#$`산ʌSH4Q0$iv5p "*W RP$msSY5(%$W *%:raۤF0.$ـF~io۪Dz\3_7c5jțz'do$]L4k, ji,*إPVU;LL!G8S9`u]yA%IUT*^H4EJoZ$Q.Y)VKnEթ%J*ݗ$`PP93j F;jgI+e4b` Ӵ*ZTnz4mfv+R\\qDtjs/IxXYmB&nF$χmp =#S@cd?~W)۵23~xIk HݕZ\t+kGݒd6'i6T[=ͶIJ}͈l%6@!FgYxZ4uG*VԓEp:RDkEx DBU$AhA5BecWD% S}-h+$!9ZR͆MqM31{EinX˖|v6lcv+ ~e~2bϑxNvwQͶӹ!Be[T3-9f{L\ySO/>^m6?FO2ڿGһ٭2>S.n&7%GM$@URB7/YIIFHLU(ǸT:ۆ:C$m:GJH "IVhAFXdosnss;kR{m 7n=Slؚi<# lF6k!V+_>4s~mǃq6_y~Dz.mlORdDURjwHR"5PgXr:Yl܏K5d{mt[>q[JH}4۠a}YsZ C=7}z?U댨Mwf[/Ёv; ԑK5脵L%pG 4BUh8x2@dd0U3((i+%FzK40lDgDD>0;M1P~Xõsg~Z+dJ͵_mL6آÜٿ9n};rv4?n6>oߢҜ(o~Qle]쪕ZWEۚvm v[ttf L3^5 Gm^5DU=&~s9%3k/=p׷Ao']Z T ZlDe*#RIh`F#Z:mq2?N+!>o9lT!3\W~~UB4/ӱ6|x>ӻӳ?I@[c6[5T*[ඡOul<]M9oyw~uIѴAVPDc+B$ (RmHB&T3lQ=)i(%@+HAHM= UG."Ncڪ%I(XF)RZ~i^IeI%Rw4 KΩ&IbA4 i HjmF\avPy=>^Jw~ݎ8H(i=߿gsZI?/??6{?SGJz~?]>+Ң1hf)dai[UI6^@a$6k d|5/[ nn.-$*aօ"nZkHXQY(–e@d!#Hj++X-E*Ih%HU:B%CP4ЏhZҴ{<f^YM=rI{̋޴^:ZߦG}W8ɕAGGҏ˜L;ÒVz}m4 ΌϳA?țY*kk-2|_|̳wҚ|{D'n}uF^=d[2Z>c5tݦ}ҠVۂfkY)z.UGW=/m>oML?SZH,!H#SEe *@dIЮTK'[YmF2 eEyض ]Z\աݎq%Ijz< i 8v51g ~é_CNRu6c5/aY}wї|/p[20÷#t+qxÖ_WȕDu^i۟zr;Hyi~f7d3_/&L??;>EW{Zi:n}߽˽{MFo~{i%)ŸeqW5M ߸I…@mT'O0h)=۹~Uu{,VcNܩN#ACRKӃcL%UCkD,d.c ?P;tD!^֫.i5R$"SһF=AZ烯Y^4WFuc_}VT_D`S!|~I&uXL?W_A?>҇G]9ٮ#^G#]*jfZiNc mo\~߼M)%./tw$'_hmoNՀثNH[n*;J-Z6Ԣ@UV}szfɒ._ KM4nT:flH1T8c\$(fΪڍm[ b+iD h%IBj5>TCu˦ΙvL2$Dcm˂n>7KT&ʮl(Mt·9aQC/WmT_Wo/"]?ۗw91F꾥W{ǟx7m)r-YjՏg^푥x7r)͘6ӄBohFf mST%B־śmT"4H7RڶH* xvD\ڭvCސ}Z=>&w $_Xc61T WX a` 6X eUi5՘J쫍}Z4p5lY4rΌƇv1+|}ZJpگ{mVsMjo#KGؤrbPUpc$V*I(cHFMm! H ErEFr5 {5F |ϲ(-_\:*mmQ?J}?}Bhkzzw,t7?|ޛ ۿqB iVUƪ$B#V¸"F2qm$+ᜈQ!aFAr-eK6 S~KB2ZGǩuͳ1~|MV`ZMoF1 eG63hdUՌHd*"@Tq[M+u%Y0R½HBU[mLI~[ q~y 9꡷ṩxJJmVۚIrҖ}- c"֕=`PSoa Te! +<ʄZm#Ϥ51!,9lK}I,P.8sL_c=VJvJ\$bOSZ CP BaF`K71R+9 Qk:z/*m3 ~_%~9p>W$!Hq|T=S#A1;}yi$>yvOooy~c/4/8Jo_t[TD:$n5KLYuyoS IZQ QS0#Rzd#`hȥ5J]$ /򲡢R͠Jl$iZĨGzi]c(%(iqTWi1#yX}y=KG tK۔* M)H"7Xj38Z,Nma+R)T*ʎKՇ>R%}{NUGݫm#VXlsaXyP~=y~G(3{f ἤqsn23i߾6Ǡܻznɏ6(w@|y}?g~>}W$J_sIP` Vј`UP PW)o{Z#u, \%5:Xs 8mV4R#HcA)!>F#vtogDϹmV(e/HDF#Y^h)ܮyo/61y_!$"܎4lڦHUTpTgue$>V?nB}mdջ 7 mZc&_Y={|=|ݾ7d9|挪|oΫ&%}i ?>ϕ WOsSznLmJ$`&I7=BywOEPFӿg4"NU3QgY*!# * p $j$R[K6m-@w-uJAcUQvFTy vrd[5cG$i)'D`ZP+1V؝"y-j, (S8uCXyOѭF5"I%+#@>tʱpiUD-KߗVFg"4ڗlh@gOll8x+![[_齹2|t&٢Qlrg8dM^п26eI˴XUh-E`$ *@BRd[P0=NAjlhl$Cf,]>=P 8#aTЂcIEGCPDG=&-Uo)DrDEZ05 .)  [I1nz /1*"kpѐ% TwIPRr?g~پ}$4~ȓ:caKs EH/dn0Թ:?ugu/?s{5K~oM2&jOo7E㚊$Qz*lH,IlD1-UjV@"PPŴBu +F$j`YR#Fƍ6>Q} ]4zDT#PC #h#JEfmgjME o)ʫBHCjJQZġ_:)Zf Զ!Qݯ]#}??wD7uunT)ZEtdLbjz\-}~|=Sޯ~-[R|WiJ7yͼ '__ObsWro~~=JC Rѣb܃m[k1֦:Z,SU٢--" FRTEP$ XjgHS!U8H#I$ƒ$[ۦj!`2ۗ9#ԩ*G^ ER\R8f,nGR*KCET# ]$+S0@G,jgh(zJtF n+WҦV+t@eT)R_Z7YÓ+W-K% ~<3Чٚ޵@Ym'Ya_0-mkm6ɼs<7?r}6ݍF:۴7͎(lBH}+7V(fBcBR:R `K$TB \ $%{PF*]Thk*<^$HV_2$Ah<C9xMJFLG̰s*1ARaF qyY4z,w5TP!3'[?zZ]po.M[>%%40z'׏f{??7-Җ*O=AM@/3Y|fjK<=W_<_yt%<]Vbe j-,UJԣfZl cCGJ6r MT#!èe *$ JU|KJp @ĵdg$EGԡ4#W%$@¨lʶт(}$g,w;j bPZ$J5CV<2 T3RK6a$U<{6~D_}CO"4dKЗ<ߜ|>ow՛_._;W%ڽVٴms X-J"EF `D%Cm #Cq n;ARdP@ IP)˪̵amUc6F.K1sTO.GX z,VhleIq{ffKAhoj~IZ3#Iv`@-bfF9[ZTY}[o~n__~ڗsǟgu`n'OOuλ7 zg><|s C_~~sW?w&{7QrQbV- Ͷ"nC+Ns+Q"Ph aJzdC1C-EcKE#S!BIHjdTX(UR؂BHo)BN kdiYa1@eH*긇1 MIHMV,5 P5cq%G?V&SGzi,$(joKV/yXG\c":||}Ð7?~?~?[~~5Ѽۯwe/jDއL-Ch9c:c(im>ͮ~mwVMh7F7wXh$ESYWrnszy^ۿOGikvdI^KŀՐh#uadEP *R# I1PPAGdA;&qwe!` *;#?DnVm͖$pS4YR޽ݦ~Ii-ɯ3l{r3Rܦ)/w)ݽM6,xni-+)CHVUۿg%R[ƀT²Z4Ȑ0$2HT*v<$̘dK0HTAZദm-21*hj=81:czڎPEKa }ZI 4Jm5U(M[<>㼪 nGnl2miHt&~.?y`paZ]uˏz{ԯ͏Sth{oNҨhzUtEާjn(MQұ+c!v7D5lVj/nvn^6*V׍iAwW[RPJӮѪP.5ڢԈ6l*FR-[.Z 5R@jE `G X X235h jkuҶj6@조HhG  m+BeI4DjH mm6GjUj٬5c^ґڵ5 (ǣӽEJz/A/9/U@΋?義5?<7_Onv{od ч}kM&V-STҦHƞ&7㣒tYm:!.#u'6M{4*)m vUJhQ.u]_KR[!iB ``b\!ˀ0CW2ERyP`jH}@Xkd*5e֨BQ J*ITW=%] 4Hz$5-Br4X^#ӑD ^n+7+MUfkqE$F!WmmO_?iS*Z9SaAU]שɟ~>HTキ~˳Ma)Ҽ)* ̤kxߕm~?>ބR!#M{%=K'-)JY["f")MUjH%sB#oH$Tƥ.)--}m^Ҩn RQ mhVTBvR`˸I4mUjWt9>}Tk6bHgPbKؽP-ްHRnP!HI5X]TNѝ45_}KDJ/UϻKXn43|sߟg|ÏfgyߪMx}?^6uO mMe{_}}}%x?>~>{Yl5DPiI7$b[KnhRTUO: RI͕D+5XeU_X:DXB21ūZVRA@3h[AlQIR+FL(j,3UaHPRdP Jm% EnI‘f^8blHB{3'ڃ"ǖE!h];(.MJ`pɱ9#hpQum}EҾGz,@ni5ѠSԮ^ó W@6S݂KH 6Л5NӇnݦha#Ll TPjݿk)2Bk$Ed8RZn+OS0]N2 #ƦUn1 t rRÓXFieQl+H#r{4ɶҀGֵp̈H`HQ)jJI -0; UFsiZgBR T};/>w\n%zuon!ҏ~vxozЫ} n`|ʳw P)I9@CUDsC@~^3}xT^h*rP)YnƷV~W&Oj.mVm=7pwMAP@WȍNj7R)R N]S3ʢRU* "IԵJZlnȒZ{v?DH46 ,Z:UQhA[;9g&M1='ZgtjSUmU.z["-xZG}6vűepj_J:fW4w}+ȇ1~|Iϫ|?x?iRoz~dz~woCZnFv#n3lZ59mT[UzFzh3uԗ*ٶ**.fJӐR8h;}]])(r0}L? -k<vlEFT !TdӶ$5vf  jGtaCg"%dUbAQPȤbÈ5r3!&c1vۿ8sݽB3:c H B$}諹O΍rEwlK+cUo^L}|J8??]tg/e֯o:׏_wWKrwOMt^QZ6j#96IoP;TMeH)'ԥl$!UJU,kv%W!nAQɀ$)GC/EgLE>RBlK,Z `Fi5)Geb;#lu=J# JH(R5bD$!-[״™3~6*Itl:*j|UURUQ֒ BGt} 'e(?,>C/^%a-Z0ntw\>es\>;?}֢#ݤΰ̂^-3F4=缎^i~1\o_ֳ=;1͟;0{?9߾y^ MOjwzG*ɽe$ mUذ"%Yb5-J[vmrXTdk),VoUϕ>{8ۨ&pc.dGrW-A{lI6T|>TQIނUUԵIb (`IlՒkjs,ܴB%"ͦTޖTJ ]|Kt!&[#٪KRin9GGonDY= |nB|2c_;w#DIoǯ_?w7?!R#_Hs~w~o?sslo۽\Iv,w){ }#&&R$,V{5W\h PY//N?}?}^)cz?s~̮_y^y>'g4{vȨMfv}1S3Q*WܐnP!BOv+PBuBv!)n[H jHK@&F(Vj5LWaEjRQ 5&hЈ+UFZ??vLm.t-:4@UܢL464"\Q1*K_|HQ}(,ۖ4ihh;T44Q5t&RIE@weK΍ޠWTjBgyw+틱$rܲw}}͟y^z5hZ C}Mlil-ᐄڟ?w-_O:rU:6iٷT/Qx\sr6j3I✺\̂y9mR:[Z&bp 4 (xF)B4 @Zh` C(UVsz7e3m@T3i'8H䥬%ՂeX@[ r+^3*]]%T"Wea8e[Q˷5jO 4LVd%ieYDVL{Vq]%-ɾ-lOōX7;ϟפR{.tZ}7e-_MiVKP\!~8|;<[<ٷhOdM[ڝ6.4N3<{iYW´g(L 5 [ Tk+#5]l*TzIv,u#GNf)DG:CG2S0^YaEaEZ-eU% ]qGTDt2U Beh:Ê$%ЂewEסroUF殺U*;ҕ\IvfVpIm3 j._oӃLiu {_ˡ-l׾TsZۺ n#^+Z/ߞ:ەhU@UBEa-jv8J;[X~:t[)>:]0NK43#r95I}IIvu ީ3tAgeM[Q-e%tN"*(G H%ڴUM+V`MpS(TIZiVSQJe v7cRX+eX2jd@@EVT#%@HMRITxEY(XFp`{-ZER/鐅P֙>h┝l,H)M>1?ޛLǙGZx3Ow>v/i9?u]sMD9Z^Y39߯uGۅi!VU%5_Cn) ˳$Isc#ݧRu_:=#m&Mىڦf IS=&5e =uB4*iZ;XI4iMCс7 $&xRB4kݬѴzS R;Aa1Qz4CTP.%_"KHܰ(`WZ@REv P9[ZN@2SNk]c0/G]k>p4^ٗEt>Gqi=l& P ގuSfTDy?3Ӷ,'a#[<'+nYPuɒohMZjI;bͱ$B1vW:J"cɺ-^Yّͩ]GvΐړL ^ҹ)=!4s%;RiK5hE0U"W VjOKAPSn\ژu@k]\-)iE@TQ.}iHkleO rA ɽ{U,0Bi*Z$Z)bAJ"&T@m:>VfܹE>ݏO+wZTTYnSX{8Ҧ䶀vnҧ[{_98~z2IPRM>54ig΅L'Xɮv2Wj}M"JH"a5t*j )J-5aJI۴Q[j*cѶ]n#K \#5L:Rwږ*&j!۴KJ6IE,yg]ZK *--PV((二$ZHiebfy,)Xѻ{n"%rsx‰JN0TezQoKs:ߟyz>׏gg@r?n̜㼨m{ȥS-i6xiv)(tթVUpWEVյfIwFa4PB]9hVGQNBQvtifz#Rݴ9H!h>ӉD/Դ4WBHƴi`cQ2 4qve ^HA;̅t.R-{Λd$im9)JeE:9hE+C$GHAK%jUa DֲfI7@/Ҭl^EijG*2/IdS!#9גZCJմ{zTSk^nߟEIF Ml{?r[ʤeFBM #V&TnW: r(RnCCtu_ZG&X\0F$];Ms^Ci&n5M)W45`&jxdMtFUIb* ^f&TKS1Gfh#Q &3Ud.fnUK1j'9H❪v= HEBT ܈#@.`"i6v1Kl\*Ird;V˺uwyPѭ{XB1RTm[\Q 0pJwy}^{/osO 3]P|s;o*x}2*E{_TM np[:aQܪS8.,-ݛ椭HLw];9R%M3{hh&:Ifo d*ZFiD 6ёR2].M6pTQQU]iA% B%qWea@#M ZMP 7z(a,ht7Quجj5򸷂&ljYjb!KT,0^WZUWު8"t4%WĄ Ya$tumYz8yK =0ۢc-/^n(SIU} n6}H X`Je r%`-H%ԙz'C}]]ⴶڢbhjv3y+ dڲiw3͠=:瞤W{DۭqPޮm[]u]Ul%\58eK]2A D^7h9wɃtisv2ij )H.hV:-Ja͖g!я= F&뙽,!WݱXF˔>siUВ4qCX+?*HhKLM-d)*@V56:Tc:M_qhԬV!%W2 Eq33;ZCdM2ky]uE3y$FmWwMfbk]>ZkBnۉI"-琄FY&rCCه-%t#`NX:'x6P=؜N>sf 7{wح97C$Vqx ex^LPSlPxv5Z}~|oKcFss,A$ U<\WF|vͤWdC^Bk@H`U2\W,ԎCH^ llaAC7( GE{$\,ݽm7@*kP@m涯L ۇ-;{l]Μ|ޞ3b9!M:"ZI]mZ48TinVChoK#v3RYۨxY‹C=!jMB~^cGCABjg3UUBs:MRiI/Ȥ32q}v%s_qڏ-/ ?Zu)g`!FoR,&]ɥ|\{bm6h_3ٜ;•}x-tϾ c&WǛNk.-_?LU$BP%UZ M%$RdC, t[ct3 ,(`nMM$U2+ EP;nvDžŲV|y^97f:%vfátb/0/ֱLmϾp"^MkPPbPbB7Pݔ]QOZhO7wL+} <YE_#&݋MZ H ݌Mc=nZiwϷ#o!Tt(nv{v9ҳ̼Ʉӏ9dn~{I羶ޗ)':vSP3*逦1.-HB$PTK!8L)$jtKU<.#K]K-,Ie$ fpKkI rbBf~\ǧټ]]ɄLUNꨒK2yba@,Kpof=|IE,0b Sp=XfX\ĭ,~8tТNu4Y?}N/=.ɥNݶBKjD6& U51W7k-:wϩ<6: L\We~&l^ko}1PMZi /\$)3r==wA/բ*/IPޖIM QeUՁ rFҪF.KZXR-ve+,/MNFZ+0DqViT+ -=fIFfQ&3CF-tiZ5=u^*./e=[j*Kn 7s[pH{ŧ~M_zìv7-ƪ鎟Gv]Hh:QrhfwUZgѷkgdYKd0,ˡe~~`I eK'H(PׅĽ߻ܻ%B^dtvrn7Zݣ݌LP0t6P`/9ݓssOeM,I77ɞݬ:pKM %!5DK44yUR5vF#h=kOM$mlSeGIwN\5Ls`4}XrAE$M"$ K ]FRzb-V[-ʁ͸#yEY4b搠mghw}qM,^?s RkVV vв:j eBi {*أunnO7}MkUp EjQH] ,AP$lLؼ=Kur#fD؅\M4a_̮9m uYPSѤ Rgf"IB]heܞh˵۠WD[ x+D-t v Dy^![MMS4ѦBhK,YIT#tHn4I^k9$Z t_,Z],AֲHBq%R$u=J֤FJ3/ܐMwI"R32HE"P!B J e/SF*WHY:wnIxT[ s)p䗮;m,%T.>;>`Fݻ{Dm?<@x/k6JS$fO4t^D)tjfЮK!3ITi!>Vre0bt',LWxP3Kr0Vau[B n0EcˤR EZh-IT52BHBL^u9uY%P 2`RvP-7]Ji`q7d!wIm[VAG7nd,q,5UhK& IڠX䣇$-d-('3THn]ƆV% ~7> O*y:;tʆ3<7{ڒsڐ2ZWѐdtM\UkP6qM۲͎%s(ؤ{fֱkϙHU2P%ٕ;Q2IH"G4mB)*?5nז@jl#,d*B# bd-QtɘX+(K5 vY#XMe*RRPԅRbTP` &XI3MUUFhQuHlե,Szu"SpI,;BE ` -dP9ďQ=Qńfw_H}~\zOe (С]LϽUQT NH {T]iOFI4maιm1v$3Ү4aڙ m)m7])[PЅ&V(Pl`?-5$e7Y d)JKEP\X`S*-[,6B"Iz,LVAHPY Ђ-T JUHY@:As-sp+0 GdVm6-/h F!CE. VYW𣸕OxK2jf't+O> o xO'3ͩ(xw.]~\<6Lv(kWjhpBv-I4AmI D"^V4( ]t;.p4UTt" f- -rw$/2Ԩc :DPZ,KQ0,]XK=RKQTT,T"`E chQ  *DB*JFZHZP!d r,iau$ݐ$-l\>H\>%ů zzl=w#]z^O{$V{Ӛ"BaR&vgJ&S&=7ZiZ%PCHM(r`e֩Hvd*-Jkͨx[KQt6VBw)bEŶS ,!KKTZTU,P[Ym=ŕX`-dR]H"BUEY @jkTj+ (P[]H`ʲ(j%#I:2*BB BZZ ݰ+k!;o?.%3uY9 >O@y7*7x¢7N7r/ޟ~~>KQ4EEhSNJ{%P') BErlƨmQdU)PdTHtN!e=%yYiu2鴤N3k5{4Q܎w$>BU[""yTJ,l-9m RQ[F-B,.E)ZC+S$`W[Tȸ+S  0VkVV$ r,\$$|r-$-dUbX%Ё ,* Gj HpP7 _\b+WM=x ;9z3Tm5Y]Pږ4u+Ξ\ IЄEl :ٙDd% &UR*FkKH ya&D IN Àlp%۶dSS%'HBpi9`$s(Zie9xqx%#*@ue6HKFmbj"ZETТŢJ2Z/@vٲb!ɮUIuP@ey~(~p_Џ߄70dT}EF>gDڱ￁+=Ih4kye=6WIN]ÙL5Sݴ$Zy{_;44U ;2l/a-Ym$UuȢBOT @}MBJJ*$Hi`ޖM%ժehj7b:F"GV+W˨`nR%In#7 $uEc`@4hU* HP@!XTZ>TBhj9d-IH𪋐VƇkW:@^l|ԵЪotC|wI?)Dܥ;DJ彼)=.n~.Ay|?>gxz>@rjBF<ԃDž,{(H♞2q褘@QjBC[Q Bt+@e9vj^T0RsӲ44Mu*lMcf/iv seUUEH:Jإu9P,lӱIeHQ*#C$5 1䂪HF !dR(UTRIJd! `Q0HHe`dŢueȕʲ78`O߈@Vx'1bm+4gn%ϳϓT\R ڦB=]t"M2FtW#=m}}>?eXFdQy(MUf'EigjP4 Mҳ!;TMkV䙔Ҁ$Q2iE -m:viV#;J mm if4Mi4I&t=ɔjIB3M6)3TiF4̘5PTaTD ):DP0t0CCF^D)) #1LTM)-\$p (,I,E܅~_~jGaz{|j0}Ch]p#v}iPC rD)N MU9,ZTՒ?ߎۧsËsקUͳ|>{m>解W?xc^>u{Ye_^ǑC˽-^,[HȒQG5E hv RVbLIhBUdi6U4)MRA*)3)i`lʤ[m$CJiLth tDiJҐQ3 %TBBIg(0dRP[`hfBBS3\O+[/j"e?;qYMRF&F :%[ BHƫֲ% 4iC1P*˫k~hs:ny>AYe~׵ǘW+X䓎Ol,܎:$L!:WԐ6X>,&I{+C1$QKKU#ZIff&mK2NfݎҴɴM#$td2ӖI3:CҤm43ɤdfoڤRrKM!i ʤi&LEh h Ju{:!4ӔR=MHIII@[$((^ I;0 "EQnK|f]+v(d  HQ"#-BV!˽-%UHmВz7'|~{ӯ:痷/oo?_^__?|+k2Wa;YeEZZHZQɳrK뼦y>yIQ7ЖN;f-fj[OIwA ڴm6Lf^ 0IW58I$m4ВlV4ޓ$;q0!UJԃ&$LII:Zf:!%$IP: )RRR*PRB[B 78'łHk.Q'k!E6*h$Z56!FE$m%B$j+JB=s]o~+_?ί8dǟ||>~ux^n߯Y=%%ɵ;WKgy^zT8m$m+&L HLiiEiZS@]VtgO;%Fӳ@RL0\4keOoӯ_~ykRP@D!""V%)  ل(---E(VRҶ0,aMh SUP>gsi!dL͐tvg6%Q SeH:%%ebHHT\*9%!ӷo#o|_j<=~=~_>W^?o?ׯo}?9~l=c~?q=Wy;vu}\sx\uu]aWIIX4XM3ti j"YM:dk@QKvBJK5Xu$ ӗ_?}y}>wӶm!dRh@(S6J(JkA mBK -i#AaIZh ÂU /?h @``Di PU-U+q(i uĔZE$ DB蚊6R_3r6<-/oYekǹ{~{\}y}_ޟ_?O/_l3;L|pKǖL/|u۷t{fdPKJkM%ٙ -LH iiGtIm!Q%ihȈ:iJԥvLM'f_?}8[Z]Z:j:i" %T )Q-vt=jP-AСiC+ @p V>{~|"GB(@[Q6$Ъ̈́U)ДNtJ@q7M3찇 ;ڹ_ߏc}{z9}288_^9?{/߮=~yۯg?z~}{4|{EI$vHhJҒJmCFڔVmv h6ɵ/~OO/=PmL6".@C ) 2@ M^'vKrKKsi W4!Cf8tuJmS%a L4eo4s眿c_<ܜߝq|_onp^N?o繯yk\{+{XoL$tճ$<5 ?ndjz^_?|ogΙJDSR&'0jL%4VĭQv2m˪*Ϋ_byؿ>xޯڝҢ@t"jE@@H) 5z|z͓١%%RPC n*@-lb@ O֜xdoۿѤCWҹ4Љvx®R`”<tJ= _v~_>sw3^h?=WMymy="VE4J{}\J]qzXhM\LYnEg?/_~*-4u!l57GCC"aRIVZi4"C6"fVv{!$ZO3_vL!0*RMm7%СPZ-%~_?\{n_ׯo<6Ǟ?9!$J.Kv"!"J?}ʗ7}_~Gޞ9}A3<=Ju K;iFW4ӉZJIuM978B^sk~|}|<ޟ_>= v'OmK,Ak9ާZQd I 4ROAㅠ; H@"2j7035{OZs vY~r3Oϟv]Ow/׀Oٷm% ,8Ωpz K039+`y Ns<|I#<:mq A>ު6 @j 3Odßm;"AٶРAd8$Z h *m۶!B["RÒ$OKO_T2/ϯ%cww!A  д&B;h 6$0^?^O[`yj^wl٢m٘KIS $ض-7-2J,@Mpu^?}nmA+,D &r[nz6$te28)$(̪yq?6m $~َ$X_k^DܶkqїzIJqY׼[9as9e}{>w[rϮp9_}֑p(,;ud˗m/߼dȴb[`˲[ a[(L9LCM jE a$ DRݎY[m5e,#o|=dA[!\` Ѳj1Ր† I^R\ڌ(s|/sNFi Hm´Iv@hI$IiNo/j FXa:H`ٖF 4lp m48 l/޶f,Vt&cD/OxE݃_?FU~ުJ w]JdRXDЋƒ]ݢm^m/zZ6aػrΗ[9y5ն$nHm[$lRےeCݖmIꖻi)$mI->R7Tec"޾_/iHj؄ jƄd`a5ZjTnKte6o۵wS}T# K;@ AAfhh @ `j8v؅mr߰ L; %4PlmqpVAVAm2$iF<'=|2J"Yc~r݅]—m~sBv5/m6k~痗x/_/OMz\tml eؠu@$H>璹]KFX:iO mjռmu چY%I4 n-XnӰ,pٲ.r0L,$Y-%`Gw ^ԥXN>9sy*o>< niTCe膄> "J 6ZaUhӗޏ˟o w?_RˀݲAuEP@`Dݶe7!}usj(2+H`G6zz*l;WoWD@ڮ9`7 ɳm6__uB ~O^|sY>v9_kxnw۶Z|xz/_nO??WsNV^9HF0Q秗? [mlxyOݟNAw۲e5D5[Ϸ+AU%[2 u-0SmeˀUlۖ;r%SՐ 5eZv{I8v1"~W{[u].˵{n|x!?R5k:uviQ4aDQjЀjȐQ]~].N9c(C^/2d!Ҡ .Y7ֆd؁( @o$~ gfVÀq4o;^iފ[C4`[DZBZ ׭??>?і)ėkұFX2XAGOŶCZ_o54>p=ތ@;^^zۿ?}~O?O{=sk4)rmO_}ӧ޾/kFi???]WoNϯG7a\&" fPr3 Lа?o7oN%ܭ)#?=/mjKHo+/x=SxXo~|+"uߝ]?y{cqYri,q^4MrcIn݉~QtX;1 ^` $Cѵȧw?Ox|JcjPz+)i`l ؅G^L{IoǟzݻGisoe5dJ B "$Ђ:/]?/.Oό8~?rә~WӕKokt ?rϻ7_=_.*~z6OGrӧ_=nr<^֗eYo}߾Ǖ?|mO<>]O?nʕ;p{~-Knہ~:9y;><ޏw~x DQ눭4ɹeV>܏e:ֈC$﷞%Gѧ1|[ 0Fp5AO( #؉ b{y91n]Ty[OAc]Woy}b8:7g{傸w~O ௉ĉm$m Wpğ?x?ȿ|r'Ȥnҏib[] CElI {P?}r[?ף_;O_޽{>_/>_ޅ7w;ϟ__Zsׯ=n><_nBS^t׹_o{/ or[˷?~ _^tw|q]:/yoΫa ii[oubȻ鱬z2\Du$̒2#mǂ$:I-q& Aw~z?x}_VݛӲ>]o?ۯ5o+~r~Ͽie_y ߽mӗ1y_~_}}w?qw~s_>jOo>g?~w5y:?=IfK1pC{~XD̥ 20[0s}YeLK1kr!iDM :9RKCPea*rz?w]u wuY0 sy;yg|e.a|ٶQcpYGDdu׽$T4L@ApuY2h Ocl kIJ*+vV^]u۷vu,k&:!d C%Y}ߟN/}D%ds.8D%a 3"0&z5ےS#"rcT,hCrz\Ǜx<<|Z惿׏x|gw}| ׿1}0/3B{ozǽo?~ˮǬ|?f4iY cffaߦQnym;9o/%8oH{Mb ~:_:-,*:9~s߼?wyY|:z32>ڎC*WowXw#*4i9]mF^ګ3S ;h.AXu,8&d{$NX2ADI"[͞}&a9pq ivWKv^w{u,ea s<#G`EslIΌhKXY^Ɛ7DuIp"+1,w>]N+PX a;W'k"_u~QoO_2D| $܌+78pkue:0v=Om;N,~4_o{s Yim+GJ"pcB[ky14 *GNt,F $RjrX h"(V梥{.tI>h(bz^F-׻ Wo~uil)s g.ݽ5[;F`YA {Dwd)@ @2s#u,}.#Id˚"hz(w5Խm@?/!岬`-1 kZ"#벘&>N<:۳wԈ.lO'be>F[wv?r4.Vd8ȥO+7׳yKU)k'??\Rs죫91u]'_m?ٷY4-vhv\ ƾu(MMIHb8wKv[Cc l;톌n-h848*- 1Nf /xc;/uef՜G ۻRI  / Ǹ;rȌ_ \HF  mvL[D&Ι`XA;IC .ij˜U'4bR#})<-%mUz9R0)"\#1Sf$ %SֵK##91FԞQAc!,ӢcQ/^o2ߟww'Nyɸ_5t<7 so-N3^ ==ord-NΆptfJٛo~qۮ}?YY>,˄*YK=fZN'#rӎ8Ur`PgAj ( RPV3R-. %AEӚȈ>aC`.\%_~h8xrZ")ВCAƒi 2I/vuz@Ft$HBd. m%Npt[n 4.x]O Sr4P0 >Ge9>3ǚ^.#T$! F(< jfDauspMܟ˻tzw{<)iPV,\k~M12~ ~ </:~MӆW//ju}LWqcDZϩa&NcIVpع^Z1t1e5MT-"Ö\2`!"G]IRvC0lbH2X  0!F,*7sA:!AB  \Fc6F48FGsbj.`&G CALj)bM]V^r/X߬9-,Sz ,%}ZgNXI q:G|Iog\',\|x [ p5^9{[cbg{ZOkYO s9#ME2%Y>6wIfC7GmGD %`Z3|Y333%dsc jۊY6 aY$wrg{adjNvDNY(E'KAm !=AGhK04@iju +IKD ˀa@Xpȉ)m*Y6)N ; D 6(U┶:Ɉ-mA ”mfwTT80\`VHtSQ#*hК )XKf#Xh$XFIr5{q/׎gSezp۰_qx{ z '_&?Rc/}f썞u{V*sznGlTAlWKAIVƔv4mK" U[ў풂K1Smؤ1a VjMyVwK%ՖS}fmr#bɤL(PV´en}bO ^}qcv?|_vӷ,{o}GyfU):ʢ]1Rau,тm%4r@Q)G$!̨&wuh,7h428PaC1Rp&bP̰MAcD0mbhɑIB G.̈́`$# % a#A¦AP E$d6L"ȐpeȔIAm0ab%@H-SD6ɔ 02K h6l r0жEfAMXjip,XIAv=0ips!4TptRNctGmd[&m[Y]*a ͘nQ>^e~OO;~nڼ5[>jξ&vfԜ.nFSXZbtZюBvuݐ $GcJm[dpF@XJA0eaPm Zt8:HiHyY\ 0#m#9bQ H"s,cY pYDPdp!)& hC ߿f 聄 X:h40d&a`D CAB6"n2P@$J&m ȀaҊl1LFiIi1FAa dXD:e$k^Hiy8s>_^ߝiNs6!(=Ie`$36G_Ѝ ^*Mdu>4ӷ|=o{ӷCmv;ٷF;GjGI"]%1Q 5R0$Ri=nS# !QdvD]6vKؐP a{T6aѤfF:3BY as7c -f_e 9d$aT h&(M&Z 4@6 -#2)fC\b `%H0dYHX2$@ lTb2B"h;;3ȱHAs\Gb F&EyĢ88H>WߝkJ!NovtK18s?- ,ĸ[qw=Vٛ֕po՘]mrMU{iSģG M BL421uCHfrť"כA`:ڂ(#Ȕ;K$ʹdmْh!`Z,FធT)۰dmj`„a)l4Ap@D؀l$@a)@ #jScRrXBx1NxI@R˚pVѻ*uI Dn”ncÞf5Z솼s9ꝪE=9S]nwkTMn&_o7[yVvv=ϾY}~)ݎQ:x9tkv]8hPBp{!AVCE.Jl2"X&\SS%4acICm NA IA2au (CZ"C0$%ba&HZ+:`$Hޞ@ "`2r1,&D056"Sh#6  HFn/" m adpPD\ A f0R=a9eh0;L%z0F4 F8$d.#.#ï>~e i6cfU82NB -49i9a=a l&ǼGs %.GXqP1UTqש0ͪvEw!&Qad[LVۂC@cAp4D1:ԤgH$Y@CdO{e0es2H33f@ $m%] w)4fdtEAn aAHA66(@$i7@ሠ0lrI[d9,EڑHI&Ј""H8;0$ &XDfKSJzɱI&0×rZs i1%8Zq/=9eaתYX)#IcQNf`$t^וK:@Izۭ^^= -~ +K[y{@1^؋[ ͘na,lXI ƔLa u. @䲫F$-wȞ0@a@k.PbwbFQUMaQ !:㨎nۇp@AF2DVƴ`{1(  I \̦l6p&lDh# N^6#Ia0%l4aK8#i v$<2X-1yb,KNy:eNg`c0GdEUs_<]N\Tf{jYE[P(Ǿ 2H u%/q=e$Rܽun^"loe;Yˈ)8`M++6ᘥ7wh` 66c 6 (Ӓe,"4(CImtu&,Xf5$[&CD eIIl*IʂCv$i!pd> 2GI@zڀ$lZED ia[6&lZ p ib" dA-Qei0D 2$ jaFT ٦ (TS}8 aED0lhVbYxKqXvwUY6H2 `j?Y_jvڔ/+6bX'qX6n+_os^^]rØV]gOivw&"K m-7Y<*mH9ܶ#(" h h` I@8$6PXP ٲ""2,GK p0Av̲[jys0,hhLlM pL m3,B` hZ`A`Z mpta Ldd2Hh1HAdK ,))r|:AD=8TAx v^xAo>ܝ݅ng\G&jN WOpe`/뒋rk9en=U6{ls~qڶ@Ӗ<<*E,iv&WC M v9Dv$f2 5β;H4v a#" u롞jdm HV%r] ò$c)5aCD9,` a7a@!#ii{&& c =@c0e(dFARBMIhۄB1ȶJ̠m`UpF6 !f02&:\ܗcD"בȁL#jad]FD8i$^N 8_.9r\7X>_/y9˖P#5"O)S2븡|ύQGo:f٥Q1m9` í0!+60D0`L&#z22B"i,˺&.dm3cDP1Zeӵ{;A-$#FRb&XR'y:їpy!Nkߟ=;[Af"#2x=r+P!jv#fcgg,G *FDvL ara3h)BAԇ;T3pb&tNE:%{x,At8 Xt\VzLN˛wV3yt[kTr0#'nu>=*Djќ჻T3Ц`a8) =CkM# @jDQ$/Z6h-4Ts,P$;M^pD8dvM@d `C#IYȳܲ,X9!#G"kJ Dӹ[7o/GڊMDHt'a4 kD-# ZD@A$¨$iɀnE ;0T . IkHX@{FXVd 3 Xi\ JD,w#.1e9σ5bX^"x<4qsϡZ5:nכMqSQH b6jc n4& -Ԃl4RGC0&9pL*!b3Sp6ҸrQ=X* 0d2 `p!-;e "Ӎ0v tM#,1P`ADv#0A&"vll4A\hQ* MݖiBpD0D[ 6|H 2$%4X p @$C."n`ɇaP6nF+ȴ2A  DZ讔ަ%fDnsVOWWյu۞UHL}0rCeKx& #rGqNfϱ㪾›TVY}D6\Qa$˪T}$xȇ 6mB 1-0v`2&1m4 `F# alV9d$"Iv[ e M""(@DZE$ !WЈ4F&$`i"D d4FZ&mC B0# l0d- l4AEa6 PMV϶A]&тI5sa6GLC&ݰݳP5mE&|pd# ~5>?y_]Ӑ ]JH<ڧ^~um7x3۩R5B7'6z *jQF[Qe0BV \afDSlA2 @l4pmiJ@[ @6(Lն$ v0li`2-KhA (HR- AY8mgi{I %.f@1yfdyBp6g"Ϝe3MpMML'ܘ-DOK=3=" Ykv{n3K$$m':gzsNB %ŒL\DJNdm2M?ړi7ty `iV28gZH#3$vu> Ϳ_`!HH"`Ô:hfG7O?ϯmO`#i2眇?$C9sL{ogfϝN9??͍$F2@ό^>ϧnPI2Ӄ'L&fS=;s}ʇy~83>C=G9+_Wۙݜe>NW6pι?GĭfmCcP9)c y='V0Aa3g.372kH$Cgn: @1y~Ż> I>񒓟=*|3/_wyL4W3{89mYa^߅qI=|<7leZ;q{ݏZ#drΓ h92;%ڜu&s'v<t|鼳qH&|& /93_̓kC}8F D$>nbٔ 2)H989t" Qlh 9&N"ɨ2Yݙyd&Wy(-Ƕl999iÝ/ #}R WM<'sxm믙_ߙonfӟsڻ݈3tKz:M[n*(.wlP1 ^*sɵķ1yH^ P 2-Йq(5@rЂZ #9ϙq&L:fff"i70q%$А:d pTș3y 9yz)di>ZH6'` PMv'\zU$&%Vk@LN̉ə0*yf&c~F۞d{f>tΑčM:^3Og&үaf39ʄ%LKcLQ=fr=uZ3n蠭s~oϟM[d'PxH[sϜdn`;&2Όl$Ij̄Ih0]AÄC2ɄI",QLN'32z<%wg3 &1Y 0cNvΡ>d' XkpƮ[5cL=O&{vnw{o~{v,K٦-_ʿ~9wuɟ~ܷEhȼM:wo7ʻ8sy:@Usb)`$H!9Ux3<̜`rs5{믷w;ɯ70{7are0[>,ǻ1͐M珥R8үaބ\B3?[9I5 /syby݃ -j6ᓣm` $<.9a^:dȥ t3ϥ3>=8*#M#$('l=vAz yDHH*!Nb0%Co&~?$8!797cfh3s 9I˙~g~泙}R|q$Mjͩ*Ι"1Mr[rɿw;gRS,.S06%JF!LtfB /4Id&8<~po+$h۝&sJjɉB$xCEdxS*LNH$IH%iʤ&) P D.C@CfBqf3S93X(!f;3q& !u3BDX88̈́t<3eVy;C'OnNp; Qg ?,f3=&1?x?!c:>7̤'ts ݄K{%Ԙ3sʤkO2? 'Ȟsxy4/ ;Le@ &^Z3Xt,>s~fubb <^U$RKD&]fra[eP=,_:ZcI2R0~N>8dv3 Lr8v1"a¶3hҙ1 fM2NeBqbJ^l!uϜ Dbl!`35s=ۙ縸( L 9̆sL>~ɩO0g'I?ɧIdB>3--cm1u2]!dB9o7s4Nf>M+brd l}+q݌ w>3#yԺ2mİtҖ0yz#t2B.dǼAs:hc~&}s<5C833R?[yW@.97pꈑ L H 05lg~|ĄAO6Afgʘ&>rd&>fBItFKIlɱ`74™"Ήj=g@3y,/l0s뙜Iߚ3]{oax@ƭ $rnM%\)?y«Œ+P$l&gF6 -QG3rǸ6hBtΒ*IrJ-BԌ13<*!?73q @&ڸd?ie2 fXr :`Lrɀq9\{0%IqJ  LО9K9'S>@$ʃ9 f3ٜ|AȉqOa9tSgg?x3ˮ&nj3o?N2#ߖ|3$DK' `Ӈ0"g뒆2q'C" SlFpL1h@%sX;S%& bT1LM!/FCQͨˈt!xp$<ᜱt(s> ږ9OtȜۤGN &ڍyN0 Y?J!]r ̷uLNjw[Gyܶ9q\l=̜IRR#r¤fT< &GRh*8&3yiLRoJa2gs>yssfy&PqNfAxrm!g@voxku)]7AMœ-w+|'iw;dΫkS7QBř3,r+6lgs?ݿaOV\d 3lK(9NJk^~åaSR/a3i]y`Hvdm%orUΘ0kkxu`С L $Z\Lh[9sB9!)"l|$fP$ݰÖ¬N[v Kp5 @I(T\W$y(@nWF|BN%D?3ۥ%i0ߵs6HfX\-Ʃ]9hYaN4WZ& Oβ,' ۺoj-.@߻}{$)y7C{ۅ4ព-?a{5+r'/e@Œ h͙)V<(dIqo!(tچiց3d*01LG&9Bm-q,HLL$C\{ٙ! ܕjPH 9f ȓMD&KNRNPcDD'ypcB GNch$$I &N*!CH}ki Itd5 Irf Ʃ%Ja+9l.qBNw;!?m|o&1tfWnN^ךؚcS3UqfB :T5R|Lf5jMXI:@ZaFIY;s>뙀MD[8Iv?2-|N@AM3A!9ZԈ:yu20Soms7{HdbV'0Ize \}f]3!%IғD$irc̈́Hf Y7$ `;2%l59Y)Ι<_elD$'>aN8 $IHJ WR@Ug欯gqq :0V*@l"̱ ̜̌jX,΄5 ܽQO20.5ºځHF)qk3;ɔ:0nm+4$ONW @ɨ@șdN3IR@+!d|֪ɤ0e3f-NI ̩\ 4PJV OVXw}s^isvv!gR1'6tdv^M2 խ8@έ59Tcdl5A/=I4T51I'ݻn sF"&v$Xo0fIP`24q0IIf3ʮ_ L PZDPTޛd=aTghQ/<ݥ24OB"Q7 DxfH^/$ U0 Fw` LNH&=ݶ2gDƲcRӤfcJgLjڜnj8'#Ĝ̣c5mK)uZ'MPOrEʛvfmff8S ]ִ$<3ߩa#mis@$a{@q.u{'̠ IĈ3m* dLHF"Ó>uΈ;3݆!&9$kK Ai; f$vBdk Tܮ l $Bib-n2A£)̤qQsjlvkXgÆ$j B2F`$Ir[g.U3dff A f*N y1%lPAM{Pg()vɐ`(}xS!IUFs+'gb!yb'ٜ.=vcHX4 AK$wzz3I |ν\<j=R$=̍9n8S=ZIq阝hgCEDinxhdtJĴvh!)5PI8PKfaʼn㐔FH0!ɔB%i3e@2ɧ$(9I3nG8ӻ`uefeHrü6gP5{2O(:'mCɉ3Z7(rLm!MVNOةfҩ Kf1Ld%;An),q Ąn&1Ca6c$bc p6LښDNДZ53r&$ 0~11͒ H\͠1d l@MX899J D i}0X2$B ځ pb1Ѐ|95L3svsr&~1$?~ sw>g(fqY3nIzRY6!ID}LbMg>Ifq%1üIhЙ'%ܧ,M>v J^zHGP)yf[C y. ǁZlLj|5Ϡ\8B (ct;S #JgRiFo-PAIY$ T3!@o0/c?by/ IZ:#+%J$c:v9uR~)!k_ޯ$iN|h!ZG .;LRpWG~&~OCXN6Ļab&ՄlNlkzm[}4x<ޟ)a_paBt *kQZT+?dX/i H߻@myFl疐8yɇ*x۶%aK6|}??R. |n|֪F}?^7]ݦ$8"i^Ṇ|hl½lNM6ft1dIo4yi@ 7Ilim%E~Bђ6%%y?Sݙ$BF#IbA }9g2,I"Qw QI}_d_#_ j3i,F[<~ed$ `MnR_2yy%mb/mG^LrKEt_8_s?Zm%--K{}##I3yda[(рaTHX $#$6BTYIrx|K~}ϸ J$hb0&=_P;&5K-%%Fb*/~0x/ևk2F M]MdGLK{b mXH)O @PP/%)@ۅG b]Hl@\4<=1bۮX~|ш#&s%3}lLrTNH!Rw`pS/Y*\ (D-Q I;l([ЀDЁ -͹VQ$y*%͗aҿq  j"ۖ%$KNm.Rǻdpއ;wj Luɼn픦?d@b2 nW/LsMĄtp[w IwlhBhf6QO?yr$D):TL%%$@b+~sj2&ywݒ4}zC]+yA@> k&d|y!7_R|_ɶ/E/1~T,O GR塲fsi I$4xdmFȃ.,oFf Er ;+Fxȿ};wҐ䬖Ru'I.\D]'u1 y)dPz7Q@~=S2p2..DC!:0 !KdUMھW4$ Oj<')*&@ѐ-dHC?M!z !!n$oM$ז$~G-@̍$`$!k 1YѨaLlޜY ym4_M$6_Q%U `_Ki3<7G! (TlH1jmrr,Yh\ami5ܟ6sh{BBiyöZ*yLi 8BS dsQKBPA.i[g 𱻿j- ĉ4 ٦z~QIz7m/k}m$$f%ܖo|_wr&5~ ЄiJ0 Mlט{d66N /kido< vg$e[sk b>) `|̔f.iE ~ɳLHz:P^Jt&%:vȹ!Z%} Qc4qn%]2EfLh#%?B%/a^@!a#H҄>I呔X|ʿ" JNL2-yF>Ca$k?)Ivx/\HF$2VKHoJN0%iM>&f߱×>DчB85Ѷ\7MiDnۯ?a6 F5t.ymaHĂ@K{asI LDiܷtms^?[W7y@m .֠y4Τqd*-2&dhDHRz,G-,#(}o5O_)?OwO$s]FHG痧 I_Iywڼ4.W^Bő_oo&G˴?\횜)I` %&?MKay4Ia^rߵd0[ɽ0e'yA'ԓҩ4p˖1F#/Po/L8=S^@RfkDyc"!@)D}?DL V>>ɖ%dh~$?'{8aD#.}lz:ww^s6 Jr㶏E=akq_&O?mzߌ`{_斘r 5I+/KQ~]u/sfۼtr7m |7cl'Bmu3(H2$Ynɖ?>bb~E#&Af _>O/Eֲ$iK$&;}'0=t5Mʱݩi$ ܺIDiM3wˣ?i x:0H~j܆Y蟐ߟ@c2mBU w<ֹYc]K$4Xm܉&1Mm_]Yvm׻J JtLk>ruSvF:k0N$ɌDHjnȌv/dccCD($ $RKr Ѽ~i6"@$7ԭI!%?!B.IVMel=@ ,,vc ,anzpz# &Jt-?%=@*4y}m)Nw|`R347G[K@VT? Gٷ_}w9Noс auҗ$ 0E'A4)%؆$lu[=80Jʟ&IVT ^#Ӂ3ݷ5D]pLTxP|RZVOӾ4:dLH^Akd(h >6jwaHsff&'1/J;=?cּ9;fT<?Đmb#~ %ȔZ-P[}^c 9< =3I$>'iB "tyے4!,H4yOP^F-!/˗@Jp$I(/y~/DmTtӅJM4Z,ͯB/FH HZ" `6$&p/QJoH#4G6ӨMC5$?+aʯ/H-? oWx9K:Amrn 屔. 4-QB7'5*/!ڶ6$O$@mm4IQi&mDӅ_NKe,-}V$4A Q77a^BJ)}8v:/mEoݨS$$ܤiK{HHⶣsBZ`wHl&`160{? &)ܣ`b8F&D1|ܯ %wyMHht\ ywGT$A}`NU GIڷ}w_kK5IoW&DEAI KHu`6Lt |BBN0a~JQ]x}iGO^~Ź? ][Җ mp1ͻ|p~}K\˾qo3M:./$9.ve*$^}W% 3a󔵙@/-佧Nm_p"0)YI&@P\k5 @rI-A%{ @yMs{ ^bii/G%C]Zgmu,J^Ѩ i#W%Gl%.yi*Ѝ#{ Vn/BN^?}8oYޟ_G2<viԘTwHx }Yr4hmI!)5}og7%ap MԅB^b0ǒtv걒v|#e"ͼIMP$mm| HdJ$-\$0Ty/#}r- <^d/Y Hsմ4/F:¢G M$^o inUIR].%lIRj55 IPAH(d%7\L#Zj2skm$vEHHЇn& i!30Lhm)y/?.d0}_s2P4[y$ee=ǹ9r'&` MHۛ5QnNKPc~'1!hHȃyھ$†:|D}I&IBT )DTbI_N' h1K-N%-[7Q$M5mhX%3ST$n%yaZS1c.IgLM}"3)/mKL?[fmFJRT)@&6D:$ 8w ܺ{̗Niڊ_L\xאAf̔ $Ɍ8BF&D6 $iM%@n~m^{$>$I}s!T!L}MC*mI6T!5H,+ JWz@H#F,ުm ėImM"nS%HԱyٹ'*kG !!{\MHȿOO?}iI&wl$Gl"Sɇce$!W 6jpmhHInm4.vh 4RTnk0,iIl@#MB~,] D 3xBRR~%|yJ&iI OxNYٝTI~vBl#EH$*\B~k6T 孩ȔBaXXD3 2ؾ_B0yl  29%C gȚ斾D#6vIMNq@$}ۨP@j$"tI]/^K*"D$qB`ง S5Iu@oِ,(<*Mg86|(NGCPD=y%44 *&hbA[΁&By!Kv3%Fn4,@r{(y)y@ï 7y#gIT ^If<Adm12@)m07`62 $D]J2ڧ*]DK+KH}ۧ. Q6$($Ĩ}< 6>AQf((h@ s%yg ~wWs{!bߝzwY`h t**yU^ !II@aoLI5},90IC2F-zzo)˹XJضE=2 /$U4%$6 I1hNe;MM Lɷ Zt)Mqs 9nM_snl` )w!M H o^2uzD@h6D#]i\\$}4Ϳ(D !e \wcJjTGVI?@C PPJ9v뱐#3?|ǣc(3}[oCgCn$yw'[>D;1k@c[vC˟-p?NVf[üٶ0PQ`Sm β] d4}MMA%!+$.ͯ$aHip!MO &;<&D/M[y$!Q LHԍ mf0V%۾^K $0. Xx(ISh6}&Ij[sI5ajȏL^}.v/4O9қk vjL$]2Tn [HlJSZ ܖ 3I 9bR/}$+ C2DSٹ/JB&/=xF%ǯ\&SnmϐœH=XH2%S`4$I`T| p[Axy8~/׻O<I7cQ^6cC[^M7GPBOgZ0\Wҗg;k^Rս_ߤtS ?_#CėGf Oy4 d E_A9i"#!f + ~o@3Ϋ*&aG[z+Ij7/Kh@okO73L4MT9`B5%G;q D4NM՗D tym3T6ϭ A6ӀH0Ia|M mIBt!Kh"(m uVv! I4J_mFe[dv}-[R> iInIw͋V.6I;DSMm!I;8<'\iiﻴE 8u_ r.3MGN:חG0mĻDд}Z4JHBMS4 :G¶@q;H%$m $'I[D_B!\>$ۑ/IVU۶hA,0h $ĤI 2x#HZd#&q [%K+%7ø[`$ӽ߯X9,}yM&MޫF L7@RSy$poI eiEۓk`+]kR S+3r~{?TiӶ$j(شtCN!f3!fӴ!DݜLM"GD)IENDB`rgl/inst/textures/particle.png0000644000176200001440000003676514555455305016243 0ustar liggesusersPNG  IHDRy=IDATx}z$Yʞ֙R80?08]!Ru_ZKJr0@M s d$~S"DM @@|$23?&_^,&pF DTJ P>Q9Z3N۩W2R⬰9Q7Ԉ! (} oo@jb  @:5+ЪY& E$NXLk[̈<DFJ (4XGhJ*ʺ'&GZ|@$32'/ ֋1$tG|_*[YJ(2Q $>5>>wRHɎ To@Uul?SKC@)qA%G/q3T?-\$ Py#JLT"3Q/˿(aw}<yV+t[V(HDmLYX;рne!H23X;5HO `V?Ho\Q(7_H5ZHI`w~)Ę/׿k?J禉$0Q DxZF Waq/ގʇEvu+Wtd@%bЛ 2d5}(I%@ KH"ӁƟ@"uԥ0*ݤfY^:CIM Q3#:3 T\UD>f]@JC´ɍ2<3-HGFͬ w ?UCTyL[*"93D7H[]PiAw'<2# Qo &GagŁv) IW $֪Qf#K4|@ܷN  ֋O@%9PX^:`zQAB1@**b"06TyI )+-  8;ᶙ@pȈPx !TE)5LߨQXV.|A5`UF`>CPUQ&@VH(C3C١2i`[\3"W1i@ze?|*UIV*&D7Dsݝ Ly3bA‘%!08 ="d~uf̌| juj 0MT XKU$@r|tU ""`Kl6v/'{37df(v#30h7_b7 +"I`8/4<@n` 0FciψX-4NT)ò!:2T hhk $ \F!:28K1; & P1ױkJx{0۽5xsF" p7X|CCN_2(s>oZ]=AZ 9dǵ5V E2ps`=hj@BN O_e2=b|Im0];e,stK;ņIvΤC~)Pfjf*PUP5Z `UUtug JyU*+*(H_evdȴ_~Fp9("ϰq uP@0@ծ w8*$S%t|?(ck@}_^vha@ ɦ,Wdc oH<[1rj15ICUJ|%S¹%N-nv; R&PSS5Z;o7ykA/&":WYu_x_yA ̨O ]0ӂv5QJ1ϡdDXԷ| ,'LaEl }=JX hĨ`;^:A_@m.*0F 23T0H RD|J  &VPEaa3TUd>٤&|P(˼`}r $?|A[Q dfx* g$8`X5v5#q\؄986<3"Rո㰍Q/4Os~Ldܫ qӀYr0F-\B9j*NQ S bg2SXaA蘁ʈ b`g4<3+Y'm"iTld}Jwx|{AjfVՃJ3+B7^?PКXfQs>:Ԑ?OU*rƚ3m>QL2QgxAwf6t̠7d 8q&D9\wрM$?r"l K`!?8_&kt"3D]8f?RHGUIH$ q5Jw! ̪셪Xc Q5B u+8Hxpn/aoDEDf8'X2TYBbQf|-\`]WTl} *@YQ~v՝" Ȕopa ?;< QґŃ QDt}'G|Qj@GGB X P` q~qiq4Q2NjMCDmD f$лVmJQ:TȌclUMLW7.QŽt)(w4-y7@PMv`&ú NXٌ `H.ny~ߐXz{lHP)x.7lnim1ͺ-W8Ltd33esQNP;'ဓyo> >by:}h2JNn uq-Sן JV6?KTj!UͣJ]L 1&xPVU!v~MmYW7'd;2NNMoUaD5<2N<pM T}j0$ ;6-1@q[ZbekO% =?*̡_LGY | \`%1i ]ahh1BpTZXj:E[8S%RD4`5> h HDWBtfvϥI <2,oҀ5MV0jvv>|`buo_4ZiV@6V)0PD6./4X#&|:=u*VLQ% (~3}Z 733*<"Bfz_8=wpH3QDLw(  z-HVl;g/CT=y'\%9Gb)v 9ͅ./e<vGZZk0r N{uE5FQ,t>؅%7a͌ u`a U)fHAb*X, &v'u(=, $cFFF FFG ?fxiZ{"Oϻ,;=X>1VC#1hD y.!*c4b]f8? K_Dݨ5 {fC) )Xsφ"\㟁 6 ؅P/.j*s\HUkџ NɊ35zWu_@V|--"[eX{؉ 2,7e!!oK2d} D$:#"ȁ; `;c" SmVϹsF Wwt_P*|2=y_fp4q=h]Մf[?,"\hu;e&~ܦt'ܒks{?2-{#=*_ed FtDQZdDնb:6+,7$eon7Ј a|t/$TTQmKCMVYͻV \1M \2*ȴ+j˶k. mdl'pv{Z=[{jt@Un3;N,]mdSwNg&PZn7KP&~x~S90" gv{kkRb[66`+~]ԅ./Ï|lv/p֞!%7U;f^nr"F60oj^k;v_٫7~ދ94,Tv5KW ;m5O%k!IvUșjw C_yAE~3] LjGxq{ fi&B=Wg<"#,Dw xz#t/fv׮0&K Ɛjv1"dTQyJBƆC>yלCj,D`ſ%ɬ* 䣞f 593NQCS쐩+ZJdt2qlqyz! q=YH2 1^LUHGxxt/0EvK6q>x0w7?OO3=R5ĽP`z1y-Q1u"33=I|h;>t>&㳤E֠z忉T ȶp_J--VYuBU&XLFڱ| t\cP "07 J3d48&0;s|1>œ_6JKm_t¥ˋ>Հ} י]ͦ/O<#jD &i A0G'lStc@vȣ^[P啝 `OvWuwT8[DV"\V/̴_.{E(Z}hdaߵmIXٛ\W2m.o(A;;5;k6/pW)2Q_hF}ʞv_Oa>NB5'~~z1eix?k:C`ߟ1*o5ʡ &#!j E8^X#Ȕ2y: %~/ u8'wN^BP(ʌguqFyG1/|Ib,ğ{'S'I78O8B=Q$fȄ^TqF&5>zw_n,*el=MϘ_fZ(]wsw/@xO\ڗ"8gP{fBCE54<4LQy!3Qѣ@v twLx{` v(jQ'H䆪hWߗ~n8I׵_j@b*!1g!l{U 2^›I,E7@S.3=EUįK@^O}R|~XSxdA_zS~3 NHJ3#+bS1[L姙6̞"~>O?0jFd푢w4}ia#r}`8<P]62q<h2%;7!e"S}\0nzfBdO\ԩFLHg;3?x)@DySx;L kD%{ dw*˱OD ZU[j] HbG"Nʗg K@ŦgЌŦvuni-t{דGny$?3_`D%Sj%p@!_ N2ۜ5; |)x>_@(.]Fܠ^ȷC3S=FvP9ˍcfs~aJ̈|>" @M<x{KC ds3fk4z\/nW*D6^_s?wլ.ّ={AN}@ "^Ȭy9y9#{`&1ggPb E^??7nXqx!;ꑐW>`c4p(b%+d/-Z C]&a> UΊ4N˵%|Õd-m>f\kҭp={=;78wpB0Uܔ3b)֋A>aMT3ejo< |>cDkopk=>D?ךeʞEX3ۻj]*x5ѿN}-5Zv=Ky#Nw#7x^[e1:ٞQ*Ӣ5n5.8[5r@،oQuTF[U%+Z9GuH1aC\]k=xd, Odsa5ԭ* 0U4[jZ>(et~Bqg}b!:f ='8OO9"G(l Ê-eT4x)jPey-HԞKc!GeNYL|+Kk>u!Oֆ ɵts3鵥$8\y\O<#}}_ͮא&V/󞒩 2_؏:?Tlz6&}=Zo51giQM ZO2" |(Qyc?iӝ-rQ\]v;6ok#nM4ڙdlc{ tX{OOj-g@mi72f?{"<}6"7 syly`ܲ nYD dw\z֢rtrmj1QuI. xl\֌U_h_m.V\E ga<ӉL$ |,LC(fqh@(^:+x, NN,Y`FƗ{< ,oW10z=ΜbGf;'4i\f5Ԁ䑗 nu|EQ3N_K5/8(UFgr} ;3EqjE|ew qqb1㕘FS\4d`^X&+qQ ꮙA;C7ϿLq-5 U} %zAh.G^n vLpKUc["';`]DzU!?q>K 3}c3DEv ӑ^׆^R|Vc=~Ӳ{jHI~f=Bٙ PN$Kx!w q+?8Z%1Q "$k• ~h]1m#{Z?0`~ƪ=lĿ?<-GF3jo,iqU4y|lO8uNn1ޖݶj-",2[#gxw ulT8Kx]g ڨC\rx)_rӻ6P0}##E=\IcruuU~*Eqx`#ܩ+k؝dC̦ҙŔY417"íA6pEs/G.QhmynjZy]y] `4鑁*`&к787gk(l0v5er:}nejzM^vj[qu#>Om>ۂ38᫹8<=2Sƴ:_3.< .07F#RIAk93y/$x+I% Qۣ{#>lRUP>DUY}?/geBt;Z6DKh@ pX HSoOmUgz9H> H[Y+ڵ8$/>N\Fxq,5O y/WWQ.J3^͈˭.7+`MZP+^t_ApOS1^::IJ#k.9KIӦc̈5޷įGP[φ+6n#KUy/JulNٜ;MՁƵF׹23b7Zݟ763;&;F3l܅Q un\xg70k*,65n~nib#zE> 13b Ty>L<Ţ37rSZo`v>`^b$M1[&; ޕ3{7P*sHRy;L( 0<*je+ sޝ6}u4)X5}zͻ0{_ollFuJL߮8 >:{G*υX T>,P#׳@I_T}{,jG?3}_Hp_N Gү.W1F 뉩9 q h"tJߥDfTXg3CX9TaYXY$~ix{[rGC0AS!Zr^\>bo>u-}5s̯HR^3"Vy@;f7fD pw_Az{V&',C’ F:#$Hx?L`dƣS#kV Օ:ܹ(;f+lc5ಷ^!˳./Ñ3xyx/+0͐6|">$ [`>ƌWar]zEnh>Wmwk'cE!{O SA6A9;{jӉńҘ,< 蕅>'7eߝq$6d܎;q4\œב6 -W"T{`iAdN{6A͜VǫxT .{# #V=( йTܰ\Ώ!l BC{y-N$<4NPE?)SW '\7-?!ʑS^q1f/J<'gPgrg5@1;zүβ_s\Nܖw\mx, r1~ f_44:>ƛIgVQVe@pc&BWPp۾ppMxFC ѧ2p?+\{~> (UtU&>J?QI."KOyCae,9Iz$AR.iphw+!^ȏ\~mǘv{it`rY *ʏcgluc-_ Tyv<@}оVϟ~Wg^bNV3>:7lP7,3e @։;A9rm/Ҁ߈NzQ`/K,Hq0 5!v@uCX Qy(: L|`MC TWSLDB&fc9g\5H.,+!|t{,|RU *3.eYgQ=;h5p^42zn%<5qHRk1e134C/Sݮ l鹺 }WgQ[H"//3 L4azش.KVBUE%0Z'D>;5&BVeS=@G[8g`kY![~iD*^$î : *'ί2nj0FFJ҆+J*."f1?8BQs>W+SL=l'PfFC87ZʄϨd >`ODJ>z/sb"bs],ts_- 30f'QcVDBq N7$>2yd-dEp{&!|x@ rd"P\ aO$W=_0H)>8ߍw<;C~Ze2|z`b>33FCg#"~]qgiD$\' % l/ЬuS]cџ߫]؎ji@MDf/]7͕QG] uI!nK5iGHw@X  'O2\Fp WZ *pwXEv6R=S _~jӮed[Nw;?PV{(Lr_|r]~x ?rN"Fx7KݶAϔJ"~j׾kq7ۼ@24y),N`(n<`J.Rafhv#ۋseQ* 0^t@E@%:~R#O $K`%@7rv+3H>Oo `1`I_r1!D l-C%SE585kj<7eՋ*.3?`O$ݍɩNpK1~*| \${NM`6H8r }XC|03E)*W%&?d^;t!B }o5ÿF]6MЕPSW&AfZ5`/9vJO]1@ؗھҀ . $~b]?dwhFPIENDB`rgl/inst/textures/rgl2.png0000644000176200001440000007760014555455305015277 0ustar liggesusersPNG  IHDR?1GIDATxW$ٕ##RҪe@7@7f0fC1f\>zX3}ȇ5#i46k$` f RUddsU]"oyGGefE8߽G|;~^m]A+@ҕ ]JtHWR+])ҕJW t+@ҕ ]JtHWR+])ҕJW t+@ҕ ]JtHWR+])ҕJW t+@ҕ ]JtHWR+]4b{+] t?x(/_x4QĿ__?wKɧ2kSO^0}>#>k߷ } ?/%]F10ߘQy`(> d 5HO83 ~H߸Wi'xjӷ-ܛp_W)"}x@6c~)Q_Ud~.dsS^W0A #l`Ʌ!`>|?gshxfa(:!Р!,>hT@ct6_,d |1+ݐ;aov>pw;`8b&͟A8J4gO/ߗ׽[^fze;v_/Ҝ i57?#on'4OH w z .E>c)(^&9OQ ֝ bX 0as^V$K~{vLA=M@Fa'(p[vpA|9b/лpw|vޝ'| ̒!0koNQ.-|2S)n+M:ݣLm+_`d~o5^ae zI1xZY< ޏګmp;e<)8oa8 q{?՟\]AQZ[O.Ŗ_R*͖fgfgK)S}{tc|*~hxFG#fDM!YqͰ'IɦYl( KL.I}ޡuj+ @Ey3? @A4 EyLfJ|+r\X;-FHmewo݁劰r\.Jy\0p4Ɲnt~pmj&[H` II V4ROi4E θ5qV3>P4!aCa&#y,&"FP$rYyT]fg\&ݗs@\)ݶݖ<*R6`[!wl{(#34N4MK C ߝ0\>6'`O :@HŰE8YӬഌˋB\d\#陵 - @'(-f*3sB1Ǽ]B[h_{Bq~}3z6Υ.xyL=qa␑;f"9j|8 ޅ'I^r5u@$r9 Gh+g+j\tv6cĦ3󳁟E4F<38?8W.cry)p!ٜ%zc5~cN`&6xG]r|%c_[{jSP?@l0^("0"bbpyzE!ssj4?<_ۜ ΛS?Kh 6yd90? (xy`!@i839nnsu6y9DŽ Fv @kd.y'wrݪkȑtqYf`qLvFJcp|-"2RC~lH"i gaw8qX*gK |kWqKr)/ESw?ϔqV;|yg(Иٍ{|~v:]^^YA?;s?+W 9&X\?pQlwhL&R#GN2xq|R}e9c?Ъdv, ,XV?<"R+$L Qdb.,.-..-,TR28 @.>J$#^ݹ3 vC|@ FJP"[m\-sxġnIJb(}qai#"Z[H(Qlیd4>m_~:b1w' O$#j$ ?C>r ]IUd6  oB [ĀH%Rx=`{ae@ -_8z*%)=òK::so]=,+>v:i4Dq[1L6͖ RFy!F]p^ I>2HkD(0I#Ǚ|IR!5Je9|ʩЮd_Y0g#A& Ǝ=W6+iDyT IԹ$q00]@&д;a$ IP7+lD@ >Ad嵵edέ.Wb8|M/v Fؽ%IN  !]p"4 pڗ&L왚]5(p{*ڨM);r:eMmvG4=9zZ=5UH/:6ВGRټ9 =EpxSp_9P.zoDg7oMLbTMg6{/{$K^dF!Bڮ*ndlGIpcֿz&+m[YkR|Pc<0lŤT?n_ATBlǽn[ =$(#!;ݏ޿~d>K)%@1bIɒ$aj6 \^R|Z*eЫKjZ-q7rҪכZ IƆ,461+Jo <+%-irEe,ʿWOytХ@I|,Hï4;XI4R@]Y|ȅ^Uϴ-i@B 1"|`}@{9mgb?GwCc}~@6_!)gff QŞ߭C@G z#h?*'IJ02+gZ|b-yHs7A.g9MeC,Fh" B{XI$ n-\(W!3F{wykfssU8Y Zض֟A;n $hJEIj:P <ݬ4)@[ Gkq>V+`}!p: cV 84ЮtZ"ܷ^N&c"`ly$.y˰|awVOP`(xI:Q_.t 6VR ]Y#7v[ nY C$xD8@ov׮]|څ qPd b޺ҡ0@'C3 degrApQ񁗁 vH}TwwvqۥwP6GӇ1!`3%f= #@EPL33Ul9B 1, ] xB*泀6QItzQG:Ԇكkϯ^|ׯ߼ycaaVO dS Y :I6Uxl fZFҠ 3uE"]ԖV  ߇r4$l4 M J-c&F\}7<)Eg2ƕth&jP|v}^l> 4Be `axQ|Zۿ߈FdqxG"K2G]8u-ȥJ$Ԇwuu)FMG!;6 QI;]D JfyIXۢg:re&_A0_鴷676߻{޽`1n7kJhh唝 )M2.8l3PB2m3Q@\="噪TuJ`h 9Yh*RL2Pfl &ˎbL]eHL+Cqդ/Ё)j *b?Oŋ罴%l)uȥɹ⋟P@IHؾ^Igki4U qv:fS8>>FaƝN,b% AH C\1cD^1/tWy֍jg- Sm]}G r"q]΢z8*'~7ЕÒ1}#t F ;i5+RViɇ&]^89WMsD``?d Lu"ݠcGss6n/nwVI#FvnYf1rǡJDlQM#FEFu(-EE,%т &W..<` %pB9{~ g"1"cc2y?ENkr Nn [@'vY@[ HZƭ3g" Iƕ EEB9~,e|<=D^Zj/u@S59hDL/F.&3>ps22HV1!lv{14}#`jiA1i~I]%/s̛KV1pQ`a t_~۷u| /?|n4h=+!?/2M! WOKY1PLAA3'ܹGaR &#g ru #TvybYmX0LQ]|3t/:NA/o\XUu1;@C|%Ȫb}%sA2s/I} 9Pt0B:)};w~urB#n5c K68+\Ɩ6?iNΓx+dn _gDRJ iW!0 S/#KX0@6N*g~(x\4(APhG(l?9'GpՐi'ؠݺ{\ryii+oJ(]g%dp'@A(KEpI*[;ICSM)R\? E$—x+ /T;UD)ڰ6},`جxF7`B!*j܃%G@xRM@Ndx4\h| lw~睷] {;!@ZK%&7#P";A0N. RG֣Uk׏áF@k7^7^z+噢& /(& 9r"6N߿sZd Y,}O~M1`;·[CVdTZ;Td{{gkkw}c޽7QCg&(]9r+9&8"@9˅6ϼ'H‹jڕV kW q\R:@bPS@An"DuZiTʘ" Y}!m?GL rÊg3poܸo?WAҿ u^5eb U Li 898 NRl<w{ 4oƧGThary@?J98+e-0"*|J**nu(ޟ˂znm:Eo0j=G@d0@x Yǀr4A2%P'x_64$vlWH @1q|jJǜX. @@;%7Ŏ3g.dԎB Mx>Flkd.*|'SPsHL^=:J |IvSރr< *QÖ*6;r9|L`@{lbӡI Da16)z'iNVK:&'=Vhj"3~iŢ$ 0OT!VT 粉%̊T pZ<[TyqZKL85@~SQzv۫LH_RVңEpMG.}mNж>+{fH='?"220ci +ɒ?*WԐb_lk ֢oT<`|}'SYNBGһ8D5ҍvɘ2cƞ7  *DM9Sdmmp.Pz|;>-dpw򐋍 lRz4 ]Ӱ,徙DKKM`ւ'#G,Or'N)/D~8׎dx& I(ɧPMtKMX1r'9z8瀑sE/_ǝȻP6$ 2 w \gL⓵H)nw;,0HŰ^ g ¼yIA&]+ FAI'AzbC\.+hw8жwPxG^j WHz&P_ZhA%RUD8{ZEmq <&f@X:--AX$H|$ 7MQ eS07wI73P$_dniCӋDa"pJ #3/Ӥbq˃<ȴpTA&rhO y8e$QkjJYiI|( y_v'-0axEؐ;?iP12̿Nwl?Q4xj یvQ‘"7u[D#(+kzpi9úLq$%1zLDDIώy|\ayH'D?,0ף4@yTl (| y| :oDd[2P1e{C+RC"a 1UǏ *3e=s{ޒ#";=,`Z|Y*4R?_Co?z ? G`~ C3tWȨ TE#-R\ 4: s~8 "g ǏBIH: 4A.;5?lije07 銍3?T~#}Y"G6؉B S9D>HzaҎO%Zpl3% a afyPBңe*YgTr}(q2`Nط#&BIS<5x#e5ք)/J08;0S/frà;nޫp q[;{GZwǫ{on6{m|?4[aɿO^=wpi ڣ>Ga},aݞ}` 3},s r9ʉ"$VE?G")5=`!!}Je4 ڹ58H&j  rOd[t=gtLjqqɌ0P1x VxV\3}M,mGYb2LFB+=+pjc1ƷpppTeB ge 1:!ځF-$/1jp`GP% qhȈL:.}i>'F&`PdLfd ξ VvuB5uf%̌BJsnP+51p@wt1cT0&Hj1ΐ=.bR̫Te'I nwp⵱u{lm LY*OUxK0 ?ov=kTn2!(b_0N{03Qgf\CzĩOJ.qf<xz6P1 T2FqB/#:us>ą`WSXdw':B?Ene}1oƛo &V[I UV=br$F$X$%(pAC˾D%}@^"/xF>#^260> P`,F'YP ˭47WAfK1t^ )c2ćq gVE9Q(J1>w߽x"f_qt0#ݘTLPj H7TJ`@Fݑ똲I{EDy *h`'5sisWeA)@̟ό h܊B;H@1qnT-ӗZwĎ͡΄ĭ|9 mNQ"%$@Rx8+ˋ+ Q,ckL-rrϓ,<&Bj/LbY(A`.CsC㣁%oj 3xVmNҮ3# \Oq.t' m[{cW$vE^eOLp a(TJϭ?O>jxjӯDh ŁˍY4C H˔,"rg]*7e6U04SxT:He"=^̠liЍ֧g oҽ_ʫ kTy!>h},ԏjpl7[M*@czG*pPXYY~捛7[έ[X> M=߾åE=n!33`-e=•e%|v-ZhDSQWD$MO0dDEkYD/N#{Cu w P1߆DJ0N#8B}&?0|_ß50:u?Bׯ_ȼ4Mfm웺@'2ecngRV}&?G2^`9i[89Sd"ML Ƭ`L5 X \KYQaэm9\@ҳDMC*dQ$]nj[D&}~sI{s|^tD7b~B+;Oe)gȣO0SbLū|ֶo4;&P(jo:]V*zRA$e8k!2 %Tr)NSP Nka8@QFF@)Ŵx,_<  ,`lH R4v|#(;=< H[̓8/"}f*A%5Gg=.laۢ5d F)2 vuƒBw˨ݡv'Nk{=&_ mn| Kp!ǯr2zF?x< /~yw&S `'UPg q"Y6lkww[@XM ѝ%,}.Lh@L'NN UVWW!0 Иn/)6s__r^'>H:(,+x _j R8A a\+m߃m!TEz_ I#xRN#2I'`((R+"[~ EA'EV=0⧨kj[;[GG'u0((=Kk˗.^YVj/7< /޾d;zRH(H.1%-dB`ȬYJ[77-{/BQhC +ҾJMn!oP`@6>T,[tBoPʏ6jFX@cM^ͽc̆9n5Q1~ P\t˗/\l-ſu6}Cv0zs.0BBX;ZmVaKbY؜I84IՉ!b E 0Q'XXLdqtFy`& oj2$"D8͠8Yý#uZ+3+1+گ[l };x!46*@"a(2Bꇽ#*T}VX1}xrZ`b@::x`)8NB[??3"-&QvjTEŎ9J](]oE}B0(`MP>۫)^d?铰91I%Թ CIFQN4!b'fJZb\-yj9Btv0Xhu'EwLhf vڥ1&{PU=H'R{2!=R&e>Ckׯv@%UgN& (XdGvա,Pvw7nk"Fp̲X`a (T2^xf cZ'6}.ĩEOJgvoo>N'd0$4F+3f|`uӹ9K.U na,J^?U;=>>؉LR ^&;`CRѦAU>lq!F'Fp! t0Cl5h=iУýfJuRh.@woMKyɶ.%B҂˨nO!3 \ ,vk-oa, fƥ#+w_'0wj_I` !fJ0fIpO[ɡFNPiK C` l[i-ɯ9e gdQh|{nƩ#B ݿ]w: >hq4fG~?~[o&ft!8*,K@ZZ`𴻰lURS*@g{N<.P&J#ǗfL,MfOHO}J 6ONJ TUg!d_f(V!9 O\bܞ( DQw/V"TZɘ64!J2JQ<W\~* o޼믽5V0e(yٍy&EԕI$\02)d'3r 530@@4q-GC Հ /}F;hG4ҕ9|ԹI auN4lQѹ/2-ST5'GǫyuE3 mE] o~#,|p띷^qG UmH9t@:_y6vU[L&D\TmU- !she[ojE &"5K #J.\<3A=7 4G.:YXRM(y]㐹e&x(Ͼ~{W}ȱ`NO% gϢ 21rHW]=/G,9h d~4PHUOzzx|wHl4-B yGQsZ[j_#TAu2yOL"Ԝ ~#M?I@,)2})??aBavn+KD %h*?^#']8XF9KuF[جSk\Q PI8 ! uf^@wq  N|[b>G_/v*s}Yt.Be*l6Kt):jZ4M#'|1ݕhwzBW0RE. pha$=^mx GDU;# 0@eg+,s,&B H\EpK=ʲ 9(&zJXU0_$$dU'qR~ {{R,`23 4ՎEqMԳ4Kj.?UӝWdq` MI7d5Vx8D,0cZTka\P6=cbTF;+kx?k8L oάM ?#b>;b~P\(I mÏʠ+VfTԿ1,g)p ӼP0@܃7O P8:F(3IaiF"D#S6$ɯ馣5z6SP2CE 0i.|rQh(p& =] Qk (F v-"4:]1f<<ssą3y@e Δ0"0޽(S9r&+%+JOo4gĉ~9I76a 'BZ:F \sBs b@b@ɠN xHo|!3fTN?'3^uN\<s'(}Xl<7PX[#5 pؑX(VB2o22vy![,bG-HB=9(*4ɹGA BYZj {h)c2Vq 81]cO}  MNŒ_4x4W*B𡰠Cy"ե &&>GaYsTe2;&|)91 !R;9`k{wc@M''NSaOV+L6Jk.l%3Jy!oB#tʣ Е4v7UO4?S}3ENAq0HΗIt8J(:%Xd{Lt/1O 0 \Q`)7w}orx:QH~%\c`u* ^Zɏ7x#8Xwmt[Pmq$RH PJYgm1*G};^qLLbX P ׆ko+ '1Mޙo 0GeL+T&01Mz'˟Lג#YL(zB|!}>%vfR{XT {œ٧&$H `#:tZ1{s+mOg:{8`|ENi03uoÿE_6|Ͷ_AXӀ|4 `u[V߶{<9LMGf~;O qGd)?b[ ]bpM6^!n +2H^!rn{xnjas1/G"΂/W{ݶΣP|gdGzSu Mo~~Gw)FT8D5IW@ϛ2n`~1428l 3c䴽bUT7 eq/o(T>TM)Ȇh?iO-L9BPSomhG ($=%ylC_?Ou]{H멏O]۹ŗӇ(0}ԓH4}O/yLׂ1\rL0 Lk{d0 No{m2#[cD%)C18s G m?<.EX9fjSoOu.۽R,aRv` E*# 8/zDZuҥo._ڭO/|ܻQg6Ր`o2. .CN?>՝E'EN=DXQFBMZ;iٺN5뷜 *OcɁVwYW(BGa[<DdQqst (jp*Y$z=i$[N= |Ͽ^9?~~g]~M֬߼)eWS E^$"\ƚxUdEŋ߻O}Y/">p֯T+6-H8u||q+rzdd8nN PFr SaPЪwxw%UF@Bpկó 0rR?,l+>]ʻ=l߅|c*t//t_jaUZH-6[RƏykxKns8y\!TeNyNkr J  uXz5b@A0PGUٗC%sscOTo? oV2YSPP,8Ԏ|*J\p[Od+WߞRWs*3VtLlP_T4^>vYe3"d(@O'*$-Ku@ m kvXΰcW//-/.< - NPQY {m|1W_sP\Uy>&\?W5Мms#ikmd!4AIRTr**A f%/ٕi;>zd#+++(`bDT=2Υxxh+@) Mo/-,c(j UW9\ˋs x*ֲt^W,3neN+,&d꺠pN@aP uК;LUSz!yrithSkm_~*sd(+U{jռZ?0`8K z¿wXs#IFl b0P-煎J379\ '[ؐ5f-d%i syl p+TTYY.KH7U_E0Pf,x2SQ8C &UMn%1`OnU93])>) y{3#+ͨ10jTK !V0&G^bXcMV2ujJנ9+ l[BJ%1AAg#`)MLX~QT o(@e0S#FTךЪyp%O'ψkt Գak(LKא N rv3lqpiB(j_)\Ol p1lx}J_es7fCQ)h=ƫ4DKpz^!9uh0Jdkq.co+$KG06P?i`jqƆ`LSΝvZb~d2cݓ-2*zRý =t䂑tO @ʾF;bCp]zt|Mohry8@ ˷(g S 6<s 0׍zH0f`8Xus{spe\7tE <pQ@F~|\A~; hՏGGv _X_Ŕ\jf2+өu|35WnN+i )QڈX/ݚ12H d¹qvtxxwgwkcsscou[[[{{{C 8c$hSF ""'&D Ej~ ~3]8;B qjd;'02Afyq<Ǜ'۫D[C? QY4S6͊.g?g7߰cL.$0m`{K1N?zm?! z\D ,=_*VY0;ET4'/YڹCo8]R׮]qWVpXdq[֫b*!ْƆLk>$ 78Conݽ{o(Voi@ϑ״Aoy% $_: `'e;<0?oe{# %X7{\5]NH>}^koșVs^JxݒR'@ZmHFll޹}jI1`R3+@`9:_ISP>d\?}۳ #`i߹}{;Rç{0wg/p0/O elz-b*?x:,|ppB!~j[W.DQ;xr􋜄lD;[XvlڔW(B$Bdd1b8O+2A/қaH1--.g?÷~{ XίzA;Vosk:o麯c |WG}A|{L@;윴IMxIh ʥ RH-y*f?>xƵ+fv'zoݾyb*D^Է :7e&_nF9ƘXQk::tV$å…G;o0u p z~}}cwO S-ff73d-6ԒɾD}ޭ 0~k=0{hec4P-?_" ([q~p۩Gn5Ѝ샐,~Wlzmʾ ;.ܺ\$<(]$F):b5iiiAhfۥRB=E%N6EjϊHLSĉI 28 M^}s[yGzpכV 1Hs|UO|9;Db՛V0T\}}з."a0A\D)LnMmENs<gvDi MT 9[ }ٗ.V|lnWN<. Κb5X9{ JQmi>Q Jp ? UħS+`,$&}G7.-xs2pZDޓ+9c5j;;a(M@1VdDUE@ > IڅGQ>\Ƙ;?`?C q^/e:#10M(63`lqЫP߄_~>? ``.Px<#BR~a D!~G0v4B y+<@ɩ%JƷ ptN.am2G30gHmVxuz$P9X|M7&Gx8Еɨ^`xoܸquli_/t~F=Sh#WGSV ri(6_WAfΛysl/x W+^1FP@5(*O/"}ںvuډJUC[{ONFfmPCFFsDA8V/^*[wOwH>px 3Dn24$tEGy7twM[2m =g$´/Q[Fh0n<#BIL(mI+_>x I; V* S8O< hc Qm{a;`*  ^O~gf_L3/Axo ȝ"A:!ڊWQ%Jr"dbH9 V % "xStSHAAkEm@l0UT|[҃/tJ*<8@;|z=A<;<|F31( d0zUAG|i~ E%c9F.i7"c#" 9 JlfIWZxsoе-S!KP W g9)HC&?Y)KezdE?yCe# Mq!"5kM3!z[f2J89/FY 1zsJv D@y\9?d?:q g0^EP,B2N/{L]L^J[Aww}uoKѡ16_Ah w0A9*$'Im38r3rɇ20q2 @? ](T~; 3'@ .Lmۑ!wHj$%Ui &nޱ@x)\ {ïd0Y`=-!\.3D22R^1O\ 7E8,N18]Мv;8Uө?ȩxUBZ V tMnz[ +G 3|ǽ^rC}IS'z~45鱣!xrNӠ:%P `0€h{y]g_y<"x N9O2W~i i3MlKdC9ha!uޔ}!0q`ɢ֟-vOdSuk *ۨ, 㑺r 90nc$}V)p&c:1Y-iBb)^ 4sAf,8Eb/˩=3&pu}K$0-HC]R~L ]{~g`cҞⳗ Z9eX3x |Sf7b:- p*&!~W`NN]wI3@`'Jxws&ș癒 ]'tJ)WZ L6p'~%3U"%g<3tyE;GsY $HEC} -Qd[[Quy/<;}"a-\^c t=4 de)_]MKo;-8JO_JCqQ9\(<2N gIS@̨J @hʨ:Q5#藵_A6= IQJP9O&njxh=ԯqE,t~cljI؂e eݘQ)V&;TWaLz׽:(up|rpa4Lo]z돾G>ɦۅrGL@6@*5Jn/)ޑw)^EJw$8NSLFESIn$\ssf󳮴 MXoDwerw祝[oBXY-S[?g/JFgl!oȿ[ɓb Lgt_fצdk8IzX>FoclI N_`EL!(<A~8B3r>_Q 띍;蠧~Q7LOQRw'[l[J[NC/NI.=~Qr Iꨳ FU}VVŇ 6m Wi!5N)H YO HiBL@F }"Bqw䕾o q @XSC iL 7f IEz#l Hx _tz(ڿ޿Lj6j] Wʮ=Yz>8 Ovzc99sa 3Y/pdC\nQqU6NaXwO?Sl)a_uՈJkU{uE=gN\38*acR) ЇZu֨c'Q1*A)SrvZV~g-IۿWNK49_pS}K('ӟcNQz$'.\_fbk#a8̵uJ6(fG|q~|iKkqm2kk{Y$ 0'|xԕw 0>#m\)rܕ'F`\Hܭ"5kvީ7{n<3$>WܠSF 9ٞ.6p֟lw8&h%mCAwdsgrB7(Q/ +y8qrfɃ6 A+_$Os2'{~JFSÔpbr N=f'sH~ 03S|3O)$LY;E#sN=tF惋m%+ sq$q'NG"&)= pvY)!xS+] -ҷ ])ҕJW t+@ҕ ]JtHWR+])ҕJW t+@ҕ ]JtHWR+])ҕJW t+@ҕ ]Jt\W)=IENDB`rgl/inst/pkgdown/0000755000176200001440000000000014771520323013470 5ustar liggesusersrgl/inst/pkgdown/templates/0000755000176200001440000000000014771520323015466 5ustar liggesusersrgl/inst/pkgdown/templates/after-head.html0000644000176200001440000000440714771520323020361 0ustar liggesusers rgl/inst/demodata/0000755000176200001440000000000014265301464013576 5ustar liggesusersrgl/inst/demodata/population.dat0000644000176200001440000001400014265301464016455 0ustar liggesusersstructure(c(1.42180393552915, 86.5899178491882, 58.4279463385297, 72.5782084880812, 94.7650395805866, 90.716798083558, 4.69523086857405, 66.0275494756707, 99.5966041105792, 28.8464020557810, 32.5199596913345, 32.8230902358943, 76.092718318592, 90.9491131042477, 67.7715461039384, 92.797656673891, 62.8763250044725, 37.8377486848826, 94.8318271447979, 16.9384257460335, 66.7528590475565, 72.7664750532169, 86.8409342723528, 42.6672130775794, 99.405982755219, 9.87878796385573, 74.0013561791278, 73.1367197183745, 95.3562400020557, 69.6064585052911, 74.8777135121351, 78.0631738216763, 93.8781220125682, 56.9874829819862, 61.3674564946833, 63.7014637339631, 72.5482760946146, 88.150868900621, 59.5874643583287, 36.0187577356162, 75.6129656479724, 58.5589693499633, 61.5365704196823, 45.4041207738696, 13.9846302678307, 68.6129614502687, 81.1038195579554, 54.9328748464894, 56.0090012748281, 63.7824110302102, 71.9080963099627, 76.2898655697447, 68.1971407037222, 1.79949925742100, 34.2445376879174, 67.752421253536, 70.0160933011249, 59.9881388477488, 62.1375791537896, 67.5026055163477, 55.4749773697637, 67.6559503769167, 99.8921368552586, 99.7317640238283, 59.5870514252659, 61.1156890017716, 67.7897419835883, 93.7373116639762, 64.8624836653151, 66.1630357404153, 70.3541452797023, 50.3392945568402, 60.5756891936938, 65.6381806437015, 70.7699265549355, 84.263331400059, 36.1455168687146, 63.4268691110022, 50.8403640938551, 84.6038580009723, 99.253448377888, 44.5136280754846, 18.3862017952805, 35.7157337732417, 84.9943843632923, 96.2500336638768, 51.939143733573, 73.937482003108, 20.8390646918768, 13.3791143487625, 2.59180364981103, 16.35253761228, 78.7863353881487, 77.0761412272873, 12.7493216227156, 97.408350521328, 2.360943911914, 49.5031567931881, 40.9086587196003, 89.0041084624836, 0.153641843226189, 0.7205303565414, 2.12973220584209, 1.95184155151989, 2.36672693229437, 3.97881615724853, 4.6945903958973, 4.97023833854362, 5.02848534249433, 5.93632710737556, 6.5305134302309, 7.18124749660055, 7.59205544134417, 8.11782658102872, 9.7053179911583, 9.69966472967054, 10.7491681958896, 11.7805969476189, 11.8846419362548, 13.2638113615252, 13.6102190943924, 13.3331649454155, 13.3510625511294, 14.2866348278910, 14.9188862315656, 17.1073522001289, 17.3771351386274, 17.4970376938342, 17.6769213814467, 18.2937976371715, 18.1794471174431, 18.4072881564515, 20.2907827372874, 20.7863900870053, 20.8977102997940, 20.7898134065768, 21.4861476674877, 21.7151264355786, 22.4866743996941, 22.9652880267625, 23.4036320422319, 24.3239211351899, 24.5629717030476, 24.9067464934910, 25.3250969786023, 25.569835321831, 25.214928868463, 26.3005548932358, 26.5032754860593, 27.9258713661520, 28.3114428871105, 29.1348144906887, 29.5927445701307, 30.4762347883257, 30.0503599176301, 30.0058225611238, 30.1513380348103, 30.9686341509616, 31.2913000003182, 31.5440713840872, 32.7657602884727, 32.5231659352135, 32.5262426292818, 33.3124010171537, 33.8478211625125, 33.8467915869427, 33.7026977228706, 34.0596679268078, 34.7846046615822, 38.1673741083982, 37.9665159877312, 38.8029702374719, 39.0682120522177, 39.5640346008735, 39.4240171975978, 40.0765304172124, 41.6115850103115, 43.1095386110501, 43.3832096504008, 45.4365823266182, 45.5690791790302, 46.1239852830125, 46.6768080701299, 46.7602784573008, 47.285367886742, 48.2420712810108, 50.5906685558592, 50.5316655747899, 51.3195670861564, 52.8660801235275, 54.8554989863782, 54.8768757654533, 55.6908773693933, 57.0974418796826, 57.7205567191636, 57.7134194371089, 58.3266436293085, 58.6607370311536, 59.3980795544102, 59.9830194632018, 4, 3, 2, 3, 4, 2, 4, 4, 3, 3, 8, 2, 2, 6, 8, 2, 4, 6, 5, 4, 8, 6, 3, 4, 4, 2, 1, 4, 3, 4, 4, 4, 3, 7, 4, 4, 2, 6, 3, 8, 3, 2, 5, 3, 5, 8, 3, 8, 5, 1, 3, 8, 5, 7, 4, 3, 5, 4, 6, 3, 5, 3, 6, 3, 5, 1, 2, 3, 3, 2, 5, 7, 3, 7, 1, 7, 3, 6, 5, 5, 5, 2, 5, 6, 3, 2, 4, 6, 3, 2, 3, 2, 3, 2, 7, 3, 6, 4, 1, 4, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 7.57114372433513, 6.85515173418126, 7.52609590470221, 3.5563844241623, 7.14112545928597, 5.12301007753458, 3.87663849439702, 5.79586417334239, 4.70184865517279, 6.21920562188609, 5.44360907485348, 4.51873716824026, 6.33491917603443, 5.20292601299676, 6.59676653073395, 5.81501493098883, 7.54559052637168, 5.6635169145202, 5.88625186391175, 6.18255547931158, 3.9011827688165, 7.92338945754762, 7.08656410296135, 7.25722570643227, 6.23413330258138, 5.88738222841769, 6.80735796658865, 5.28594790472374, 4.39548032693523, 6.12184517302476, 6.74384685192469, 7.60827115628042, 5.07457171988406, 8.50778221649775, 4.38150950099637, 7.52973226807595, 6.5506735931328, 3.87367222602665, 6.3649749543402, 5.84328626826638, 4.12479223028613, 5.88500632343836, 6.93493363615338, 6.66363247928469, 4.65955611058411, 8.15391551804086, 6.76397691227767, 5.36981173805678, 5.98744841170566, 7.11136219546026, 5.78287045204801, 6.14081537593665, 3.82726802701466, 3.20879873107543, 6.17821147407116, 7.37261655390293, 6.52738206698354, 7.04683222470034, 4.8916109987783, 6.56523496429719, 6.83082908120187, 7.87149902967823, 5.62770948691443, 3.2651491532768, 3.59665266985329, 6.54074671207657, 5.77568350127988, 5.96246550437346, 7.05488722838375, 6.38605274449675, 4.96442316344611, 6.48378363921246, 3.84255493400238, 4.38857837779543, 6.19366965736775, 4.84260035340659, 5.07260834973452, 2.88965797522147, 7.15143574153486, 7.12539568924814, 7.40644952344348, 6.59220641889174, 4.81483959103117, 5.32577121795078, 4.23104750753301, 8.90629459075072, 7.92242700824242, 6.06571137725015, 6.31187612654388, 6.60321800321983, 5.8189575929551, 7.40216872384802, 5.58163040684314, 4.68926346360419, 4.50539905884038, 6.21368299483713, 3.96679382670128, 5.61336655902108, 3.52559103095651, 6.69183050760578), .Dim = c(100, 5), .Dimnames = list(NULL, c("x1", "x2", "x3", "x4", "x5"))) rgl/inst/demodata/region.dat0000644000176200001440000052544414265301464015571 0ustar liggesusersstructure(c(3.71114253706474, 4.01779675877195, 4.28656904179763, 4.50076660092056, 4.64619071647352, 4.71349254349867, 4.70016541088465, 4.6115552355105, 4.46032928164021, 4.26421093830594, 4.04246933185776, 3.81237141855995, 3.58704556714176, 3.3755855810663, 3.18495554003389, 3.02218397671240, 2.89530357041327, 2.81254466310459, 2.78056540241673, 2.80300294351220, 2.88011139818937, 3.00931780934633, 3.18596283700096, 0, 0, 0, 0, 4.4710591748498, 4.70948819878899, 4.89872181207017, 5.02051921157744, 5.06013125543746, 5.00806359728137, 4.86128360217772, 4.62371056612909, 4.3059981576005, 3.92478071983061, 3.50164515839338, 3.06203621718930, 2.63406742028284, 2.24685725266602, 1.92776393521573, 1.69808969649104, 1.56769252810029, 1.53026304325852, 1.56198954045970, 1.62591227445305, 1.68203461740870, 1.70009636765875, 1.66977099576159, 1.60362803966042, 1.53152411467252, 1.48923433055194, 1.50658148407650, 1.59976708640559, 1.76980341966483, 2.00588212663519, 2.29087619783296, 2.60634981646881, 2.93570324219523, 3.26537586715308, 3.58475345647643, 3.88553154486786, 4.16105219094723, 4.40584254917525, 4.61538792773383, 4.78608624645687, 4.9153144358217, 5.00154838089022, 5.04449334533078, 5.04519407167202, 5.00610295131046, 4.93109270334441, 4.82540890084237, 4.69556887426935, 4.54922639597066, 4.39503116727252, 4.24250812929838, 4.10195127908395, 3.98426397117676, 3.90059628895129, 3.86157237320898, 3.875930868916, 3.94857501129059, 4.07834266816769, 4.25616177675292, 4.46446713258873, 4.67862714035609, 4.87058793953534, 5.01412481357765, 5.09033389715201, 5.09168693783603, 5.02332625411098, 4.90119624927908, 4.74770066164599, 4.58635961145821, 4.43710111451504, 4.3133594571693, 4.22135156130706, 4.16114656990489, 3.89700585253865, 4.22886109942203, 4.51989598517139, 4.75159744128911, 4.90823191543841, 4.97952661958404, 4.96293748642882, 4.86476859750004, 4.6994670657364, 4.48686171586016, 4.24795638915308, 4.00078219162283, 3.75810141673599, 3.52794979776719, 3.31638022180937, 3.13041853986297, 2.97924097477999, 2.87297940538678, 2.82023105721542, 2.82600130300695, 2.89112371800521, 3.01296791072630, 3.18648583748062, 0, 0, 0, 0, 4.50221868296492, 4.7516899946142, 4.9516531839248, 5.082955652852, 5.1300650773303, 5.08292656463883, 4.93823727132185, 4.69997410774362, 4.37919223567675, 3.99328528742998, 3.56498907339343, 3.1213377615046, 2.69250181926538, 2.31002585322016, 2.00370441153561, 1.79658133865914, 1.69859792364187, 1.70098738444312, 1.77466075574443, 1.87532702065300, 1.95543750057437, 1.97928918103662, 1.93507581107475, 1.83836096274211, 1.72538731886278, 1.63955718677841, 1.61732045387912, 1.67905006815417, 1.82715792126502, 2.05006946864233, 2.32873107131955, 2.64253414898331, 2.97302597060795, 3.30531446627761, 3.62793280033241, 3.93205639715069, 4.21068787819006, 4.4580836524531, 4.66946367582298, 4.84094343206792, 4.96960661004997, 5.05364903135097, 5.09254206573137, 5.08717842625571, 5.03997454196596, 4.95491342105982, 4.83752207099119, 4.69478986941448, 4.53504840526328, 4.36784376135249, 4.20382689937575, 4.05465166788792, 3.93279588797054, 3.85112544719211, 3.82195505112571, 3.85539873784604, 3.95701349573957, 4.12511594726059, 4.34857545942243, 4.60613454167730, 4.86814875657774, 5.10098478490398, 5.27333376568751, 5.36279239738902, 5.36069847492058, 5.27363958658383, 5.1211611847113, 4.93051219370601, 4.73020510080281, 4.54435513247573, 4.38920343104757, 4.27226439017113, 4.19362928795208, 4.07491302868166, 4.43137640497536, 4.74406166052454, 4.9926297010233, 5.15982359856952, 5.23448867730731, 5.21412680149075, 5.10612385396442, 4.92684837773999, 4.69834717863986, 4.44338253639325, 4.18064029313238, 3.92227731972436, 3.67496540712135, 3.44357440615526, 3.23497684833404, 3.05949095243323, 2.92925673262058, 2.85494715648567, 2.84303490375728, 2.89496815677644, 3.00804511559018, 3.17680092865961, 0, 0, 0, 0, 4.51256600745384, 4.77118198839211, 4.98039115601543, 5.12027121224973, 5.17461961486849, 5.1328918519855, 4.99153538658068, 4.75455222836937, 4.43331664565167, 4.04585702517308, 3.61590167934052, 3.17189678677550, 2.74588183039085, 2.37164001810793, 2.08122868154864, 1.89929185486929, 1.83576647020625, 1.87941363534475, 1.99593213579537, 2.13383002199728, 2.23816559651834, 2.26793236038767, 2.20992248050721, 2.08269328009899, 1.92880792169203, 1.79920002605776, 1.73685986555595, 1.76628213628716, 1.89127491418130, 2.09953411782598, 2.37014302001071, 2.68039813788614, 3.01007734098488, 3.34304116504317, 3.66705045981566, 3.97283202531075, 4.25310580572896, 4.50189387402052, 4.71416321029967, 4.88573462611568, 5.01336445036647, 5.09491781913378, 5.12957205259379, 5.11800578767904, 5.06254334590535, 4.96723546090745, 4.83786880428998, 4.68190988310029, 4.50840402964777, 4.32786160512497, 4.15215729250468, 3.99442669625632, 3.86885892017108, 3.79017369120736, 3.77249647693588, 3.82739440219987, 3.96108511064196, 4.17127365178147, 4.4445675267108, 4.75570559773734, 5.06964350463872, 5.34676455354722, 5.55032940147435, 5.65421722586217, 5.64858771723579, 5.54160930140493, 5.35670754719982, 5.12633272245133, 4.88434721757477, 4.65934894211133, 4.47058257016638, 4.32695132260256, 4.2285720486294, 4.24122540292336, 4.62116113538191, 4.95438657223701, 5.21876415677214, 5.39555008410446, 5.47275846063356, 5.44800604047671, 5.32984611012871, 5.13665838969873, 4.89277650468045, 4.62273732336765, 4.34582023497493, 4.07343636722213, 3.810702008461, 3.56110913684306, 3.33122436372728, 3.13241919836277, 2.97880859607307, 2.88313687697481, 2.85334285313893, 2.89148043165617, 2.99476492550612, 3.15731440882888, 0, 0, 0, 0, 4.50171657383887, 4.76725753659364, 4.98391420212611, 5.13116282900903, 5.1922661357174, 5.15627751914707, 5.01942414072968, 4.78570024311716, 4.46670539018071, 4.08095251099637, 3.65296076842997, 3.21233916861373, 2.79270466101750, 2.42975911543662, 2.15750800485746, 2.00194697805369, 1.97290760545717, 2.05680079909251, 2.21448505094414, 2.38783204204583, 2.51511906195553, 2.55050705299750, 2.47956187763093, 2.32366368567253, 2.13125434717041, 1.96024829618887, 1.85969010927111, 1.85789019005685, 1.95995656723782, 2.15292894462235, 2.41419938144864, 2.71917457572363, 3.04605980854715, 3.37763903739759, 3.70104207993791, 4.0066596719188, 4.28701275012887, 4.53594203423922, 4.74818224238988, 4.91924859716058, 5.0455312332008, 5.1245042206177, 5.15497690116675, 5.13733511295875, 5.07373669524447, 4.96823945877397, 4.82685190757809, 4.65751022716956, 4.47000078714063, 4.27586004803647, 4.08827750731205, 3.92198115254226, 3.79298841716358, 3.71798094621164, 3.7129773306653, 3.79103740160411, 3.95902096501416, 4.21393440130147, 4.53996622440893, 4.90763596210863, 5.2762508723412, 5.59996715677052, 5.83641800129229, 5.95565099187045, 5.94663664988127, 5.81921394310418, 5.60085503437514, 5.32941642729954, 5.04431237182853, 4.77878912630848, 4.55520577161284, 4.38390793508276, 4.26504410647743, 4.39225106037538, 4.79396804520538, 5.14611996984028, 5.42483326807406, 5.60993793463673, 5.68867132093289, 5.65880980205548, 5.53010717831344, 5.32297639746498, 5.06405217388541, 4.77965665147626, 4.48967031795952, 4.2047542989952, 3.92843467196028, 3.66273953019106, 3.41378301857579, 3.19379583799207, 3.01865975830088, 2.90300820605021, 2.85611884970752, 2.88058823266243, 2.9735423438331, 0, 0, 0, 0, 0, 4.46990199737718, 4.73987574167139, 4.96190456482528, 5.11505470389628, 5.18220991309226, 5.1521245533833, 5.02084405362733, 4.79232338272826, 4.47828509589732, 4.09755449206992, 3.67519853986911, 3.24167134108731, 2.83177400292007, 2.48267477890587, 2.22987001970025, 2.10034909124184, 2.10372263900162, 2.22431142235542, 2.41881776360557, 2.62348424628304, 2.77088172818290, 2.81114872275059, 2.72890006867141, 2.54799419315954, 2.32192590149148, 2.11457523794484, 1.98014614227148, 1.95019548051183, 2.03093866001168, 2.20886850617957, 2.45996734876978, 2.75808668983349, 3.08017203900379, 3.40819131657945, 3.72884861202347, 4.0323551632616, 4.31114613407575, 4.55895262928926, 4.77030771005267, 4.94041222908187, 5.06524654553613, 5.14182247384686, 5.1684913753007, 5.14524718176656, 5.07398365091871, 4.95868121045947, 4.80551075245565, 4.62285369501289, 4.42125318798466, 4.21332585330744, 4.01365902931349, 3.83866990671195, 3.70629693370025, 3.63525496763948, 3.64349213032120, 3.74555519446323, 3.94889875892279, 4.2497504163714, 4.62978257035287, 5.05520033820381, 5.47958685929801, 5.85082565729932, 6.12090902055605, 6.2560655785137, 6.24410445923309, 6.0965665384933, 5.84499696590647, 5.53267619305043, 5.20458022402375, 4.89860926258534, 4.64024189155383, 4.4412730926733, 4.30189217947355, 4.52437843842459, 4.94563928171095, 5.31461493278886, 5.60579355197354, 5.79766253426646, 5.87673715030005, 5.84096762741382, 5.70128032214276, 5.48006656370948, 5.20621525860416, 4.90783916928748, 4.60550604955838, 4.30927790978361, 4.02123569485505, 3.74198478298928, 3.47705295448595, 3.23922363790154, 3.04574632229705, 2.91276616126612, 2.8506343693205, 2.86236864768995, 2.94500619894028, 0, 0, 0, 0, 4.12222479140656, 4.41797158524696, 4.68967588389628, 4.91477578678273, 5.07213798082884, 5.14444018331966, 5.1202545958934, 4.99549272909628, 4.77404215624414, 4.46764166314082, 4.09524084058210, 3.68217814680073, 3.25937678434531, 2.86233933325241, 2.52912956051951, 2.29614783229777, 2.19091846344185, 2.22269982825905, 2.37410529101064, 2.59864656642528, 2.82834566045499, 2.99156227602585, 3.03553236305217, 2.94428795541026, 2.74366537143984, 2.49103886233603, 2.25481679152423, 2.09309511383225, 2.03986703294317, 2.10217310107382, 2.26609933197402, 2.50659806475214, 2.79641767544558, 3.11166318452061, 3.43383089199968, 3.74946598763345, 4.04880064228538, 4.32432820259532, 4.56976229176694, 4.77947640978951, 4.94835162817009, 5.0719107669163, 5.14662085877274, 5.17026705559572, 5.14232768936262, 5.06430542447896, 4.93998767039331, 4.77561956268827, 4.57998103510349, 4.36437362187791, 4.14254024951007, 3.93054203452818, 3.74656882028543, 3.61054702563459, 3.54325576201809, 3.56455833759209, 3.69043278348098, 3.9288500657618, 4.27518835558542, 4.70857618845026, 5.19094717819963, 5.67028165339388, 6.08837049564086, 6.39176004025996, 6.54301567131396, 6.52885584921441, 6.3624875003779, 6.07939557972459, 5.72808957229962, 5.35889914276413, 5.01420232528685, 4.7224820692474, 4.4969364326753, 4.33780790914313, 4.63421938830739, 5.07227150071444, 5.45551299468007, 5.7569257384984, 5.95375956164311, 6.03186111487858, 5.98933751524211, 5.83819900578265, 5.60268443709929, 5.31382887495504, 5.00153336867663, 4.68721254691924, 4.3806286030896, 4.08273662556706, 3.79288595030719, 3.51590031888879, 3.2647051722316, 3.05733804039149, 2.91089328509889, 2.83639988339644, 2.83712101701803, 2.91001356693944, 0, 0, 0, 0, 4.0543607583253, 4.34736224864797, 4.61795771556188, 4.8436641730507, 5.00337316297953, 5.07974246107731, 5.06129049907384, 4.94385172790372, 4.73122381735371, 4.43505553174343, 4.07422493220536, 3.67404450441306, 3.26548937511235, 2.88421419523044, 2.56851599557929, 2.35501014538399, 2.27121533388073, 2.32588941918418, 2.50041178801474, 2.74628426000971, 2.99302708185691, 3.16661181858213, 3.21273515564775, 3.11529049044952, 2.901474139069, 2.63109859583607, 2.37533608091850, 2.19461689755169, 2.12437094604672, 2.17210895143643, 2.32367111983467, 2.55343394154111, 2.83358575614840, 3.13989495230659, 3.45379970060349, 3.76200642296972, 4.05500907683318, 4.32553334507004, 4.56738891660688, 4.7748450398943, 4.94246285798426, 5.06525723075913, 5.13905691870026, 5.16095262730448, 5.12975404584442, 5.04640853204392, 4.91435404130698, 4.73978391717514, 4.53180134197104, 4.30245183870978, 4.06664520380553, 3.8419899662917, 3.64852363251879, 3.50820520953431, 3.44387022921621, 3.47723195202623, 3.625593168207, 3.89733066737768, 4.28691161216511, 4.77096401128823, 5.30733666655624, 5.83873597184363, 6.30127921832531, 6.63648269389814, 6.80355558332298, 6.78824153148795, 6.60530669563235, 6.29387482578498, 5.90726611599113, 5.50072664962259, 5.12074485150309, 4.79856590173797, 4.54868793977738, 4.37142159085302, 4.7187537334399, 5.17038151825482, 5.56492718242987, 5.87402972368622, 6.07382604157255, 6.14954753947655, 6.09941609168555, 5.93638765885159, 5.68635505133456, 5.38233892247458, 5.05601431996438, 4.72985390975367, 4.41373154731433, 4.10793127797224, 3.81081313222161, 3.52639439536079, 3.26725180149393, 3.05149037241562, 2.89644672123608, 2.81333110434166, 2.80543617425376, 2.86965475010813, 0, 0, 0, 0, 3.97276990451914, 4.26003827386985, 4.52662843436359, 4.75038429011679, 4.91045465809386, 4.98967195069152, 4.97663788054682, 4.86717522795664, 4.66497712374533, 4.38150211772178, 4.03536286842535, 3.65154249683142, 3.26063219669426, 2.89785357656792, 2.60102157708710, 2.40621480555622, 2.34035190548911, 2.41152425671554, 2.60039579848306, 2.85775890850993, 3.11252956113543, 3.29030690300051, 3.33675835840157, 3.23613351553983, 3.01630841857296, 2.737940830149, 2.47301318314949, 2.28256188320369, 2.20233976406911, 2.2399254990554, 2.38108202905808, 2.60010443649768, 2.86921683847191, 3.16440717976567, 3.46751559778716, 3.76576988490860, 4.05020054491997, 4.3139677763999, 4.5511127295829, 4.75587093369906, 4.92249161473922, 5.0454315521492, 5.1197785152016, 5.14177936138252, 5.10938726619937, 5.02278285546114, 4.88484459005568, 4.70153796336422, 4.48217798052837, 4.23952307863794, 3.98969096073363, 3.75191916753923, 3.54817065938062, 3.40246917042756, 3.33966775355409, 3.38321937126527, 3.55159762097857, 3.85344158868433, 4.28224854432901, 4.81225009743090, 5.39753065171361, 5.97605304705234, 6.47891727676002, 6.84324649908228, 7.02535203845866, 7.01016403787899, 6.81383246277487, 6.4786560782124, 6.06213079339533, 5.62375927405432, 5.21358637646652, 4.86525276239859, 4.5943970849878, 4.40141421275043, 4.77546662845339, 5.23706235859208, 5.6396119297589, 5.95360135952351, 6.15419628043112, 6.2260694989708, 6.16750298426093, 5.99223302771255, 5.7275764863723, 5.40834472437697, 5.06795586800001, 4.73016670230584, 4.40542273210376, 4.09385713114715, 3.79315858297812, 3.50644401879233, 3.24540859071695, 3.02742952271926, 2.86930348489247, 2.78187582184568, 2.76823579037145, 2.82523519053189, 0, 0, 0, 0, 3.87978717178604, 4.15840456595246, 4.41811953779152, 4.63735115314415, 4.79573949470505, 4.87648947745451, 4.86842849995224, 4.76744071693814, 4.57711001969853, 4.30861626343306, 3.98012512985339, 3.61599788647548, 3.24601284159768, 2.90437370106838, 2.62768987153482, 2.45073550259769, 2.39921458462532, 2.48036807259369, 2.67465472685892, 2.93346486607224, 3.18703015316856, 3.36262512130317, 3.40742927317881, 3.3065633091387, 3.08790545990051, 2.81135161723768, 2.54771570179163, 2.35688407219232, 2.27379476309823, 2.30567581129097, 2.43837355966422, 2.64659616284687, 2.90320645446021, 3.18498162837201, 3.474642893516, 3.76032259671493, 4.03388750059585, 4.28915894929571, 4.52056679695071, 4.72240115387749, 4.888619823768, 5.0130766434524, 5.09001008090792, 5.11465230098389, 5.08387080641865, 4.99680776886555, 4.8555012931597, 4.6654467300428, 4.43601388338495, 4.18062732793338, 3.91666534239503, 3.6651017464766, 3.4499250982844, 3.2972618002663, 3.23392854340511, 3.28497616207010, 3.46985570012423, 3.79728930839534, 4.25973082572584, 4.82915138004083, 5.45629424288163, 6.07508712789851, 6.61249218490676, 7.00208872258732, 7.19789390827433, 7.18423025782933, 6.97839584318949, 6.62525644206309, 6.18565703788797, 5.72249974146896, 5.28866546469499, 4.91971103171681, 4.63220334211714, 4.42663627985062, 4.80247001974546, 5.27011984986897, 5.67710917415651, 5.99297990875967, 6.1920811930721, 6.25859178170409, 6.19080433947539, 6.0030744433197, 5.72391457799209, 5.38972528172021, 5.03561747695123, 4.68682724142573, 4.35479710821947, 4.04000121045724, 3.73975859791, 3.45618724819807, 3.19957112216633, 2.98577352569701, 2.83028377649005, 2.74305417182548, 2.72675266739475, 2.77821840223208, 0, 0, 0, 0, 3.77799821273446, 4.0451988389428, 4.29527887839908, 4.50747407829273, 4.66214473016431, 4.74306393537978, 4.73942888709712, 4.64726453978517, 4.47005239376277, 4.21862203745574, 3.91053285711592, 3.5692593131588, 3.22337051905335, 2.90550429476842, 2.65037921316086, 2.49072978166204, 2.45044578003383, 2.53571639760076, 2.72724328731843, 2.97821386434215, 3.22195787365123, 3.38934015348133, 3.43050612202610, 3.33195066185616, 3.12094566484782, 2.85514474475821, 2.60235786695393, 2.41968393932387, 2.34017744180246, 2.37031303278676, 2.49615784678524, 2.69328648233986, 2.93576354761783, 3.20169818691637, 3.47516141836105, 3.74557766914899, 4.00596416322597, 4.25104989168577, 4.47583230700778, 4.67476556528333, 4.84155526598606, 4.96942026972381, 5.05164194277751, 5.08224630517719, 5.05673694463811, 4.97286837074075, 4.83146355008879, 4.63721748976397, 4.39934022568186, 4.13186305316887, 3.85350688050387, 3.58714199106592, 3.35893523856651, 3.19718841270064, 3.13063968044945, 3.18578743988191, 3.38284051465872, 3.73038101535741, 4.21969441824634, 4.82060119165937, 5.48097166753056, 6.13154589915124, 6.69623301907905, 7.10612256961282, 7.31368087262304, 7.30287233450894, 7.09185969716232, 6.72735312017427, 6.2725696847365, 5.79279915422354, 5.3429061428228, 4.95979278259604, 4.66069645025358, 4.44621974538603, 4.79860028523471, 5.26818118744296, 5.67586205647178, 5.99045848687793, 6.18566518356959, 6.24524371809209, 6.16747362750522, 5.9672101989973, 5.67398017565461, 5.32560026115805, 4.95880616361247, 4.60043058473645, 4.26321394554523, 3.94833086278696, 3.65293865547108, 3.37803332202554, 3.13200584711355, 2.92851767527852, 2.78109765660189, 2.69837299276269, 2.68242570116859, 2.73011443197831, 0, 0, 0, 0, 3.67012243594377, 3.92336961540529, 4.16124489744943, 4.36402907112446, 4.51302016005368, 4.59274747878707, 4.59291996744294, 4.50978748110112, 4.34674844919528, 4.11423170043855, 3.82906175490214, 3.51360340906885, 3.19487578232719, 2.9034725414926, 2.67161600734074, 2.52934242352246, 2.49817540779703, 2.58303543420119, 2.76520599139444, 3.0006606739691, 3.22732978128740, 3.38130321466654, 3.41695207805157, 3.32260734787202, 3.12445336790189, 2.87667284560786, 2.6425295108776, 2.47494704538026, 2.40417987802154, 2.43559163585020, 2.55557107065122, 2.74093494065728, 2.96743054869448, 3.21497767734516, 3.4694279090718, 3.72187123433537, 3.96679308934991, 4.20009137352893, 4.41753157285494, 4.61386708248057, 4.78261784834966, 4.91635929340923, 5.00731746407215, 5.04810232990364, 5.03251676161986, 4.95647863238416, 4.8190966484354, 4.62381882883875, 4.37940811596318, 4.10043587619462, 3.80710271694531, 3.52442723654263, 3.28100292878479, 3.10745670064492, 3.03445813751898, 3.08983017901495, 3.29431218824815, 3.65606030142776, 4.16494679171776, 4.78862365602126, 5.47250834207583, 6.14509006302842, 6.7285090651162, 7.15263446380243, 7.36926941872251, 7.36231427498401, 7.15047829911452, 6.78151390553348, 6.3199354818303, 5.83230999794829, 5.37454732821478, 4.9842607055508, 4.6790643453964, 4.45966912577065, 4.7634856335994, 5.23076900575989, 5.63529075412713, 5.94535452443002, 6.13416198359387, 6.18514947255902, 6.09660462278803, 5.88384180215846, 5.57731514373678, 5.21615202759857, 4.83863476552199, 4.47319293099221, 4.13395930843905, 3.82293806528228, 3.53716203774516, 3.27633243203328, 3.04654801236977, 2.85875886266293, 2.7240914258893, 2.6495936061982, 2.63669325733159, 2.68230312557212, 0, 0, 0, 0, 3.55889181126306, 3.79594771068907, 4.01931107143418, 4.21051792131906, 4.35200445658842, 4.42923138352605, 4.43255526596698, 4.35853750062431, 4.21052526831992, 3.99851988778449, 3.73851929427134, 3.45160874590754, 3.16298948564507, 2.90082773675253, 2.69435640992194, 2.5703659877223, 2.54753586126203, 2.62928854357335, 2.79768573910094, 3.01219107666590, 3.21645166373023, 3.35302627013252, 3.38149648473676, 3.29242683457909, 3.11060265631865, 2.88585172770531, 2.67575439064467, 2.52801921172838, 2.46939931592673, 2.50385738417156, 2.61815868255717, 2.79063294160187, 2.99907671408684, 3.22560597861603, 3.45822286881537, 3.69002612717348, 3.91728021029953, 4.13732273336216, 4.34690939191277, 4.54125968138225, 4.71381302806997, 4.85653078244177, 4.96050740798815, 5.01671212005329, 5.01684043272585, 4.95439695021873, 4.82611405788608, 4.63359335579182, 4.38477145477466, 4.09469359599033, 3.78526629606398, 3.48405142062912, 3.22247076890368, 3.03376104727827, 2.95064289135499, 3.00222025713222, 3.20955346363039, 3.57998755983265, 4.10150103756086, 4.73926847566972, 5.43648881936621, 6.12037394678793, 6.71280568240996, 7.14396878714872, 7.36606453278633, 7.36327269215247, 7.15450409877892, 6.78770415429329, 6.32756779313453, 5.8407931148302, 5.38336348402251, 4.99293816218283, 4.68718950595144, 4.46691971061376, 4.69757891029593, 5.15833718320386, 5.55582856579325, 5.85804226439464, 6.03783803563582, 6.07843403802448, 5.9782073782275, 5.75300153549868, 5.4342476440385, 5.0623829469143, 4.67716123492882, 4.30846801165701, 3.97165680185852, 3.66938359593077, 3.39835858017991, 3.1567365882599, 2.94802503287358, 2.78019128707897, 2.66181278484295, 2.59836226726451, 2.59068853468894, 2.63579375395151, 0, 0, 0, 0, 3.44693260499254, 3.66591909353684, 3.87278899234073, 4.05052278041977, 4.18287369302662, 4.25639153578144, 4.2622064772513, 4.19727810136438, 4.06494567962549, 3.87478083678907, 3.64190313848658, 3.38600753643480, 3.1302926568833, 2.90022415967459, 2.72168450510276, 2.61780382286102, 2.60403081730423, 2.68205361867667, 2.83475031096862, 3.02545346316872, 3.20419874371826, 3.32080452789023, 3.34072612333029, 3.25707944082382, 3.09313046323638, 2.89386250328332, 2.71050184252012, 2.58490456492980, 2.53987223674973, 2.57775810509896, 2.68570866826787, 2.84371768025971, 3.03186441761490, 3.2347352122373, 3.44277607762599, 3.65139453604868, 3.85892854314071, 4.06443074725669, 4.26589154423311, 4.45920230865071, 4.63787942450616, 4.79335499867336, 4.91555325333559, 4.99356849345013, 5.01649976832395, 4.97470124064199, 4.86165776558416, 4.67632840308658, 4.42532897311606, 4.12412219381925, 3.79667769381832, 3.47370220716348, 3.1900731270557, 2.98213144353705, 2.88495564266196, 2.92903863614969, 3.13560230704533, 3.51063656133243, 4.03933253218333, 4.68354556016222, 5.38411550899288, 6.06794065661645, 6.65846353627748, 7.0881032627675, 7.31076184568369, 7.31130239155569, 7.10846201214203, 6.74950276616621, 6.2981912279164, 5.82023721715296, 5.37074647706468, 4.98676170346079, 4.68568020452808, 4.46835448130839, 4.60215383659388, 5.05226742776673, 5.43891969104848, 5.72995327304418, 5.89801692942429, 5.92622972127119, 5.81320742197126, 5.57552300620124, 5.24579898853505, 4.86591441281175, 4.47703875130912, 4.11022672391526, 3.78158811108863, 3.49390500928120, 3.24308915916836, 3.02538968250961, 2.84152048657846, 2.69646476542108, 2.59646435043476, 2.54575487559735, 2.54487406447010, 2.59094677305295, 0, 0, 0, 0, 3.33665719647678, 3.53610669512673, 3.72487822429742, 3.88756488980770, 4.00939130688132, 4.07813280841131, 4.08580568729736, 4.02985149668746, 3.91365442663768, 3.74637764030111, 3.54225028317313, 3.31952628563305, 3.09930249040823, 2.90418533796918, 2.75648424196924, 2.67539528529486, 2.67285012869733, 2.74856602238639, 2.88612093755650, 3.05276886421297, 3.20515479320831, 3.30068473203858, 3.31101972959487, 3.23205880337121, 3.08561788191272, 2.91174422699507, 2.75511253171016, 2.65149904924011, 2.61956085029432, 2.65991867187630, 2.76005604427085, 2.90166058375622, 3.06719064523968, 3.2438592740398, 3.42476481264968, 3.6078714589543, 3.79386080942959, 3.98377555355549, 4.17710831013604, 4.3706750550028, 4.55829441326756, 4.7310296683252, 4.87765208755995, 4.9851447288948, 5.03942606726333, 5.0267668491283, 4.93627330280364, 4.76322009932108, 4.51226584406615, 4.19925375346751, 3.85075130384167, 3.50149033381804, 3.1907404033999, 2.95874060952439, 2.84351757830052, 2.87730400737198, 3.08141353219187, 3.45969318691837, 3.99299890232162, 4.6381704789745, 5.33293446850391, 6.00479717775991, 6.58103895596515, 6.99880610184325, 7.215358359247, 7.21672436277878, 7.02104281064125, 6.67398971985216, 6.23733798050489, 5.77477054362346, 5.33963458646905, 4.9677268484968, 4.67583093682652, 4.46477635134101, 4.47926509606809, 4.91482817825166, 5.28698242329011, 5.56355255431041, 5.71707883282257, 5.73070678084673, 5.6035057911057, 5.35311112710058, 5.01372233718404, 4.62893586750874, 4.24131480388836, 3.88266603637585, 3.56911035028463, 3.30268521238054, 3.07773961839196, 2.88812668375766, 2.73163941325851, 2.61054677043347, 2.52936888944549, 2.49184180398565, 2.49870155329940, 0, 0, 0, 0, 0, 3.23017308556017, 3.40906799032475, 3.57855020799175, 3.72497534993697, 3.83516794636285, 3.89824116634359, 3.90719331057992, 3.86002572242012, 3.7602268320787, 3.61659294495419, 3.44248712307173, 3.25472765361836, 3.07229114563930, 2.91487484108862, 2.8011248718597, 2.74616591476099, 2.75822653530803, 2.83482562398059, 2.95999120091270, 3.10465835665471, 3.23189208047814, 3.30658960326434, 3.30664250881027, 3.230879776214, 3.0999036661104, 2.94909257748605, 2.81680175405271, 2.73287461221186, 2.71186749418326, 2.75262609604792, 2.84288421813823, 2.96594285597348, 3.10660817077224, 3.25476307583297, 3.40628074223116, 3.56187250678000, 3.72480266294644, 3.89837378190258, 4.08387148675017, 4.27934362658137, 4.47921957278528, 4.67445046343636, 4.85274751112202, 4.9987535163439, 5.09451770022406, 5.12106641091667, 5.0616877091622, 4.90663578065608, 4.65780570637303, 4.33141124723265, 3.95737499831703, 3.57568492909152, 3.23133501077393, 2.96965110914430, 2.83258760726373, 2.85481264661715, 3.05779381541624, 3.44210288909926, 3.98177775273799, 4.62572292632957, 5.3069194193525, 5.95434525584665, 6.50205366900407, 6.89523167870392, 7.09665432697269, 7.09409918614135, 6.90460025584298, 6.57130051258724, 6.15297636131757, 5.71036744799306, 5.29429220278684, 4.93873052332892, 4.65951484307744, 4.45733782852156, 4.33167479118716, 4.74909910063414, 5.10334209735486, 5.36229619107485, 5.49846336248573, 5.49514087676297, 5.35211964347078, 5.08854273463045, 4.74072171474158, 4.35437588265863, 3.97347988957932, 3.63007770987852, 3.33932666269526, 3.10135509648407, 2.90792391225931, 2.74986011270857, 2.62194916591391, 2.52426041983072, 2.4606168066579, 2.43543542182541, 2.45043950744652, 0, 0, 0, 0, 2.97344218018593, 3.12921608661597, 3.28701407566672, 3.43645213099226, 3.56578448860047, 3.66353842806582, 3.72025128160923, 3.72997992123203, 3.69135414653498, 3.60802865711773, 3.48849020909223, 3.3452904882166, 3.19386559091311, 3.05112343314247, 2.93389702996387, 2.85719566616386, 2.8320574429166, 2.86291610088224, 2.94488459695206, 3.06209302955571, 3.18868524901235, 3.29362421082383, 3.3488525175471, 3.33825944936905, 3.26367282051659, 3.144845635162, 3.01304121369429, 2.90087499419422, 2.83270996951723, 2.81924091573587, 2.85756488811465, 2.93554698813950, 3.03793126398214, 3.15173279579461, 3.26944748333081, 3.38976442452100, 3.51627269359202, 3.65502131737835, 3.81183198170264, 3.99009599803087, 4.18946013319694, 4.40536874700664, 4.62903177529908, 4.84728759143595, 5.04222914967591, 5.19124105222819, 5.26869587263126, 5.25028022328335, 5.11955915865457, 4.87466338821773, 4.532196732451, 4.12644981139801, 3.70430667601366, 3.31828736850245, 3.02047149832711, 2.8582030784654, 2.86971551759795, 3.07686048023836, 3.47536510633018, 4.02877907539078, 4.67359920474169, 5.33531818784261, 5.9451845723945, 6.44780557744068, 6.80077245255206, 6.97517023185617, 6.96123207716454, 6.77426781787476, 6.45387392807673, 6.05489912357131, 5.63437453429027, 5.23996024422837, 4.90332532684795, 4.6390188912505, 4.4474352959063, 4.16274941799028, 4.5588652692192, 4.89213696675141, 5.13057148024099, 5.24667313206902, 5.22400969537815, 5.06339116608385, 4.78598361581786, 4.43084091263388, 4.04629681549938, 3.67778778827195, 3.35702517790374, 3.09708589854954, 2.89482980120673, 2.73821417840603, 2.61428656725282, 2.51474547462886, 2.43816872232292, 2.38908506680046, 2.37421532265966, 2.39734769007181, 0, 0, 0, 0, 2.89906013805462, 3.03511400935256, 3.1717544869414, 3.30083496397157, 3.41263464558465, 3.49746135667763, 3.54733586830952, 3.55742872391485, 3.52705455336936, 3.4600947411168, 3.36479364371859, 3.2529686886872, 3.13876446201234, 3.03712710631874, 2.96214658363033, 2.92531688215127, 2.93367673474855, 2.98785817960997, 3.08039281875047, 3.19511050554772, 3.30873662905555, 3.39537648745556, 3.43331946153897, 3.41202661423296, 3.33632538510119, 3.22556274347878, 3.10763523632784, 3.01024030310296, 2.95292957427452, 2.94291719943478, 2.97563134333662, 3.03893004687893, 3.11876653402510, 3.20414471831733, 3.29003502221851, 3.37791023170032, 3.47430721859514, 3.58821901818592, 3.72822827945377, 3.90016215909498, 4.10569332493038, 4.34178683219985, 4.60040757521324, 4.86781711600791, 5.12338335705618, 5.3389354454232, 5.48053766940134, 5.51414148822056, 5.41460771601759, 5.1750937798981, 4.81263613422296, 4.36716562102616, 3.89453348147839, 3.45709893535271, 3.11588615819973, 2.92561491280031, 2.92968434741858, 3.15074107459817, 3.57762081538562, 4.15842101728362, 4.81106543872888, 5.44960003977639, 6.00826012272442, 6.4468939322818, 6.74098990483432, 6.8734235267304, 6.83772395108897, 6.6467401631873, 6.33544635349738, 5.95392167572155, 5.55489864212975, 5.18241046913411, 4.86541006287187, 4.61683879663252, 4.43657905487276, 3.97633259201855, 4.34848512451084, 4.65819775208086, 4.87361353771054, 4.96726076030818, 4.92308577938877, 4.74321299247322, 4.45135170375098, 4.08993872162705, 3.71042586201945, 3.3597686858072, 3.06876935823662, 2.84727868731623, 2.68747467674014, 2.57222191178495, 2.48396558326460, 2.41122662993522, 2.35192102756040, 2.31297262152434, 2.30539076496224, 2.33634987114765, 0, 0, 0, 0, 2.83153026896765, 2.94878488244903, 3.06466998087394, 3.17350788351283, 3.26771921308467, 3.33944499779784, 3.38222103841321, 3.39236358276451, 3.36991325690597, 3.31903238764742, 3.24779338526998, 3.16736990205453, 3.09073063373577, 3.03100590072448, 2.99971929373339, 3.00504262922821, 3.05018334841783, 3.13203943916300, 3.24043080331649, 3.35847691968396, 3.46478465934995, 3.53771783049348, 3.56106401030619, 3.52930556952157, 3.4502126350067, 3.34319565997406, 3.23362916200651, 3.14524437108951, 3.09357270341429, 3.08281321835009, 3.10684158178854, 3.15336458952563, 3.20927529066909, 3.2652936140982, 3.31866473920329, 3.37354897164441, 3.43944047556447, 3.52838664756657, 3.65194664902691, 3.81872193526978, 4.03289005429385, 4.29353837760983, 4.59400687818541, 4.92039148599671, 5.24921202705784, 5.54578683653053, 5.76601271095609, 5.86366217923944, 5.8025601719825, 5.56948755595432, 5.18196008025102, 4.68701325790465, 4.15191648255108, 3.65170100020195, 3.25904020663015, 3.03847890775467, 3.0405808209992, 3.28934656549153, 3.76426258224486, 4.39190420179898, 5.06400119187248, 5.67812054147124, 6.17206159783088, 6.52628725261033, 6.74056390123656, 6.8135830525179, 6.74312919372171, 6.538795727515, 6.22986822826848, 5.86095679581458, 5.48011106056629, 5.12744539060914, 4.82888674493855, 4.59545438141169, 4.42625258002827, 3.77659940928052, 4.12273595443875, 4.40689908580827, 4.5973858157634, 4.66676902570298, 4.5994699087366, 4.3991830661453, 4.09260605457652, 3.72610103033774, 3.35465454598279, 3.02676345251464, 2.77178315881945, 2.59529297988016, 2.48349371245741, 2.41295368647685, 2.36072226387708, 2.31205086645285, 2.26505559285676, 2.23085989105553, 2.22691575509856, 2.26522236485806, 0, 0, 0, 0, 2.77096329340621, 2.87076905384715, 2.96671280368765, 3.05581916732458, 3.1327487301397, 3.19150094160704, 3.22712991738684, 3.23710548292177, 3.22221769137659, 3.18695348610930, 3.13928043610568, 3.08982300732643, 3.05050216558398, 3.03280126763361, 3.04588978114086, 3.09485981998592, 3.17931655856058, 3.29255697105795, 3.42161669023175, 3.54853086542541, 3.65309173939183, 3.71700770541613, 3.72866123079236, 3.68694405722511, 3.60246319274612, 3.49513881623100, 3.38867281422055, 3.30380730404465, 3.25287863497306, 3.23756772058768, 3.25033528110471, 3.27859957309134, 3.30991488733271, 3.33641828128333, 3.35738773057208, 3.37951989929339, 3.41521494618795, 3.47962907801373, 3.58747556079393, 3.75046152131317, 3.97578150974308, 4.26532167502292, 4.61452265342356, 5.0098351342609, 5.42488000707292, 5.81750101564328, 6.13145390118676, 6.30568538487825, 6.29043926040268, 6.06460491662167, 5.6461932569541, 5.09073589868851, 4.47954053853865, 3.90372457763539, 3.45080963091094, 3.19784911138688, 3.20471708495402, 3.49737243496062, 4.04330357228846, 4.74099960258526, 5.44769800618729, 6.03887265613734, 6.45620580197203, 6.706205424001, 6.81947284160728, 6.81466776571767, 6.69485543088777, 6.46567350305626, 6.14983739322152, 5.78604328356676, 5.41752870346985, 5.08038918193803, 4.79731631512887, 4.57710713573164, 4.41777495437382, 3.56789876672984, 3.88664062177226, 4.14398003768039, 4.30840904718231, 4.35258781294774, 4.26149868888499, 4.04058486472658, 3.71981627568066, 3.34980626466824, 2.98929498807042, 2.68825444087012, 2.47413356152744, 2.3474250529762, 2.28736050506937, 2.26328331975812, 2.24622513712234, 2.21811870423259, 2.17807247564713, 2.14307410392058, 2.13902119491254, 2.18407511680987, 0, 0, 0, 0, 2.71730993084346, 2.80128737521429, 2.87843071720471, 2.94866151700838, 3.00894289854844, 3.05512512882298, 3.08375472724777, 3.09343821893772, 3.08571881116011, 3.06543719139277, 3.04051362361533, 3.02111340581506, 3.01823908125481, 3.0419044316063, 3.09915538899459, 3.19227752459288, 3.31754749791225, 3.46485282263715, 3.61844149110566, 3.75896375335697, 3.86676902657477, 3.92604734095404, 3.92889620479501, 3.87799457556051, 3.78663799794285, 3.67563754095677, 3.56780013384325, 3.48179446817262, 3.42754818228495, 3.40470853466195, 3.40446729683216, 3.4138343020348, 3.42075892617112, 3.41849242211591, 3.40807720839415, 3.39854743891005, 3.40509635223444, 3.44597969383978, 3.53918995543674, 3.69984195666981, 3.93866109348705, 4.26104422598751, 4.66532438829371, 5.13891499620287, 5.65257992397829, 6.1557998494768, 6.57825048650009, 6.8413953398006, 6.87936295823035, 6.66177773471189, 6.20707552070228, 5.57980045616913, 4.87751834342646, 4.2118569150382, 3.68906500555838, 3.40114539303782, 3.41905462172027, 3.7711600857035, 4.41049646717339, 5.20147620586737, 5.95922889999484, 6.5318081425021, 6.86465366467221, 6.99473666945029, 6.98901049209942, 6.88966361922856, 6.7060372843336, 6.43945842049027, 6.10566065906394, 5.73741203369638, 5.3733344602206, 5.04561444356019, 4.77360406758822, 4.56360041958991, 4.41217936291879, 3.35459043807896, 3.64528018227744, 3.87533272162249, 4.01352653174248, 4.03269736232261, 3.91846917867983, 3.67810178899181, 3.3448831692826, 2.97367821866426, 2.62689753658539, 2.35577975751455, 2.18551410500624, 2.11103579562234, 2.10409253235635, 2.12634363401394, 2.14252027658199, 2.1313027644062, 2.09340902136285, 2.05289978831835, 2.04555121784742, 2.09663254047198, 0, 0, 0, 0, 2.67048956741527, 2.7403101211381, 2.80000791770546, 2.85249790205626, 2.897045736795, 2.93130408863033, 2.95325570572498, 2.96260215469286, 2.96162257507743, 2.95552279786498, 2.95221844823384, 2.96149366688900, 2.99355346330721, 3.05711630368322, 3.15734007875519, 3.29399366065968, 3.4603319535582, 3.64307859473147, 3.82376878676735, 3.98146838364582, 4.09657047290969, 4.15499346058377, 4.1517496628285, 4.09270922164694, 3.99366908179732, 3.87661632903924, 3.76411314559936, 3.67354609522914, 3.61312891117978, 3.58091542042977, 3.56697352847246, 3.55780953480374, 3.5415295746332, 3.51220786974913, 3.47236791686811, 3.43313995978013, 3.41233447772712, 3.43122560623353, 3.51114100479252, 3.67084734284009, 3.92507291045114, 4.28341510257027, 4.7478964843256, 5.30754978786203, 5.93043527381376, 6.55696650273776, 7.10104395721, 7.46427310426379, 7.56255284606779, 7.35557738013864, 6.86196038307621, 6.15304848396789, 5.34327441137094, 4.57152433930050, 3.96810557914353, 3.64138288183969, 3.67392464937056, 4.09648924847856, 4.84588750848624, 5.74842726648532, 6.57196816801213, 7.13324412294515, 7.38066468123711, 7.38371069389517, 7.248609170289, 7.04312311469008, 6.78370353949187, 6.46766489515861, 6.10416658622602, 5.72067473273998, 5.35179661123596, 5.02614602315886, 4.75974206394064, 4.55613964643839, 4.41011822849517, 3.14088432885009, 3.40359917705138, 3.60676320845211, 3.71960444213394, 3.71528688548001, 3.58015524186393, 3.32322138250247, 2.98084383715788, 2.61173596445998, 2.28151755556621, 2.04230118498996, 1.91678609161437, 1.89430358438933, 1.93921235769805, 2.00566091536894, 2.05229383899859, 2.05480224872650, 2.01586296148607, 1.96704779427740, 1.95444225699088, 2.01067486525502, 0, 0, 0, 0, 2.63046977257235, 2.68761707105262, 2.73131412714189, 2.76740277983112, 2.7973598705751, 2.82054288285505, 2.83628371181846, 2.84531322049920, 2.85060794524701, 2.85773040371859, 2.87461539336677, 2.91072618821718, 2.97557550025195, 3.07674910182225, 3.21774786156653, 3.39612110497025, 3.60243417321788, 3.82054361311801, 4.02943047659954, 4.20649467786359, 4.33180243812622, 4.39239221904954, 4.38550405034041, 4.3196508557569, 4.21290698684653, 4.08860583105834, 3.96955400571817, 3.87248498440708, 3.80447002321572, 3.76234600704290, 3.73519490467666, 3.70895278079344, 3.67168053857061, 3.61800484306997, 3.55163866472917, 3.48552765015361, 3.43985953795976, 3.43876635667718, 3.50688042295492, 3.66677424239622, 3.93755705020269, 4.33362279088033, 4.86140760298578, 5.51221376158566, 6.25167628668956, 7.0107485466791, 7.68636582716565, 8.15857467932695, 8.32392641277419, 8.13303033492234, 7.60407266339695, 6.80754237417285, 5.87203188539307, 4.97482452146988, 4.27840895676929, 3.90697327036445, 3.95290597301953, 4.44847755811869, 5.31366579762761, 6.33599514655835, 7.23512075028946, 7.79514546332882, 7.96582382924355, 7.8475177025166, 7.58454513129263, 7.26987077385593, 6.92758545030435, 6.5522189626106, 6.14789388996675, 5.73821695174993, 5.35484165202111, 5.02337714302335, 4.75663052458874, 4.55522559502561, 4.41180256215167, 2.93069002877573, 3.16621342559867, 3.34373683134264, 3.43318235805533, 3.40826793780982, 3.25614003066633, 2.98735867467201, 2.64079346962257, 2.27817174168776, 1.96745478985646, 1.76103502094789, 1.67901820699985, 1.70554033378606, 1.79833547838306, 1.90493548549391, 1.97870949522303, 1.99288123623077, 1.95210968295862, 1.89492051108615, 1.87682083260713, 1.93713255340154, 0, 0, 0, 0, 2.59725770492085, 2.64283211169289, 2.67195370394137, 2.69311324055598, 2.70979527898147, 2.7229103368618, 2.73302225583074, 2.74180300920132, 2.75286732365775, 2.77210521750345, 2.80747323165808, 2.86815266091363, 2.96304881818309, 3.09876039539758, 3.27735207895690, 3.49445256099218, 3.73829065635408, 3.99020139693295, 4.22685534517716, 4.4240289292659, 4.56124482128938, 4.62621212607346, 4.61783819639964, 4.54678699385445, 4.43315084203131, 4.30165808334177, 4.17567513369992, 4.07173431754297, 3.99619950990590, 3.94499474860153, 3.90634288389397, 3.86557113813202, 3.81053130875373, 3.73615530029516, 3.64704836127708, 3.55765348101761, 3.49023127474187, 3.47152649555714, 3.52934390076991, 3.69009392396166, 3.9774965673251, 4.41116734591979, 5.00251940851281, 5.74570237870044, 6.60433425266361, 7.49995654330209, 8.3121489408904, 8.89881773227751, 9.13752183331333, 8.97237491897058, 8.41976971319293, 7.53518171888935, 6.454696568358, 5.40988158394625, 4.60666567155930, 4.18227345899916, 4.23424138050449, 4.79430784416509, 5.76646354257127, 6.9030624058498, 7.88006861955056, 8.45106418152925, 8.56465289259888, 8.3459930578016, 7.97126675834142, 7.5552694545348, 7.1298401338749, 6.68900870762301, 6.23466480775634, 5.7888669128835, 5.38182586208392, 5.03692528806415, 4.76399385430463, 4.56060925389635, 4.41697980425133, 2.7274852158865, 2.93723317171141, 3.09112835111875, 3.16010727726025, 3.11873537454509, 2.95504413748439, 2.68080988036966, 2.33656658682861, 1.98582366888244, 1.69764167467021, 1.52391323912367, 1.48216566262718, 1.55217416248747, 1.68644742194713, 1.82749402365235, 1.92481678573146, 1.94996454042724, 1.90927102081138, 1.84661977158542, 1.82466243205682, 1.88777976283807, 0, 0, 0, 0, 2.57079596354694, 2.60542685674782, 2.62130990575043, 2.62908531742244, 2.63392769034692, 2.6380966866048, 2.64324402593544, 2.65187496842788, 2.66816427320271, 2.69828003694764, 2.75018124605378, 2.8327831760547, 2.95444614757391, 3.12090783078064, 3.3330046128452, 3.58474228595963, 3.86238389659017, 4.14513395455165, 4.40767755069159, 4.62433020106473, 4.77400441484487, 4.84478630137484, 4.83681507476603, 4.76247083719335, 4.64357134456754, 4.50617095284446, 4.37434210545033, 4.26469479606899, 4.18318634587034, 4.12505917859546, 4.0777899217226, 4.02608222955441, 3.95744882348718, 3.86690012877755, 3.7596302502574, 3.65122542430324, 3.56565198718497, 3.53193606886032, 3.58081098936982, 3.74241011524621, 4.04509898673008, 4.51389868426603, 5.16551898675086, 5.99739382448138, 6.97165568619586, 8.00103986376478, 8.94847456448094, 9.65067976917799, 9.96796533248832, 9.84062154842272, 9.2803304190552, 8.31181349570841, 7.07101984454836, 5.85893378113683, 4.93595881691178, 4.44879194102041, 4.49363473115277, 5.09852130023022, 6.15372499197171, 7.38442652038774, 8.43301714227922, 9.02827613119029, 9.11448023249484, 8.83120347999217, 8.37531980897472, 7.87710817838605, 7.37578403470041, 6.86809642489001, 6.35761803332862, 5.86789173145916, 5.42953762962525, 5.06464548146878, 4.78039980384675, 4.57131161987348, 4.42495114215577, 2.53421118462931, 2.72011615943038, 2.85300341923453, 2.90519804947298, 2.8524547816582, 2.68377248987657, 2.41171291156281, 2.07740899897806, 1.74461953702026, 1.48198082103023, 1.33997150105553, 1.33365527620950, 1.43961853732567, 1.60704419943099, 1.77556464509530, 1.89270276793779, 1.92934165105760, 1.89291040921661, 1.83020216873038, 1.80759494298872, 0, 0, 0, 0, 2.48918136174444, 2.55079919421979, 2.57470342535592, 2.57858429936695, 2.57455206695902, 2.56906215395669, 2.56547874957470, 2.56637675969028, 2.57497128364860, 2.59590277891122, 2.63554962511253, 2.70183323108199, 2.80339648661491, 2.94809482168631, 3.14091118526168, 3.3816478618729, 3.66298268315183, 3.96959827886201, 4.2789995449002, 4.56428374981886, 4.79857591982774, 4.96024688746697, 5.03760665174635, 5.03170389169992, 4.95625205328373, 4.83447318828757, 4.69357418024436, 4.55832856531413, 4.44554736441134, 4.36096044652253, 4.29929176407554, 4.24736788616121, 4.18927021115577, 4.11206710204873, 4.01063409281969, 3.89044146387618, 3.76782996428519, 3.66804596066751, 3.6219832629581, 3.66294698093175, 3.82451931745257, 4.13952255864519, 4.63827836505577, 5.34280626769745, 6.25406131366127, 7.33332550333899, 8.48576890707182, 9.55971539433808, 10.3735166357038, 10.7727078610951, 10.6930690611438, 10.1359405665549, 9.08837608148785, 7.68402161160696, 6.29697388798957, 5.24619361042816, 4.68669985211064, 4.70767134447054, 5.32949185407167, 6.43197890030913, 7.72458186520583, 8.8306989938654, 9.46301834708647, 9.55807082573969, 9.25644248629193, 8.76092011991896, 8.20868547774631, 7.64550075596836, 7.07458069482475, 6.50572447270615, 5.9673439641739, 5.49244409481865, 5.10280631156478, 4.80338220757185, 4.58570674242587, 4.43462614717222, 2.35320236345218, 2.51756446465764, 2.63245862005482, 2.67199107681924, 2.6134641760817, 2.44691916067040, 2.18521635023211, 1.86890700388932, 1.56031273704002, 1.32598412550823, 1.21401696490579, 1.23720035374202, 1.37030516615607, 1.56137197042896, 1.74960621534692, 1.88268618061421, 1.93193945491839, 1.90515253793803, 1.84912172238643, 1.82993107971309, 0, 0, 0, 0, 2.48511060022732, 2.53660229848625, 2.54977908093329, 2.54283544688290, 2.52858142972784, 2.51429791687079, 2.50418805830229, 2.50157348631018, 2.51024509075478, 2.53520221405369, 2.58295047358448, 2.66131575046851, 2.77864240189102, 2.94230097594528, 3.15660784748144, 3.42051220827332, 3.72565471631403, 4.05553328572906, 4.38641567853637, 4.69026813550976, 4.93938466365049, 5.11177545164295, 5.19593925838841, 5.1936078157627, 5.11949095930829, 4.99787278873228, 4.85685464321291, 4.72178203206265, 4.6096612140301, 4.52607066440634, 4.46531820701356, 4.4136560485275, 4.35454962492979, 4.27452919571564, 4.16812485273032, 4.04075638948042, 3.90909746152691, 3.79919734737178, 3.74333162683068, 3.77691784557464, 3.93656105113424, 4.25912804204893, 4.77983570282564, 5.52569400911278, 6.50117789215991, 7.66742310927255, 8.92392172117137, 10.1079147264498, 11.0243124716946, 11.5067932349023, 11.4805228065412, 10.9270898506646, 9.8026615257441, 8.24438222099197, 6.69454395836211, 5.51505869528966, 4.87617964673346, 4.8567904808988, 5.46503337889872, 6.57373944723597, 7.88970766312196, 9.03413483060018, 9.71401195893566, 9.85508545376471, 9.58471511334539, 9.095581327482, 8.52230175444343, 7.91599694728247, 7.28999439373371, 6.66475011300998, 6.07674461112536, 5.56317218323831, 5.14641925580262, 4.82965873133224, 4.60166105903879, 4.44460963105653, 2.18615401155911, 2.33147512138044, 2.43154169420566, 2.46260933011599, 2.40386425436048, 2.24644935215608, 2.00303107914507, 1.71240547069632, 1.43379099086349, 1.23002367769882, 1.14588922189432, 1.19213653011999, 1.34313498009064, 1.54798979332901, 1.7479225041859, 1.89286390467722, 1.95564749913148, 1.94366212853676, 1.90084817663536, 1.88906900726808, 0, 0, 0, 0, 2.48784666611036, 2.52709547937699, 2.52959749029701, 2.5130221393433, 2.49013269286312, 2.46859140817617, 2.45317798024781, 2.44778267523289, 2.45663309830342, 2.48497255862730, 2.53933978121376, 2.62739344549079, 2.75713763181817, 2.93546176168889, 3.16608852341744, 3.44728292377754, 3.76993327084702, 4.11675286557328, 4.46325507310223, 4.78077355799657, 5.04119650418263, 5.22244018213885, 5.31324921244186, 5.31588952319771, 5.24577094087536, 5.12788693888328, 4.99091535134283, 4.86055247755703, 4.75389549975115, 4.67636572861515, 4.62190407330455, 4.57623836045583, 4.52221561879092, 4.44572973846253, 4.34074487938065, 4.21228372201708, 4.07690037292331, 3.96092807781107, 3.8974825291285, 3.9235550622725, 4.07822609015741, 4.40180742155019, 4.93374146089095, 5.70540039138742, 6.72453365070441, 7.95285430415555, 9.28661820836957, 10.5568841213412, 11.5622193707845, 12.1287247044626, 12.1620530366758, 11.6107725539074, 10.4051631085523, 8.68345432942746, 7.02347246399391, 5.71910527234693, 4.99828576767851, 4.92698237870272, 5.49535618688456, 6.57205202076107, 7.87377466771425, 9.03575846498451, 9.76971586172651, 9.98861363845765, 9.79407144274035, 9.35420404553007, 8.79232330782743, 8.16350998948944, 7.49405676064897, 6.81857485423036, 6.1840483350735, 5.63318717116485, 5.18969520104399, 4.85542545838042, 4.61671685907145, 4.4533129466213, 2.03412859237132, 2.16294815403227, 2.25126199369108, 2.27777633894250, 2.22383731952961, 2.08172463790495, 1.86346259351669, 1.60504663477616, 1.3611192420883, 1.18937478351013, 1.13049903436992, 1.19345322961877, 1.35350309745098, 1.56279533783913, 1.76670514269714, 1.91919806484991, 1.99548194827741, 2.00190943286615, 1.97723168393029, 1.97591662420701, 0, 0, 0, 0, 2.4951692111281, 2.52078918319345, 2.51298060946788, 2.48805384989154, 2.4581103363518, 2.43081474911840, 2.41128659175990, 2.40381458353105, 2.41292446225033, 2.44398520997621, 2.50346834119990, 2.59878518700403, 2.73754761734534, 2.92615644164646, 3.16780200575315, 3.46022317599021, 3.79383220271446, 4.15095459311913, 4.50683847266356, 4.83270470944862, 5.10050075183307, 5.28837297808136, 5.3854353022629, 5.39439940106919, 5.33111632098913, 5.22093931807658, 5.09277219945559, 4.9723828477099, 4.87678807554634, 4.81118552065404, 4.76915189863359, 4.73590799516898, 4.69365554232599, 4.62753128801385, 4.53068864516324, 4.40737955411096, 4.27355705274528, 4.15528862515246, 4.08595428320877, 4.10353683033133, 4.24897731368991, 4.56532043656676, 5.09538785409189, 5.87405558847084, 6.91188969707187, 8.17185752617379, 9.54974948636217, 10.8762681763014, 11.952408152049, 12.6034921614212, 12.7095963821235, 12.1709315848717, 10.8994407405519, 9.0529224721195, 7.25905811148125, 5.83390609751141, 5.03549854409491, 4.910162793399, 5.42276893061381, 6.4394150709056, 7.6968941820341, 8.85767141569128, 9.64708352957119, 9.9648884403333, 9.87839682169243, 9.52071714981243, 8.99726862434646, 8.36564109858221, 7.66657675861329, 6.9507327013967, 6.27679803310619, 5.6936048765709, 5.22658544932844, 4.87670088373727, 4.62830297322504, 4.45907971083568, 1.89759724653608, 2.01234788772209, 2.09168647630904, 2.1169698760942, 2.07188901234193, 1.94986508460679, 1.76191744456867, 1.54042360994558, 1.33431244279957, 1.19505003456062, 1.15864831803422, 1.23252920949391, 1.39391012833550, 1.59952608185143, 1.80051068839159, 1.95613042611781, 2.04454263877208, 2.07063442719238, 2.06648430457382, 2.07718441480537, 0, 0, 0, 0, 2.50427129385027, 2.51599757566291, 2.49871661128628, 2.46684615136025, 2.43141344257659, 2.39980775719830, 2.37729289934151, 2.36840100778523, 2.37782274467254, 2.41093582902773, 2.47404331798631, 2.57422643791626, 2.71864887251054, 2.9132097939168, 3.16062113666318, 3.45824396799634, 3.79627896411591, 4.15704839362882, 4.51601528462398, 4.84480709970159, 5.11590911136409, 5.30805138857643, 5.41088291447177, 5.42751865397792, 5.37402953698831, 5.27579753473932, 5.16159731615537, 5.05696452285448, 4.9786273648358, 4.93145180898637, 4.90861148197413, 4.8947964189187, 4.87149484878442, 4.82292418801489, 4.7411427656167, 4.62922325384856, 4.50200793757161, 4.38472891306743, 4.3104448794834, 4.31754895489206, 4.44823537740554, 4.74756632186432, 5.26085547990002, 6.02552527065688, 7.05435734275163, 8.31212574174283, 9.69689217458477, 11.0448780986016, 12.1684832062527, 12.9008728510732, 13.0965274769561, 12.5938710758196, 11.2815905491785, 9.35431859210125, 7.37201844220321, 5.83387479738699, 4.97294605927871, 4.80407978508779, 5.25901936966817, 6.20213152039266, 7.39712114048219, 8.54227831408041, 9.38293115161734, 9.80698897256262, 9.8441012175374, 9.58739812309495, 9.12083798221783, 8.5031409344399, 7.78931966290077, 7.04601078133739, 6.34334502642348, 5.73605107402748, 5.25135079591565, 4.88968450624849, 4.63395222526803, 4.46031439738531, 1.77650917173984, 1.87940622365401, 1.95210248770907, 1.97868398474010, 1.9452620837687, 1.84637084165127, 1.69177444875207, 1.50970681080349, 1.34267041193203, 1.23524378036628, 1.21845484513846, 1.29841503575975, 1.45502888006276, 1.65062233126866, 1.84304345324694, 1.99752284218379, 2.09541473278899, 2.13995483008131, 2.15601676271013, 2.17866130479253, 0, 0, 0, 0, 2.51230805597391, 2.51108016294049, 2.48566250854132, 2.44837440418327, 2.40897833276683, 2.37442197046277, 2.34996485106885, 2.34024662480189, 2.34999889640925, 2.38449695752686, 2.44977846208635, 2.55251516446994, 2.69936890734359, 2.89572455721868, 3.14386634819420, 3.4409171826444, 3.77711515175976, 4.13514205947947, 4.49113115491975, 4.81761398595632, 5.08808044272563, 5.28220198302789, 5.39034991925628, 5.41603481382573, 5.37536570352238, 5.29345684077655, 5.19862084004685, 5.11586346778194, 5.06140605659799, 5.03964985944301, 5.04328784731348, 5.0564051824568, 5.05965000662126, 5.03609814005259, 4.976374031422, 4.88191947395619, 4.76592778054468, 4.6522150609483, 4.57294664463384, 4.56639448258106, 4.67549288587896, 4.94673647535492, 5.42717392763591, 6.15588864796632, 7.14723478051295, 8.3681433705429, 9.72120493476256, 11.0529201745332, 12.1940138300532, 12.9928987730693, 13.2830122579865, 12.8349631100172, 11.48647895911, 9.44698520435983, 7.32275055170774, 5.69512775242125, 4.80167390963627, 4.61296075849017, 5.02209237398498, 5.89283992961107, 7.0193265999462, 8.13934318241592, 9.02172831443447, 9.54553941684167, 9.7046600652096, 9.56098050078914, 9.15220994888641, 8.56131597664301, 7.84767438489529, 7.09193258388646, 6.3739938793188, 5.75346890696851, 5.25909473767731, 4.89109147719361, 4.6315036494888, 4.4556017803458, 1.67037933889657, 1.76335171712258, 1.83121894670606, 1.86074999079595, 1.84044031119523, 1.76587639243934, 1.64543967509192, 1.50300672075006, 1.37439262076982, 1.29708057588848, 1.29707878527945, 1.37938898312202, 1.52699589373580, 1.70825513084903, 1.88803890907202, 2.0376320344437, 2.14153615651960, 2.20137147136424, 2.23511398950068, 2.26829523651567, 0, 0, 0, 0, 2.5169054403656, 2.504661847782, 2.47283370903927, 2.43171755865972, 2.38981224674195, 2.35355585813413, 2.32809840592153, 2.31807106528536, 2.32813432302842, 2.36335948402351, 2.42943097788537, 2.53254077121636, 2.67880359336745, 2.87308331135043, 3.11728789859888, 3.40843385445842, 3.73702651369883, 4.08643905923348, 4.43389059565212, 4.75327260604256, 5.01951209907872, 5.21356177769464, 5.32670686181397, 5.36287238125814, 5.33806678391916, 5.27689013265322, 5.20690621227528, 5.15232618555997, 5.12865890796121, 5.13969603481176, 5.17753483094664, 5.22552141953563, 5.26326277410553, 5.27239389772408, 5.24169920645492, 5.17048801685093, 5.06973677566776, 4.96125947892874, 4.87578781582479, 4.8510352275608, 4.93034528706804, 5.16133280976874, 5.59234181901631, 6.26349468222401, 7.19015459990983, 8.3415023781885, 9.62602893758016, 10.9030887851826, 12.0244562609207, 12.856603110322, 13.2178525330765, 12.8174074428160, 11.4372897007839, 9.2975347896573, 7.0724873994259, 5.40441527285881, 4.52439853836277, 4.34941711383963, 4.73401929730131, 5.5441480960504, 6.60529831695207, 7.69427598658427, 8.60442861133145, 9.2100947240149, 9.4756677771742, 11.0070105074411, 9.0863562861471, 8.531079385428, 7.83197710039442, 7.07995549421753, 6.36193219115038, 5.74077617616276, 5.24619822643, 4.87842616133017, 4.6192686790549, 4.44380610638197, 1.57838429201714, 1.66304686434006, 1.72737466217328, 1.76066170032533, 1.75365120256807, 1.70289559915564, 1.61538229498841, 1.51070727893428, 1.41815532578149, 1.36832181038292, 1.38240821927248, 1.46447594315356, 1.60066726045558, 1.76530397761755, 1.93004421022512, 2.07186175603605, 2.17813668369441, 2.24907205732595, 2.29664088583873, 2.33814399763739, 0, 0, 0, 0, 2.51647733084520, 2.49576878804313, 2.45945900534221, 2.41608610775369, 2.37301684845839, 2.33618110069259, 2.31054767871754, 2.30064172969243, 2.31095412142299, 2.34626329032706, 2.41182583708335, 2.51329757626183, 2.65621452178116, 2.84492373204992, 3.08101253096381, 3.36151561361129, 3.67741302027234, 4.01306232081835, 4.34713174188077, 4.65527031222434, 4.91422177476704, 5.10652439135911, 5.22455982376708, 5.27270720664495, 5.26678253831666, 5.23068827755951, 5.19101842242827, 5.17097920478782, 5.18519195265323, 5.2366918022505, 5.31682747475204, 5.40800261141339, 5.48849348490946, 5.53810509157051, 5.54330048223133, 5.50070259940333, 5.4184736963565, 5.31583532546797, 5.22158545177214, 5.17256700636295, 5.21245897178684, 5.3900884301228, 5.75515205323046, 6.34863961568705, 7.1865670699185, 8.2401899649041, 9.42416182084014, 10.6105759207556, 11.6699498219255, 12.4837340515773, 12.8608484137322, 12.4696535813820, 11.0571372616460, 8.85943104739656, 6.60606167202327, 4.97223906717111, 4.16182448696471, 4.03658677007398, 4.41994529255244, 5.18496561967392, 6.18782536680549, 7.24105247248146, 8.16169149683667, 8.82391262182217, 9.17060437912843, 9.79474366912428, 8.92270736532926, 8.40963317250536, 7.73835843434309, 7.00623724458038, 6.30382848665447, 5.69529138908518, 5.21060478320733, 4.85016458847983, 4.5961447130041, 4.42414122563700, 1.49945678734891, 1.57711804384436, 1.63872653839866, 1.67585748650205, 1.68128907447904, 1.65243613979010, 1.59497792160065, 1.52454297795299, 1.46437982506593, 1.43873498963183, 1.4644103412092, 1.54466405066029, 1.66861862290093, 1.81611233409004, 1.96495790604231, 2.09715888788684, 2.20258176331726, 2.28030159375940, 2.33747517157711, 2.3848496722315, 0, 0, 0, 0, 2.51029596657563, 2.48385775494629, 2.44499383857533, 2.40083270476060, 2.35780176757706, 2.32136052123693, 2.29624680082857, 2.28679806365053, 2.29725142244545, 2.33201844985901, 2.39586964009487, 2.49388603828370, 2.63101113778332, 2.81109411142833, 3.03546413208480, 3.30129213799474, 3.60021558509235, 3.91782465058201, 4.23453804551324, 4.52808929764088, 4.77735180050369, 4.96670510263903, 5.08979104988904, 5.15149914153371, 5.16741071782829, 5.16061982677224, 5.15660978206894, 5.17744139734991, 5.23671655737288, 5.33657118992896, 5.4674131324302, 5.61042236348722, 5.74215586709215, 5.84010316003595, 5.88785151598753, 5.87873948436238, 5.81749459396392, 5.72014943851274, 5.61310253981775, 5.53214760483436, 5.52152777135892, 5.63187815819184, 5.91494836058505, 6.41303116586691, 7.14276172598473, 8.07707261126662, 9.13598034426014, 10.2018577139994, 11.1577113811886, 11.8926176312343, 12.2118249254316, 11.7739993739031, 10.3295921089896, 8.139582042131, 5.95619572057033, 4.44267829180161, 3.75534050456659, 3.70815152318242, 4.10727852212514, 4.83925528109783, 5.78917659094294, 6.80059597089343, 7.71242226625984, 8.40287439532384, 8.80217113155368, 8.8860650242433, 8.66768650706328, 8.2006960587575, 7.56900450703507, 6.87187353861381, 6.20002465857028, 5.61687894288707, 5.15192516505756, 4.80582795158565, 4.56166629048139, 4.39620651601538, 1.43237228746685, 1.50406714194092, 1.56339949615569, 1.60392888646832, 1.62020928745191, 1.61040816286244, 1.57905290487032, 1.53828082260547, 1.50602619452782, 1.50094527864752, 1.53596934680369, 1.61365765620337, 1.72575844791200, 1.85692899576568, 1.99028246989441, 2.11206116292724, 2.21419403668266, 2.29494547643291, 2.35787986817062, 0, 0, 0, 0, 0, 2.4983583645165, 2.46875753031928, 2.42909910731742, 2.38544837088782, 2.34348968987344, 2.30825879815419, 2.28422458712786, 2.27546851686572, 2.28590437705771, 2.3195190756803, 2.38055702438073, 2.47350608663771, 2.60272391919892, 2.77159798891926, 2.98127052179582, 3.22916070650597, 3.50772003197963, 3.80397117013846, 4.10031699510367, 4.37682420628588, 4.61473345151534, 4.80046437964433, 4.92905744897372, 5.00598212426463, 5.04659339539922, 5.07314368131692, 5.10995272546462, 5.17787407257413, 5.2894083193513, 5.44565616776305, 5.63584922602454, 5.83957699482984, 6.03118323053453, 6.18526422475194, 6.28192307165544, 6.31059952492682, 6.27196244591415, 6.17825010898878, 6.05300647185257, 5.93090549080871, 5.85728683592661, 5.88573889448707, 6.07149429633454, 6.45929274337035, 7.06676292486413, 7.8679818870619, 8.78675350972279, 9.711981706078, 10.5315463908670, 11.1340851389619, 11.3275108041878, 10.7943680316534, 9.32967282898245, 7.2240996664462, 5.21022145325165, 3.89116674798176, 3.36195431154378, 3.40402025868286, 3.82333245673302, 4.52573028499586, 5.42248851594828, 6.38316700839612, 7.26632336240472, 7.95751136448811, 8.38198559939036, 8.50488664458807, 8.33272288758558, 7.91415882224313, 7.3317748635362, 6.68257812343122, 6.0543074146674, 5.50780472562043, 5.07135677498206, 4.74594458488367, 4.51599249457905, 4.35998777388975, 1.37582314148465, 1.44235951176019, 1.49959095977461, 1.54274578942494, 1.56787965105252, 1.57380769075585, 1.56410354311551, 1.54797433053553, 1.53887400582627, 1.55072761017196, 1.59316965081921, 1.66812988874313, 1.76952804602821, 1.88602882597932, 2.0051223290515, 2.11650113132646, 2.21377140551706, 2.29469136189550, 2.36032433055767, 0, 0, 0, 0, 2.49859643589447, 2.48114729666650, 2.45056413467425, 2.41160097827543, 2.36954969740515, 2.32951523024998, 2.2961473924465, 2.27361335353661, 2.26568169136098, 2.27588764120952, 2.30775226786186, 2.36497301027632, 2.45144735654128, 2.5709754131927, 2.72653742885273, 2.91916939736611, 3.14664509556696, 3.40236033472388, 3.67492085418472, 3.9488778639063, 4.20679894767227, 4.43245087521633, 4.61443142793509, 4.74928898343998, 4.84315279725952, 4.91120848993955, 4.97491096218256, 5.05745267877949, 5.17849851856086, 5.34941698254553, 5.57014225216724, 5.82844510732893, 6.10186384317467, 6.36192825266677, 6.57968992847393, 6.73115046602325, 6.80127922754853, 6.7861026225879, 6.69345147517189, 6.54352654186786, 6.36985342326598, 6.21964714982411, 6.15111637802044, 6.22514012934982, 6.49078024918842, 6.96747933955074, 7.62989283514535, 8.40364352013914, 9.18037379998823, 9.8466744135374, 10.2855391435888, 10.3143949476916, 9.6664009030031, 8.20967378558434, 6.26018608041607, 4.49037510358825, 3.40668317787488, 3.04075612553028, 3.16159226030582, 3.5909276173844, 4.25718501274439, 5.09403058715656, 5.99232890791816, 6.82807859725506, 7.4962056864029, 7.92255880908457, 8.06796574818454, 7.9340145580762, 7.56509909590137, 7.03920511911996, 6.44785715134165, 5.87330536157647, 5.37233597506213, 4.97143968716634, 4.67191339561957, 4.45983767361976, 4.3158265813969, 1.32847894222033, 1.39048803496155, 1.44563259035269, 1.49050633393587, 1.52240587355204, 1.54070393209805, 1.54823429323292, 1.55184898664591, 1.56136199381108, 1.58681801106845, 1.63510224338895, 1.70754522931699, 1.7997493324903, 1.90357132606927, 2.0100042090987, 2.11149919284358, 2.20303886458939, 2.28214974862465, 2.34827536096727, 0, 0, 0, 0, 2.47772947694326, 2.45938712743726, 2.42953236309223, 2.39244736370943, 2.35286249881562, 2.31541985095754, 2.28440516832705, 2.26365329027946, 2.25657324257794, 2.26628024131742, 2.29580457169627, 2.34829453516536, 2.42708085338430, 2.53545549488122, 2.67606383001568, 2.84992558371957, 3.05526994847046, 3.28654179727896, 3.53403264657306, 3.78453864861364, 4.02321699607095, 4.23644206636322, 4.41506709485808, 4.55722688830908, 4.66979703721869, 4.76789446423048, 4.87229223448571, 5.00517528264662, 5.18511366227674, 5.42235877829222, 5.71554468771339, 6.0506371784326, 6.4025586053153, 6.7393207887896, 7.02774258394759, 7.23917817084513, 7.35370077484042, 7.36222891192322, 7.26757535542422, 7.08601100363595, 6.84981490642998, 6.60897852613645, 6.42840251502251, 6.37740753868595, 6.51191051733564, 6.85441508931346, 7.3796439948058, 8.01300317201422, 8.64589264030354, 9.1605840078726, 9.433882504481, 9.29926255494085, 8.55423382026633, 7.1477690928431, 5.40678197834047, 3.91428501754484, 3.06418631125657, 2.8354573679138, 3.00551652486643, 3.42326100555404, 4.03931676532813, 4.80502987441205, 5.6284689535018, 6.40103545275006, 7.0278073037093, 7.43854000572773, 7.59354967041763, 7.49153373762878, 7.17220769081254, 6.70702076771977, 6.1798050577098, 5.66561204515428, 5.21615488446086, 4.85569325464417, 4.58579452480237, 4.39435952263885, 4.26436522310411, 1.28903354024552, 1.3470165869893, 1.40001838442632, 1.44573110124208, 1.48246723269283, 1.51008979067056, 1.53090224729185, 1.54993512484811, 1.57412613455558, 1.61039603365406, 1.66334409265717, 1.73368655148299, 1.81823154321226, 1.91128706121808, 2.00660349393934, 2.09885118695899, 2.18419709251151, 2.26018243064254, 2.32529584589393, 0, 0, 0, 0, 2.45134425318502, 2.43385932185581, 2.40599123998748, 2.37167144121148, 2.33520574762311, 2.3008446279568, 2.27251603231286, 2.25369369122068, 2.24738995329613, 2.25627146321668, 2.28286796220143, 2.32979379976205, 2.39985562556477, 2.49590585299694, 2.62034327882711, 2.77426925425175, 2.95646356772239, 3.16250091893084, 3.38441696217958, 3.6112870033271, 3.83087353738269, 4.03216804285098, 4.2082991009094, 4.35903551598269, 4.49208820962468, 4.62264155726228, 4.77096296437984, 4.9584207711161, 5.20264735977708, 5.51282651811249, 5.88614381601368, 6.30634112303107, 6.7450432804349, 7.1659454347636, 7.53096745720493, 7.80646286291578, 7.96748325037485, 7.99961175217142, 7.90005944464966, 7.68040185187624, 7.37135072483379, 7.0265064044373, 6.71972388819803, 6.53197184899673, 6.52903048490644, 6.73805998522611, 7.13346618617274, 7.63853618090317, 8.14245770509429, 8.52321985625904, 8.65492275691076, 8.39214884305961, 7.59671039143536, 6.28664635544501, 4.77954066854441, 3.55520669943093, 2.90032685420737, 2.76097901635789, 2.94061183024626, 3.32057330461252, 3.87002543860800, 4.5528798731979, 5.29098056738028, 5.98927304035438, 6.5627404891082, 6.94645536258757, 7.10223285197093, 7.02706258934952, 6.75581501032446, 6.35237107099348, 5.89170157513582, 5.44076935257165, 5.04567725145219, 4.72819060528927, 4.49006071813468, 4.32102276863074, 4.20647640443917, 1.25624030360506, 1.31060775691633, 1.36141056070413, 1.40722473778967, 1.44720408162005, 1.48166286768850, 1.51256619909665, 1.54357829427647, 1.57939199426391, 1.62440750670214, 1.68127694174955, 1.75003464276783, 1.82825638122995, 1.91208077489821, 1.99744130408185, 2.08086455219464, 2.15962762594591, 2.23151802404519, 2.29455355700041, 0, 0, 0, 0, 2.42073372771172, 2.40529758182597, 2.38029222323388, 2.34936590433156, 2.31647754649424, 2.28552204454185, 2.26006465369887, 2.24319211234791, 2.23749209767720, 2.24516595771293, 2.26824669306665, 2.30884504486796, 2.36930256899639, 2.45211665790091, 2.55954065869373, 2.69286108369783, 2.85149733861128, 3.03221282029364, 3.22880637185471, 3.43261190252393, 3.63394888374743, 3.82437185143262, 3.99925283763219, 4.16001209004611, 4.31528210933897, 4.48047517213112, 4.67557390783204, 4.92137418223268, 5.23477339858561, 5.62395510151678, 6.08447633757187, 6.59734256535088, 7.13006868330411, 7.64115444326442, 8.08705489029211, 8.42912050499299, 8.63775560273426, 8.69337461058996, 8.58707021348233, 8.3246915401444, 7.93466230797674, 7.47471378265132, 7.0298044543094, 6.6958273182291, 6.55161694907472, 6.63080340841573, 6.90729218174897, 7.3006110364242, 7.69648913570317, 7.97036705789654, 7.99881326199578, 7.66012948834808, 6.87041571020083, 5.69367369168079, 4.41847378519406, 3.42237820331211, 2.90465984299650, 2.80072908219947, 2.95157304312457, 3.27069835831637, 3.74034924914542, 4.3322448455849, 4.97921371159353, 5.59800629854559, 6.11258249573004, 6.46343666439151, 6.61462478405522, 6.56203368477586, 6.33580039479886, 5.99203231790645, 5.59660702481531, 5.2082541080984, 4.8673720245234, 4.59313094505726, 4.3873443940084, 4.241457568315, 4.14318753565034, 1.22893752346215, 1.28003950319424, 1.32863344628759, 1.37402502528539, 1.41609264980611, 1.45559383478089, 1.49432297712145, 1.53493603152758, 1.58035135876304, 1.63286807787271, 1.69338266751314, 1.76112086956132, 1.83403646950529, 1.90961625493292, 1.98558754652073, 2.06014982511333, 2.131733641375, 2.19860680168126, 2.25866989477328, 0, 0, 0, 0, 2.38696514967807, 2.37434974724438, 2.3527852161458, 2.32566669228692, 2.29664331452775, 2.26926745734447, 2.24673103621401, 2.23171223106684, 2.22635480760866, 2.23238867388055, 2.25136550175786, 2.28493515352429, 2.33504574540716, 2.40393594169488, 2.49382343249508, 2.60628594035165, 2.74146441246969, 2.89735018604688, 3.06949097858768, 3.25141319218737, 3.43589192565623, 3.61693763521817, 3.79208924728295, 3.96440707120976, 4.14352259350775, 4.34524717222693, 4.58952479568825, 4.89685375544058, 5.28362265198176, 5.75708032898116, 6.31092564941276, 6.92280465550127, 7.55517039857036, 8.16039270915537, 8.68908874512601, 9.0981289340105, 9.3543589434394, 9.43375234944676, 9.3208832533337, 9.01450450360187, 8.53946500541417, 7.95758407672075, 7.36659702754773, 6.88022841194575, 6.59335524097765, 6.54793781702217, 6.71749519509717, 7.01657626809259, 7.32657188195435, 7.52218282825858, 7.48675694897398, 7.12206598466895, 6.38414806537986, 5.3585102382366, 4.2913022242345, 3.46941113999732, 3.02982512733957, 2.91562247074262, 3.00970677890596, 3.25365441502007, 3.63731721118023, 4.1364808410929, 4.69271842014371, 5.23289777597018, 5.68867528106453, 6.00536056710982, 6.1492544315125, 6.11543283433204, 5.92968687297854, 5.64081808195374, 5.30613408532858, 4.97659413101387, 4.68716579359682, 4.45446210394022, 4.28021107405351, 4.15732945633887, 4.07560828637782, 1.20606565288663, 1.25421421282435, 1.30066231864060, 1.34535251309758, 1.38882993234567, 1.43231836345282, 1.47758328423813, 1.52652944811658, 1.58060424229874, 1.64023439342099, 1.70459891933358, 1.77192509955108, 1.8402014178506, 1.90791570764917, 1.97437800581131, 2.03944576924146, 2.10285736712601, 2.16361281530643, 2.21976679180033, 0, 0, 0, 0, 2.35089953806267, 2.34158013771217, 2.32381174154831, 2.30074283653064, 2.27572561380628, 2.25197053668352, 2.23228443464743, 2.21892085022508, 2.21356871104365, 2.21748961046812, 2.23177878097753, 2.25767722249045, 2.29681983761623, 2.35128978590875, 2.42338271637842, 2.51507236637938, 2.62729468303392, 2.75929072256875, 2.90831563086255, 3.06998649255612, 3.23939155869329, 3.41284833973909, 3.58994922458977, 3.77535578958465, 3.97976033218111, 4.21954013050206, 4.51485020612870, 4.88617199026598, 5.34961100892964, 5.91152601072113, 6.56346617897762, 7.27898070336888, 8.01437975586553, 8.71495390934437, 9.32539546847843, 9.79929235162343, 10.1019024448376, 10.2061711103796, 10.0899111547744, 9.74303765319415, 9.18487488359958, 8.48052053919352, 7.74132397195514, 7.10089653754508, 6.67250267780056, 6.50814278068918, 6.58147626452975, 6.80152477879146, 7.04474217052064, 7.18600354384817, 7.11736935015841, 6.76125805258769, 6.09966551369841, 5.22085069484382, 4.32396685645033, 3.62237259265737, 3.21377150759756, 3.05982791041228, 3.08341420779945, 3.24833467153915, 3.54780709997840, 3.95925910220801, 4.43120625347217, 4.8989601736221, 5.30048362169184, 5.58501598367906, 5.72075471200924, 5.70211842826168, 5.55117512325328, 5.31037936020038, 5.02952733685511, 4.75270509050335, 4.50999262598091, 4.31559099792489, 4.17098131264011, 4.070233138594, 4.00486791374166, 1.18667765607189, 1.23216214884194, 1.27661051373452, 1.32056633404268, 1.36523790816362, 1.41236683981667, 1.46380718883518, 1.52087558405586, 1.58369648671110, 1.65087449337239, 1.71976439227842, 1.78734262843177, 1.85132701122618, 1.91097857589350, 1.96713623572600, 2.02144815241893, 2.07521429963710, 2.12844640652063, 2.17957951246521, 0, 0, 0, 0, 2.31324207856646, 2.30748785729263, 2.29370531132109, 2.27478919657539, 2.25379495815632, 2.23358680751080, 2.21657687292294, 2.20458418104395, 2.19883969949914, 2.20014781391917, 2.20917954954549, 2.22682516430250, 2.25449085839079, 2.29420933499682, 2.34846644565757, 2.41973135880834, 2.50979826870736, 2.61916409970780, 2.74672883058054, 2.89007241399503, 3.04642446235736, 3.21423027364242, 3.39499314771191, 3.59491104751698, 3.82577636917009, 4.10467933250215, 4.45221694772085, 4.88911504609991, 5.43139867398959, 6.08454690739054, 6.8376091837589, 7.65921130548991, 8.4983595747814, 9.29237007209738, 9.980286477217, 10.5143519806139, 10.8611227963603, 10.9926120596909, 10.8797848056906, 10.5016430286641, 9.86942035294467, 9.04985689949563, 8.16764927243616, 7.37705601593919, 6.8110000934521, 6.53287417714597, 6.51750501069021, 6.6688107450653, 6.85824294007336, 6.96084437223142, 6.87685238678253, 6.54477455362544, 5.96143099255248, 5.20718335766344, 4.43752018517431, 3.81064072823252, 3.40213644491087, 3.19561964416985, 3.14770871759873, 3.23846103773240, 3.46189523958871, 3.79587514915668, 4.19438933636943, 4.59955122424253, 4.9542911073487, 5.21085818354018, 5.33878909373255, 5.33187390739138, 5.20930159003085, 5.00850376081484, 4.77312172833259, 4.54149607019016, 4.33952063165366, 4.17920162293066, 4.06161281762631, 3.98161683761619, 3.93206613057439, 1.16994340640654, 1.21304013272826, 1.25571536077983, 1.29912620821700, 1.34518620837775, 1.39622976605656, 1.45429568531838, 1.52019536440507, 1.59274634247182, 1.66862973792080, 1.74314548434927, 1.811711737981, 1.87149903335033, 1.92241015845596, 1.96688650142564, 2.00861885406513, 2.05080416285709, 2.09477459438702, 2.13955077449285, 0, 0, 0, 0, 2.27459154764584, 2.27252541347698, 2.2627926206159, 2.24802002505989, 2.23096117859329, 2.21412933714842, 2.19953633101943, 2.18856328709272, 2.18198736214093, 2.18017363960115, 2.18340651110356, 2.19228666322309, 2.20807621331569, 2.23285924845593, 2.26941750540511, 2.32080536720233, 2.38972630858839, 2.47792502121998, 2.58586789007695, 2.7129527809588, 2.85836047380605, 3.02246490576831, 3.2085158258222, 3.4241578106264, 3.68229350588584, 4.00083864226083, 4.40102351501945, 4.90403705169121, 5.52598522397428, 6.27144185821721, 7.12657695257184, 8.05424874053263, 8.99502746225112, 9.8775227192836, 10.6358138279517, 11.2234006648209, 11.6117439932324, 11.7744851501521, 11.6757203242273, 11.2812578305583, 10.5913226927977, 9.67201520802684, 8.65993623766617, 7.72828900961081, 7.03014321645144, 6.64436846750306, 6.54345830329711, 6.62980824988952, 6.77074556319454, 6.84118151339995, 6.74745013141078, 6.43892775702012, 5.91943722367799, 5.25763088590064, 4.57347346232937, 3.98663528137074, 3.56152535364551, 3.30166001895060, 3.18933100471787, 3.21571242674804, 3.37453703849588, 3.64378395842255, 3.98171835729106, 4.33574981220292, 4.65269825076043, 4.88701365862487, 5.00845290003945, 5.00969548552707, 4.90842240523296, 4.73896653520659, 4.54019380417687, 4.34574966799579, 4.17805859407902, 4.04718276214137, 3.95364436507638, 3.89273848881779, 3.858238621134, 1.15514894949594, 1.19612582682779, 1.23732228394382, 1.28055809539945, 1.32852773954161, 1.38424932980366, 1.4500241190378, 1.52617845412254, 1.61013812545242, 1.69644543108620, 1.77802324030755, 1.8483847386571, 1.90389952474165, 1.94505210152343, 1.97605169190590, 2.00296720518222, 2.03128406534258, 2.06398501069747, 2.10087184818367, 0, 0, 0, 0, 2.23547517908129, 2.23711097794002, 2.23139286236143, 2.22066250721248, 2.20736518225758, 2.19366057296698, 2.18115953579781, 2.17080841064772, 2.16294144945914, 2.15750810562381, 2.15444727959763, 2.15413155233648, 2.15775987052441, 2.16756169666548, 2.18670893977409, 2.2189173091196, 2.26783630113496, 2.33643693155641, 2.42666213474849, 2.5395731596979, 2.67610278593241, 2.83834371878788, 3.03111212238366, 3.26338566918785, 3.54915266909298, 3.90721994028471, 4.35958490337302, 4.92805705479792, 5.62893287717366, 6.46583278631527, 7.42169860200956, 8.4528859194901, 9.49060498789824, 10.4543464289842, 11.2743219962568, 11.9083018112911, 12.3364970385716, 12.5366995420882, 12.4659534111347, 12.0746015911347, 11.3491105561784, 10.3524984363824, 9.2308463936093, 8.12890161367402, 7.25108809323415, 6.86230806980814, 6.6745294834076, 6.69281459774883, 6.78263801853232, 6.81895414276739, 6.7117918733413, 6.41648541847007, 5.93873711041304, 5.33572921501037, 4.70138952716579, 4.13016316849818, 3.68127226730480, 3.37345522824251, 3.20677370682689, 3.17962250709848, 3.28536704668414, 3.50230842383782, 3.79208352025031, 4.1063092731464, 4.39550439562052, 4.61587298756253, 4.73391844634879, 4.73856003960357, 4.64946365420038, 4.50198552076855, 4.331177846978, 4.16624879148418, 4.02662348856374, 3.92065362711973, 3.84819504680122, 3.80465076849706, 3.78433618785478, 1.14169155629438, 1.18080815893123, 1.22086669278678, 1.26442139705819, 1.31504246459453, 1.37652876568757, 1.45150518815679, 1.53978949179532, 1.63726609395243, 1.73605475974759, 1.8263295841792, 1.89933788387611, 1.95041761514602, 1.98062230399381, 1.99614662999498, 2.00581406620747, 2.01781214628319, 2.03710818862552, 0, 0, 0, 0, 2.18261118504317, 2.19636750074306, 2.20163353684381, 2.19981486049210, 2.19295019676112, 2.18317110148287, 2.17228430392275, 2.16150422597762, 2.1513518588606, 2.14173573875310, 2.13221825915690, 2.12243604623615, 2.11259299274029, 2.10389881586543, 2.09881051426766, 2.10096889423559, 2.11480990748984, 2.14494960346525, 2.19555106635462, 2.26993589189022, 2.37067062203381, 2.50023949031142, 2.66224085196883, 2.86286699940368, 3.11229271936026, 3.42552869144426, 3.82228208721348, 4.32538073648985, 4.95733844825089, 5.73469799153308, 6.66008382285581, 7.71298024585169, 8.84278798375668, 9.9708802197353, 11.0077301376417, 11.8811586252550, 12.5562249200948, 13.0252371694272, 13.2718501220904, 13.2453324038565, 12.8785602037281, 12.1423912900149, 11.0949293671124, 9.88883882995543, 8.5467218774983, 7.38690239704012, 7.20028586517441, 6.92043014430779, 6.86143897644225, 6.89059907129659, 6.88405298591553, 6.75375272735434, 6.45704940593019, 5.99827023740558, 5.42489406846863, 4.81312363509525, 4.24164599830188, 3.76717516319476, 3.41849141084796, 3.20687868985864, 3.13531160799788, 3.19726936232059, 3.37187355001604, 3.62363677543904, 3.90835991174716, 4.18271251920784, 4.40525039755585, 4.52804728137545, 4.52660271870405, 4.43310912163146, 4.29534519965863, 4.14419234461087, 4.00209980777877, 3.88513476360589, 3.80006647929475, 3.74600714192558, 3.71820914728559, 3.71121514895179, 1.12907174741704, 1.16657503920103, 1.20585455515754, 1.25027802286868, 1.30438875168590, 1.37285790802295, 1.45867934271824, 1.56111418076886, 1.67432970685413, 1.78772224047499, 1.88834590715381, 1.96484058717613, 2.01131146996977, 2.02939422600685, 2.02749713054915, 2.017566957081, 2.01088694359659, 2.01472049875274, 0, 0, 0, 0, 2.14106436937397, 2.15769709688887, 2.16645279746909, 2.16835275671587, 2.16511658361561, 2.15855887975471, 2.15013770888115, 2.14068077509741, 2.13029921693778, 2.11849889035789, 2.10448787534990, 2.08764460278591, 2.06805976147979, 2.04701820758887, 2.02727166803889, 2.01298976888780, 2.00936771450538, 2.02199095204544, 2.05616791944931, 2.11649542949621, 2.20688808432580, 2.33118528688089, 2.49428034835324, 2.70354544055190, 2.97019564338028, 3.31016017147592, 3.74399425930201, 4.29534153748999, 4.98742454365918, 5.83703986372478, 6.84581573225755, 7.9897683612796, 9.21136267386093, 10.4223586065191, 11.5250256568069, 12.4465668740278, 13.1619399067332, 13.6774765121676, 13.9827265434522, 14.0174649685661, 13.6956202838429, 12.972263545503, 11.9002302195401, 10.6362347126091, 9.34161440054387, 8.2488564383788, 7.66401998970449, 7.28287742927576, 7.13308039718399, 7.08700701496978, 7.0241709780143, 6.85774670783103, 6.54442480070732, 6.0851708912103, 5.5195858110821, 4.91214095201913, 4.33161677927973, 3.83278821984338, 3.44986296786115, 3.20049046074421, 3.09064101768301, 3.11467707821387, 3.25325229041775, 3.47387581742023, 3.73870854457766, 4.01901163307043, 4.27864379610441, 4.42603391976134, 4.39727270511581, 4.26429950241995, 4.11597565992685, 3.97577724902600, 3.85118814414364, 3.75269361262722, 3.68536079333201, 3.64751843520065, 3.63409589415079, 3.63963599884458, 1.11688373731934, 1.15300022096017, 1.19184407594847, 1.23766659626951, 1.29606689322007, 1.37266166545810, 1.47084267985751, 1.58926037216047, 1.72020225812903, 1.85007694348328, 1.96250284019761, 2.04322996587519, 2.08497157275856, 2.0899661002218, 2.06903191016032, 2.03754764277234, 2.01021774039954, 1.99685779115398, 0, 0, 0, 0, 2.10052554036014, 2.11984620894457, 2.13189612790536, 2.13728110665595, 2.13738903470545, 2.13371732847486, 2.12738347627678, 2.11884315624598, 2.10781888823772, 2.09344232101834, 2.07460353686438, 2.05046674091682, 2.02105950660020, 1.98779468185492, 1.95376872129204, 1.92371904727234, 1.90361759239201, 1.90000364560147, 1.91927230689419, 1.96718838753431, 2.04886113090591, 2.16929682817279, 2.33447938215127, 2.55276197050079, 2.83622444353239, 3.20157080027028, 3.67008977667765, 4.26614716749673, 5.013600320537, 5.92946873971242, 7.01446010012979, 8.2414125807649, 9.54649567372274, 10.8329766324908, 11.9965841671648, 12.9613224645721, 13.7274244183203, 14.3015555286402, 14.6811613493057, 14.7935647529786, 14.5329897428001, 13.8407001792527, 12.7659258918045, 11.4677283177979, 10.1621040379609, 9.0483827073821, 8.24549741800722, 7.75411718136203, 7.49807943177817, 7.35969717590859, 7.22477095174145, 7.00803658123804, 6.66409980910448, 6.18955101284335, 5.61755260720478, 5.00451339516068, 4.41217241250260, 3.89250573714906, 3.48126355315427, 3.19903741029168, 3.05398784809124, 3.04231150818417, 3.14714937391073, 3.33993058860954, 3.59453190784398, 3.91419386929792, 4.27455190741087, 4.48400173261203, 4.3886753952194, 4.15270259423548, 3.96081669218834, 3.82163577293503, 3.71069325406455, 3.62790352015387, 3.57614276736261, 3.55294955067899, 3.55285289535755, 3.57026733138316, 1.10480588951478, 1.13973162005644, 1.17843198443470, 1.2260872133063, 1.28940317363614, 1.37498417524279, 1.48663118671564, 1.62234087119777, 1.77240892207476, 1.92008131109204, 2.04533581806943, 2.13085143587836, 2.16784817585825, 2.1591805155286, 2.11820167367268, 2.06391821677194, 2.01466346755079, 1.98297010969913, 0, 0, 0, 0, 2.06135881741654, 2.08314695574494, 2.09825417536246, 2.10684992459736, 2.10998321025265, 2.10883765811510, 2.10420204500342, 2.09617942249999, 2.08413034146384, 2.06684578792876, 2.04293721230291, 2.01139763444192, 1.9722350149735, 1.92703007919652, 1.87925540372025, 1.83423323987825, 1.79870787627895, 1.78013891287312, 1.78593848109967, 1.82292987154011, 1.89726915130456, 2.01495126868194, 2.18285495801099, 2.41011538483469, 2.70948566853317, 3.09826405257952, 3.59829975373812, 4.23451290313271, 5.03124981506028, 6.00569320793327, 7.15779911939937, 8.45785116316068, 9.83703725607356, 11.1922022626508, 12.4150425494835, 13.429023634366, 14.2584506108118, 14.9094824933427, 15.382049538181, 15.5868770037456, 15.3986609694871, 14.7487072048178, 13.6857805326760, 12.3708418675633, 11.0208794507340, 9.83358911217194, 8.9267386569962, 8.3168854357185, 7.93984863736648, 7.69228884269417, 7.4694352068031, 7.18864091443858, 6.80205916532897, 6.30176804201687, 5.71571489134189, 5.09419634748297, 4.49255684214331, 3.95800974971464, 3.52438396348523, 3.21271543602515, 3.03306250979564, 2.98458543785135, 3.05416906913482, 3.21877790913008, 3.47143818277871, 3.87017025185080, 4.4110412396696, 4.73015199042386, 4.51870743560812, 4.10015754496742, 3.82506291242926, 3.67709851184234, 3.57758799314518, 3.50919055327683, 3.47186580712054, 3.46239311652179, 3.47491689112451, 3.50369239351861, 1.09259269147293, 1.12648339577914, 1.16524806343820, 1.21500253681346, 1.28356356219863, 1.37852245442349, 1.50408149356672, 1.65756594079698, 1.82725089434319, 1.99318083806216, 2.13164880624121, 2.22222201355131, 2.25460013174145, 2.23224829147454, 2.17107291958425, 2.09374520194346, 2.02227160734264, 1.97194195927519, 0, 0, 0, 0, 2.02385469450301, 2.04787621287714, 2.06577585061504, 2.07727974459240, 2.08309786312332, 2.08410746087856, 2.08078412841083, 2.07290215729709, 2.05949197482675, 2.03904228088324, 2.00992787943252, 1.97101190133932, 1.92231837591571, 1.86562144672995, 1.80478164335074, 1.74570116043695, 1.69587162858016, 1.66362349825449, 1.65730755902768, 1.68469548948433, 1.75284901504695, 1.86858419878932, 2.03948826027335, 2.2752808678303, 2.58918415954514, 2.99887867182532, 3.52655048868287, 4.1974420706442, 5.03618119754002, 6.06003094517858, 7.26844923641765, 8.63008352683753, 10.0730401286278, 11.490609498157, 12.7735953381492, 13.859570732391, 14.7582444727795, 15.5082139254609, 16.0933365680617, 16.403500205769, 16.2953983287967, 15.6944155728285, 14.6507378870934, 13.3276769786089, 11.9417718903158, 10.6869744463448, 9.68007697911116, 8.94571807706118, 8.43589070391587, 8.06494045040962, 7.74038200218037, 7.38356170095187, 6.94461424064093, 6.4118111914697, 5.8092350770206, 5.18202740304209, 4.57827642745096, 4.03754234763704, 3.5883017366014, 3.24998128814764, 3.03455908826655, 2.94550183256647, 2.97501293051948, 3.10727837905074, 3.35925100133783, 3.85699179802917, 4.62207194042947, 5.07742364844644, 4.72240672794806, 4.07745934275981, 3.69818066439022, 3.5372794716143, 3.44906817798646, 3.39508750413308, 3.37199116091975, 3.37589375486047, 3.4006519255279, 3.44041619577327, 1.08006941171753, 1.11303351990491, 1.15196055072232, 1.20385925895660, 1.27760313584406, 1.38171852944129, 1.52078082950781, 1.6914625903671, 1.88009741953985, 2.06366082483967, 2.21491584050317, 2.31044780039043, 2.33849642650003, 2.30310586541981, 2.22262209449609, 2.12322295416734, 2.03043406280274, 1.96219133030469, 0, 0, 0, 0, 1.98822513480713, 2.01424941184788, 2.03466233903327, 2.04875622803230, 2.05690969807065, 2.05970509849795, 2.05732383739838, 2.04923971406282, 2.03419017985666, 2.01040495418473, 1.97606651803535, 1.92994662703966, 1.87211138967514, 1.80453746605977, 1.73146436715107, 1.65934812215865, 1.59638497251012, 1.55171516746302, 1.53454527461601, 1.55348748741996, 1.61637556392836, 1.73068938353014, 1.90454718696872, 2.14805801548179, 2.47469950028785, 2.90229819262905, 3.45311387834772, 4.15242914554776, 5.02489680007215, 6.08775452521722, 7.34026435846657, 8.75054013360485, 10.2458641616154, 11.7192773124281, 13.0640222316845, 14.2248586067824, 15.2200764777282, 16.0902680999717, 16.8052834716266, 17.2329313614732, 17.2157969596821, 16.6738148072042, 15.652824301889, 14.3189478582656, 12.8957048652500, 11.5756912917554, 10.4705437171529, 9.60911487249641, 8.9593041871031, 8.45516520067462, 8.01872120775808, 7.5767285976454, 7.07833864314502, 6.50949506182001, 5.89209572424734, 5.26660327920551, 4.67201804160830, 4.13660293493871, 3.67985213986765, 3.31766935872385, 3.06417573767813, 2.92873110016263, 2.91071774297832, 3.00249836411837, 3.24126650706821, 3.8065945528039, 4.73998983425282, 5.29924711404113, 4.83471715932010, 4.01829740614448, 3.56322341568362, 3.39745293558043, 3.32289991287684, 3.28445457161840, 3.27611273462255, 3.29351067730285, 3.3303752413731, 3.38087173527404, 1.06713002335740, 1.09922749153532, 1.13829306041276, 1.19213039961673, 1.27055123700846, 1.38290919050791, 1.53410399776426, 1.72021668235851, 1.92583964625228, 2.12520203281832, 2.28791045343511, 2.38788469246961, 2.41205938506642, 2.36499607544323, 2.26722168779241, 2.14805012207708, 2.03615596930510, 1.95184537704106, 0, 0, 0, 0, 1.95459748064579, 1.98241176742155, 2.00505871223768, 2.0214232339632, 2.03156768928051, 2.03579441987043, 2.03401290541399, 2.02542949632247, 2.00853196825542, 1.98134013289368, 1.94189083024759, 1.88889856749748, 1.82248446930261, 1.74481620732901, 1.6604797095875, 1.57643821492466, 1.50153701323129, 1.44566114759945, 1.41879317146479, 1.43028514825263, 1.48861824734302, 1.60178789861258, 1.77827291839082, 2.02837869529967, 2.36561880680999, 2.80771321005069, 3.37670570693602, 4.09760315226874, 4.9947922372049, 6.08535313334075, 7.36864872697784, 8.81338684659615, 10.3483193389227, 11.8694830388866, 13.2755167451802, 14.5188886570903, 15.6240161744333, 16.6279181930830, 17.4839414521584, 18.0430092103202, 18.1420802389593, 17.6863773225027, 16.6925310275615, 15.3295980154114, 13.8512616554676, 12.4605649283117, 11.2589700457949, 10.2719300141831, 9.48031532413198, 8.83838744821754, 8.28418213055386, 7.75129254868271, 7.189454422257, 6.5843832704453, 5.95771108233163, 5.3453706760025, 4.77480329209743, 4.258811065195, 3.8040825604423, 3.42113261463858, 3.12661209595853, 2.93761053594246, 2.86279814919386, 2.90280003875365, 3.10247055966783, 3.65148959664572, 4.59463912741762, 5.16456011917996, 4.68797264296615, 3.85669885566685, 3.40469996560978, 3.25417010726751, 3.19768589086478, 3.17661919791165, 3.18403606951675, 3.21535790931586, 3.26437442727869, 3.32542452905029, 1.05373826206938, 1.08498750668122, 1.12405115101024, 1.17937436795693, 1.26152462447726, 1.38052009457523, 1.54151654111819, 1.74010774056429, 1.95946602784159, 2.17158529555505, 2.34350552182260, 2.44698094094939, 2.46788870926009, 2.41121638280840, 2.29927054024881, 2.16392142663445, 2.03640976401455, 1.93897380325536, 0, 0, 0, 0, 1.92300341189822, 1.95242368059682, 1.97704055614641, 1.99537258319747, 2.00718593941892, 2.01251970427202, 2.01103672537121, 2.00171498124666, 1.98284430746182, 1.95229170163348, 1.90799800852569, 1.84864756140624, 1.77440997945218, 1.68760354421847, 1.59309813272143, 1.49829673939532, 1.41263250243384, 1.34667873815119, 1.31113017384015, 1.31599419230321, 1.37028674365481, 1.48237787144252, 1.66094017154617, 1.91628269879467, 2.26173177423158, 2.71463974300915, 3.29653188143405, 4.03180738357422, 4.94427625174843, 6.05069938841322, 7.35077555435101, 8.81479446015053, 10.3749771964701, 11.933047648378, 13.3950862941261, 14.7208014855859, 15.9372886349607, 17.0746191726552, 18.0728327922758, 18.7819689109905, 19.0498215546726, 18.7413749319490, 17.7851491559766, 16.3529971717198, 14.7784924757846, 13.3011177454035, 12.0045899517902, 10.8975281102768, 9.96758708178804, 9.18823880386408, 8.51451087277347, 7.88851115379281, 7.26274118402454, 6.62517372760472, 5.99894341616321, 5.41508807658444, 4.88653615271766, 4.40625227493652, 3.96431661130635, 3.56410940312005, 3.22536472505094, 2.974961224473, 2.83320110592435, 2.80905957708161, 2.94110106049522, 3.38107326319098, 4.1585850375097, 4.63589378141589, 4.25474719101611, 3.58154148214524, 3.21965569624523, 3.10653197426286, 3.07300734355814, 3.07142764969769, 3.09580823819109, 3.14162071114107, 3.20291526187436, 3.2743752788748, 1.03993096743807, 1.07032506278931, 1.10915422040637, 1.16530236003887, 1.24985351040254, 1.37327921592104, 1.54090578269681, 1.74798197608328, 1.97668728999166, 2.19745668079912, 2.37554255859186, 2.4811943005693, 2.49956039740852, 2.43593723946017, 2.3138853166153, 2.16706883744929, 2.02852574841233, 1.92184611431169, 0, 0, 0, 0, 1.89335692834254, 1.92423545781155, 1.95059195453422, 1.97062812081397, 1.98383390417540, 1.99000074286832, 1.98857312252786, 1.97834856081856, 1.95748385704106, 1.92376298043183, 1.87508502212178, 1.81011977154413, 1.72904799651139, 1.63425395678879, 1.53078650933030, 1.42639734853349, 1.33105062474711, 1.25597923457848, 1.21256311962543, 1.211411446722, 1.26197998777612, 1.37287780156612, 1.55280284612479, 1.81187155803477, 2.16299676879371, 2.6229005437734, 3.21228713952599, 3.95461727220578, 4.87281016789061, 5.98311729788887, 7.2857057106199, 8.7531697265089, 10.3226590640286, 11.9033762536789, 13.4096698359776, 14.8068372803984, 16.1210409587582, 17.3744911103895, 18.5038525980048, 19.3847990086172, 19.9041130512343, 19.8464802537508, 18.9532559612267, 17.3896685486017, 15.6493351107782, 14.0569217638778, 12.6670247632186, 11.4495894290264, 10.3894065779757, 9.4770002289530, 8.6852423654237, 7.96709030326162, 7.28076695178615, 6.61908452410128, 6.00774301348632, 5.47163844031236, 5.00582514077527, 4.57919786790578, 4.16177142964374, 3.74830792210543, 3.36234228104793, 3.04275693243495, 2.82403385935268, 2.72463338607132, 2.77043376386471, 3.05127103059847, 3.57237838895841, 3.90393146915024, 3.67272405948706, 3.24593091793093, 3.01946034615338, 2.95629916357576, 2.94937582021758, 2.96921223283823, 3.01170241753335, 3.07255030832972, 3.14624127435675, 3.22796105396074, 1.02582227735342, 1.05535398010028, 1.09366666455625, 1.14984267233729, 1.23520043808051, 1.36041691508426, 1.53089004583244, 1.74169333963475, 1.97451871926256, 2.19904037891091, 2.3796420139239, 2.48584769501000, 2.50246639841505, 2.43496755809966, 2.30754814471535, 2.15476873636519, 2.01055731316446, 0, 0, 0, 0, 0, 1.86541400026264, 1.89764559278251, 1.92557064266269, 1.94712147246933, 1.96152283961485, 1.96832814962070, 1.96679499632654, 1.95560239003385, 1.93286068677209, 1.89636171443199, 1.84402491466019, 1.77450279970846, 1.68790028616861, 1.58651274585118, 1.47539821025578, 1.36253540125810, 1.25838046817508, 1.17485391772142, 1.12406298478324, 1.11721975882330, 1.16415227772011, 1.27357620378512, 1.45403703985966, 1.71525169820105, 2.06948817308672, 2.53257843880859, 3.12411413435815, 3.86630317586712, 4.7808723243819, 5.88335331639968, 7.17439714024284, 8.6293046100876, 10.1909711212168, 11.7768733985851, 13.3092807134415, 14.7565594420184, 16.1405702081968, 17.4768492530923, 18.7118810468321, 19.7776776555536, 20.6336883419751, 20.9567254733387, 20.1905312905105, 18.4368799194418, 16.4358974300351, 14.6880865090464, 13.2078603818306, 11.8937715287394, 10.7151077223166, 9.67680551964508, 8.7707404423834, 7.96405347528263, 7.22451050750371, 6.55214557735801, 5.97508532814266, 5.50966420860472, 5.12941704385461, 4.77545403140032, 4.39492809181753, 3.97286574558289, 3.53742652035223, 3.14175059845003, 2.83714487530986, 2.65388962117223, 2.60835772508618, 2.73527565521623, 3.0181145572862, 3.21518880476227, 3.12034977198468, 2.91958396012209, 2.81995730616512, 2.80662444296583, 2.82800835642973, 2.87069122287679, 2.93216716840114, 3.00844211571620, 3.09456735506986, 3.1863558190438, 1.01160692005338, 1.04030039310963, 1.07782166782766, 1.13318975351891, 1.21765094975431, 1.34181858340324, 1.51105468975107, 1.72044037845002, 1.95172517475660, 2.17468391714116, 2.35382349043897, 2.4587847402046, 2.47445847719687, 2.40634217928974, 2.2786037271608, 2.12573034201601, 1.98155804488291, 0, 0, 0, 0, 1.80571245523669, 1.83870729719839, 1.87223773454329, 1.90165705271267, 1.92465775213268, 1.94018807590714, 1.94755953591264, 1.94587816313595, 1.93378904125657, 1.90947818779140, 1.87087092489650, 1.81598263814625, 1.74341723463298, 1.65303825066996, 1.54678659087214, 1.42945912233753, 1.3090961678708, 1.19664226746488, 1.10483148670934, 1.04665642590097, 1.03402305912932, 1.07710666674731, 1.18459803298698, 1.36469201085675, 1.62647743890647, 1.98133527911457, 2.44395176251166, 3.03253294660888, 3.76774852598455, 4.66985828454912, 5.75345862370587, 7.01959745320356, 8.44638212353566, 9.9826787329912, 11.5541925777933, 13.089971779318, 14.5586816027459, 15.9751365178099, 17.3501886522649, 18.6507911295221, 19.8825028983498, 21.1011581492899, 21.9076135585424, 21.3991627093274, 19.4573344121182, 17.1016779487026, 15.1550901622987, 13.5923416173947, 12.1995553630542, 10.9170582732069, 9.76201466768818, 8.74701461383123, 7.85772770074768, 7.0759989785008, 6.41101138509752, 5.89178733369965, 5.52255782341881, 5.25170513338048, 4.98970874147798, 4.65891959304474, 4.23385970992346, 3.74809644009125, 3.27115150847581, 2.87371813795380, 2.60068769548145, 2.46676036581926, 2.47372129758928, 2.59176441179691, 2.69808088644139, 2.69127447932974, 2.64064813640115, 2.63139328360380, 2.66067468964316, 2.71053522530999, 2.77682909505654, 2.85775480882934, 2.94960469240545, 3.0480705784283, 3.14967137491526, 0.997560833168382, 1.02550650870025, 1.06203178454735, 1.11582761818357, 1.19775845870028, 1.31810176223002, 1.48207287757926, 1.68494000934542, 1.90905194218795, 2.12514213213168, 2.29882976606676, 2.40071305212298, 2.41618607260544, 2.35063044824133, 2.22752001009542, 2.08029734653683, 1.94172058476645, 0, 0, 0, 0, 1.77844961285460, 1.81245387349484, 1.84729560355688, 1.87828754911457, 1.9028723207533, 1.91966875185731, 1.92771836301546, 1.92601592787383, 1.91329259713944, 1.88798811774479, 1.84834189971688, 1.79256304977836, 1.71913294370706, 1.62738893422765, 1.51848345492207, 1.39652960430952, 1.2693994152888, 1.14857967646170, 1.04789722601920, 0.981568187364813, 0.962421739139982, 1.00101935893633, 1.10589406182318, 1.28465681062745, 1.54550250291555, 1.8986620078655, 2.35742179991282, 2.93835197471374, 3.66033604349328, 4.54193169491662, 5.59659737110635, 6.82562257656828, 8.20979359859746, 9.70373901076467, 11.2408219115957, 12.7554843511631, 14.2143872003541, 15.6234904712394, 16.990295021882, 18.3046725687164, 19.6358834173618, 21.1306534213728, 22.4193711475810, 22.3317915446646, 20.3087811164344, 17.5741399424383, 15.4169231902559, 13.7915701342804, 12.3424419361091, 10.9732112904132, 9.71257058497935, 8.5959430797656, 7.63238090969573, 6.8225536703692, 6.18608786672666, 5.75024942052392, 5.50305044944623, 5.36462829290447, 5.21315129344, 4.94511203633521, 4.52394758664736, 3.98914260286382, 3.42837028305348, 2.93396977353382, 2.56785806383231, 2.34997571673175, 2.26918428036199, 2.29002893094672, 2.34526432339046, 2.3814311638208, 2.41038952347654, 2.4569403207109, 2.52113916551417, 2.59873921282632, 2.68868722828663, 2.78904477181651, 2.89632728488181, 3.00688157151414, 3.11795975784644, 0.984037617612806, 1.01142577913925, 1.04688246331256, 1.09852127422955, 1.17653306272647, 1.29060180722814, 1.44568764038464, 1.63740576875896, 1.84919936749818, 2.05354893195050, 2.21809699771135, 2.31517460981324, 2.33106855504908, 2.27091151955522, 2.15686636572407, 2.02042677837346, 1.89235158995455, 0, 0, 0, 0, 1.75046567422901, 1.78544347752892, 1.82170404672001, 1.85457966148879, 1.88118542316903, 1.89969050580836, 1.90879934625308, 1.90744212002496, 1.89460870245747, 1.8692541895626, 1.83019492870750, 1.77596590734405, 1.70479202840582, 1.61502809557940, 1.50636097477801, 1.38157747456271, 1.24805851934897, 1.11797049930290, 1.00673427444189, 0.930388249777948, 0.903113906686615, 0.935989418225768, 1.03725336190731, 1.21364634387706, 1.4721459822684, 1.82153491212993, 2.27344110884513, 2.84257092452241, 3.54581550106296, 4.39984306342527, 5.41680175869754, 6.59804067283221, 7.92676641837584, 9.36292478732141, 10.8467825920663, 12.317049538971, 13.7370919754603, 15.1033319566973, 16.4199189104114, 17.6933213203939, 19.0237410563955, 20.6095439135118, 22.2188626310053, 22.6063942969818, 20.6879126499616, 17.7190356512176, 15.4310682503249, 13.7853663323208, 12.3063087472732, 10.8697740238746, 9.51748017916185, 8.30960819619003, 7.2829633190412, 6.46116886212965, 5.87487364340106, 5.54652397299636, 5.4442169056116, 5.45799949366485, 5.43344230965492, 5.24090197752489, 4.8320995086088, 4.25239832010788, 3.60876548925047, 3.01689490316301, 2.55734624787037, 2.25913678351461, 2.10939421956693, 2.07127145460335, 2.09703828474162, 2.14898225717742, 2.21566338306058, 2.29684069169086, 2.39036364004672, 2.49435124963134, 2.60729066599064, 2.72657623840116, 2.84885288638491, 2.97107923724482, 3.09121785707345, 0.971459825966679, 0.998608387801888, 1.03310739535480, 1.08227516275883, 1.15537359751239, 1.26126590969737, 1.40455577620029, 1.58133197252920, 1.77654366860293, 1.96508015610592, 2.11737513845789, 2.20814765403943, 2.22490652083426, 2.17242098419243, 2.07101385167732, 1.94944995496044, 1.83568867163124, 0, 0, 0, 0, 1.72013756557919, 1.75593099331962, 1.79385886230853, 1.82926913088081, 1.85877049157812, 1.87986245279258, 1.89078723474865, 1.89046453866286, 1.8783891512508, 1.85441023343660, 1.81829942659656, 1.76909963657125, 1.70456629821716, 1.62138418292203, 1.51676866200750, 1.39123951801067, 1.25123677804825, 1.10985515997004, 0.984909542681677, 0.895210507253769, 0.856990131620135, 0.882096804517931, 0.978332001473723, 1.15120605394432, 1.40607555683809, 1.74992462178705, 2.19244991741391, 2.74628547671905, 3.42616592921611, 4.24673419917158, 5.21869864711565, 6.34329575596431, 7.60585055526862, 8.97111210415583, 10.3855659085724, 11.7916028342807, 13.1492077446017, 14.4457194156585, 15.6810222003548, 16.8677818483120, 18.1010066263597, 19.5734998698562, 21.2063283183735, 21.8932605275869, 20.2567827517088, 17.3918329834376, 15.1670487856400, 13.5658197212973, 12.0854091878812, 10.6032646693369, 9.17723319793398, 7.89306432177594, 6.81798063906048, 6.00112326851375, 5.48402595584097, 5.28177355884121, 5.34043238069579, 5.52007898796947, 5.63495465499833, 5.52966047127258, 5.14333444614876, 4.52639616282374, 3.80530853151601, 3.11996347561404, 2.57024913967037, 2.19554051486398, 1.98546433293506, 1.90347862236651, 1.90702297218895, 1.96153189552628, 2.04660978120843, 2.15167149821511, 2.27045950715575, 2.39889469376168, 2.53352868353043, 2.67080017165063, 2.80736152759876, 2.94069055277642, 3.06939451619883, 0.960304672553514, 0.987677299121674, 1.02154740039932, 1.06826304251503, 1.13595183804885, 1.23247101413344, 1.36197799310928, 1.52111886785725, 1.69665042694228, 1.86636462022055, 2.00406363665093, 2.08734910026752, 2.10520025245428, 2.0619317077013, 1.97561219993721, 1.87166102921054, 1.77459698802378, 0, 0, 0, 0, 1.68527264287413, 1.72157695304012, 1.76162662482731, 1.80069387835730, 1.83456306635897, 1.85970677738001, 1.87369910893414, 1.87551085349473, 1.86548337196194, 1.84489140260310, 1.81499122388366, 1.77558308756392, 1.72364403229993, 1.65321331791367, 1.55761724599420, 1.43379341370010, 1.28663014722083, 1.13053587657899, 0.986890539118945, 0.878663861761312, 0.82517221100699, 0.839441049516308, 0.928684413003913, 1.09673007501431, 1.34680764216297, 1.68368345913019, 2.11482577465671, 2.65060143279348, 3.30346349199873, 4.08594462150438, 5.00723262382784, 6.06831290531273, 7.25634340697171, 8.54039808108924, 9.87267756652758, 11.1992210893923, 12.4775644811400, 13.6873659481387, 14.8233752228127, 15.8956791010380, 16.9716607077361, 18.1909248319357, 19.5496972662868, 20.2207474975313, 18.9591158259112, 16.572309222692, 14.6320193187002, 13.1402849439639, 11.6854023349000, 10.1813034950558, 8.70423833413912, 7.36432636824328, 6.25912159862487, 5.46350230607213, 5.0290873101669, 4.96239808572317, 5.18786565697386, 5.53818949960021, 5.79921302317837, 5.79082766217718, 5.43850076788906, 4.79598841851855, 4.00818186708345, 3.23874264422896, 2.60650405166979, 2.1609912627801, 1.89527366584608, 1.77378330784233, 1.75537409197107, 1.80557447497989, 1.90006431843874, 2.02283956497768, 2.16320722078109, 2.31358228336464, 2.46809783519404, 2.62205527429776, 2.77196559636319, 2.91569578505082, 3.05239980169906, 0.95108431862122, 0.979296291134575, 1.01309687174522, 1.05773805474051, 1.12006525818608, 1.20679335420813, 1.32155811949481, 1.46159975713152, 1.6156611535216, 1.7647417172567, 1.88637429982743, 1.96135587235192, 1.98029209092176, 1.94697638701850, 1.87693656735675, 1.79180994307366, 1.71220806897508, 0, 0, 0, 0, 1.64313780895901, 1.67950006823137, 1.72241378354199, 1.76687450374331, 1.80734742429013, 1.83874514594204, 1.85766267787651, 1.86318868704515, 1.85696672644755, 1.84241223274065, 1.82297720053463, 1.79955286195461, 1.7679242287051, 1.71818378613949, 1.63788293426548, 1.51863469676055, 1.36297933160555, 1.18717661192765, 1.01776123889828, 0.883743431564935, 0.808937460543945, 0.808126858991371, 0.887779735982757, 1.04948459952473, 1.29372161134567, 1.62253971874503, 2.04084954081546, 2.55656402380479, 3.17976387245663, 3.92083331079112, 4.78740695862813, 5.78012414830259, 6.88773443428403, 8.08323190163563, 9.32420037641722, 10.5606676796553, 11.7492516880401, 12.8639236355331, 13.8941630674096, 14.8431696557821, 15.7459705448660, 16.6729213615750, 17.6154514033032, 18.0500693150149, 17.1520604402034, 15.4217580767356, 13.8783653683135, 12.5310254397431, 11.1230212238664, 9.62188792597147, 8.12109991371683, 6.75148798548525, 5.63761875990788, 4.87763738861606, 4.53185936986394, 4.59877947886043, 4.98445002216841, 5.49937412237967, 5.90565188495454, 6.00040288398029, 5.69441361842045, 5.04222512395637, 4.20451983294783, 3.36656361762337, 2.66443738885096, 2.15674249219377, 1.83994160584543, 1.68008881535013, 1.63756973029919, 1.67839321125631, 1.77638327608945, 1.91185591043523, 2.06991836427751, 2.23927423955255, 2.41148672357498, 2.58056674055624, 2.74271608348126, 2.89603813126163, 3.04011558962406, 0.944321349231223, 0.97413216462925, 1.00864314347021, 1.05193401519828, 1.10947861334332, 1.18676344310755, 1.28684332786640, 1.40754381463176, 1.53964993106133, 1.66748411922763, 1.77245602370390, 1.83868758872101, 1.85847301947430, 1.83504086330994, 1.78121552444379, 1.71459162057188, 1.65157546381819, 0, 0, 0, 0, 1.59066540136799, 1.6265162393636, 1.67341322380626, 1.72574728140143, 1.77596143762750, 1.81666697296651, 1.84304217216708, 1.85436023334117, 1.85414512378412, 1.84886751201615, 1.84508388963736, 1.84520621633481, 1.84331604339017, 1.82393503158163, 1.7664861778473, 1.65508736015079, 1.48894656788663, 1.28686141641603, 1.08252593839058, 0.91336341077317, 0.809477951249996, 0.788166530985535, 0.854986314439343, 1.00862756370898, 1.24608383898218, 1.56610736518297, 1.97068886507764, 2.46510587815061, 3.05700531631018, 3.75462542712121, 4.56405793658297, 5.4855433235809, 6.50922894777293, 7.61169038632372, 8.75565883442602, 9.89561594094782, 10.9889300900854, 12.0060563680472, 12.9318772742126, 13.7624067607966, 14.5073926251239, 15.1830224441504, 15.7536867068034, 15.9347596638694, 15.3176922803559, 14.1616865657102, 12.9769006224760, 11.7707795854786, 10.4244574754927, 8.95139450492716, 7.45736349516749, 6.08803266404915, 4.9886916550443, 4.27580596401902, 4.01648451833252, 4.20330973257952, 4.72969740190946, 5.39136964768243, 5.93305041105437, 6.13233062231567, 5.88492361990525, 5.24301829243355, 4.37868390070267, 3.49447306420965, 2.74043206381528, 2.18251099439081, 1.82047048549797, 1.62307473198842, 1.55371786424714, 1.58038465460896, 1.67651266359201, 1.81974534784172, 1.99138408158093, 2.17649225264571, 2.36399380578766, 2.54646223877838, 2.71961641540144, 2.88163580103803, 3.03240626237118, 0.940520392826103, 0.972813640618701, 1.00900436813902, 1.05196900200722, 1.10577428392406, 1.17463950837842, 1.26099578674977, 1.36320596725615, 1.47404390910284, 1.58110007216261, 1.66961137203939, 1.72698791228199, 1.74718853113531, 1.73285216638162, 1.69404702753879, 1.64421882698868, 1.59541751656278, 0, 0, 0, 0, 1.52490024895367, 1.55962774542444, 1.61208515856043, 1.67559440691135, 1.73964973418194, 1.79359552085616, 1.83061657529745, 1.85022844834583, 1.85852800423004, 1.86614411384209, 1.88383365622318, 1.91605687159231, 1.95461277726707, 1.97657209774334, 1.95049907378614, 1.85049900161375, 1.67130934836900, 1.43506886513072, 1.18496673358818, 0.96960564997879, 0.827476146612508, 0.779286287713264, 0.829515407999217, 0.973218459144729, 1.20307745135217, 1.51390885409132, 1.90439867220483, 2.37701508957244, 2.93693583458744, 3.59028980438135, 4.34167150068762, 5.190904694509, 6.12937868503407, 7.13695184995947, 8.1812797710307, 9.22168143450828, 10.2177330283435, 11.1383812060573, 11.9650592230322, 12.6882945965448, 13.3030426732305, 13.7976665799820, 14.1261695848349, 14.1499407790244, 13.7122720225944, 12.9247537182098, 11.9857068901775, 10.8975519295202, 9.62293084625415, 8.20186265486921, 6.74578945161239, 5.40796298625173, 4.34605635211064, 3.68814073987062, 3.50577693763167, 3.78869060652350, 4.42490758274026, 5.20426466826687, 5.86204719724194, 6.16129629004797, 5.98349048239127, 5.37512166132239, 4.51347830628261, 3.61173227650245, 2.82888864940137, 2.23593771907048, 1.83610214877894, 1.60252940303681, 1.50375661143898, 1.51166476345846, 1.60074379941130, 1.74685331232132, 1.92791289939314, 2.12547072498189, 2.32576502208277, 2.51979714497249, 2.70263936429807, 2.87239409212799, 3.02912819319809, 0.940137068732055, 0.975889392626321, 1.01487076475651, 1.05876035020866, 1.11022734736570, 1.17222542804948, 1.24653527418860, 1.33197959112864, 1.42318074121202, 1.51080437555082, 1.58370599640577, 1.63241103046983, 1.65244818468030, 1.64585658752975, 1.61998352854213, 1.58414362717846, 1.54599696937540, 0, 0, 0, 0, 1.44371219856101, 1.47678383050616, 1.53688786050227, 1.61567928262773, 1.69856483431866, 1.7704449494099, 1.82179996350593, 1.85242568123711, 1.87176717880221, 1.89585460621644, 1.94088038579939, 2.01396453507321, 2.10403531722876, 2.17872407094179, 2.19283540370433, 2.10778475397795, 1.91262732692944, 1.63369508909225, 1.32615447957068, 1.05273034101848, 0.862535190925361, 0.780654754585628, 0.81033019850482, 0.94221818904408, 1.16383536907563, 1.46540847182790, 1.84193693851122, 2.29292302944723, 2.82106569533526, 3.43044967863505, 4.12424553199568, 4.90186856467112, 5.75581987459988, 6.66895748061567, 7.61359535989933, 8.55407723726236, 9.45325548844007, 10.2802197381240, 11.0142092677115, 11.6422054105729, 12.1525880542070, 12.5255697225560, 12.7216429219752, 12.6753583411735, 12.3348472040677, 11.7383740124419, 10.9446852039132, 9.95151747934865, 8.75591687676917, 7.4081264134003, 6.01910050400593, 4.74211475321368, 3.73812106318327, 3.1393066725737, 3.01900719997446, 3.36723467703441, 4.07410761766882, 4.93296374264173, 5.67880276340669, 6.06702697031743, 5.96739433944242, 5.41757558500513, 4.592450504489, 3.70698982387233, 2.9225673607012, 2.31242542198641, 1.88372574324765, 1.61619752025296, 1.48604497533583, 1.47113203530700, 1.54843495700823, 1.69287680709756, 1.87941417065286, 2.08622333930752, 2.29683744401105, 2.50058081155786, 2.69174250301902, 2.86821510562679, 3.03013683520428, 0.94354564375181, 0.983787386357153, 1.02675280552026, 1.07295699757722, 1.12371510950438, 1.18074845445232, 1.24517546475670, 1.31618367801439, 1.39004416549649, 1.46020800792066, 1.51882724818684, 1.55927229317398, 1.57849612815685, 1.57793900104003, 1.56232788310408, 1.53695717193831, 0, 0, 0, 0, 1.35271072387667, 1.34672504611843, 1.37785678824035, 1.44819982498715, 1.54703011471877, 1.65436466257631, 1.74932452688019, 1.81887070844607, 1.86308633196447, 1.89556572055070, 1.9390322954291, 2.01639759254752, 2.13810363653531, 2.28969692155518, 2.427504372846, 2.48982672335683, 2.42285040369026, 2.20879317432130, 1.87897606141514, 1.50288071153121, 1.16013063439487, 0.912573335938535, 0.790591133594649, 0.796045458530972, 0.914487103973513, 1.12747697504965, 1.42005384450062, 1.78319316238872, 2.21331005740126, 2.71064434367517, 3.27732646536599, 3.91519716760642, 4.62329005734311, 5.39510456168936, 6.21621757327717, 7.06327301242258, 7.9056052297844, 8.70999107284356, 9.4469034688277, 10.0945462295239, 10.6377911612855, 11.0628781323255, 11.3507040461026, 11.4727456489421, 11.3958976497151, 11.1004131347047, 10.5939821656954, 9.88658154300633, 8.97332299910585, 7.86228671352143, 6.60515880166245, 5.30766424451044, 4.11621685142323, 3.18646404006103, 2.64746228968406, 2.57146590101964, 2.95124046979819, 3.68553460661292, 4.58003896186162, 5.37921139998847, 5.83940340887789, 5.8229104324573, 5.35607422557408, 4.60293024962532, 3.76997450626262, 3.01328345100888, 2.40527823300771, 1.9577693963065, 1.65955376513281, 1.49713048904909, 1.45637228309705, 1.51806507254699, 1.65697080329399, 1.84549145126302, 2.05860725754754, 2.27717769870547, 2.48879719654197, 2.68687859175995, 2.86900330070003, 3.03529057594503, 0.95100699763883, 0.996777418088754, 1.04493853403867, 1.09489171735182, 1.14666407008325, 1.20080029597647, 1.25775824488018, 1.31698976653930, 1.37618399211406, 1.43123344170487, 1.47719934470206, 1.50996994964733, 1.52774809125958, 1.53138611245173, 1.52313790116606, 1.50445774682786, 0, 0, 0, 0, 1.25717033989132, 1.23631649997316, 1.26567685675133, 1.34927921487272, 1.47323274442430, 1.61079077120577, 1.73390142958542, 1.82514919323654, 1.88487390658289, 1.93156622510922, 1.99585310968938, 2.10856640545299, 2.28413007258993, 2.50438077278172, 2.71289653815108, 2.82930920342713, 2.78256120706929, 2.54710393882458, 2.15985337690282, 1.70642682024983, 1.28551561074783, 0.97335542336343, 0.806345766466208, 0.784860642541372, 0.888796920438674, 1.09315143126948, 1.37732370797529, 1.72802632558869, 2.13852609768343, 2.60665928553805, 3.13271442675496, 3.71731220065095, 4.35914436375287, 5.05260755479131, 5.78571780613993, 6.53906689754941, 7.28675649935905, 7.9997713338195, 8.65082460150697, 9.21808220509489, 9.68525907585324, 10.0381560450378, 10.2604089776522, 10.3321653603728, 10.2343516080589, 9.95575171538123, 9.49350282273242, 8.8439393319599, 8.00210252152164, 6.97951179241517, 5.82576825235773, 4.63806265082522, 3.55043386770376, 2.70615779064204, 2.22498257869636, 2.17526501123687, 2.55386996610945, 3.27295854630929, 4.15800711278785, 4.97239170287795, 5.48289914436722, 5.5499692083799, 5.18702264977242, 4.53896565214011, 3.79326171665902, 3.09279857136931, 2.50610459938342, 2.05040417954058, 1.72595044009793, 1.53189208252267, 1.46381202181983, 1.50738416128486, 1.63787149840531, 1.82552799994552, 2.04237436114477, 2.26670819978793, 2.48441575204783, 2.6879987672148, 2.87466592179464, 3.04445098675135, 0.962638766407284, 1.01493860768696, 1.0694611551687, 1.12455298837906, 1.17903163013805, 1.23233516045771, 1.28427466268385, 1.33447119597981, 1.38179651568390, 1.42422544856909, 1.45931987873487, 1.48513962227921, 1.50095527745115, 1.50705398216142, 1.50339897192472, 1.48784167048130, 0, 0, 0, 0, 1.15582885129295, 1.11845060027401, 1.14687235533435, 1.24701547383466, 1.40101680322886, 1.574053465753, 1.72959445735005, 1.84504100250775, 1.92092301293643, 1.98122831494475, 2.06546046634203, 2.21333398343283, 2.44384371760246, 2.73507944527938, 3.01716561082883, 3.1899368554317, 3.16401988849397, 2.90558224317328, 2.45740739780048, 1.92214812768634, 1.41864848471555, 1.03836076112613, 0.824060586871835, 0.774576625384017, 0.863875564125216, 1.06009187759571, 1.33678016028384, 1.67630866118825, 2.06882214094618, 2.50985322138440, 2.9979826054215, 3.53273226158439, 4.11250145569231, 4.73249455572551, 5.38289428164228, 6.04782807996747, 6.70580904613466, 7.3320351253735, 7.90199073879248, 8.3946253993592, 8.79320211278241, 9.08352898775428, 9.25152754880851, 9.2827756499107, 9.16487693270687, 8.88988780971758, 8.4528090167962, 7.84811864990748, 7.0730449039241, 6.14113140479597, 5.09867483929346, 4.03223862561108, 3.05970217261452, 2.30697453157639, 1.87990324937794, 1.84043047804881, 2.18969061962957, 2.8559619426594, 3.68989268434652, 4.48195280417731, 5.01857471122153, 5.16452133132806, 4.91978395647558, 4.40311269282096, 3.77353370012533, 3.15367626124512, 2.60543954053048, 2.1520488739111, 1.8070468380001, 1.58389552573572, 1.48899451597961, 1.51361062547930, 1.63402370037281, 1.81875932438784, 2.03720584533219, 2.26531873101537, 2.48739127399064, 2.69504803998947, 2.88510824513838, 3.05747959769399, 0.978389826513545, 1.03813366409216, 1.10007752811983, 1.16157462697492, 1.22031632545043, 1.27471197345863, 1.32395084031110, 1.36774223687365, 1.40592127165896, 1.43820233855814, 1.46425397202840, 1.48397280984886, 1.49752542336446, 1.50467194900804, 1.50329881247949, 1.48794868948076, 0, 0, 0, 0, 1.05709619079297, 1.00305150595891, 1.03220828539262, 1.15217992513101, 1.34038110092724, 1.55282393715889, 1.74345625430759, 1.88385599320229, 1.97465376049709, 2.04569999655414, 2.14595535941778, 2.32458327286331, 2.60559224037445, 2.96366597768010, 3.31578864106576, 3.54230933990802, 3.5357812336089, 3.25414662311207, 2.74587039503826, 2.1302653105808, 1.54590855345934, 1.09915102497817, 0.838997519291495, 0.76273694887476, 0.83850002303247, 1.02768326158842, 1.29812302143778, 1.62797108260356, 2.00438808882176, 2.42075480076785, 2.87409929395491, 3.36297456965993, 3.88554367635094, 4.43774166523155, 5.01166154797571, 5.59455071851085, 6.16890329556817, 6.71394387367587, 7.20819344433113, 7.63201776894453, 7.96882915560246, 8.20456069716965, 8.32655819498416, 8.32351701974324, 8.18669176875442, 7.91056465626032, 7.49141734951126, 6.92599733293301, 6.21523289241848, 5.37472215879375, 4.44700857293932, 3.5069433059011, 2.65422556307159, 1.99458964805460, 1.61716226714645, 1.57550060664533, 1.87426515142982, 2.45859358391074, 3.20733255644979, 3.94401805812457, 4.48238796568358, 4.69733798684732, 4.57603232131514, 4.20631227259223, 3.71189458582795, 3.18990842922118, 2.69353254025187, 2.25217334812197, 1.89351647770082, 1.64594462224690, 1.52696437239695, 1.53367160366248, 1.64371328895448, 1.82433426272097, 2.04273146507718, 2.27286457470668, 2.49765381101943, 2.70795405608894, 2.90022442043484, 3.07423178856951, 0.998021522634223, 1.06599193535286, 1.13625821691098, 1.20524093898920, 1.26958929611484, 1.32676579415690, 1.37537343261551, 1.41514899165220, 1.44670231100576, 1.47118287959050, 1.49001119269525, 1.50461881104138, 1.51591961397429, 1.52320460244987, 1.52253001599029, 0, 0, 0, 0, 0, 0.972530748310331, 0.903652747420896, 0.936146147682005, 1.07891424140846, 1.3040367114461, 1.55766448773798, 1.78362889201175, 1.94733442562736, 2.04942578295794, 2.12567843298615, 2.23457370640998, 2.43476691847413, 2.75550769134523, 3.16883327409701, 3.58008607076567, 3.85213060874572, 3.86123366657837, 3.55785080230452, 2.99540733027766, 2.30800631595915, 1.65177413137852, 1.14629653275103, 0.846065077276777, 0.746906208714226, 0.811640146078131, 0.995542024076472, 1.26124249505557, 1.58304567249008, 1.94539200193690, 2.33971780030030, 2.76167349935783, 3.20897824116357, 3.67961965035758, 4.17019935526695, 4.67448772742593, 5.18245530312672, 5.68012075060947, 6.15042970961559, 6.57499702276399, 6.93603977479963, 7.21763948728686, 7.40599676237211, 7.48926813769046, 7.45787634505296, 7.30529734448447, 7.02822804455271, 6.62554792895963, 6.09779696280771, 5.4502614749264, 4.70058043875242, 3.88733193833194, 3.07339783517054, 2.33983097283263, 1.77134631066104, 1.43921123844401, 1.38734951416898, 1.62270673564244, 2.10646236722098, 2.74633362867571, 3.40207518672835, 3.91981417491746, 4.18918162452068, 4.18612518308838, 3.96577393150584, 3.61317407285830, 3.19725774590358, 2.76125180718354, 2.34035575503723, 1.97599371421654, 1.71079927613797, 1.57274383841660, 1.56448005581144, 1.66520486009922, 1.84136756699013, 2.05853715091498, 2.28915460822616, 2.51509137194218, 2.72661114233193, 2.91988532118113, 3.09454875014395, 1.02109811365829, 1.09790342533427, 1.17719009048300, 1.25450575084211, 1.32554067992114, 1.38689493588371, 1.43663133811434, 1.47447683105750, 1.50166585111370, 1.52052859982120, 1.53393542575763, 1.54459492985968, 1.55404924406943, 1.56119995998691, 0, 0, 0, 0, 0, 0, 0.915847593483214, 0.836178187324251, 0.875480130812127, 1.04332674785114, 1.30606534444417, 1.59982787176808, 1.85833499845374, 2.04086468873261, 2.14802588501659, 2.22124836777596, 2.32801635511758, 2.53592940752266, 2.87944091474338, 3.32909590659129, 3.78127729870511, 4.08506749972566, 4.10379415256363, 3.78185336753706, 3.17637374494268, 2.43287500555873, 1.72107155818744, 1.17076414429705, 0.840588188079475, 0.72505655214225, 0.782638398039884, 0.963599267521557, 1.22626441339956, 1.54170030578401, 1.89201579739259, 2.26696334976238, 2.66100738159669, 3.07117041737781, 3.49532733412199, 3.93069437616132, 4.37251379082112, 4.81311646953738, 5.24159839168944, 5.64425894952087, 6.00571113154896, 6.31026924221787, 6.54309629105133, 6.69087657669489, 6.74229376488013, 6.6887408728011, 6.52514406252388, 6.25019178285313, 5.86570934984937, 5.37637703463917, 4.79176790447123, 4.13124097277968, 3.42930154841628, 2.73724520476704, 2.11821535980161, 1.63660232929412, 1.34607659103837, 1.28045981934670, 1.44764883334241, 1.82300341445903, 2.34171244382718, 2.89992350191968, 3.3781526383509, 3.68364261009139, 3.78353529376821, 3.70155861445238, 3.48457317695637, 3.17341483169433, 2.80105752002886, 2.40749067506522, 2.04615779488076, 1.77198432394136, 1.62185467835522, 1.60322642431847, 1.69687763630723, 1.86898490450481, 2.08416487647675, 2.31393362349772, 2.53952899506404, 2.75086226826116, 2.94392521474323, 3.11824870798495, 1.04698870124727, 1.13302591180298, 1.22179279190668, 1.30802470296969, 1.38653678222321, 1.45315414868666, 1.50545649829038, 1.54314808464400, 1.56797825694887, 1.58325629897395, 1.59305535739375, 1.60114856913319, 1.60961659810622, 0, 0, 0, 0, 0, 0, 0, 0, 0.81691646749394, 0.867125300745832, 1.06128177128617, 1.35988257768077, 1.68951397339454, 1.97448497955243, 2.16845745132994, 2.27202631803578, 2.33168781075535, 2.42284394184180, 2.62091209999590, 2.96522795905121, 3.42629756241166, 3.89521364154706, 4.2124161656575, 4.23296354613966, 3.89720643703607, 3.26426960091667, 2.48644635383678, 1.74157674767460, 1.16551106082893, 0.819179027180778, 0.695990753155584, 0.75139246948324, 0.932172577397676, 1.19358073071636, 1.50426052920568, 1.84448284332969, 2.20262009069874, 2.57215357606824, 2.94954499328021, 3.33261809474438, 3.71916167562529, 4.10571197600133, 4.48663879076049, 4.85369981623029, 5.19616183053425, 5.50143883339176, 5.75602686729301, 5.9464551535049, 6.0601320482048, 6.08622711336624, 6.01675634857708, 5.84766706022691, 5.5793693166554, 5.21648480606116, 4.76753249734669, 4.24580282314573, 3.67182507608913, 3.07601097925181, 2.49889834633584, 1.98726553989541, 1.5869197986809, 1.33521914606134, 1.25612577941662, 1.35734387230074, 1.62599999458328, 2.02177020221556, 2.4747138105083, 2.89875488006732, 3.21978978640451, 3.39908688355389, 3.43302494959382, 3.33424684601163, 3.11813968400205, 2.80797251378519, 2.44698704747002, 2.09779480929386, 1.82456958601457, 1.67081156251671, 1.64764684741713, 1.73734479132087, 1.90635779973579, 2.11910753107059, 2.34686295539809, 2.57070788873595, 2.78048174931621, 2.97212921515105, 3.14511870004991, 1.07488233402268, 1.17030687045977, 1.26875038845306, 1.36420104678364, 1.45068622401101, 1.52334886742425, 1.5793545116302, 1.61839580979482, 1.64266533324465, 1.65629750065933, 1.66436886814943, 1.67154218303007, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.859988926328235, 0.925387645432164, 1.14571378157589, 1.47581342112195, 1.83384838008954, 2.1361120403578, 2.33163001235434, 2.42110196592037, 2.45524539856815, 2.51582174010639, 2.68445471255491, 3.00477213172692, 3.44883593178079, 3.90673049854943, 4.21631183063711, 4.22989168356035, 3.88617155301026, 3.2442822533598, 2.45783834117892, 1.70638443567208, 1.12692378908942, 0.780509371398886, 0.659702823351634, 0.718496349117792, 0.9020081073232, 1.16385755570947, 1.47121450837058, 1.80307376959759, 2.14675786597573, 2.49497171626316, 2.84374669331355, 3.19091299455228, 3.53479653522567, 3.87307431254636, 4.2018756273931, 4.51524726296719, 4.80504711380782, 5.06123645568000, 5.2724558151044, 5.42676050042888, 5.51249437202479, 5.51940221771552, 5.44002264525108, 5.27109890601879, 5.0144804236469, 4.67718291527662, 4.27091814387309, 3.8118625830857, 3.3210717114422, 2.82492775611449, 2.35430162974645, 1.94159241695243, 1.61634970510073, 1.4015304432725, 1.31202473176993, 1.35451811405628, 1.52532890180802, 1.80463870786004, 2.15197834004424, 2.51133629491611, 2.8267262644497, 3.05668703867201, 3.17624594293406, 3.17035656642909, 3.03349663987821, 2.78042638937409, 2.45575336694569, 2.12764802490539, 1.86578134979490, 1.71749999905522, 1.69622209978043, 1.78553685769358, 1.95272359282419, 2.16280027422348, 2.38750286356452, 2.60826803791570, 2.81516136192555, 3.00422340300394, 3.17490815514169, 1.10381703385098, 1.20852101478370, 1.31655895366297, 1.42124541840417, 1.51591497159556, 1.59512964508367, 1.65572359371210, 1.69741251796481, 1.72279361400564, 1.73670819100034, 1.74506637690714, 0, 0, 0, 0, 0, 0, 1.58913223619438, 1.41598580635647, 0, 0, 0, 1.05925270670365, 1.30399724473805, 1.65876206107144, 2.03498685710559, 2.34294928940853, 2.5284247028218, 2.59243961947721, 2.58892076466361, 2.60411397348901, 2.7239117871326, 2.9954225156128, 3.39380705770754, 3.81254480068033, 4.09319738622028, 4.09107973534012, 3.74575018104702, 3.11429412472072, 2.34599761313982, 1.61545190923992, 1.05573713201989, 0.725783429075148, 0.617577325805072, 0.685296595311754, 0.874276045471402, 1.13801459150929, 1.44319834524063, 1.76812814386961, 2.09941166780816, 2.42917935805868, 2.75315378304392, 3.06922240301793, 3.37621589099452, 3.67281862841475, 3.95667819631171, 4.22380357634307, 4.46829496713612, 4.68238567601624, 4.85674315443798, 4.98100425324561, 5.04460155967666, 5.03798725563302, 4.9542488933575, 4.79081835849201, 4.55071524650956, 4.24284502913428, 3.88133186127395, 3.48433190076046, 3.07279612182018, 2.66921594808487, 2.29599474279330, 1.9732859808457, 1.71691514719209, 1.53762662129107, 1.44235879801677, 1.43627176974171, 1.52240752253846, 1.69706257147505, 1.94371483086022, 2.23161503426386, 2.52125760340776, 2.77150663783849, 2.94297735906016, 3.00081056505363, 2.92413923044157, 2.72079671722104, 2.43476422239831, 2.13588014014083, 1.89531933285732, 1.76136131097607, 1.74826635091782, 1.84073166298714, 2.00738559330348, 2.21460928602487, 2.43529942720185, 2.65173708957056, 2.85450211587011, 3.03986921048686, 3.20732533533317, 1.13272223312905, 1.24632293455985, 1.36358966899601, 1.47724946083230, 1.58005075000077, 1.66608872427905, 1.73196718078598, 1.77748593064693, 1.80563656441920, 1.82186428430149, 0, 0, 0, 0, 0, 0, 1.82818274792173, 1.72016401595309, 1.55700193551130, 1.36868976861155, 0, 0, 0, 1.53597772554033, 1.90652038010271, 2.28879729360916, 2.58949630434193, 2.75280829160933, 2.78039345977335, 2.72830941004451, 2.68528190015393, 2.73940138154712, 2.94029224481665, 3.26751165421069, 3.62194296080942, 3.85464596586699, 3.82925217272897, 3.48850329820454, 2.88556260501965, 2.16019138272887, 1.47590045361875, 0.95717773124494, 0.65877166581228, 0.572360077705241, 0.653835610052532, 0.85050967163483, 1.11717347627125, 1.42096130239861, 1.74003134534842, 2.06059400838958, 2.37439379202220, 2.67695382320466, 2.96626084636526, 3.24161781556638, 3.50259770530758, 3.74815701729101, 3.97598286572712, 4.18210424208891, 4.36075396658593, 4.50446462788384, 4.60443402299454, 4.65127275375803, 4.63626288703977, 4.5531137158434, 4.39989760941735, 4.18056056977183, 3.9053845573589, 3.59012602149661, 3.25406002823669, 2.91747866220481, 2.5991759676545, 2.31428090153480, 2.07277699111193, 1.87924141228758, 1.73440438482568, 1.63850419670026, 1.5949200855714, 1.61121794429414, 1.69551117374148, 1.84946241051312, 2.06225374677320, 2.30865166050146, 2.55055388604577, 2.74106308917444, 2.83352556384665, 2.79745406797097, 2.63546264693904, 2.38905259253247, 2.12603127237674, 1.91530178534082, 1.80333911765207, 1.80388271163292, 1.90252165188919, 2.06969163634698, 2.27381927211465, 2.48957817820306, 2.70052759208614, 2.89801328975798, 3.07866320134031, 3.24203739251773, 1.16047268182674, 1.28231270322883, 1.4081653948512, 1.53027180036267, 1.64091679830306, 1.73386207323319, 1.80561094102969, 1.8561470204207, 1.88887360650809, 0, 0, 0, 0, 0, 0, 2.01418402420495, 1.97624829064800, 1.88429332146759, 1.74071683852030, 1.57565607668087, 0, 0, 0, 1.83317610261374, 2.20917224394844, 2.58449486166266, 2.86486217669856, 2.99465770613541, 2.97652371644275, 2.86759278060010, 2.75711638453790, 2.73336636045576, 2.84744219422562, 3.08419094421777, 3.35507215725952, 3.52530950966963, 3.47115320328226, 3.14042553627108, 2.58087208424029, 1.91855345224886, 1.30097184626700, 0.840271230334566, 0.585374590846591, 0.527887622155729, 0.626679012147843, 0.832489312112698, 1.10257752089357, 1.40531312469854, 1.71918780033912, 2.03029545585425, 2.33016276382057, 2.61420843496804, 2.88055056744862, 3.12892949038351, 3.35969784384671, 3.57293671785234, 3.76776421208188, 3.94186102690868, 4.09120402558669, 4.21001221043862, 4.29097605444281, 4.32591917657511, 4.30704428959211, 4.22875710043187, 4.08974523390393, 3.89466620166816, 3.65470572080841, 3.38654492531177, 3.10982300742053, 2.84371874449599, 2.60355302706262, 2.39829274084098, 2.22964599656710, 2.09320019655252, 1.98170753505404, 1.88993629468463, 1.81939886972948, 1.78033608030089, 1.78883517476457, 1.85940534877062, 1.99605318128625, 2.18547832946248, 2.39478422166905, 2.57564192534864, 2.6767961741364, 2.66332683367458, 2.53425155373529, 2.32707536404968, 2.10445345286167, 1.92983436474716, 1.84558890843558, 1.86378911776330, 1.97072235947375, 2.13899429322787, 2.33962223127864, 2.54954626345937, 2.75394380164527, 2.9451195256032, 3.12014276090564, 3.27867437111918, 1.18595047135674, 1.31511065825414, 1.44864681779150, 1.57843303827926, 1.69643347083971, 1.79624008561057, 1.87443825326451, 1.93136601543285, 0, 0, 0, 0, 0, 0, 2.15144608160418, 2.16785899957252, 2.14820253853788, 2.07882004428627, 1.96271667087556, 1.82926638892322, 1.73348908286837, 0, 0, 0, 2.54982295880739, 2.90541488482461, 3.15352329687586, 3.24043237613358, 3.17009607183148, 2.99974886426401, 2.81740345559856, 2.70969959801621, 2.72816397847552, 2.86332985971484, 3.03927896800437, 3.13851951428038, 3.05282821077945, 2.73641011421366, 2.23061882110381, 1.64504013412787, 1.10788737008959, 0.716468790280311, 0.512806000269353, 0.488623369603515, 0.60665191459664, 0.82208438674549, 1.09549046658595, 1.39705821044548, 1.70598346089853, 2.00847460191902, 2.29598371206182, 2.56390483545322, 2.8105093472821, 3.03593638340988, 3.2412156599455, 3.42738749676315, 3.59478404302079, 3.74249423233591, 3.8680071662102, 3.96705070318566, 4.03371567002569, 4.06103561038481, 4.04219082045169, 3.97234165321069, 3.85077014853933, 3.68265790155845, 3.47968141934326, 3.25883838660123, 3.03950057885107, 2.83937676540556, 2.67054750625636, 2.53680934213301, 2.43325180583861, 2.34844118940113, 2.26893998786809, 2.18516611111501, 2.09678572660448, 2.01524643982469, 1.96142924738289, 1.95818318054281, 2.01993211659863, 2.14312681804187, 2.30160260188047, 2.4503770832384, 2.53935243399608, 2.53338289364685, 2.42929154999747, 2.25953243925632, 2.07931202733739, 1.94427691908829, 1.89100205875764, 1.92904601158496, 2.04523934393604, 2.21460125997096, 2.41111114475552, 2.61430439073402, 2.8111982755683, 2.99517584889536, 3.1637975036378, 3.31683700654693, 1.20811063964749, 1.34343611054927, 1.48352257051535, 1.62001447179709, 1.74472404169159, 1.85128780450055, 0, 0, 0, 0, 0, 0, 0, 2.25610851203507, 2.30456781263028, 2.33881140971639, 2.34122637984402, 2.29910136927369, 2.21573094371425, 2.11890438431439, 2.05945474842546, 2.09494824937105, 0, 0, 0, 3.23085001614218, 3.43693271846854, 3.47448795653554, 3.34902735700967, 3.11702236962071, 2.86375195333720, 2.67270206297544, 2.59482500609754, 2.62622289095952, 2.70442325756072, 2.73064634307501, 2.61357143475623, 2.31443496760008, 1.86779887676710, 1.36554349466498, 0.915126777142455, 0.597915673658236, 0.448577993970889, 0.459094835268186, 0.596530133416168, 0.821075779667278, 1.09708573932872, 1.39692330789751, 1.70074174564101, 1.99504000482028, 2.27131258069640, 2.52499367503291, 2.75452039344010, 2.9603882619978, 3.14420568951296, 3.30782125493992, 3.45258834864133, 3.57878975055936, 3.68522007563787, 3.76894981696584, 3.82537057286111, 3.84870060595031, 3.83312820316907, 3.77460717037644, 3.67299051428576, 3.53382069757677, 3.36891350158564, 3.19507503161619, 3.03089436455697, 2.89233678433220, 2.78846749367076, 2.71877045640911, 2.67312552894624, 2.6347446672627, 2.58552063267218, 2.51249767926561, 2.41358853397694, 2.30035601024567, 2.19602761519184, 2.12827746375067, 2.11843893406658, 2.17081927974661, 2.26683709461991, 2.36814661873962, 2.42988927325365, 2.41973767887059, 2.3334382677585, 2.1978440966363, 2.05933648360871, 1.96434499586503, 1.94263432220751, 2.00073852574286, 2.12592085823554, 2.29572799126509, 2.48728263585603, 2.68286896858281, 2.87143736413667, 3.04748950901527, 3.20908548219699, 3.35610768063108, 1.22604506057333, 1.36618376375796, 1.51149646899304, 1.65355354641900, 1.78421819221163, 0, 0, 0, 0, 0, 0, 0, 2.34789685662057, 2.40845413416048, 2.47159455942912, 2.52496139211373, 2.55155656496459, 2.53909369520177, 2.49059728757422, 2.43155284246791, 2.40768225020221, 2.46948798159920, 0, 0, 0, 3.53862790656612, 3.69571964862813, 3.68083836417071, 3.50116054516308, 3.21163213829372, 2.89359183302795, 2.62616721611798, 2.45881418270592, 2.39262949090085, 2.3782798814911, 2.33554799706293, 2.18996274470457, 1.90983237280123, 1.52306842303713, 1.10406243944429, 0.739750171634011, 0.495749881858436, 0.399506344069225, 0.443344558959055, 0.598740635461294, 0.830984311298498, 1.10833924712990, 1.40548630030094, 1.70367792390586, 1.98982753210891, 2.25556440451787, 2.49641424251601, 2.71098419981336, 2.90008058148339, 3.06579545108281, 3.21064608412376, 3.3368336581044, 3.44564476698143, 3.53699626747860, 3.60915052859866, 3.65870287991286, 3.68102082351696, 3.67131340106537, 3.62635058298124, 3.54652923252766, 3.43761047028734, 3.31125367573521, 3.18365479363746, 3.07220547462993, 2.99092102908619, 2.94605959441686, 2.93352069821074, 2.93915247915308, 2.94220024476678, 2.92115701161484, 2.86053175900124, 2.75663524714938, 2.62040230265254, 2.47565919754716, 2.35235539647253, 2.27611572902241, 2.25751268133508, 2.28576694832718, 2.33102843506127, 2.35613328098747, 2.33347911679211, 2.25856455726405, 2.15256798552461, 2.05255193639809, 1.9952128903169, 2.00314599753532, 2.07967446787523, 2.21242684136470, 2.38146506925647, 2.56705178813062, 2.75420362719664, 2.93377357033393, 3.10134663493129, 3.2554526412217, 3.39606347133714, 1.23903912121117, 1.38249131269775, 1.53156446701519, 1.67792781627440, 0, 0, 0, 0, 0, 0, 2.37558064060418, 2.44436689354214, 2.50873926007134, 2.57734105000107, 2.65242379262148, 2.72396788656705, 2.77483241507891, 2.79202633007052, 2.77741333966449, 2.75353108568906, 2.7605234457676, 2.8416420119923, 3.0208696560738, 0, 0, 0, 3.91207927758807, 3.84506437763035, 3.61566723194194, 3.27662405486756, 2.90438724617906, 2.57281359890838, 2.3290360976616, 2.17822678137015, 2.08299063422304, 1.98026459945442, 1.81123195549146, 1.55082885982748, 1.2208956190649, 0.879716887738974, 0.595306331979489, 0.418769654631335, 0.370927418846663, 0.444493544282463, 0.615119260895567, 0.852928467641754, 1.12993777245864, 1.42311336620650, 1.71485702721190, 1.99257692882189, 2.24810859326581, 2.47710924276053, 2.67835397636956, 2.85291227474585, 3.00326826667825, 3.1324781816075, 3.24343354064689, 3.33825490148798, 3.41781844730609, 3.48144313316361, 3.52683737457090, 3.55047851625861, 3.54859769363507, 3.51879161662979, 3.46197123667605, 3.38399295111442, 3.29611356696794, 3.21357847103744, 3.15225316105981, 3.12405164835344, 3.13261532252379, 3.17087221251100, 3.22161501778013, 3.26126807530427, 3.26597905445538, 3.21844207421044, 3.11357039717430, 2.96123026587739, 2.78470152775824, 2.61448594389697, 2.47864116439284, 2.39267284379267, 2.35328674026335, 2.33977229945632, 2.32373005447298, 2.28321268344814, 2.21404157464721, 2.13204274449874, 2.06521527069588, 2.0407754002183, 2.07435270493022, 2.16615325656306, 2.30414046780150, 2.47076976958298, 2.64928019857049, 2.82725783486654, 2.99732172966528, 3.15604101124509, 3.30235350404580, 3.43628994501087, 1.24661611499534, 1.39179213671918, 1.54307424172695, 0, 0, 0, 0, 0, 0, 2.43060842126561, 2.54237249483591, 2.63024833964687, 2.69890941290796, 2.76714144462936, 2.84740751009105, 2.9333628480457, 3.00643340627799, 3.05105829361992, 3.06663280466995, 3.07211920444284, 3.10200531795, 3.19271331889607, 3.362816040078, 3.59646762917577, 0, 0, 0, 3.95602813629378, 3.68433378704683, 3.30672322120981, 2.89402542326643, 2.51415333603156, 2.21119166855654, 1.99326343734887, 1.83312934868986, 1.68264151616750, 1.49668531171301, 1.25606097455875, 0.977410936433074, 0.705073415315327, 0.490652503607115, 0.3726733705991, 0.366242537884173, 0.464478173035092, 0.646756393582717, 0.887527138594408, 1.16221195493624, 1.44991052148943, 1.73415985423387, 2.00291134841989, 2.24826211170257, 2.46603201507261, 2.65515739643772, 2.81692277379015, 2.95411690466575, 3.0702144739631, 3.16865379173592, 3.25223637194869, 3.32265162033971, 3.38015282538813, 3.42347679573661, 3.45016881417882, 3.45747430365819, 3.4438171971261, 3.41059109544556, 3.36364217678308, 3.31362398699383, 3.27456159269035, 3.2605425831304, 3.28127816805857, 3.33797006692024, 3.42109133616192, 3.51118546648375, 3.58279748225431, 3.61060329287770, 3.57610505423249, 3.47306754052286, 3.31009256323332, 3.10924546864765, 2.90050156805307, 2.71307869610434, 2.56628393903703, 2.46358562581604, 2.39313401835895, 2.33530717421169, 2.27399040375227, 2.20568721950417, 2.14148044362069, 2.10112150936363, 2.10318092279693, 2.15695554667143, 2.25984236239613, 2.40013789612733, 2.56248563412111, 2.73281547739397, 2.90100891705192, 3.06123527352589, 3.21090193438083, 3.34927089972272, 3.47639424058882, 1.24856530173493, 1.39384819316798, 0, 0, 0, 0, 0, 0, 2.41819411523256, 2.59777130642435, 2.7567185519997, 2.86513147984249, 2.92852500415571, 2.98265142049340, 3.05686560052103, 3.1504889786602, 3.2417121396971, 3.30979107320048, 3.34990577481436, 3.37677519958257, 3.41942873702670, 3.5083315627451, 3.65797351069995, 3.85271982266417, 0, 0, 0, 4.007093672664, 3.7025015391757, 3.29901939373993, 2.86127284730575, 2.45074073164693, 2.10783817275225, 1.84245188969289, 1.63545452101794, 1.45098207452119, 1.25530784147137, 1.03417868531941, 0.800053756191255, 0.585859332504032, 0.42974064283669, 0.359908028759545, 0.386812262300497, 0.503974411126009, 0.693939455739319, 0.934853627055834, 1.20509874496898, 1.48569362645017, 1.76126063304262, 2.02032306415148, 2.25528359349319, 2.46214924893792, 2.64000798219648, 2.79031214266137, 2.91607281156416, 3.02107191851490, 3.10916366862723, 3.18369185760342, 3.24702644914452, 3.30024234475556, 3.34302307732855, 3.37393548274495, 3.39122131776857, 3.39412192162006, 3.38448067878475, 3.36804591506348, 3.35471139344925, 3.35707968699715, 3.38728238679617, 3.45277645656877, 3.55249620645451, 3.67489914944607, 3.79894447591149, 3.89806790394557, 3.94619400389797, 3.9241712628075, 3.82489394376102, 3.6556847256857, 3.43707534556907, 3.19790021684427, 2.96768524257795, 2.76856019292168, 2.60977070252456, 2.4874308694533, 2.38999328011322, 2.30683392472665, 2.23533581345614, 2.18261792169177, 2.16135563743933, 2.18268329549423, 2.25047675977652, 2.3597724406411, 2.49921817826900, 2.65538723697543, 2.81653760622159, 2.97450283377708, 3.12473866714307, 3.26531820069744, 3.39573267870688, 3.51601611227033, 1.2449510949895, 0, 0, 0, 0, 0, 0, 2.31877747181360, 2.55084585109469, 2.80833448869359, 3.02929729686779, 3.15896040672430, 3.20428289247598, 3.22641672531111, 3.27986866984907, 3.37214302074471, 3.47605982429608, 3.56256010020446, 3.62054739521273, 3.65977952285755, 3.7041803454781, 3.77939621530557, 3.89740574913533, 4.04435529505723, 4.17905109559009, 0, 0, 0, 3.66949889339742, 3.25334363040277, 2.80615975372559, 2.38264213361332, 2.01902487876089, 1.72583035069756, 1.49001085173346, 1.28533599837908, 1.08712593126027, 0.885141371675876, 0.688678137370672, 0.521807461035736, 0.412193878879833, 0.380018890060422, 0.432142670980614, 0.562482154738458, 0.756181810512439, 0.994438459794531, 1.25813413037513, 1.52997879692287, 1.79561860253198, 2.04416773214968, 2.26837091071543, 2.46444202821530, 2.63160950406052, 2.77144855090943, 2.88711640423451, 2.98260065428365, 3.06205251915758, 3.12923194458304, 3.18706739104822, 3.23734864047664, 3.28062353217357, 3.31642609256387, 3.34396355340408, 3.36327289038583, 3.37661251973715, 3.38956346404198, 3.41114763423052, 3.45241031205621, 3.52342286889907, 3.62938988315687, 3.76715524019138, 3.92354079582932, 4.07646899151008, 4.19888987740432, 4.26456325590382, 4.25414232936117, 4.15993644465779, 3.98809303836819, 3.75752527912844, 3.49562352749531, 3.2316566977389, 2.98972379035988, 2.78373564014786, 2.61652823940039, 2.48351228821768, 2.37890062550632, 2.30103503282786, 2.25391263461343, 2.2444692072627, 2.27779224768849, 2.35338367218992, 2.46443725431281, 2.59998236025051, 2.74824163246063, 2.89940567576053, 3.04688890518693, 3.18715256019502, 3.31875582467781, 3.44132381917822, 3.55483591674010, 0, 0, 0, 0, 0, 0, 2.15489970590758, 2.39081310549088, 2.70536239050772, 3.06090377551620, 3.35795956294746, 3.50897440518838, 3.52297505081532, 3.49485470341704, 3.51245175323197, 3.59397755823822, 3.70480841404044, 3.80449022030639, 3.873613293625, 3.9162838016825, 3.95173549867233, 4.00202500133583, 4.07825614238096, 4.16989339296694, 4.24318720787045, 4.25135957634614, 0, 0, 0, 3.17225638684078, 2.73017172866809, 2.30993363850969, 1.94320406748616, 1.64016164728746, 1.39201138625677, 1.17975080823682, 0.985614424206795, 0.8025231631086, 0.637532847885169, 0.508182716659592, 0.434364441369483, 0.430310037901873, 0.500258716036647, 0.63851807622943, 0.832315555040257, 1.06531253191588, 1.32047370033431, 1.58199314447030, 1.83648436200484, 2.0736685340943, 2.28666395635014, 2.47190749946052, 2.62875642069685, 2.7588671134083, 2.86547380412696, 2.95267819454637, 3.02482133384418, 3.0859645345613, 3.13948119527874, 3.18777236391576, 3.23216367810119, 3.27309063424794, 3.31067927201531, 3.34572652678189, 3.38086839897939, 3.42146738918477, 3.47560620802839, 3.55270554116043, 3.66074686442612, 3.80274081265035, 3.97363091380934, 4.15893836037867, 4.33599842838345, 4.47777238419762, 4.55832138912471, 4.55848161148757, 4.47024800846079, 4.29875988683818, 4.06136748756696, 3.78390747897819, 3.49501707425565, 3.22002482595880, 2.97638274496369, 2.77228129909174, 2.60880042454835, 2.48419006422399, 2.39774760134698, 2.35116558412482, 2.34698391725088, 2.38564914090003, 2.46335043303097, 2.57196584870496, 2.70094187243720, 2.83987470665108, 2.98049811821300, 3.11744443498035, 3.24790922524557, 3.37076801120264, 3.48569302136469, 3.59257900027179, 0, 0, 0, 0, 0, 1.96510614229525, 2.16942873207622, 2.46280470152225, 2.87093302981427, 3.33763845491763, 3.71985841195565, 3.89201955996671, 3.8656092079168, 3.77475026536904, 3.74600362628862, 3.80993827792461, 3.92305779597308, 4.03135851021596, 4.10563873491944, 4.14385710300896, 4.16098935517456, 4.17668454579957, 4.20272383323769, 4.23329174013053, 4.2429180806114, 4.19454052733131, 0, 0, 0, 3.06065031214002, 2.63618381206430, 2.23306592381181, 1.8781284990826, 1.58042843272462, 1.33390934270248, 1.12478018673622, 0.940394008315007, 0.776105981994396, 0.637496821658005, 0.537514653805246, 0.490544793255309, 0.506612515848655, 0.588151344607697, 0.729859942842646, 0.920622062654355, 1.14607947867995, 1.39093655089365, 1.64070410028482, 1.88292047271246, 2.10793042001900, 2.30925350613365, 2.48356273726449, 2.63033277275432, 2.75126354577641, 2.84960477071336, 2.92949108748288, 2.99535775748613, 3.05146331679129, 3.10151975726206, 3.14843711414796, 3.1942261370379, 3.2401446022253, 3.28717307000321, 3.33681757410609, 3.39205077497573, 3.4579829735831, 3.54173388500537, 3.6510979911925, 3.79201022130004, 3.96540309783438, 4.16452844429218, 4.37390824581615, 4.57065809261371, 4.72813692459467, 4.82106392634924, 4.83075555117925, 4.74912859131509, 4.58050067337631, 4.34078528062473, 4.05426525912366, 3.74869638275875, 3.45000764026545, 3.17814193689904, 2.94530956246004, 2.75697134059101, 2.61458888613107, 2.51835699848749, 2.46839430296415, 2.46408142618946, 2.50252613540869, 2.57759000024291, 2.68032584311639, 2.80063312452758, 2.92923049119615, 3.05904075064743, 3.18558675791509, 3.30655731470082, 3.42099705265026, 3.52855370291116, 3.62901647669827, 0, 0, 0, 0, 1.77244922681495, 1.94359970066235, 2.17435363713948, 2.52460626678491, 3.02565009375498, 3.60282356621945, 4.06970043177021, 4.26286776359110, 4.1961567218787, 4.04254961855753, 3.9669779498333, 4.01216789613556, 4.12557411215034, 4.23934601800604, 4.31414771842082, 4.34169391885483, 4.33314815465628, 4.30679707310553, 4.27645971817758, 4.24222999890118, 4.18753563607219, 4.0849828395871, 3.90876804178728, 0, 0, 0, 2.52814598084648, 2.15301131862877, 1.82153524313441, 1.54109509184299, 1.3072045346518, 1.10969925072650, 0.939628180391214, 0.79419349647664, 0.678082935892959, 0.601160465165412, 0.574071901603192, 0.603997806084035, 0.69220674997142, 0.833795014777213, 1.01897728925256, 1.23500633057837, 1.46806706349688, 1.70486432452605, 1.93383459535406, 2.14596362264024, 2.33519612783253, 2.49845159166775, 2.63531120363672, 2.74748531143051, 2.83818568113983, 2.91150929674246, 2.97190150957415, 3.02372425215154, 3.07092847630907, 3.11683170539890, 3.16403046986294, 3.21451190805152, 3.27002915913330, 3.33273130182279, 3.40588278105038, 3.49432389992020, 3.60422769509665, 3.74182144749493, 3.91110453897710, 4.11110144082727, 4.33360127366316, 4.56240286010961, 4.77470094026124, 4.94454327889799, 5.04756569962799, 5.06578333141435, 4.99122424271838, 4.82755965237284, 4.5894149877291, 4.29957267669513, 3.98473974877174, 3.67092494635606, 3.37963969114084, 3.1259121379487, 2.91840608806161, 2.76102165324091, 2.65475827376112, 2.59876869971583, 2.59033354202060, 2.62434512058174, 2.69318929233023, 2.78751851551428, 2.89771772549129, 3.01541416037564, 3.13441940329611, 3.25087229609419, 3.36275656333311, 3.46916897940182, 3.56968009734216, 3.66396289281138, 0, 0, 0, 1.58470883618565, 1.73502766441058, 1.91293748271447, 2.16544683257109, 2.56279486334244, 3.14071030794898, 3.80962124506377, 4.34822143472737, 4.5625616679788, 4.46801453198972, 4.26831134239462, 4.15880707713804, 4.19171357318822, 4.30688595677406, 4.42476880035141, 4.49705839511362, 4.50967433307981, 4.47044307900645, 4.3971506361736, 4.30675574453578, 4.20618317953089, 4.08813920853112, 3.93466889864969, 3.72704295875385, 3.45666894480143, 0, 0, 0, 2.07119345927457, 1.77153447615679, 1.51696945227641, 1.30373832209976, 1.12412172397465, 0.971788558414307, 0.84532620851451, 0.748933935238174, 0.690484264697459, 0.678174931411305, 0.717341715064971, 0.808562478853373, 0.947342251813863, 1.12499555121899, 1.33012327782522, 1.55020887240436, 1.77306835145094, 1.98802249249218, 2.18671472401152, 2.36353430355025, 2.51565455685885, 2.64275303480229, 2.74652211509233, 2.83009040977700, 2.89745726584049, 2.95300543293126, 3.00111668580166, 3.04588818196336, 3.0909447941045, 3.13936399280101, 3.19375729885602, 3.25655272678010, 3.33046259982005, 3.41899429843264, 3.52671360829156, 3.6588974593937, 3.82031683572445, 4.01320455905818, 4.23489384431806, 4.47595838785879, 4.71972970936481, 4.94372373201054, 5.12288798436222, 5.23394880968571, 5.25976584826393, 5.19261651848062, 5.03567216853659, 4.80241207716812, 4.51419053256754, 4.19655349565783, 3.87517187638026, 3.57235651203448, 3.30493488999421, 3.08376397042768, 2.91450441882712, 2.79884787394118, 2.73545344532717, 2.72035274358822, 2.74713253033366, 2.80739463046763, 2.89173615357247, 2.99105436225786, 3.09771388920992, 3.20617693777928, 3.31298428740456, 3.41626448554906, 3.51508274826301, 3.60889977955296, 3.69727166427682, 0, 0, 1.40762850517197, 1.54356551208450, 1.69184062105183, 1.8731953670748, 2.13897022493002, 2.56499922078711, 3.18930796011415, 3.91429815709294, 4.50000495051887, 4.7359189632402, 4.63751260733886, 4.42391051723218, 4.30583069472527, 4.33998243423948, 4.46159729941088, 4.58386050158338, 4.65211122168397, 4.64746249937767, 4.57491313819493, 4.45241172893453, 4.30086310124321, 4.13463683569654, 3.95583914784051, 3.75554805686767, 3.52141052758602, 3.24706978452943, 0, 0, 0, 1.98926544665286, 1.72672626326508, 1.50364941129365, 1.31643121693145, 1.15895130047359, 1.02670983981757, 0.919318892883576, 0.840740438080126, 0.797596361491718, 0.796524857007629, 0.841709965392032, 0.933371164639679, 1.06743530404756, 1.23616251375303, 1.42932555000198, 1.63558552166351, 1.84381662366256, 2.04421756417642, 2.22910289706122, 2.39332030253168, 2.53430107868726, 2.65180966256681, 2.74749683820238, 2.82437102693737, 2.88628442542472, 2.93749580103737, 2.98233361193315, 3.02495599808626, 3.06919786732236, 3.11850971285308, 3.17601367169845, 3.24470271999271, 3.32776162479576, 3.42888834359992, 3.55237961749726, 3.70269327697016, 3.88329507548647, 4.09486493876461, 4.33329713894825, 4.58821014935076, 4.84270664801166, 5.07481954142049, 5.26054212545999, 5.37779567929201, 5.41036819680875, 5.35087569738822, 5.20210074949845, 4.97649669847743, 4.69406139213703, 4.3791044158219, 4.05663461616103, 3.74914895739608, 3.47445266574726, 3.24477267635244, 3.06696422013101, 2.94328978443445, 2.87225556851223, 2.84928663597351, 2.86735808637113, 2.91781627508257, 2.99146594492362, 3.07973671498197, 3.17560163018607, 3.27399728079993, 3.37171249340596, 3.46691809257337, 3.55859634057817, 3.6460842941179, 3.72882937020616, 1.13862439837727, 1.24886650514417, 1.36948426978059, 1.49964412963501, 1.64438996768607, 1.82517052719911, 2.09350010878334, 2.5247872389276, 3.15666083030701, 3.89225552970043, 4.49355225877902, 4.7512440155177, 4.67912065116954, 4.49227214427259, 4.39772056850018, 4.4504005229523, 4.58479882844077, 4.7126502454617, 4.77643622746442, 4.75380896887505, 4.64746264417377, 4.47597619611878, 4.26469412878976, 4.0357064359194, 3.80035946397417, 3.55818295357547, 3.30244306870974, 3.02840488196622, 2.73916485990489, 0, 0, 0, 1.68613205732468, 1.49764140040155, 1.33955628661032, 1.20676675017779, 1.09603487279523, 1.00771312839694, 0.94565792284478, 0.915708967998724, 0.92352189044543, 0.972584307882505, 1.06297865845425, 1.19106585655980, 1.34995342006370, 1.53047221973131, 1.72238265750590, 1.91558238798266, 2.10114324511268, 2.27205856250902, 2.42364193695782, 2.55358327388246, 2.66172502758510, 2.74965738377641, 2.82023944527764, 2.87713688734118, 2.92443420540394, 2.96634394541410, 3.00700845039080, 3.05038017292837, 3.10017489650203, 3.15990716064601, 3.23301746388505, 3.32306490053411, 3.43388304152265, 3.56951146775960, 3.73368342299261, 3.92873710150251, 4.15404228724653, 4.40432849588217, 4.66852444425504, 4.92972589817951, 5.16664160640235, 5.3564066501984, 5.4781884719715, 5.5167386353996, 5.4650598735507, 5.32562276022907, 5.10994847528762, 4.8367403357636, 4.5290212736803, 4.21089402139157, 3.90457121621668, 3.62819985390263, 3.39473276272095, 3.21176472159953, 3.08200647099949, 3.00403636300597, 2.97312711434449, 2.98213939266291, 3.02254327649321, 3.0855383628711, 3.1630995098901, 3.24871690625825, 3.33768106160447, 3.42692907913671, 3.51461402193046, 3.59961227680278, 3.68113959991685, 3.75854999474245, 1.11490596258492, 1.21746500400875, 1.33068383281863, 1.45450530104452, 1.59435789685668, 1.77064528031373, 2.03102038182961, 2.44464496781032, 3.04615125821035, 3.74786587113109, 4.33361166215026, 4.6124521682447, 4.59482299030328, 4.47309368174986, 4.43226194717193, 4.51950275586099, 4.67239466126442, 4.80696185054038, 4.86635970273613, 4.82619117443242, 4.68734542981815, 4.46931732357689, 4.2020657613266, 3.91531380231444, 3.62918653984859, 3.35090920151279, 3.07857027120059, 2.80850865145037, 2.54130773842145, 2.28330441604469, 0, 0, 0, 1.49627862836685, 1.3687038680505, 1.26181845743125, 1.17323545602336, 1.10381984026965, 1.05737032628166, 1.03921924669722, 1.05439418625223, 1.10597119191249, 1.19403621593253, 1.31539332251495, 1.46393547665058, 1.63147790773773, 1.80882702315909, 1.98687704209767, 2.15756457675672, 2.31456160881382, 2.4536481696328, 2.57276978944406, 2.67183856559807, 2.75236943549468, 2.81705053303882, 2.86933128311166, 2.91308235090138, 2.95234843607927, 2.99118869513595, 3.03358762271483, 3.08342231653485, 3.14448183374219, 3.22053442124954, 3.31541223226893, 3.43302813442487, 3.57717939961188, 3.75097766648094, 3.9558239429871, 4.19003354662125, 4.44745280482681, 4.71658261542471, 4.98071670219097, 5.21936939559485, 5.41087735489576, 5.53566808379867, 5.57945757748482, 5.53565264610614, 5.40646021084725, 5.20253818515901, 4.94134473227312, 4.64458285894915, 4.33527065787538, 4.03498744117652, 3.76174652067782, 3.52873937263188, 3.34394498578749, 3.21040388575408, 3.12689774071283, 3.08884439527264, 3.08932215177195, 3.12017781666368, 3.17312847740902, 3.24070023644204, 3.31684010147145, 3.39711819912598, 3.47856486557535, 3.55929020988994, 3.63806475112512, 3.71399778931041, 3.78637001794014, 1.09188406585655, 1.1867702646611, 1.29248502285010, 1.40960799480358, 1.54351256621766, 1.71224839828413, 1.95665150208050, 2.33539928410403, 2.87823049050663, 3.51277441276375, 4.05909081491502, 4.35706205085785, 4.41262912877952, 4.38202306676106, 4.41506387530762, 4.54694250801797, 4.72122996233016, 4.86256092159563, 4.91752384880367, 4.86088023275456, 4.69216262974548, 4.43190627704159, 4.11454351739848, 3.77696500236929, 3.44729903186153, 3.13954011472925, 2.85578267679157, 2.59297731198958, 2.34920209157961, 2.12615141084551, 0, 0, 0, 1.49755876290754, 1.40059186639343, 1.31981750612936, 1.25340045363647, 1.20253355948688, 1.17095424720170, 1.16363583998975, 1.18518519957772, 1.23843776633043, 1.32356824330926, 1.43782813687044, 1.57585420666493, 1.73039404158674, 1.89325804686860, 2.05630992345363, 2.21233555811269, 2.35567650262400, 2.48257261001142, 2.59121848286486, 2.68158788063999, 2.75510984330572, 2.81428678899658, 2.86233114190169, 2.90287038404625, 2.93974003022505, 2.97685883170384, 3.01816680517532, 3.06760554537202, 3.12912569610113, 3.20670623982507, 3.30435215808875, 3.42599942789833, 3.5752179017429, 3.75460085695245, 3.96480234437206, 4.20333669498829, 4.46344220671707, 4.7334415696771, 4.99701285825899, 5.2345827483786, 5.42572474939115, 5.55211703978422, 5.60041989595217, 5.56444165565444, 5.44615335437923, 5.25539853989353, 5.00842806379239, 4.72560355894371, 4.42873133488814, 4.13850587877219, 3.87246163913000, 3.64367013681048, 3.46022305632848, 3.32538005642876, 3.23818658337317, 3.1943814793407, 3.18746330208466, 3.20980903123879, 3.25372439221187, 3.31228648502577, 3.37986222514606, 3.45226233985309, 3.52658938352087, 3.60091146253159, 3.67390994985792, 3.74461106900567, 3.81224493941861, 1.07026372592183, 1.15767372570678, 1.25596290001564, 1.36623166122068, 1.49354227807448, 1.65295242759273, 1.87713148341531, 2.21237822158047, 2.68267893268369, 3.23360660254866, 3.72772623666776, 4.04120458491798, 4.17510098685708, 4.24382238112272, 4.35645092704759, 4.53452146745413, 4.72906247793486, 4.8754793372483, 4.92534616398045, 4.85345392640295, 4.65837899491003, 4.36168923319156, 4.00184922242105, 3.62207651767243, 3.25741739369703, 2.92755470080684, 2.63777515042005, 2.38528066070761, 2.16578277520868, 1.97686880789185, 1.81778416012911, 0, 0, 0, 1.43283751776409, 1.3776574045039, 1.33294131738330, 1.30006155026154, 1.28266535875656, 1.28544065420169, 1.31269079214767, 1.36711047025258, 1.44901241761836, 1.55609417206325, 1.68370340475189, 1.82547681178858, 1.97418850148329, 2.12263919522315, 2.26443942996105, 2.39458202732166, 2.50975319985863, 2.60838672753998, 2.69051037117643, 2.75746020998052, 2.81154441660302, 2.85572583512572, 2.89336891448340, 2.92806894752807, 2.96355770285526, 3.00366475391114, 3.05230939433117, 3.11349988367112, 3.19131620122957, 3.28984079623043, 3.41297828528225, 3.56408388323718, 3.74532934735591, 3.95680116655056, 4.1954512070155, 4.45416664332298, 4.72132138718432, 4.98114392550232, 5.21506143432146, 5.40390405984195, 5.53057917658037, 5.58266121171737, 5.5543471500008, 5.44738719195837, 5.27084540303876, 5.03979450009628, 4.77324209110322, 4.49169477508484, 4.21478572154111, 3.95932616506175, 3.73800960507951, 3.55883626972672, 3.42518456319499, 3.33637499933483, 3.28855506352506, 3.27575104890068, 3.29094978738854, 3.32707814990448, 3.37775851987497, 3.43775702151722, 3.50311069402926, 3.57099686599909, 3.63946020349719, 3.70712029912735, 3.7729484145144, 3.83614744096230, 1.05059323138323, 1.13087615675246, 1.22197194862392, 1.32541294291459, 1.44587712931296, 1.59544710315555, 1.79883585635717, 2.09034255719478, 2.48834934379523, 2.95565331388578, 3.39571873548935, 3.71969112487733, 3.92407593324908, 4.08323790930754, 4.26728812773101, 4.48487708465108, 4.69454378572426, 4.84252456992379, 4.8857745234712, 4.79968566091026, 4.58226556324352, 4.2560094943269, 3.86270598960471, 3.45071520924541, 3.06063788586858, 2.71663980272575, 2.4264126234485, 2.18715980685862, 1.99248488111799, 1.83648697312294, 1.71447039876835, 1.62186020976991, 0, 0, 0, 1.43315322641093, 1.40930783497610, 1.39365712881330, 1.38972313711766, 1.40194330000757, 1.43438413650957, 1.48965793663878, 1.56824224821917, 1.66827322116090, 1.78577794962549, 1.91523955296635, 2.05035159590123, 2.18481135739359, 2.31301979123288, 2.43059396593474, 2.53464680133075, 2.62383840278582, 2.69824315324739, 2.75910024129735, 2.80852051411542, 2.84921190239315, 2.88426460526933, 2.91701241017701, 2.95096424534415, 2.98978482442097, 3.03729644191089, 3.09747304258166, 3.17439673711927, 3.27214015030528, 3.39452535726587, 3.54470236477056, 3.72450713125474, 3.93361927040213, 4.1686421514235, 4.42234140006735, 4.68334514347253, 4.93657611682778, 5.16453420500296, 5.34931661981225, 5.47503418827409, 5.53014333930387, 5.50921381420093, 5.41378391913419, 5.25216481698338, 5.03827513751599, 4.78976323370399, 4.52577784684331, 4.26477057386836, 4.02266063635552, 3.81158143786094, 3.63929021490754, 3.50919552224571, 3.42087317162883, 3.37090727092116, 3.35389377212846, 3.36345767262729, 3.39315213198819, 3.43713443567222, 3.49055921210406, 3.54969101241148, 3.61179884275513, 3.67493254270021, 3.73768256547729, 3.79899474962318, 3.85806703563638, 1.03325387607961, 1.10687464537406, 1.19112843878319, 1.28790968793202, 1.40156533395809, 1.54167127229001, 1.72626878057395, 1.97960205263942, 2.31529352933870, 2.71033873780678, 3.10208487827513, 3.43069359999023, 3.68892415037654, 3.91799136017974, 4.15580723134169, 4.40055926803801, 4.617364837776, 4.761921955517, 4.7962097365191, 4.69664270489517, 4.46107879851684, 4.11277370652571, 3.69591942877376, 3.26255888644113, 2.85727044937054, 2.50742086337273, 2.22236948890332, 1.99918118831456, 1.82970826033451, 1.70522967938628, 1.61787728654501, 1.56022685912558, 0, 0, 0, 1.48483415696717, 1.48075581838127, 1.48139823889911, 1.49012918915727, 1.51115481018967, 1.54834594319383, 1.60426802117389, 1.67957638294644, 1.77283249562845, 1.88070870109337, 1.99848808897871, 2.12073290583915, 2.24198791538204, 2.35740130019072, 2.46317971917133, 2.55683789874721, 2.63724696623977, 2.70452082302163, 2.75980050194440, 2.8050010787368, 2.84257647646803, 2.87533905124877, 2.90634876356742, 2.93886623280203, 2.97634880644253, 3.02246038491342, 3.08106272256651, 3.15615458925371, 3.25172196751327, 3.37145794096708, 3.51831301921288, 3.69385928252499, 3.89750659422779, 4.1256931092233, 4.3712591805505, 4.62325941245907, 4.86743077891069, 5.0874033445071, 5.26654582738454, 5.39014698227567, 5.44751581797809, 5.43358064469267, 5.34967549440945, 5.20338162621793, 5.00748598189253, 4.77827966838813, 4.53351859066436, 4.29039448893895, 4.0638215384846, 3.86524741905452, 3.70207545761200, 3.57766838960735, 3.4918205483228, 3.44154346827729, 3.42200260213301, 3.42745595229838, 3.4520698398114, 3.49052212974591, 3.53835029975639, 3.59205566148708, 3.64902266776875, 3.70733884248895, 3.76559905886319, 3.82275205697845, 3.87801077488972, 1.01846245416217, 1.08596522231222, 1.16381248583751, 1.25419754674637, 1.36124003210115, 1.49266035111562, 1.66154860969250, 1.88467476778556, 2.17203327508198, 2.51086928716400, 2.86321941941278, 3.19041952939142, 3.4824721337435, 3.7563694313197, 4.02657666236156, 4.28386604965095, 4.49858415629745, 4.63396194058052, 4.65639639560549, 4.54375292320476, 4.29421527669551, 3.9316014103196, 3.50145035698493, 3.05785732260728, 2.64768642865787, 2.30021115575356, 2.0257936816726, 1.82131800644783, 1.67730883421136, 1.58290445186134, 1.52779889669951, 1.502352376644, 1.49741853310843, 0, 0, 0, 1.54617351681349, 1.56201919569497, 1.58252643284234, 1.61168624875025, 1.65320372197589, 1.70962099791543, 1.78177549000019, 1.86863522675990, 1.96747919031069, 2.07433860155178, 2.18458668021080, 2.29355877779082, 2.39709958854758, 2.49196454494462, 2.57604114984397, 2.64839437858394, 2.70917084321743, 2.75941435387429, 2.80084957162299, 2.83568250710539, 2.86645059554793, 2.89593561591211, 2.92713409675187, 2.96326518301462, 3.00778663548733, 3.06438515160104, 3.13690550363198, 3.22918224913165, 3.34473898025788, 3.48632907306034, 3.65531802881571, 3.85095750287805, 4.06967021184535, 4.3045312942045, 4.54516109536225, 4.77820586802213, 4.98846872528999, 5.16058942093507, 5.28101092454485, 5.33987000619984, 5.33244332687322, 5.2598698631536, 5.12902386399512, 4.95158436521112, 4.74249505279488, 4.51810302132087, 4.2942938334519, 4.08490497321481, 3.90061472432456, 3.74839308402287, 3.63149391202176, 3.54988638616927, 3.50097956319621, 3.48048348697432, 3.48326383195433, 3.50407551075807, 3.5380993159726, 3.5812513256948, 3.63028136242496, 3.68271435522076, 3.73670730937121, 3.79089076093828, 3.84424155941835, 3.89600443054483, 1.00628450053785, 1.06825865148231, 1.14018676351800, 1.22449483517342, 1.32516748811905, 1.44868247823096, 1.60480818602342, 1.80528950962512, 2.05757388542862, 2.35542634965344, 2.67687346563795, 2.99700110650081, 3.30398627309056, 3.5990315277161, 3.88140372352312, 4.13730045076750, 4.34099988058508, 4.46147455888737, 4.4690569874273, 4.34357869198301, 4.08406587048391, 3.71469055258403, 3.28123798308875, 2.83818698333673, 2.43300278861692, 2.09563385729956, 1.83687165924124, 1.65345353278183, 1.53502820183057, 1.46924561667954, 1.44403316447306, 1.44809904623695, 1.47104611969705, 1.50381369589417, 0, 0, 0, 1.63478623209085, 1.66609180875735, 1.70266706244031, 1.74807695669765, 1.80485743188951, 1.87402634875251, 1.95493465655361, 2.04542469077374, 2.14221869209131, 2.24143715793677, 2.33914293089052, 2.43182083095639, 2.51672975443408, 2.59209801750564, 2.65716601138003, 2.71210658593476, 2.75786901082306, 2.79599587643666, 2.82845551482373, 2.85751872134787, 2.88569156780901, 2.91569939648281, 2.95050323441458, 2.99332020555260, 3.04761410124275, 3.11702027317715, 3.20516985569721, 3.31538332339215, 3.45021683045662, 3.61087265356914, 3.79653054311968, 4.00371405095934, 4.22585669459168, 4.45325044777678, 4.67352049583792, 4.87267077966629, 5.03660614712572, 5.1529013130225, 5.21250025893569, 5.21102205537556, 5.14942275344968, 5.03389464444246, 4.87503641814197, 4.68646290701431, 4.48311307836235, 4.27954539912761, 4.08848056159983, 3.91977556439039, 3.77991253393513, 3.67198616007347, 3.59609659303435, 3.55001102511492, 3.52994637662036, 3.53133973092166, 3.54950337848745, 3.58010055222968, 3.61942061876687, 3.6644723613827, 3.71294363399539, 3.76308887384712, 3.81360105817135, 3.86350604353301, 3.91209354538042, 0.996655591760163, 1.05370603367693, 1.12022717078657, 1.19880518452999, 1.29333869910162, 1.40951813781563, 1.55504160932863, 1.73852716919131, 1.96572042201598, 2.23402009374511, 2.53069906303622, 2.83884580552865, 3.14555961857880, 3.44282014443302, 3.72109729032250, 3.96420436485056, 4.14935747902563, 4.24996585389531, 4.24008381783721, 4.10208774651978, 3.83635042886715, 3.46719090748236, 3.03959109257189, 2.60684843471031, 2.21548120520981, 1.89501860542648, 1.65621291542219, 1.49573783798510, 1.40280427343256, 1.36416340103234, 1.36656089973262, 1.39753509727659, 1.44577223949901, 1.50164149353872, 0, 0, 0, 1.69940219038339, 1.74045076831376, 1.78367494537268, 1.83252342060699, 1.88953878419951, 1.95591315812570, 2.03135254734056, 2.11421529080554, 2.20185335078485, 2.29106648824451, 2.37857776565024, 2.46145209784892, 2.53740374672383, 2.60496813430901, 2.66354198166961, 2.7133182876486, 2.75515579481555, 2.790425581881, 2.82087166210826, 2.84851067773448, 2.87558108508614, 2.90453742903638, 2.93807249482535, 2.97914053403599, 3.03094884344276, 3.09688274474900, 3.18033076747626, 3.28438409974449, 3.41140031192302, 3.56244958618097, 3.73670291857426, 3.93086962743357, 4.13883060572379, 4.35162318277508, 4.55789605529798, 4.74486601706752, 4.89969012057047, 5.01105170345668, 5.07068392321108, 5.07454557358913, 5.02342494185975, 4.92286080789125, 4.78240454584048, 4.614370362514, 4.43230521222256, 4.24944082318072, 4.07736605110765, 3.92508959768323, 3.79857134489516, 3.70070876640221, 3.63169293953141, 3.58960740414762, 3.57113310107799, 3.57223732322918, 3.58875504330334, 3.61680901372792, 3.65305401990703, 3.69476462429895, 3.73980914588502, 3.78656171495677, 3.83379887443283, 3.88061150569851, 3.92634383747083, 0.989407728698556, 1.04213052576847, 1.10376034408225, 1.17696688075729, 1.26556474609777, 1.37473199680037, 1.51090990359831, 1.68084688469862, 1.88915561297960, 2.13496057993436, 2.41031039821192, 2.70250120504745, 2.99809930788061, 3.28427924783234, 3.54699840399249, 3.76914675151517, 3.9302376277605, 4.00732973160839, 3.97820402500549, 3.82832655604089, 3.55983521573081, 3.19699389919866, 2.78306891704274, 2.36884365130202, 1.99859309867743, 1.70053382984475, 1.48502213047514, 1.34877078337863, 1.28093975424263, 1.26787973984197, 1.29563923771478, 1.35098376483591, 1.42196159329102, 1.49853501916205, 1.57324087574687, 0, 0, 0, 1.80560319499509, 1.85467028327924, 1.90648308643058, 1.96359997542579, 2.02737717919741, 2.09784437279557, 2.17382553264225, 2.25323839000422, 2.33349158066208, 2.41189905363817, 2.48604413014339, 2.55404717218354, 2.61471636915147, 2.66758559629159, 2.71286234827063, 2.75131980770798, 2.78416960957234, 2.81294699353731, 2.83943003899967, 2.8656020788393, 2.89365342823949, 2.92600692687918, 2.96534258856354, 3.01459057483643, 3.07685932248257, 3.15526783463227, 3.25265952718128, 3.37119198466342, 3.51182450310044, 3.67376250228009, 3.85395824962838, 4.04679776858659, 4.24410776079991, 4.43558100081747, 4.60964294561013, 4.75468128549187, 4.86046177807934, 4.9194888290629, 4.92805980257479, 4.88681278320138, 4.8006653181217, 4.67816096010097, 4.53035180776468, 4.36942361811347, 4.20730035515056, 4.0544447612906, 3.91901041669511, 3.80641734175127, 3.71933918077137, 3.65802377540445, 3.62083087191931, 3.60486195556032, 3.60657199078188, 3.62228240622752, 3.6485504640882, 3.68238520641597, 3.72132898766727, 3.76344210428365, 3.80723415188373, 3.85158030231255, 3.89564753572349, 3.93884061408813, 0.98429787646103, 1.03326159955897, 1.09050345666027, 1.1587009728831, 1.24155260481659, 1.34385388195948, 1.47124219558739, 1.62932247570893, 1.82191435815329, 2.04877499839305, 2.3041516128958, 2.57738153752452, 2.85488098937414, 3.12166317231885, 3.36171658247996, 3.55787751785972, 3.69159670941005, 3.74316411276498, 3.69416507256708, 3.53355004138851, 3.26548786938717, 2.91399038194909, 2.51989680138182, 2.13047003590497, 1.78677878922676, 1.51507530275764, 1.32507322294075, 1.21362104225962, 1.17013513994537, 1.18095524036117, 1.23181212222478, 1.30901375964012, 1.40019842897687, 1.49506382632774, 1.58602211400506, 1.66855789820847, 0, 0, 0, 1.91593119273262, 1.97021830948827, 2.02729475213662, 2.08866700178163, 2.15465422702087, 2.22449386526868, 2.29660445356706, 2.36893267133387, 2.43931395042686, 2.50578848741466, 2.56683376591396, 2.62149676240963, 2.66942974094464, 2.71084952258249, 2.74644932077416, 2.77729428030962, 2.80472775562618, 2.83030694517231, 2.85577578789859, 2.88307179711184, 2.91435310066615, 2.95202335657251, 2.99872623432513, 3.05727868949966, 3.13051453411475, 3.22101848822217, 3.3307478129108, 3.46056468380693, 3.60973583212125, 3.77549026505748, 3.95274989430216, 4.134148404891, 4.310420962064, 4.47118130159226, 4.60601605699508, 4.70574181628952, 4.76361399626521, 4.77626702454272, 4.74420774369438, 4.67176844664525, 4.56653116140943, 4.4383348382603, 4.29804884102675, 4.15632499922834, 4.02252339695444, 3.90395250507901, 3.80548900346554, 3.72956647211429, 3.67646194807557, 3.64477487520872, 3.63198556538711, 3.63499473849683, 3.65057365005089, 3.67568729899854, 3.70768435709699, 3.74437185871179, 3.78400734350301, 3.82524514110234, 3.86706823592148, 3.90872614967556, 3.94968705695471, 0.981036071702848, 1.02676872825389, 1.08010272623824, 1.14365412906355, 1.22095655141006, 1.31646116195585, 1.43521582582284, 1.58205197982836, 1.76018281647741, 1.96945865787537, 2.20503343437007, 2.45722560941292, 2.71257940388393, 2.9553992238202, 3.16908661654145, 3.33690594419035, 3.44205843645630, 3.46782711644265, 3.39960824302985, 3.22999542184572, 2.96526149277495, 2.62897480103630, 2.25906921047412, 1.89865225923299, 1.58499175659681, 1.34197732615628, 1.17853384399147, 1.09171741080109, 1.07141391264593, 1.10422847657316, 1.17585349463411, 1.27238186323125, 1.3812269060421, 1.49194644144224, 1.59690328744549, 1.69157590400225, 0, 0, 0, 1.96798807420075, 2.02425101958404, 2.08113605459916, 2.14028257041227, 2.20226301117679, 2.26667549503418, 2.3323749489044, 2.39777657097369, 2.46116954781212, 2.52099113709973, 2.57602848683248, 2.62553457249673, 2.66926211157664, 2.70743260523844, 2.74066523282422, 2.76989195770565, 2.79628175417964, 2.82118981981359, 2.84613860395416, 2.87282784717024, 2.90316165223405, 2.93927274628812, 2.98351839911336, 3.03841999871947, 3.10652044778438, 3.19014197561672, 3.29104309626787, 3.40999753215762, 3.54634763504836, 3.69761411754045, 3.85926316037331, 4.02473044808846, 4.18577194633775, 4.33315374539383, 4.45761878309764, 4.5509957735821, 4.60726662691539, 4.62339930864516, 4.5997887043824, 4.54022101725935, 4.45136960544761, 4.34191925879745, 4.22148073690825, 4.0994842164245, 3.98422584361197, 3.88219318035069, 3.79772803230727, 3.73301682463156, 3.68834467431102, 3.6625185328149, 3.65335860719038, 3.65817100830655, 3.67414040524932, 3.69861133520263, 3.72925422973035, 3.76413283697369, 3.80170136213877, 3.84076216108501, 3.88040992021412, 3.91997907834917, 3.95900143987746, 0.979311034029364, 1.02229205775147, 1.0721680678856, 1.13143485886290, 1.20341076835116, 1.29219580857105, 1.40233175382803, 1.53804545194894, 1.70204388366240, 1.89405163606996, 2.10958020972056, 2.33950805204987, 2.57072578573078, 2.78759998542917, 2.97367000485966, 3.11289599287481, 3.19012468016824, 3.19142974571062, 3.10586681109293, 2.92956528473920, 2.6707781930074, 2.35244652773382, 2.00935304903594, 1.68017947925733, 1.39815266260958, 1.18463689477061, 1.04770624142637, 0.984661949470643, 0.98597820315383, 1.03869732096663, 1.12866570663423, 1.24194385528637, 1.36587140622321, 1.48997731017580, 1.60664915183881, 1.71140712328495, 1.80272077296229, 0, 0, 0, 2.06929903150842, 2.12583437037089, 2.18291647623716, 2.24133357567293, 2.30099220621183, 2.36112118327016, 2.42053748055964, 2.47791942225485, 2.53204449077602, 2.58196455067183, 2.62710764351679, 2.66731016601749, 2.7027942038143, 2.73411095327446, 2.76207242665669, 2.78769073790838, 2.81213840371748, 2.83673553122336, 2.86296157274309, 2.89248134216544, 2.92716793399159, 2.96909989925006, 3.02050763379118, 3.08364586813093, 3.16057698217558, 3.25286476453081, 3.36120005789846, 3.48500597472935, 3.62209544511033, 3.76846952381531, 3.91834233539642, 4.06445195652672, 4.19866669197048, 4.31283219163133, 4.39974257567581, 4.45407618486782, 4.47312776998936, 4.45719891115245, 4.40957132718672, 4.33606838609358, 4.24428875081898, 4.14265391153049, 4.03943577364762, 3.94191821561482, 3.85580392676124, 3.78491825368888, 3.73120117151686, 3.69493058650575, 3.6750930293345, 3.66981271150737, 3.67676266588647, 3.69350511816347, 3.71773488893094, 3.74742353704180, 3.78087934827008, 3.81674756277165, 3.85397673728144, 3.89177268076191, 3.9295537614436, 3.96691349968626, 0.978811843109271, 1.01946837906650, 1.06630223286624, 1.12164285354922, 1.1885505831545, 1.27075370299581, 1.37231321674407, 1.49692438927756, 1.64684692717403, 1.82162151526949, 2.01693897554637, 2.22413318643129, 2.43062455487792, 2.62126966687782, 2.78014676099454, 2.8920773804575, 2.94347406883842, 2.92296048642173, 2.82292454011760, 2.64268418250945, 2.39218161467503, 2.09355814720675, 1.77840296234867, 1.48101409742367, 1.23063663191078, 1.04614054584052, 0.934750456596723, 0.894015125933936, 0.91503421466933, 0.985373241680259, 1.09115695617991, 1.21855130716731, 1.35494897618424, 1.48995086990437, 1.61604138997588, 1.72883111972684, 1.82683959265194, 1.91091058144659, 0, 0, 2.10621418936578, 2.16223725410227, 2.21739593564350, 2.27265625171364, 2.32818241411175, 2.38351766946127, 2.43781797107382, 2.49009037723629, 2.53939968804596, 2.58502078281235, 2.62652818101244, 2.66382658629306, 2.69713513763487, 2.72694303654151, 2.75395515748654, 2.77904381137935, 2.80321797676516, 2.82761502434076, 2.85351305742739, 2.88235511952733, 2.9157702913391, 2.95557189481672, 3.00371074194998, 3.06216301976961, 3.13273945040791, 3.21681576815996, 3.3150039789277, 3.42680683954659, 3.55031947369334, 3.68205494739546, 3.81696768237766, 3.94872517779301, 4.07023552496618, 4.17438335134649, 4.25487343613724, 4.3070444723829, 4.32850735839572, 4.31948764853555, 4.28280575995636, 4.22349846125699, 4.14815388816216, 4.06408325652751, 3.97847426209068, 3.89766076357059, 3.82660618233877, 3.76864585513503, 3.72548040648186, 3.69737020207634, 3.68345726015809, 3.68213681708541, 3.69141231260132, 3.70918844571650, 3.73348041622297, 3.76253814718622, 3.79489892332317, 3.82938932733947, 3.86509819439984, 3.90133833873526, 3.93760845985712, 3.97356028292907, 0.979244880162183, 1.01795147529461, 1.06212356346342, 1.11389150802058, 1.17602722529847, 1.2518697372102, 1.34500694025926, 1.45863855938017, 1.59461955421556, 1.75231766960331, 1.92758300810687, 2.11223058217109, 2.29436658110745, 2.45960443192772, 2.59281621847570, 2.67980439949160, 2.70846674460336, 2.66968257027097, 2.55870547052601, 2.37752105626718, 2.13735494166486, 1.85939315401696, 1.57214381566834, 1.30579481432334, 1.08588638419100, 0.928962829448148, 0.841442264914652, 0.821094282804529, 0.859620791347573, 0.945135456532062, 1.06411881368398, 1.20295004925268, 1.34918519305629, 1.49259043743587, 1.62581605746341, 1.74460974968725, 1.84757140950584, 1.93555914829633, 0, 0, 2.13592503119266, 2.19127291609556, 2.24462843709787, 2.29709769004391, 2.34905418649294, 2.40030007142141, 2.4502722836937, 2.49825120252474, 2.54354062067395, 2.58560047246548, 2.62412583588802, 2.65907590544851, 2.69066390647160, 2.71932283670051, 2.74566257969313, 2.77043187975579, 2.7944946633991, 2.81882499487175, 2.84451918228573, 2.87281769996791, 2.90512416949716, 2.94300435378202, 2.98814599792895, 3.0422617162897, 3.10692330668493, 3.18332768137331, 3.27201162379451, 3.37255249873985, 3.48331039523361, 3.60127790932314, 3.72210082377877, 3.84031260540725, 3.94978880962711, 4.04438068691073, 4.11864169976094, 4.16852907054392, 4.19195520162539, 4.1890850445569, 4.16232157451352, 4.11598168746814, 4.05572430352232, 3.98783677107463, 3.91850484407253, 3.8531827101939, 3.79614743736494, 3.75027696936118, 3.71704468214806, 3.69668709894072, 3.68848091498736, 3.69106205181875, 3.70272975325042, 3.72169706773265, 3.74626945930657, 3.77495102287576, 3.80649006462926, 3.83988180699983, 3.87434639700080, 3.9092969332162, 3.94430697036087, 3.9790818290311 ), .Dim = c(100, 100)) rgl/inst/WebGL/0000755000176200001440000000000014265301464012760 5ustar liggesusersrgl/inst/WebGL/template.html0000644000176200001440000000047614265301464015470 0ustar liggesusers RGL model

%WebGL%

Drag mouse to rotate model. Use mouse wheel or middle button to zoom it.

Object written from rgl %rglVersion% by writeWebGL. rgl/inst/fonts/0000755000176200001440000000000014265301464013151 5ustar liggesusersrgl/inst/fonts/FreeSans.ttf0000644000176200001440000077527014265301464015420 0ustar liggesuserspGDEFU]rGPOSC0GSUBGhOS/2NҸxVcmap# cvt !y-Pgaspglyf_OT@headzn6hhea 4$hmtx>!loca ss-T"maxpX name0-qWpostkpO{Eg*r_<WW5`u 8Z:`m@.1 _P`PfEd@  8Zuˀ!M|c4,, y40MIM&(H2WM.W,+,f,", ,,#,+,.,%,&nnH-H2H2,M"O0YZcZ ,SdO,PAKL &[ &]0cU c@,,M,*,6,,(,,FB:DAF,F,$,6,ME",A N+dNHKMy,4,,C, d,+Mr%,bH(M.M^H2__M\,A0WM'_=m(,be=e=ec_ 0ZZZZG L & & & & &H_ UUUU [cC,*,*,*,*,*,*y",(,(,(,(A,$,F,$,$,$,$,$H2c,A,A,A,A+6,*,*,+0000Y{,Z,(Z,(Z,(Z,(Z,( ,, ,, ,, ,,S,',B`^dvBO::,F?,P?,P$D,PD,L,FL,FL,F,FL,F &,$ &,$ &,$+(]ME]MA]M00"0"/"0"cc4cU,AU,AU,AU,AU,AU,A  ccc,O,6,00N,6Z &0c,  ,:,F &,60"ccYY  P PDLL F,* &,$U,AU,AU,AU,AU,A,(,*,* y" ,,O &,$ &,$5YY  ,,L,F,* y" c,n,0,s,4<1 ., ,,Ml"M,,.0"cS,F,*Z,( &,$ &,$ &,$ &,$ ,*,,D,6,,,(,("",,,F,F,FB^DAFAFAF,,F,$MEMEMEMEMETT,A $:,MMM\MMMsMOM9MM&6'LnKYtJFR Pt#A-EJ @8vA2P~Nt(t'$4*`0'#38(T020%'&-8B0>N&"569h"*(.<*$()"($ZOcZ00d8SSOLSOOcO,"O?0OOO!LOO &OO0c@OO<OROQhOO0S ,*,$ FFZ,(E,"7F7FF-FjF.F,$-F@F<=BFFFF9F(FF,(,(8F"BHFRF8:,F,FO(F[,6cZFcZFcZF?E0"O:O:O:O:S,F$SFS,F00c<    S`FSESESE &,(',(d?E,O:S,FSE,*,* y"O,( &,( &,(?E,0"0"O7FO7F &,$ &,$ &,$0OFhOFOOSROTJ?C?]UB"JL3O/-o1 [(JBJ*JOJ-Jo<L*~$ 0'5EM+XAA,J<#EI&<L*^,?8DF0!B-<B,+*GB$(('(+ I I5,E#AA&#P@bGwI,E! `LU+LC2*!FZo FOIIFFIFF&>FnF:O:V&n?>_'o?`=:&&9X%o?m0>z3_=K$?98? N3^>#%;#X8423,jjjrTrW>>>#9>kkmIdspXakk>>~Ikcp)0)0)0)0)nG%+++??%M-?})`ph(HHHHH/HqHcHNHfH(,, &lllvN0L @I#TTxddhd0xTTT&j"P>, >2"""Tab~xd84jh0<0T!!H''((((u'd'k'9&(f'l(^(Z'w(((('f'&'X'(Y$c''B(&((FX'.'('P'8'X' &(FEN!P!O!!!ufK'(&''''('.0xv)\<:D5D4?55 <l055! &,L3XXXXX08/S} D P - - - P  :1_ ie [ ey ( $ }TT     Mv[  qlVlOXr>:DMUq5F\c Kb= H #=H ` ` = m l l @&O=@7O2 -@2@7`-@-P<> $'>F%\ #\?F#v v &F+\\\{!F%\ v F%\ F\v,'>F*v5v/>(| !*TT0TT0TT0TT0!?' ' 'vPsCsCgAd4d48m8m8kEh8h8&&"&&"&&"2s( ( ((${${$$*qDT0T0''&"&"(($$TT0TT0TT0TT0rrr!rr?rrrYgYAYdY4YdY4YY${${$$*qDT0T0T0T0T0T0T0rM6cMCC44YAF6F6M6888FFM ((((669((~NMM$$$$$yw*M\MM.,A@@@M0M1M/M1,&,&^2^Fs P 111111M[MUnb,|,MRXMBMB|0__________=___a____[]e<,!g):j LR?**O"o2-ccZ8e=ee=eeee=ee=eeee=d,dBddd,P0YAKBBBB    BD,AF [-1[-['-[,,$Z,+  -,7i7i$)H(H2@[[((,ddd,d_%HKHH_H2|5$ H-H-+++7'+7fPcMX22PUwYzuYrb_?R1(~`ja:aMU{__rUU@L++{__XmN`e)`Vz MM8kLvzSMmkMiK}mR1_?nsVqRlNZ9yrvcl2N..mmaajLLI((ZdtQ]o_]oW,+,", ,,#,+,.,%,&Mt,f,   , ":1:K%z:P&h? 9R%i?%#H2;;;;:::O:V&n?_`= &&9X%m0z3_=?98?N3^>#%;#>O:&98?H#|` ~3TY\ajmsu (uz~_V^ ,J   3 9 C E I M Q p  ( 0 3 6 9 < B H M \ ^ p t        ! + 0 3 9 C G ` o EMWY[]}   # & 7 = D I K q y ! !!!!"!(!-!3!!!!""" """"" "."4"<">"C"I"`"e""#%&j00000000A6<>ADO &PV[`emouy &tz~1Za0     5 < E G K P f    * 2 5 8 < > G K Y ^ f r         * / 2 6 > G ` f  HPY[]_    & 0 9 D G K p t ! !!!!"!&!*!0!S!!!"""""""" "'"4"<">"A"I"`"d""#%&j00000A00098>@CFponkhfeda_^\[PON)'X,*(%#~|{wujibaUSJIHGDA?<' &%" {ysVUTyNMLGDB@?94-,*% vxwvtIDC>l I 3 2 1 0 / .~{utho  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`ardeixpkvjsgwl|cnm}byqz!yVVVVvNxJz( 0 T z v &  . <rd*NrP| .HbZ,n8T>v  |2r !"d"""##$*$`$%P%j%& &"&&' 'V'(V)))**X*+++,,-,-p--..2.b./,/0"01L122230334(4x5567\8N9:.;(;$>J>x>?@?@:@A&AB@BrBCJCDDdDE&EEFFGH&HIlIIJJ(J>JK2KL"LLM4MMMNNNOOPnPPQDRR(R>RSSSTTxTTTTU U UjUUVVV6VNVVW<WlWWWX4XrXXXYY>YzYZ"ZZ[0[|[\B\],]D]Z]^`^_`*`vaajabPccccdefZfgg,gdggh8hPhfhii,iBijjkNklDl\ltlllm"m\mmnnVnnno"oop pqq q6qLqbqrrs<st*tptu8uuuv.vvw8wPwhwwwwwwxx(x>xVxlxxxxxxyy&y>yVynyyyyyyzz&z>zTzlzzzzzz{{&{>{V{n{{{{{{||,|D|Z|r||||||}}*}@}X}n}}}}}}~~&~>~Tl&>Tl`t$:NdtBRfV D4V&<T hx0D ,^vd,>Pv(D^*BZr0d,`0Tx2h2xP&6@R<*pp.P4Db,X0@f(^^XXFV$P:dt8H D~2P"8Njz>Z&|:X"THzª8fÌð$4XhČĜĬ:jŠ2FVjzƊƢƺLvǬ "8HXpȈȘȬ "8nʆʜʴ0F^tˌˢ˺,D\̺&ͼvTzЖрў&td6՚VֺP׬2ؤِTڶ`ۼܮzt4`zL"`~&H(`~nhj`Z~>r $Rj*X~&|NhRPjfh"~0>HR^jv   @ f62@tDP0rP&Z8t6x0t $ J n ""##$%(%&'N((f()*+,-H-.".//0T11123334@45J56>667d78f89"9n9:R;;t<<<==>>B>>?@??@0@X@AATAACJCdCDHDE6EFFGGdGI2IJ JK(KLjM0MNO OP PQvR`RSnSTJTUdUVVWXY&YZ Z|Z[v[\<\]]]^_2_``a$aabbbc*ccdPdpddeveffggh&hiHj*jkRkllvlmzmnfno@op ppq>qnqrNrjrs&stt4tLtdt|tttufu~vvzvwdwx^y yZzznz{L{|Z|}j}~,~PP f,P.n^0F`R<~4j~*@,*Xxh >HfVJ^<P $j hD&D2lBJ @T$,~*ĚhƄ<VǘǶ6Ȧɒʊˀ̪L τϦZrBTB צ0vڨݰJ޴ ~ZzvXxPl<zT<:fHV4ZR&`B8J("j    ,  r   t|D,<$!."$%'0(*J,./1236f789; <> ?*@:ABDG,HlI|JKM^NP&QzRST@TUbVVWDWX8Y YZZ[[[4[J[`[v[[[[[\\\0\H\^\t\\\\\\]],]D]\]r]]]]]]^ ^$^<^T^l^^^^^^__(_@_X_n______``,`D`Z`p``````aa(a@aXanaaaaaabb b8bPbhbbbbbbcc c8cPchccccccdd&d<dTdjdddddde e"e8eNedezeeeeefff2fJfbfzfffffggg,gBgZgrggggghhh2hJhbhzhhhhhi i"i:iRijiiiiiijjj4jLjbjxjjjjjjkkk0kFk^kvkkkkklll4lJl`lvlllllmmm4mLmbmxmmmmmnnn0nHn`nxnnnnnooo0oHo`oxoooooopp@ppppqqjqrr:rvrrrtuuuv<v^vvww"xxTxxyyz>z~zz{{||<|}n}}}}}}}}~~"22@ZZ RH ~@.X6Vv&>Nf&6Nn~6V~Tn^<b(>6L>B<,p > <n8\&~LP,6n(b0@4l*ŒjĜX\ǀZɆ^˄"ϸ@ҎӤ֔>ݦF& >h:L&J>&^:xn FPRbH:H"`D@   Z   8  pZl(&jV|nlX<6:  Z   !!h!","n""#<##$$%%&&4&J&`&v&&&&'''$'4'D'T'd't''''(j())*,*+n++,,j,- -z. .j.///01L223`34h45:5l566877<78>899V:2:;z;>4>?8?@:@!n./<2<2/<2<23!%!!!M f!X| #'#5'STRhh41 3#'73#'4]']'ooo3#3##7##7#537#537337#3$]jiu'L&|'L&erly$L$}#0| }DDDD 18A3#&'&'&##5&'&73&'&54767567654'&;~/O9dUD 1K;+O#G]!G`=*/6 ]&/M" 0jh= gg u.:J0 3_* LZ(<=[!%5F2#"'&5476"327654'&%3#2#"'&5476"327654/&T3?/18Lt8!4$JF A.?2Eljp&;Y$]]$Y;&2 ##5#5353FF FFWmh 73#5676=#Wii+ ,R>TU(=$/L(GZdT](4X6GOS;SwD4B$/V.?(3f%. #6767!5B ^2]7]J/1ګeW%,<#"'&547&'&547632'"327654'&"327654'&zV?Y|C/yHQ7Mt;&- P =#P A!Y'B".['C#u:wp=.R:Pv:-0c5%L0AD):F 9K @!*R&A!*R&&02#"'&'332765"'&5476"327654'&A5as7XI o" F\p>,R>WL(G&S)=%dQ](4X6GMS;SwD4M@# f%A$0W.n 7#5#5hhhhhhhhnm #53#5676=#hii+ < hh\x&'-75% -vEOO2oa!5!5aFFFF25-5v EOOM%)%#5476767674/&#"#47632#5JZ#J=RU~83? Z72%!BBF :"@S$+F;:hh"rFX3327654'&'"#"327#"'&'&5476767632#"'#"'&547672'"32767676'&SZ  @53acq"cilOrprz_#l%%{tVLn`BLR/"OMeT&B2-/:,!,# HGWxY\f"qad C*kd'be^yfYMHE1AmTSWG?PC"A0T6 %!#3# Mcxhepx')LOo'3!2#32764'&+4'&+3276O(g7:ei89fH"(("HfG"A "34Rp/)PX;=vHW #$0#&'&'"32767673!"'&547632_&6Z=(_;Sm3 `!RjfRK#,sKpO1M *GUmo[Y 3!2#'327654'&+YO!tIl% ل+Ql_=R-8 Ze !!!!!dLRRRZC #!!!]t\LRR,)#'#"'&54767632#&'&#"276=#5;h^WfUQ! __*5G5=HprB1{atrhn Fv1Bb$hNs~T HP](#!2#&574'&#'327654'&+]P) H> qPy& I:x!*b3 (%V` 0GAmRVB 0m7#&'&#"#"'&'332767654/&547632TXm (h) 6)x: IL*X 3uY-,nh@[?o>8 1!aT? 8h9^-"=8L#0%|8"o1Q##5!b]<yRRU3#"'&5332765(]hHiI)]n"*|-A-e:Qu P",!#33ddci !# #333ffhdhWPP # #33sqqov0vc #33]socG !!5!5ELfTRR5R@,#3#ggHH#/7,53#53ggHHS,I3# #IEzyE,PB!5B~22P#'`<䔔*->%#"'&'"'&5476767676=4'&#"#6763232'53276#G W[n+\$^I QgT!7w- R jCH4 1? ?LK#-f&   @ K H%=t )v^ 6 A/6  3632#"'#"327654'&6S9i;%[9Pk;KS'E!,T*H%VlDcM1ZCT2E}4O3F5 #&/"3273#"'&547632T T^#O'kT h+8>)\;Rj:\ad.?-~.iFeM1D+$#5#"'&547632"327654'&J:V <&Y9Ol5U)F$/S'H!'ESpGgK/QR&3z6R2E3($%!3273#"'&547632!654'&#"~+Sf#Th,6?'^X%N'Y#R J@ <X''1)fR @MO6[Z0B/\.?+F367632#4'&#"#FS6Bn'S" *T%SF J'tk7M*:B#7#5SST  ii&3"#"'532765#5FS 4 SS gG %ii: 73##kgQSU޵PD#T'F*36763267632#4'&#"#4'&#"#FM6JY+6?zT?=%TG >%T JL AA bwiQ6%.iW8$-F367632#4'&#"#FM6Li*S;T%T XUF )tkF M*:$2#"'&5476"327654'&9f8O XY$ x7+7E%'B8 %BX?&(7L! c?4J .W?$&*'C',%'#"''7&547'76327'"327654'&:5(<5)380 687,5:(;979 /!7 065391+;9-7575:7)42//7-: !#3##5#535#5333着XUUb3M33M3cBd,3#3#d<<<<oo++BP#54'&#"#"'&'&53327654/&'&54767&547632654/T76 +Rm0G2Bd4 U7@ 7TO ,D2Cc0II>  G+ $^58!s)70U1"E!56,/2&u:Q T333O1%J+<{'?=3m(* ) d(#5!#5h hgggg 8H327673#"'&547632#&'&#"2#"'&'&547676"27654'&6(RG1We6'P1Dx'G2 K wnl jg mkgf\\[_|\[\[f_0rO%FU=U@(M L)Igenl fenl >]]^^_]^]%/M+7!5%#"'4'#"'&54767676=4'"#6723232'5276@", 18J9 D+C/ ;szT>? 04 b33_,%+8>  + g^G3  +#bj 757757bjj5jjYzSSSSyYzSSSS(V w!#5!(FNw.8#58HH!9I#32#&574/3674/#72#"'&'&547676"27654'&F΍ ! O.G4anl jg mkgf\\[_|\[\[E~3+=#*(;? ::genl fenl >]]^^_]^]w.!5.FF2#"'&5476"327654'&/J- <)4H. <(44,7,;)3L-;)4J.9,3.42o ##5#5353!5FFFFFFF!!676?654'&#"#67232C&;:;+3 >W' `?1V:U* /- '+;R/ "B-527654/"#632#"'&53327654'&'&U25 ?` 9GG$0q >? H( 3 4 #%B;LR"VN 8 .\P-3#q<A$  %#"'&5#"'#332765332 !O;h6$SS:U&S-1? ISF N*9)L)0O ####&'&'&54763 9@R@M0IM>U@J(=i pG9W.#5|}}'*;632#"'&'72765&'"'& FB ,?  9 & ' 87?( "= #5767673#c= +>D.)W(/D$!52#"'&5476"327654'&:lO#e T ;7;: b33j%w% _"+~" 4C&]Cabj 57'557'5llall=YzSSSSyYzSSSS=Q #5767673#3#%#533##=c= +>:<:.CC>D.)W'x; 5d=L 1#5767673#3#%!676?654'&#"#67232c= +>:<:&;:;+3 >W' `?1D.)W'N:U* /- '+;R/ " Q-1<?527654/"#632#"'&53327654'&'&%3#%#533##=U25 ?` 9GG$0q >? H( :<:.CC>3 4 #%B;LR"VN 8 .'x; 5d_' #'3327653#"'&54767676=3Z) J=&RU71? ZE72%$ BBF:"@U->F:9hh %!#3# #'McxhepxX`<')L %!#3# 3#Mcxhepxq<')L %!#3# 3#'#McxhepxH_`?QO@')L`` %!#3# 3#"'&#"#6763232Mcxhepx:J@# :;*'')Lkh %]  %!#3# #5!#5McxhepxZh h')Ligggg +%!#3# 2#"'&5476"327654'&Mcxhepxw2 +0 *   ')L+ 1 */ ,   %!#!!!!!!#Ug+n`dRRR(_0*B632#"'&'732765&'"'7&'&'&'&54767632#&'&'"32767673{ FB .D 9 & ' U- maR+_&7X=(`;Rm3 `!!7?( "E N+/o[K#+sKpO0M +GZe !!!!!#'d`<LRRR_Ze !!!!!3#dq<LRRR_Ze !!!!!3#'#d_`?QO@LRRR```Ze !!!!!#5!#5dh hLRRRFgggg#7#']`<'ҔG#73#]Cq<'Ҕ #'3#'#]_`?QO@'Ӗ``  #7#5!#5] h h'ٲgggg#53!2#!327654'&+3YEEN!uIj]"SCC+Ql_;S*2%CL ##3'3#"'&#"#6763232iXe}[:J@# :;*''OTh %] &"&2#"'&5476"327654'&#'a8R[bWo_H8_CaH:bB~`<{&`iMuhk[RfPvS;dOuS8&"&2#"'&5476"327654'&3#a8R[bWo_H8_CaH:bBCq<{&`iMuhk[RfPvS;dOuS8&")2#"'&5476"327654'&3#'#a8R[bWo_H8_CaH:bB_`?QO@{&`iMuhk[RfPvS;dOuS8``&"82#"'&5476"327654'&3#"'&#"#6763232a8R[bWo_H8_CaH:bB:J@# :;*'{&`iMuhk[RfPvS;dOuS8h %] &"&*2#"'&5476"327654'&#5!#5a8R[bWo_H8_CaH:bB|h h{&`iMuhk[RfPvS;dOuS8gggg_" ''7'712212211'?&5476327#"'7&#" 327654QLp_]W(YTp_aMiIbH7}JkH7Yjj[Q_$ajj[ZT@gOuh*[JgOurU3#"'&5332765#'(]hHiI)]n"*|-`<A-e:Qu P",ҔU3#"'&53327653#(]hHiI)]n"*|-q<A-e:Qu P",ҔU3#"'&53327653#'#(]hHiI)]n"*|-_`?QO@A-e:Qu P",Ӗ``U3#"'&5332765#5!#5(]hHiI)]n"*|-h hA-e:Qu P",gggg  #33%3#]soq<cҔ[h7#332#'327654'&+]]Ћ8N5Hd N"½x_1Dn:(RK[ C;1674/&#"#47632"#"'5327454'"+&K&sX]8R=O@"1=!  hJ V(q4S)8_3J'$4K*->B%#"'&'"'&5476767676=4'&#"#6763232'53276#'#G W[n+\$^I QgT!7w- R jCH4 `<1? ?LK#-f&   @ K H%=t )v^ 6 A/f*->B%#"'&'"'&5476767676=4'&#"#6763232'532763##G W[n+\$^I QgT!7w- R jCH4 Uq<1? ?LK#-f&   @ K H%=t )v^ 6 A/f*->E%#"'&'"'&5476767676=4'&#"#6763232'532763#'##G W[n+\$^I QgT!7w- R jCH4 _`?QO@1? ?LK#-f&   @ K H%=t )v^ 6 A/g``*->T%#"'&'"'&5476767676=4'&#"#6763232'532763#"'&#"#6763232#G W[n+\$^I QgT!7w- R jCH4 :J@# :;*'1? ?LK#-f&   @ K H%=t )v^ 6 A/Oh %] *->BF%#"'&'"'&5476767676=4'&#"#6763232'53276#5!#5#G W[n+\$^I QgT!7w- R jCH4 h h1? ?LK#-f&   @ K H%=t )v^ 6 A/Mgggg*->O_%#"'&'"'&5476767676=4'&#"#6763232'532762#"'&5476"327654'&#G W[n+\$^I QgT!7w- R jCH4 q2 +0 *   1? ?LK#-f&   @ K H%=t )v^ 6 A/t+ 1 */ ,  "M;LU%3"'&'&'#"'&54767676=4#"#6763267632!32%5"32767!4'&#"Td32k; ][g+d6jF vgT!7u/1^oB ~+Se![g<=21P&A"-U)v,Ca H$/i%  NM H%=RE P 7pH(Dge0=&&],K$*?632#"'&'732765&'"'7&'&'&547632#&/"3273 C B ,<  7"& ' 9$Z \;Rj:T T^#O'kT[2!2 ?) "G @M1D+Fad.@-z5($(%!3273#"'&547632!654'&#"#'~+Sf#Th,6?'^'']&M )Z'Re-'(,/-%)DAfq ?>WB# (f\0@1X/B.F-367632#4'&#"#3#"'&#"#6763232FM6Li*S;T%T4:J@# :;*' XUF )tkF M*:h %] $#2#"'&5476"327654'&#'9f8OEJGsF$AA0\0@B 4\0@DA!#5#"'&53327653'#'K8Jk)S;U&S`B%#"'&'"'&5476767676=4'&#"#6763232'53276!5#G W[n+\$^I QgT!7w- R jCH4 1? ?LK#-f&   @ K H%=t )v^ 6 A/?FF %!#3# 3327653#"'&Mcxhepx;TM ; V*')LzB99*->L%#"'&'"'&5476767676=4'&#"#6763232'532763327653#"'&#G W[n+\$^I QgT!7w- R jCH4 ;TM ; V*1? ?LK#-f&   @ K H%=t )v^ 6 A/^B993%!#3327#"'&54767# Mcx`H%0!$?F$epx'.;7 - 9:&)L+3T8I%327#"'&'4767&'#"'&5476767676=4'"#6763232'53276HH&*+=/ 9Qan+]#]F uhT 8v- R jCH4 1?#87 - <. CMK#-e'   MM G&=t )v^ 6 A/0##&'&'"32767673!"'&547632'3#_&6Z=(_;Sm3 `!RjfRq<K#,sKpO1M *GUmo[Ɣ $#&/"3273#"'&5476323#T T^#O'kT h+8>)\;Rj:q<\ad.?-~.iFeM1D+B0'&'F0i'&&\F0&#&'&'"32767673!"'&547632'#'373_&6Z=(_;Sm3 `!RjfR_`?QO@K#,sKpO1M *GUmo[1`` '#&/"3273#"'&547632'#'373T T^#O'kT h+8>)\;Rj:_`?QO@\ad.?-~.iFeM1D+``Y 3!2#'327654'&+7#'373YO!tIl% _`?QO@ل+Ql_=R-8 ``$0#5#"'&547632"327654'&3+52'#J:V <&Y9Ol5U)F$/S'H!d097'ESpGgK/QR&3z6R2E3 gL &V#53!2#!327654'&+3YEEN!uIj]"SCC+Ql_;S*2%C-(3##5#"'&5476325#5353"327654'&??JFbv>.Y8Oa@SU)D$0T'H 5;ReKoK/N5LQ1Ev5R1B2Ze !!!!!!5dbLRRR8FF($(%!3273#"'&547632!654'&#"!5~+Sf#Th,6?'^X%N'Y#R;UM ; V* J@ <X''1)fR @MO6[Z0B/\.?+B99,i'*&&XJ,)4#'#"'&54767632#&'&#"276=#53#52'#;h^WfUQ! __*5G5=HprB1Dd;97{atrhn Fv1Bb$hNs~T HPX%N'Y#R%d;77 J@ <X''1)fR @MO6[Z0B/\.?+gX&TS'+'K'!5%53!533##!##5w,]w],,]^,ZZHFLF3#67632#4'&#"##53536Bn'S" *T%S??S5F J'tk7M*:X5L0i',%&#7#5^'٫FF#7#5S  FF*',&B4327#"'&54767#8"  I 3 +'38(  - 14, 4327#"'&54767#7#5* " F -  ST &1 *  - /0+  ii`#7#5^ch'ٺhh^ #T  dr'-,B&1'ML '-&3"#"'5327653#'#FS 4 _`?QO@ gG ]``O #33 #3#52'#]]kx,nd;97qPvNgX&V: 73##3#52'#kgQSd;97U޵PgX&V: 73 #%#k0gS  F !!73#h;Vq<yRҔ?#73#T[q<'ҔP!!3#52'#h;d;97yRgX&V?#3#52'#Td;97'gX&VP!!;+52'#h;d097yRgL &VD1#;+52'#Td097'gL &VP'y/D'yO( 7!!573{(PP]yLzR9M8u 7#573BBS??S3@392@2`L ##3'3#iXe}q<'OTҔF367632#4'&#"#3#FM6Li*S;T%Tq< XUF )tkF M*:L ##33#52'#iXe}d;97'OTgX&VF"367632#4'&#"#3#52'#FM6Li*S;T%Td;97 XUF )tkF M*:H[;|e6336d}GRJ\\deEXLRRexNMLN(%9B%3#"'&'#"'&54763267632!32"327654'&'&!4'&#"$Tf,7|@?8z1B=6gsA ~+Sf]&O(['Q&A"-U)x+]g>W?jXR7pH(D]'5 /Y0A. ],K$](,#!2#&574'&#'327654'&+3#]P) H> qPy& Iq<:x!*b3 (%V` 0GAmRVB $EK367632#3#EM::  H;Tq< _]U+n](3#!2#&574'&#'327654'&+3#52'#]P) H> qPy& Id;97:x!*b3 (%V` 0GAmRVB =gX&VAA367632#3#52'#EM::  H;Td;97 _]U+n qPy& I_`?QO@:x!*b3 (%V` 0GAmRVB ``0O367632##'373EM::  H;T_`?QO@ _]U+nO``0m7;#&'&#"#"'&'332767654/&5476323#TXm (h) 6)x: IL*X 3uY-,nh@[?q<o>8 1!aT? 8h9^-"=8L#0%|8"o1f"04#&#"#"'&53327654/&'&5476323#XfRBPvZ4JX!GT 6NwT1D# q<zT1-F`, /#/.3+]*eI0m'6"&VV/*mV632#"/732765&'"'7&#'&'&7332767654/&547632#&'&#"OFB -B 9 & '  ,u1X 3uY-,nh@[?Xm (h) 6)xG#8 7?( "Eb7C-"=8L#0%|8"o1Bo>8 1!a^@"*M632#"'&'732765&'"'7&'3327654/&'&547632#&#"FB -B 9 & ' X!GT 6NwT1D# XfRBPvA& 7?( "G/#/.3+]*e!T1-FO/ 0m7>#&'&#"#"'&'332767654/&547632'#'373TXm (h) 6)x: IL*X 3uY-,nh@[?_`?QO@o>8 1!aT? 8h9^-"=8L#0%|8"o1і``"07#&#"#"'&53327654/&'&547632'#'373XfRBPvZ4JX!GT 6NwT1D# _`?QO@zT1-F`, /#/.3+]*e``*Q'z7%&zWQ##5!'#'373b]<_`?QO@yRR``A ##327#"'&5#53533+52'#V 'Y GGS5d097 D&FC DgL &VQ##5!b]<yRR#327#"'&5#5353V 'Y GGS D&FC DUi'8A&pXU3#"'&5332765!5(]hHiI)]n"*|-2A-e:Qu P",FFA!#5#"'&53327653'!5K8Jk)S;U&SGIO F )F N*9)FFU'8A&lXU&63#"'&53327652#"'&5476"327654'&(]hHiI)]n"*|-2 +0 *   A-e:Qu P",+ 1 */ ,  A(8!#5#"'&53327653'2#"'&5476"327654'&K8Jk)S;U&S2 +0 *   IO F )F N*9)+ 1 */ ,  U3#"'&53327653#%3#(]hHiI)]n"*|-q<q<A-e:Qu P",ҖA!#5#"'&53327653'3#%3#K8Jk)S;U&Sq<q,6A4  *327#"'&547#5#"'&5332765;- 3` `8Jk)S;U& "4 (  - 6=2IO F )F N*9)'8:'Z '<&&V\  #33%#5!#5]soh hcggggG !!5!5%3#ELf#q<TRR5RҔ !!5!573#EV9q< JIKxIؔG !!5!5%#5ELf;hTRR5Rhh !!5!57#5EV9h JIKxIhhG !!5!5%#'373ELf6_`?QO@TRR5R=`` !!5!57#'373EV9_`?QO@ JIKxIC``3##53547632&#"SFFJ :DYXE5-GG@Opi6 ""327654'&!!632#"'S'E!,T*H%9i;%[9Pk;T2E}4O3F54IVlDcM1ZCp 7327654'&+532#!57537Q)A#.ԥ T=UOO]R>#.T'XrA/4M4qqL ("327654'&'632#"'#57537S'E!,T*H%9i;%[9Pk;K??SBT2E}4O3F5VlDcM1ZC2@2zN3@0&0/547632&#"1#&'&'"32767673!"'&547632?I 3_&6Z=(_;Sm3 `!RjfRY\ O(RK#,sKpO1M *GUmo[.,(632&#"#&/"3273#"'&547632R 3T T^#O'kT h+8>)\;RT>E(Rad.?-~.iFeM1NpGC@6 GDA@ZeG(@&'67632#"'&547!&'&#"!3276/{Rla8R[bWa e?VH e;MH,ĠM4{&`iMuh I-f-/--&C 73#"'5325#!!!Z]X$ D]]t\OQ;RR ,!#"'732767#53767632&#"~K.:M$ENq}-3@#, G Fsg/7 TaFhP,0O~F,9547632&#"#'#"'&54767632#&'&#"276=#5dI 3 ;h^WfUQ! __*5G5=HprB1Y\ O(R{{atrhn Fv1Bb$hNs~T HPQI.{&`iMuhk[I-eGfFE*dA6&HP"2547632&#"3632#"'"327654'&V 3EM;l<&Y'4a@S'E!,T*G#YdE(RO^oGhK! NT2E}4Q2E50mG6@"GV@G 5!!!!5 fmTRRR&!&'#53533#327#"'532765PGGSVV r 4 CDD&` G !3#327#"'&5#53547632&#"VV 'Y GGJ :^RD&FC DYXE&Q %327#"'&5##5!bD v]]<;QFMyRRY'?'Y'@''@,GP'-,/P&'M,/D&w'MOLn'-1L&k'M1F&'M,Q'$*&pD"',&&'2$&nRU'8A&oXU'qCA9&qm|UN'vjA'vUP'kA'pUN'CjA'CI(H)'qC*9&ql|'q&*&qn\ S'q"M'q,'*&&ZJO'.'N&#'2$#&TR&#S'q$#&qk&&FY'='Y']''],G,'v*&'vJL'C1F&CNQu'v*'v 'v"M'v='v 'v'j$&,Dn'$0&nDe'p(&1Hse'(4&rH<',1&',&.'2&)R'2,&jR'5lA&U"'`5A&U'8&*X'8.&lX0m7B#&'&#"#"'&'332767654/&5476323#52'#TXm (h) 6)x: IL*X 3uY-,nh@[?d;97o>8 1!aT? 8h9^-"=8L#0%|8"o1gX&V"0;#&#"#"'&53327654/&'&5476323#52'#XfRBPvZ4JX!GT 6NwT1D# d;97zT1-F`, /#/.3+]*e)gX&VQ##5!3#52'#b]<s:&5J&7)8Q"J/PB96 VTko;&Y7B`<-`0D) 6  .547632&#"#3632#"'#"327654'&6J :SS9i;%[9Pk;KS'E!,T*H% YXE5RGVlDcM1ZCT2E}4O3F5F&L."327654'&#"'&5476323327#"5 U)F$/S'H!r:V <&Y9Ol5S*  R&3z6R2E3xSpGgK/Q8 GmF."327654'&7#5#"'&547632547632&#" U)F$/S'H!J:V <&Y9Ol5J :R&3z6R2E3ESpGgK/QXE(GH)@(H)"G@"&@7G547632&#"'3#"'&'33276="'&'&547632'"327654'&V 3MM)0m 2U$;Q#;IS=BU9Qb>X%N'Y#RYdE(RRJ@ <X''1)fR @MO6[Z0B/\.?+&JF3 K, F %547632&#"#367632#4'&#"#FJ :SS6Bn'S" *T%S YXE5RHF J'tk7M*:F&-4'&#"#47632&#"67632"#"'53276" *T%SJ :6Bn' 4 L7M*:eXE5F J'gG #5533##5#5TSPPSKii_HHB 327#"'&5 'Y  U&FC ^ D&3327#"'&DT  mF5 G`F P@ F8 (#"'&'"'&53327653327653M6J!Y+6?,zT?>%TG >%TL AA bQ8$-IW8$-IF&:%3#"'53276536763267632#4'&#"#4'&#"#Tr 4 M6JY+6?zT?=%TG >%T` G XJL AA bwiQ6%.iW8$-&'73#"'532765367632#4'&#"#FTr 4 M6Li*S;T%T` G XXUF )tkF M*:F&@'%327#"'&5367632#4'&#"#  M6Li*S;T%T5 G`M,XUF )tkF M*:$!2#"'&5476&'&#"!32769f8O7j B@"#"=336? JL/ Ocj nm I#')ЇKCUK&{j-&Y02#"'&5476    / " " f'&q' !'#'B)'.'L2_&B!#'!#3&'jTNffHh = Z%VD&Jg#,%#!!2'4'&'&+32764'&+32g> < ; U%M3 #F?Hm*^; 0P$`0 5E bR6!#!6|`x !&"#3&'&'Z8E7f   &AI\Pf )!!!!!fXtTT#Y )567!5!!Yp+pDX7TTAq !#!#3!3q^^^t^R&-$(#"'&'&547632327654/&#"!5!j]ZKP01lZ`hV@^BY6H9P]fY$%OM}fUV\L7>YN!AkRE3#3^^J !##33~r^^bxjrb !#0#3j %ffsMWh@!###373\V\&XbE%r8l !##33l`\bxZ22Ad !5!!5!!5!S9gI"iRRpR2#47632#"'&7327654'&'&#"2oZXNM21j^^C`V@^Bf7R:RcR%&PNzcW|ZI6=WK&@P!#!#!^^0iNp"+#!24'&+3276p^4CbR> :d[V(^!5'5!!!^p%t V#RR&&'_###5!_^8ijR #367\p>n*.'g)##5"'&547635324'&'676RR|S|RR]QsQSG[\.;p5 o6[.XzKMGGMJ{QEPP[Mjp8c T2 P#+u;$!##36767673tpm  x f$gH 4#+#5#"'&'&5;3327657((@ J^i0 FZC#<VqZdX25  9qVg%; 8H*)476323!567654'&#"!53&'&/W[nMo \./SAa{A.s_cg0H)+[ IM$JMZLJ&[@8&B(_&3N0G"2"'&=&5#"'&5476763533274'&#"32763 )'2!a#*o3H +t)"Iz t ) 5Ch FN[ ECB7~!2:2%#"'&'#476763227654'&+5327654'&#"Q4IV1 V# 5V-`i'/L2*^ "!0;)w:%( p4/b'3z"\G#JL 8)jS: #5&#"'472 V  */vF4~%*%#"'&547632'5!!'";2767654'&x5QiDA& 8LZ*_/6 R!5DC{7 HH)M5T+7"(\z)'-%#"547&5476732#&'&#";#"32767j*$'654'&#"'&54767#5!&L" W\M/:dOH.+4K*7aE!. =2q3%HXXr <,(%#"/5'&'#&'&'&#"7632327,0!2 X [ `   !5   0@6W0$E R  'Yf N8"'&'#3327676=3#5 A' XX = #!!VP': * x#= 7j>=  #367R\s r4,Y <>;'67654'&+"'&7456767&'&54767#5!#";#"32'J 9;"25=K 4 dt2"[1Rn`5M&/JE'=^Q  N+>U// ?$F. FF8%'L@D+M" P""'&54762'27654'&#"="DCCD]=Xe$I!.e$*( uAZDCCDI0Jd*8/g*5b135i%#"'&5##'!#32767i07^F(@  <P>FF' 98$#"'#476324'&#"3276"+Gc5XGGbA'Z,,BC),++BA-,b.: G֊>>jAa`222/ed1105J.#4'&#"'67654'&#&'&/&'&547672[S W+Q"ZW0ZHZ0N"Lx>)DbN(Bh.  0,n 48 5hS:uQ6"N""'&547632!#'27654'&#"="DCk@]=Xe$I!.e$*( uAZDCRRfI0Jd*8/g*5b13*#327#"'&'&5#5!   #!P / O .>2D(%#"'&'&5332767453 /#Y_#/ X $=<# Xa31c@b [ .8 $/7;32+#5#"'&'&547674'&+3276E0BXN=l7M XI b!*^E+<_.[6&]IkM$d"4.XD<[e2L,,= +"/#&'&##5723327=B1ah  8:!`à YhN1  *8l%##5"'&533327653l(1V& ZD!7Vq Z֩% Ƒ '0y!TN#9$7%27654'7#"'#"'&5476767367676=3ZlP3$c "0`0.bu03PE H) T ?zu)jJ@<ZZr;Mce0E^(0  $$&jB(&j`N"&@H(&5N$'RZe'C(OZ !!!!!#5!#5dh hLRRRFggggl !+536754'###5!#32& #?Qc4B]c,G" B 8 A5PPK%,ZC 3#!!3#]tq<R0$32767673!"'&547632#&'&'"!b8Jm3 `!RjfR+_&6Z~= lLG'M *GUmo[K#,p'2R0m6d,'j,-S%!##527645!36#74'&+3276R =89fzG"A "6)^_'j*?&#Oo%O83#!!]tR"y %!!67645!3#5!#5KU[PPR5k'XqчOZ !!!!!dLRRR? # 333 ##nEt]tEv]Dwb44D0m:5327654'&#"#67632#"'&'332767654'&#XI4!H'4Xz#.T'O %#!332327654'&+#oT=U] =Q)A#.m^rA/>#.T'h'Op %#!332327654'&+oT=U] =Q)A#.rA/>#.T'0#!5!&'&#"#632# 33276Hlf/<[2&_+RfjR!` )f @'LR;+#K[omU!G*R oBS+##3367632#"'&"327654/&'v^]yLhW;ROXZ=D=$f8Q>&m ,LT2biCZ|IgM*xHhJ o #"'&'4763!##";n3 89fI]A "" A::!(X;=':M#$76$#*D$ 0632#"'&576?67653"327654'&u,o9f8OE<fXo",z59SZ4JX!GU'#L75Tw I%2G$,P`, /#2%F 33##FTlSm ccF 33##3327653#"'&FTlSm?;TM ; V* ccB99F 73#'#`jS  F !###5276ST%d<  aPIF$ 33###FhhT2T FkCF 3353#5##FTTTT $RF !###FTT @F&"3632#"'"327654'&FM;l<&Y'4a@S'E!,T*G#O^oGhK! NT2E}4Q2E5F< !###<tT L@& \=&R"2B632#"'&'##"'&54763253"327654/%"327654'&-d0`%.E.S*1 ' h,<^1S_ T^ Wfa^ ^^=TD+>3@A^t&1$ h*6%~"+p'1 [F$ 33333#5FTT=F @4xF 3;53#5#"'&5FT+TTN* )2*Fn %33!333TTTL @F )333333#dTTTnA[G':? י\0@0X/B.  7&'&5476;#5###";n )(JTEgw. & V!>,+" (&CtH(&j{H\+"##53533#67632'5676754'&FX$STTS5Co'kD; /4I" R)5T@EE@EJ'S6(0Ec7Fm !##3#F'Tq< L@Ȕ#%#3273#"'&547632#&/"3XR kT h+8>)\;Rj:T T^# % ~.iFeM1D+Fac"VBL &j&MF0 .32+##5276=3276?4/&+q-6+7 %f< S|U)" | 7  H+Z*PP@" 7F1 )32+5##33533276?4/&+q-6+7TTT|U)" |67  H+ @" 7!"##53533#67632#4'&FX$STTS5Co'R" R)5T@EE@EJ'\7: 73 #%#73#k0gSq<  F 33###'FTbSc`< ccȔ&&S\F !#5#333:FTTxx @Oo %#!3364'&+3276o89f]=VG"A "X;=j*=W #$F 2#!327654/&+x ))IT. &  L%>,, @*[i36& SZC93#!53!]]t`Fmu353##FTT i@ZC3#!!]tRFm !##F'T L@ZC3#!!]tRFm !##F'T L@? # 333 ##nEx]xEn]Dwb44D3 %# 35373 #%#wg0kSk0gS0m:5327654'&#"#67632#"'&'332767654'&#XI4!H'4XzE<fXo",z59SZ4JX!GU'#L75Tw I%2G$,P`, /#2%O 3#33 #]]kxdn;D: 73 #%#k0gS  O 3#33 #]]kxdn;D: 73 #%#k0gS  O 3#33 #]]kxdn;D: 73 #%#k0gS  O 3#33 #]]kxdn;D: 73 #%#k0gS  S !#3!3#&^]v^^L;'F 3353#5##FTTTT S !#!#3!!!^^]vL;RF !#5##335!#TTT' LS!#!#&^1^y'F !###FTT @0&F0&FQ7< !###<tT L@ <  !#33[^^ W <  !#33[^^ W; [Sy %33#5!3&^\P^RqчyF8 33333#5FTTQF @4xS* !"'&53!3#N ]]].= ZY'E 3353#5#"'&5ETTT@ !S* !"'&53!3#N ]]].= ZY'E 3353#5#"'&5ETTT@ !S* !2#!#3N ]]]= YE !#5##332TTT@ !& (H'FHTM(Hd,?'Tn,'O 3#33 #]]kxdn;D: 73 #%#k0gS  S !#3!3#&^]v^^L;'F 3353#5##FTTTT S* !"'&53!3#N ]]].= ZY'E 3353#5#"'&5ETTT@ !'h*&gh'jh*&jj "MOZ'm('&N(H)&'j(&jv?h'jVn,'j0mh'jo"&jP0m:5327654'&#"#67632#"'&'332767654'&#XI4!H'4XzE<fXo",z59SZ4JX!GU'#L75Tw I%2G$,P`, /#2%OG'qpFz&qrOh'jpF&jt&h'jv$&jn&2$R&h'j $&jn0h'j&j1kG'q{&z&qTkh'j{&&jVk'{&&\O9h'jF&jXOh'jFl'jO%#"'&'&5327653CE<<= ^!+M0/D)aWE#(0X)*7?A%275#"476;54'&'#"'#"#47676;23#+"'"'"'&'&T!,F]4/l,*> z_ 0B,66h5Q   YN 1"1,BT ('p P4IKNx9 L)C~)"'&=47672;533##/"2767670@(5\c`h2; +'%.IH  R3H~3.dKr<Wk<. =?q!"#367632#54'&'&'&_+ ^b b&eC> ^ +DB& D9*k4 _ %4(3t,4-)KL72'&'"#&'&'%6, && 7t,g.-"83PAO2&'"'&/47672676=4'&'&#"'5476762767&'&#"LG.))+(/I/I-A "R +B0"g  7&_^0>'`>X?]LJ(%: "(&&e 1*bAV,z* 8 2=BiF   " O!#4'&'"#547676323+(;D! _*l!=aS ;2/QY /4@/q")476767&'7672/&'"qi- /<; =Bz@0o# X=u&/%/۵("=G7?C7-BHEy5CKcj-#"'&'&53327653j9 @eh?@_--g|'|E "'(@Ibb0/[,^1*A%#"'"'&'&'&5327654'&+5327674'&#"#4767632*eAZIC];<('<<4502)(u F`22Ow<5  v;&4), HMF\((('95MO!!  +( 33276=3#"'&'&'' "+M0/D)acE#(0X)*7BG*%56767676=4'&'&'"547632n 660)&)AN2_@KsG#&7)0iU%87ZUC%/ 9"C@HSDK*%tN9<# (J}$%#"#54767632#4'&'_^9%@ei>M_,F2)a*+E#(0X)*7b1p*P32674'&'&'&#'4'!#533276='&'&#'"'"'547676;2232IX0 dL)#,=5pSEYZZZ4! \FgP I 0'#8 T"'{s 2"8"1%CVGJ; d767*& 4YD#:h 560..|V#lJ%34'&'"#4767632}KO]--gl+ ^9%@ei>MP0/D)acE#(0X)*7O3#"'&'&532765#_2'>i= ^!+k4 _Z %4(3edt,4-)K^-g7"#"'&5727654/&'&'&'47632&Hx" rt+= /j&*8 Y c1TX%e@WC [ @'--64J $3)G:2!9l6#`#& J}#54'&'"#4767632}_--gl+ ^9%@ei>M&x0/D)acE#(0X)*7<9;P2#"'&'32767654'&/"'6767&'&'4767627654'&'&82 1$/p #xE=]#!&"%% !$" h#j"46`a #- -!!$!ظL(  D %;;4S?7a8 !A="" 5,G$*) !<. 0# L_33##L__Pu*#*54767675332#5&'&'&'&76767674'&'*CAF<)^"ADCBBDA$^KB 2C_z9,2 ")j|FC77 FF~GE// !%D) d1g#76 $V-"'&'!!#5#534767632'3254'&'"sA'& }]WWE5P5 t.A)00-.?.NyyND/@'(#6>$R+70""'&'4767232654'&#"aQ`^a),4o?EGhks:FdJH wcfdp$SnkVh.gJKI%EE' A#3276=4'&%375#'"&'&547676;32#"'&'&'&533'"'&..F+)m"f & )`_.9 O3R.:7%  ] (%G-"4"A7E#8H&%@ /ن)#VeC( #) p5 53'65=^.5mfPA$"NL73X)hLI."'67676;27+t,  "),0$(N$/  0-&+G#'3GqvGS,"4'&'"#56767632#"53276!$D/ $&?J?Z, %+'&5I 0DZ& A("'332765332767453#5#"'X6$%XH "!8XO!Gt= dE $$Q-i %k  I9[[J-%#54'&'&#"!!#3632X 7G' JXO,[rP <!#5#"'&'&'&'7!3276=3O:k\. YQ "6+)WJU4*8\M #$da*/B,747632533##"'&'&'&27674'&#"*M7S>"" Rc)U l9 H#>(a 7L76p:A l ##Y/72t&.i6^e %/#33#>KVJwM?0 #4'&'&#"!%3632X 5B'H_O-0F*476;533#+'"'"'&'&'&%#"27676'&0B8UYbbi0C& V^zI<# xI=D>  8վZ753&4*B33632#4'&#"BX>]XX D(G!"Ip 4 $<<0#3W}S|B."##3327653#5"'&'&'&760UU $8))XO8mW0wL $"eJT1%<2+ +@"'&5476?67637&'&'473#'2767674'&'&#" B 0.AU3;)f H9PT#x s ~AQ:(' (=64( @T!tE6FeV@ ^*$G-'"'&'&'332767653X=_s*XnG&XEN)L ~7 %;B33632#4'&#"BX>]XX D(G!"Ip 4 $<(2I#5#"'&'&547676767674'&'&'47322765474'&'&+"La*M" >>23  #DS*$)H8C*Z"%/  '&&l= e6C?!">EL $ 02;*1  1x8 \.,  67'/#4'"#3676323Q[%VR))DK#$d,[S S3 )'2+&!&'476767'767&'&'&'&# ='&E@1>fh$1 6(#8\u\\1@2zUkX %NfZKI0476;2'"#5"#"'&53276754'&'&'&d@ T( 1, T8#CT/V Gz$%J D 1.b8$B"Tp !.27653#"'7 ,X60*3(!݀# KI-!#5"/&/47676;"2727673P (&(0 -HAf! . %(WS"  .!A> *='  9Z35//4'&#"'672;67#"/"'&'&'&'47676?6=) 3.+;VO3'("f\ F<   #m"% B4#8:I@0<@;*0&&? ;/!8E#4'&'&#"#3632X 3E( XO,) VG)=&EC W c '$4 )D:*U56  ^\ A+("'332765332767453##"'X6$%XH "!8XO!Gt= dE $$Q-i %k  #9[[&/7V6763237373#"'&'476767654/&'&574747"6?6767654'4'&'&'&-T.+!X !u7#p \HG (%*'$ \ N !.&N(.m)wg,!#?>-'(&#L HS$#:Z !49; 7P)654'&'"#36323'5276.(H'XO"7 "CMX, *!+%rQM a@!5#"'&'&'&5332767653=hF6  X 8H&XLX* )-%BM66 "CG-D"'&'&'3327676533=_s*XnG&XXEN)LD~7 %;KI@5#4'&'&#"#5#"'&'&'&5332767653632@X 7H' T=hG6  X 8F'U<))*+;:*(K7J??w3QJ - OM UDo@^g.///c_010+L3#~E>+2"52#4'&/#"##"'&'&53327676736qM5  X 5E' U=gG6 "X :I& T<.)(* L55 "CX+ ,hBJ97 FX/7/%"'!!#5#5336763274/"#"27276UP25VddQ#">>8-Hf\$? !8)U "A:UU:;At;Pc;5 0/Q`1`#2!47632"'&7327654'&'"2(1jDEP7FmCCZ,*CA+,,*BA,*9GE{C FDe0112f_2120*/o'0847672732##5#'"/&'&533"'&327654#'35"Y}r=*d2=-W( -'(N;87%_ HbDnߗ@  !;Jn#$Fi&0E >F!7275335"'&'&53VP%'-(4VCDR/%9`UZ5353Zdddee^dd & %"'727&AU*Z.&!'0"L G3#53#GGGGFGO 3#73#3#73#53#GGGG@FFFFFF3>Wd 3#GGGF3#FGGGn G3#GGG:FX##5&76767'367676753#0 W9 &f/ W: &fE > %TP =$QM :6X%&'&'&'&'#533!5 "j^1 () JL'6 'L  4= LLX%#73'&'&'&'&'&'4#BuQ > RWF"2X˧. L*R "&X#!5!W  LL?:X#&'&'&/&'"'#5!3:W  &9 S2#! Wzt7 L 2Bw>X33>WX'(X##5!WW  LL?;X#&'&'&/&'"'##!2;W  &9 W@? Qzt7 X!)=:XD"5632#"'&'&'&'336767674767475&'&'&/&'&: -*&HL$"  #MHIM!$ W  2 +#    3  R+1AG,!++!4@z8 "18:X3:WWX#&8X#&'&'&/&'"'#53W  &9 S2#! z<7 L 2B9X-3#536767676767075&'&'&'&'#53㪤N    "j_7 ()  "5L   .6 'L  4= E/E%!%#47676767675!53!W.[W.*aEx1+$%)V 5ᕙ<9 $$?<X )32&'&'&'#;UT'3W) 9GX*?5 +3' @0:X##532!534'&/&#:X:NM5U-#$8  L!A-;L+&%>8X3>W 3FX)53&'&'&/&'4F  4 IMUL(7L+.=9XB!"'&'&'4'!2'6767674767475&'&'&/&'"'#;IM!(@B $"  #MH+#    &9  2 +!:9z"1AG,!+L "18 8$X73767676?367xYs?  W %AOnC .#XJ)*LO98 X)32#&'&'&/&'"'#3/&'&'&'9@? #! W  &9 yB"(G$+X!2B<7 4 L$7 ?X93#53276767675&'&'&'"+3/&'&'4'53287 , ,;5 XB"(G%+LB / $ #aL<9* 4 L$: 5?&= !* 8X676767670753#3.  W !"&,WcT *70"/63X67676767670753!5!3<.   W !"&FdU *70" L >8&X%#5367677!5!#,>7h o 0W!L*!2LG( Iur%X#&'&'&/&'"'#53W  &9 T2#! zt7 L 2B;X:72;7676767453#&'&'&'&7336767676=3' =$/R' 6!W^ @GRG?C-$Wc' W 3R52  4&(RfT#?:>R  +#3#{X.6+532767676=#5!#&'&'&'&'&/  % AT2)<0! W  &;  ?+L,)LH2@t8  87/?O_o%2#"'&547632#"'&54763"327654'&'2#"'&547632#"'&54763"327654'&%2"'&547632"'&54763"327654'&'2#"'&547632#"'&54763"327654'&@"! "! $! $" " ! " ! $! $" #  #  " #! $! $! $! %! q " " " "" #! %" "" "" #! %" !" !! # $ " " " "" #! %4c72#"'&5476k" !  " "22#"'&5476i" !  " "3d/?O_72#"'&547632#"'&54763"327654'&'2#"'&547632#"'&54763"327654'&j$ ! $ ! $! %! " ! " ! $! $" " " " "" #! %" "" "" #! %,p/?O_2#"'&547632#"'&54763"327654'&'2#"'&547632#"'&54763"327654'&d" ! " ! $! $" " " " " # $"  " " " "" #! % " " " " "! %jq/?O_%2#"'&547632#"'&54763"327654'&'2#"'&547632#"'&54763"327654'&R"! "! $! $" " ! " ! $! $" p " " " "" #! % " " " "" #! %jq/?O_%2#"'&547632#"'&54763"327654'&'2#"'&547632#"'&54763"327654'&R"! "! $! $" " ! " ! $! $"  " " " "" #! %p " " " "" #! %jp/?O_%2#"'&547632#"'&54763"327654'&2#"'&547632#"'&54763"327654'&R"! "! $! $" " ! " ! $! $" p " " " "" #! %n " " " "" #! %Ta5/?O_72#"'&547632#"'&54763"327654'&'2#"'&547632#"'&54763"327654'&"" "" # $! $ ! $ ! $ $!  # " # " " % " " " "" "! %W9p/?O_2#"'&547632#"'&54763"327654'&'2#"'&547632#"'&54763"327654'&"# "# $ $" $ ! $ ! " %!  " " " "" $! % " " " " "! % $/?O_o2"'&547632"'&54763"327654'&2#"'&547632#"'&54763"327654'&2#"'&547632#"'&54763"327654'&'2#"'&547632#"'&54763"327654'&7!5y#  #  " #! " ! " ! $! $" K"! "! $! $" "! "! $! $" " !" !! # $" "" "" #! % " " " "" #! %" "" "" #! %\\$ /32#"'&547632#"'&54763"327654'&7!5 $! $! $! $! d " " " "" #! %\\m7'7702M~Y-$/?O_cgw2"'&547632"'&54763"327654'&2#"'&5476%2#"'&54762#"'&5476#3!52#"'&5476%2#"'&54762#"'&5476#3!5"327654'&%"327654'&"327654'&#!!#  #  " #! " " " ! " ! ee" " " ! " ! ee# $! $! $" $! $" e3 " !" !! # $" " "." "4\\" " "." "4\\! #" $" #! %." #! %4(\#wz!##67676=474'&/&'3&3!,S9.U3 N;OA8-*K.Z2%)DC7O9t2##6?676'&'&'&'33  S!U #)%#@.&6/"%@# )5!5!5!ZXa""'&547'!5!73#""'&5'73( tmM  d'f #! Z-=Z# $} a%"'&547'!537373#""'&5'73( tmb(M  d'f #! Z-=Z# $} kq#537!5!754'4yy('(;=S5M;Rh>6<(6$+?&5%f?1G>Qh=0G=3!&<'4&9(V\s2'6767&'&5476; 0 : $Gss1^*{5-4DO"!#'#'!53547O$JzppssZ\r_ '!5!73#_J.DZ,>Z__ '!5!73_JZ,>%'!5!5jieO`ZpS/?AQo2#"'&54762#"'&547632#"'&5476'2#"'&5476727654'&#"%35'###"'&'&54763" ! U" ! "! U" ! /& +"/j[ 'K E6 B.Dd> " "" "" "" "O5 %E+9'$K$?ObD,EX!V<"$-v@-a(%#654#"%632Z\@DtaE\I[ؕWHO]qZU;Rnp)5!7pHfUJZCkv )##5!5#=SO^Xk?ks'R D1Z)m+B#B@)5!'#"'&'&54?'032 >%C8/ -w< FZJc*3 $7 @##"'!327654'&'H?) 8C%>  )FG @3*cN& Z31 $ +!5!"'&'&'&547;635'#"'&'i) I]  +D< i 8"7<IZT| +_A[ >O] !7W ' &)"'&'&'#53!5#& "F AdGk`#53!5!754'4{{('(;=RZxSZS!#"'!5!'#5!3/\  ;;ZZYck%327676&'"#"'&54767kn*1?>((46U15[GJ*K 9& OIhg^l''7'77''7' &%Y(,$"5'=d+jA!5 77''7'77m &$Y(+#"5(>j+jA!5O 3#3#,####s /'K7K{ //K7Kq!2#"'&5476'2#"'&5476$! ""  " "\# " '7''7'78!8 8KK7R^_`]_g 77'7'!9 8 8KK7^_`]_ 3#'3#'r####K //|KiK}@K[ 535#53#3HHIIL"< <"D 535#53#3% HHII."< <"Ov2#"'&5476%>"! B " "C{2#"'&5476/537    /++    U y!;9=2"'&54767#'7%y  s.++-     w";8v2#"'&5476>"! " "(fq#53%qbb]>v2#"'&5476>"! " "(Ov2#"'&5476%>"! B " "Cx!2#"'&547672#"'&5476@$! "! V " "" "w!2#"'&547672#"'&5476%?"# ""  " " # "7/12#"'&547632#"'&5476'2#"'&5476" ! "! U"! t" "" "" "/147632#"'&747632#"'&2#"'&5476% $" " $"","! n! &  ! &  N " " %N,`H%' RHfS7!#7777''7''7''7''7'$"$$#"  ; ; ;> ? ? @ @ ( D C C C B @ B A  #.9GQ\jt533##'#7472"'&5472"'&274&#""'4632'#"'&547632'43#""'4632'#"'&547632'43#"4'"276'4'"27654'&#"36V'SR'U    r  * r  *  PO%QQQ   z  cz  cd  |,0'7#"'&'&5432327671///:%57  .E%--.d#6 F#p'7*333O333)D23275#53#'5'&'#"'&'&54323254'&#"'676367654#"'6D7+&/01G-&9>&+R[>0._"<#23,!v/&%('.((Y. 9!d 8* Z  = ")5H23275#5!#'#'5'&'#"'&'&54323254'&#"'676367654#"'6D7+&/01E--&9>&+R[>0._"<#23,!v/&%('.((Y.yY. 9!d 8* Z  = "77"'&5476;5#5!##"7632''&5432327654'&0%7cd% <)'Qm"v6 )) .$$)/A((g6 ;' al", K7"'&5476;5#53&'47632&#"3##"7632''&5432327654'&0%7c2--( !* &nd% <)'Qm"v6 )) .$$)/A(A78 1$E& 12(g6 ;' al",  14'&+5!##"'&'&5432327654'&#"'67636?4#˞A)G=&+Q]=/.B <#12/-H2(()4*&G:$e  8)!4 F4'&'&+5!!632'654#"#"'&'&5432327654'&#"'67636C6 D*3?;$ 8?9:, >&,R]=0.B =#226.H3 ((,1)-1$': F98):$e  7*!4>!65432327#"'&54767&'&''5'75&#"'6325!5!T!5 mT"%)F/7`-G]? EDL '-    /1'& * 0.h v5*! ("'654/&=#5!##/32=#0F*D+ 3K"67J&  }$(($ '  ,3##/32=#'654/&=#5!&+'32\MD+ 3K"67 0F*6T.8%23+G($ '  &  }$(M0P)5p]#"'&'&54323276723275#5!#'#'5'&'#"'&'&54323254'&#"'676367654#"'6*:%57  .E%D7+&/01E--&9>&+R[>0._"<#23,!v/&%M#6 F#('.((Y.yY. 9!d 8* Z  = ")5R23275#5!&+'323#'#'5'&'#"'&'&54323254'&#"'676367654#"'6D7+&/011Q/8%22,B2ME--&9>&+R[>0._"<#23,!v/&%('.(M0IZ(Y.yY. 9!d 8* Z  = ")5g23275#5!&'&'&547632&'&/"54323#'#'5'&'#"'&'&54323254'&#"'676367654#"'6D7+&/01-29$ Ac! !((LE--&9>&+R[>0._"<#23,!v/&%('.(5 *fH 542(Y.yY. 9!d 8* Z  = "[-:!67632'67654'&#"'5#"'&5476325!5!5&#"32[1/$* # ! !>-0D<(:R-[4@* ) P+ ;)&5+  & '%8.q/%: ?(H"- t!<#'5'&'&'&7632676=#5!5&#"325#"'&'&76325!32t=-k[T_S tj2Dba9>.=U-?#%G.! =*)qY.;YMD&  (#5?E65'5&0!y7!:$#'##"/&54;5#5!F-63yY.y(8 (2#'5#"'&547&'&547#5!5!"&#"3276F-AY/0=2, 2sA"C:&?FJ Y.8":%% ( 6 584'74'&#"'&5476;5!5!##"32#"'&54323276-..;5Da$1k&1&G87K(u e~D&&$- >2A((g>$"O  {( #'5#"'&547#5!#3275!5! F-AKD1%Xf-9CUg Y.z22%,((%;8(G<I##"547&'&547632&#"3273#"32767&'&547675!5!"654'G5_UX%0 :)#.:8 6 KC()aT 401?|G)&*-Y;TA:^&%/  >(7' J %'6T( 17)%#'5##"'&'&76323254'&'7!5!5!)D-T14AF 9,(9%)>H)Y.K,1 8+.%&b}G u "(2$25.$((?&4##"'&'&5476767654'&#!5!4#"3276%H*5?H: df  sn]0+0?]+.L'9/, J( 2(Y 6#'-A 0%4'&#"'&5476;5!5!##"32#"'&543232765Dc$1 s%(.I88J )u f~> p- >1A((g>#!M  {%$2##"&547632#"'&5476;5!5!4'&#"3276rW= :E#B dGJ%Kk% Q KZ<6 )J-K DA^%"_(+G%*#'##"'&=#5!5#32E-}0.0%)- CY.y, $( #'5#"#&'&'&76;5!5!F-@}-P@ Y.?R}X2($> ](+$&0#'5#"'&'67&'&5476323275#534#"76$F->auF E92(+DO$^%#H P\`KI?! Y.2<E2!:3  A(eE<')7476;5!5!##"723&5476'#"'&*Q!bcyT 639,# DI TLS?U((|/-!! , ps26+/=#'5#"'&547&'&76323&#"3275#534'&#"3276E-,RY.0 / 5 )$ "(E ( #'5##"/&54;5#5!5#F-/ (psY.// (߷$#'5#"'&5654/#5!5#3276F-.F[8&! s+(*+'_+Y.(3$00 (%/ !  ?#'&54323276=#5!?pJ"8 ?K C)(?7'7'4323276=#5!#'&333& ?pJ"82333)((K C+/#'5&#"'67&'&#"#"'&5476326325!5!+F-% 9)+: ^+ 7C<+; H+Y./0!*9N  reF ?.z(0!/:7"'&547632675!5!#'&'%4/#"3276'&#"327J,H$,]&QN) ?O!) <"[B Tl,B0='2@86r((s1!Q' $Q5 'c<+6i+ 3%#'5#"'&5476325!5!5&'&#"32F-.B D0$E'*`.s& -8!<DY.{& 2%,7@(- !=Q44#"7236%!#'#''&'&5432767&'&547#3e-:.3QE-10/G) 7(4[A"e?f 4(Y.y"C:86 (5' 03"#'5#"'&=#5!5#54/3276F-A 1.$)s (> Y.*"!(ʢ5 %7276=#5!#'5#"''&5432%5#32 F-6H,0"9  4C) ((Y. +" B)*8##"632#"4327654#"&'&547&'&5476;5!5!Y!/J-$ bG+1tqMA  :h()#& "$ -- 2!% 6.:(& $-A(sT'7333Z333-0p'#"#"'&'&54323254'&'&5476;p-T-"$:O2  ( ]-F-+%E,$1"'<  P)0;'$#'#53E-DY.y(b47632&'&#"3#'#53& ?!%w0]**INF-EC 2 zB &(Y.y(?~#'#53&'&#"#&5476323E-DE 3$(Q!!$:Y: OY.y(A,4 75@P,5}O#"'7327654'&#"'632arpm7#  .6/,(a;lY  "$!)E47632#'&#"326;'&'&-,/0#)' $ 5  "P/ 'x"     ~&'&'&54763"327 *Q-C!0V ) 0r (/ %  0p#"'&'&5432327670:%57  .E%M#6 F# #&+'32F&T.8%23+G͆M0P#&'&''&547632&'&'&#"5432>*2.$ Ac!!()7 *fH 543p#"'&'&543232767#'#53:%57  .E%E-DM#6 F#Y.y(`#'#53&+'323E-DBQ/8%22,B2MY.y(M0IZp&#'#53&'&'&547632&'&'&#"54323E-D>29$ Ac!!((LY.y(5 *fH 542hO #&'&+'3$-=;+#QKc4,*&d(DW(iw'7#"'&'&5432327672#"'&'#"'#"'&'&5432327654'&#"'676367654#"'632332?64#"327670---.%89  4'p8"$ +>/ CT2@&+R\>1/E">#112!y+"&%ND8 &I)8-H+r4+$ )0%%'W!5 1%Z48< &3 L :!c7*"5  = "'.)1\1yQ2% . s#7 ;&>dbk%#"'&547632'"327654'&1+2W$8(-]#D 7A!>-(=&=, <.2< /K *#"'254/7&'&54763274'&#"67+.`D(;7&iV I4  )`1 "= 7&(9i#67$2'#"'&=47632327654'&#"'6*M,v{ (  7/ G<G@)5`:"201%!!*%'&'&5476327654+'3254'&+'32Z N!S:$51H'-=, BH-] f @)B'E,(1#(+*/&#"'&54?'774/3276O&D !5()%5 T#:7U98++  "2 ,4+ q!'#"'&'&7673254'&547632X#3^. EK- $H *2<!*BSD 6c5'"'&'&547&'&5476;#";#"3254'&5432!S;A 1!2""' 9s0"$,uD '18(G'.Q & N&!+%#"'&543232767#"'&547632#4#"32G(8qND3=lH!?%*R$.R"FCr4v##vd|E# +3 H#D! 5f7327#"'&547P"W<""E&$T82 ?\81*3" )#"5254/&5476324/#"3276#* 8D+)O$(!N+q8.15.6$4"((L7 [((DW(iw'7#"'&'&5432327672#"'&'#"'#"'&'&5432327654'&#"'676367654#"'632332?64#"327670---.%89  4'p8"$ +>/ CT2@&+R\>1/E">#112!y+"&%ND8 &I)8-H+r4+$ )0%%'W!5 1%Z48< &3 L :!c7*"5  = "'.)1\1yQ2% . 2 476'&'767'&'&Z#" #" F&@9.@/4> '  &  @W&75(%ph(327654'&#"032760'&#"0'&'3&E"3&E"2*4*44vnf("hz/,/,$4$4 6%d #/"'&7632'"3276'&"'&7632'"3276'&Q!IQ!I2 !3 !Q!IQ!I2 !3 J4+),4+),'$'$4+),4+),'$'$X%#''&'7676''&'676!'l(PxLa_NQ!CyNE@ .)!-938#0 (X<䥘 L151eRQ=.&! RL< X-!''#''&'7676''&5476!'!53#<')vMb_NQ!AyNG@ %.'"+84V  1 ((d(PJ<䨜 N33/bWV?2!1(.L<<<<64/&'36!!'&'&1'7676'&''&5476|>Zj)u! >((d+(p)(]x!%s$2D5/ _hoa*hXf0[<<hG)|c<+0# L 3 #2S3#=!!'#4/&'36'&7'7676'&''&5&766767>(((|>Zj)u! $4)5F(b[0F6" 1+% /21C<2MX<R^92|PeW5E* d*"((@[l+x"4F'GK?uf|PWtI/4F(Z1'\8+X<.D ^#(&)z&+DF<9 $7.* vX#)!3'#'#'&'&7675&'&1&P(d<<(n# *&/003PYE0h) 3m+%6[36'&'&76'&/6&767'&'&/7676'61M@SX#!%/   ?XL'4;<5;N *!?d^ ^((=Sr.>O>$(4HNu6(<<X*6763'#&/76'&'�&) \LkP(dMB=,9 -&("S''/n6rS<*f; P&?;#2#,5 X$53#'&6'6'&'&547632rd(P5+! .Y2 +B_&*:RBLeDU?RG'F /(? Y# :  X 676'&'&'&''#'!!neXj=~7 5]n/`x%()okFTJ6=I qM3<<'X.6761&'&'#'!!&'&1'76'&nIR'<%K %()G, 7/JhlF(n.ZQ Ě@!OE53 <<49:J6 fDyJ<*'IX5#767'&&576765'&/5#'!!07&'&70'&@Z(4K,FMGl ^;A@ d"(v(BH2H %*"+Z&3\ $<\ 5:\9$$e,0T<<>djTHP<}/bX!3'#'!!5&'&1P(d}G;UI xXI'&766'&767'&'&#"'&5?606'&'&767616764/ %'.%6/7 39%RY+,}  *69P<6S/. 9!3{HCR:1/6:/ <I`(H GL H0(awa0!^u\V33c330b(4<l.&<!20<X"!6767'&'&576765'5#'(\# I6'R\Uy  oJVK&(Q F(X<("[$):QGScAT6A, F<X!67676''&'&7676'#')[R[e6/" 1E" [s %(XQ<G{?n&-O"-WX!'!307677&767'n})*(( : .;  <<EX)?6'&#"'4763253#''7&'&60x 2"Ae(P=6cB  *7* <<T*4L%C  %X-&%&1'7&'&7#'!!032'&767&'Wo&NW((( zg[8<5;N *!?dH^ n%:<<4 n?:1r.>O>$(4X0!'!#4'&/%^?:((P]^=S<<JkIbX.'!'&'&'7676''&7676767(N(UfmRC"NYQE;X?*+-0  3**) 0<Q22AzGn%:<<X#761&'&7#'!#'&765!@'-ER((P<.:H,3,Yb,,p%%6<<<2A &+#7 )N1$)+ #j7#sRRKK44 7?2tRR sRRK44K44hX!#6'&76761#T(2M6( 4>!jX!jX<<<<)7 4- T(2M6( 4>!jX<+17#N6 '@'#3'#4'&#"'&52<((P#tl>#P^Yil! _Yik |X"'&763227654/&'(_ie!,= h" IohD,FeR=B1.'>,,]"+/.sTZR P,3? 0x~f#*Yv>n4.gX$0&767632#"'&76"3276'&'276'&#"I? ;-3M41 ! < :.7H53e%'EK&"^b#'HJ'"+'XO6)KFI/'VO6*IFI7;..06/-5>:-.26/-5_X !&'&7&'&77'&'&767 09$ h%F(]"D1"l=TI>#,Ds?92$2 6;&%ZSY!&766767'&'&57676''9ME9)T_Uy nJUM&AiF*"-<_&*:RBLeDU?RG'F^V'&7676'&'5&!B.;QY! /+I6"$,!X=UK!-Q,5 2 J5:'9W!'&764?66767,0[ Z&X_6[mZgfN2 % E|%#  }X$'6'&'&76'276'&/&(m5W %7)55 .$"4: lID`_i/%~N@-/<,3(n95LPd8X 0'&'70!'!#4'&/%?>+17?:((P]^N6 '@V=S<<JkIX0!'!#4'&/%0'&'e?:((P]^?>+17=S<<JkIN6 '@h[ 6'0'&'&#i-(5n&,T(SV2'#)6#3676'&'&7!'!54P (d%8E6$ 2?!\7)@4B T<35AQ )M&EfL574'&'#53676733##5##"547674'&'#"54~/ 2U#$ =+4&r2@ "1;4 .1 V(@l&9'h'/ A#L 9#Q@B9HJ -N A+%:At&&&aD&0 D&0& &D!*33#"!##"'&'&'&'#53627654'!!!676 `69$Q!hQ$ +: >$ C>&9^T.Bb( `,2L(9Y+*!7H0>3&*"27476326765!5!##&'#"'&732767&'&#"#H+8FQ! @*@B&_1$c.E4"9@;4 C M(( {99vf'Rg)%; .2 #,##5#"'&'654'#53!535!322@-CZ^6'' V*rrTbP#\*A&':][+9T]}53TZ !%5#"32!5!####"'&5476;(//+$LZ2@zZ=9?!a+ //+99#}f=9LU .##5#"'#"'&'654'#533654'332732@7`4(]R'>*>gA(N*.2D.;9r#D*<!;`O-9Cu[= .pfrK- 1w'1!!2#&'#"'&547632654'&#!5#5!&'&#"32N,IL"FIWO/P"(s9@6 FPSVtCb7- !=0 )G F.30 9L( 85 ##"'&5#4763!5!5!!3254d)7]9,8HbX ):2^I[E89-+E@'0;#!"3!2#"'&'&547&54763!5!5!4+3276%;5#"@2 -@) ,nh<2  7*2@h^-1@0/-: ݕ  +@E$  :/#0D \9]@& (!##5##67#&543235!5!2@@8` #G :\89.6!3276#''&5476323276'&'&#"#"/7&'#5!#%e&!F8 ^9/+++0+F  "I*3: :z'3>. )C݋5G% <& ! + +@99MA" %#!"3!#37#"5"'&547&'&5#5!5! ) =@GK$?>`&ݚ0' 9k93"D > 9a,5!#&# 327676;#"'&'676;5!5!-+g;4,%" 86<:LKI!ZJ XU^/""<.044ZZ9&#2#"'&547635#5!327654'&#">GMDBllBDMG>LA74<88H/5M6){9?HL0220LH?9{9+&%&%C'0% 3%&'&#"325!##"547632654'&"##"5432765S4\@qF22D7ceD  4LG;999'UF% XX= ' $%#)-.M)/*%#"'&5#476335!5!#!6324'&#"3276P&< 8@r2.aT,?7ML8R? {B[K899h%=,#" /(.*"'&'676327&'!5!#&/&#"327GjE-70)6&". Z2(35S;F  N99zTS4t#N+3Z990<" G)f$1 @'|d3 .5!##"'&'76767654'&#"5432765/ ON!4vD QqP&0!LG;;;e> 7KP4K#L# 5-.L). %5!32'!5!'#5!##5#"'&'654TbP_ 2@-CZ^6'i(,T2299#\*A&':][#!3276;#"'&'#5476;35!5!*24 >0:- 8%$n10F0$$*G G9 7327!'#5!##5#"'&'64jTbP$$i 2@-CZ^6'T?IFA99#z*A&': +##5027654'&'37"'&547675#5! b)?W,7,&L1-=961c6#A%f g<)ALQ#;#@?) ;72$;5"/LA%@g973273##5#"'&'64'#53jTbP$r2@-CZ^6'' V.T?I9#z*A&':+9ReD"0#!"67632#"'&'&5476;5!5!4#"3276T=N!S'K%,]&| lDV< DBݯF:>? 0 Dl 5@r v9P0 & ! ""##5#"'67&'&'#5!5!5#"32"2@9=nS6&(,"rht^- 'K 9#@V&@ Z9јl,ȏ/;  ?&#"3276327654'#"'&547632654'!5!##"'&'&76H.D>)@*(`6#C*We" Q!)^7~2.U.:zR6  #,#!") ;J /N 99f>!L?Y(R3##5##&5476?&'#53r2@ '75 H  9#z#:?EH(B9E"!&'&'654'#5!##5#%535wj$'46 2@-%d1Q+8_cI99#SZPF & !##"'&5476;5!5!5#"3276 2='2SUQ6h rC;76@L*IEVG 9}~888+88A"'&54767&'#5!##'5327654'&'&'&'327!676Y8+1K#Ɔ#J1?7D671&C"956 3%;*'D#"82';->;12j99j11;N/)9*!$34 0  50!0%9PN)N<HQ72#"'&5476"'&54767&'#5!##'5327654'&'&'&'327!676Y8+1K#Ɔ#J1?7D671&C"956 3%;*'D#"82'< >;.=;12j99j11;N/)9*!$34 0  50!0%9PN)N<&#!"3!#37#"'&'&'&5476;5!5!  & Fi"@2D)T$8"nݚ ( 9W9C(<1>a9*!32#"'&5476##5##&5476?&'#5~2@ '75 HR 9#z#:?EH(B9!3##5##&5476?&'#5r2@ '75 HR 9#z#:?EH(B97325!5!##"'&'&5476;#"a9/<~}2K*1*':#484F4+199=:6I!9Tr7#5nrrr##53|@<99*#54'&#"3###53547632*@% )<<@225!&>&(-' ,9#9.<%3 &###5354'&#"#54763232@<<% )@5!&>&2#9,-' =%2 %.aa #"'5327j`;:``:;`;b #"'53#"'53l_?=W,h_?=W,hR88_88~$ &#"'&5476*s& Gmn$k sx  &#"5432&'&"#'&547630gmP$Fa]9On!  Q_d @%8(*8  FId< #&+"'3;2D4_0J<@F<7 5"'&7453372#5254'&#"3d:9 \@   R(&9I)o$ #4H2 &##"543532SW"H@WM -$.##5#"'&'654'#53!535!322#"'&54762@-CZ^6'' V*rrTbP#\*A&':][+9T]}53T4 Z !1%5#"32!5!####"'&5476;2#"'&5476(//+$LZ2@zZ=9?!a+ //+99#}f=9LU  )##5##67#&543235!5!2#"'&54762@@8`  #G :\89& 67&54327654'&#"#"543276765!5!##'#"'#0(>;B'2*7]m)>#  1 OIHH2!LD@Z% $0 /9  ,.99P8 0JI1L: $T"0@#!"67632#"'&'&5476;5!5!4#"32762#"'&5476T=N!S'K%,]&| lDV< DBݯF:>? 0 Dl 5@r v9P0 & !  8" 47632#"'&%4'&#"3276ZNrvvRHJ?SbC7J?SbC7 QGvvYOpbC:L@SbC:L@$)!#"'&=#"'&5476324'&#"3276BB 4I]8(L2?]8(/?"K" ?"K")Sl'>,=W0 >,=@#{E 4E 4%%%'#"'&543267654'&#"76u3[C'LvOA>LWosYA]Yx )R9D$5)+5 FA) _-P8C+6,N2$8PL'3HBM DK ~4!#A9@$0N2)CM,9)4C)2NY'95> /5'727653#5#"'&'654'3A/@@&Y}I "B3$E`;HMDVFG:=2#'"3!!"'&547&'&54767&5476'"2#"&#"3R5O-3O$93 !',56r8@ &f(H,&; (% 298%G 0`$>-Y;F5&"$&#0 !&547632#52767654'&#"r O/=h9% &yrr < )N "!!^-E.?!K99A>fF$;!  !;#"'&5#4763 @H..\LPY9FP;hVYX(!3#"'&5#47633&547632&#"ij!:Q.SAH"KWf(3 I=VA 46+"9bMTHIeh"92>e#654'&#"#&547632( " 2 &:B >" 0 & 0& !(%#"/4767&'#5!##&32763'5!?/:`GgC N ,C-*t,O0$^T.Bb( `,2L(9S0D<(?%C7H0>3+*!3JT]m#54#"&#"!##"'&'&'&'#5367632632"'&547632#"'&=%!36764'#3276%4'&#"3276@9uC+2>+7  I!*D=@ @+3(3 Yi6$ I. ?)/S+`BB &@ # +6n7 -0 +0 O(c:J #9SG )7W"57[%:>3E39 TS"0?#5'74'&'47632?37&5432#"'7327654'&s_A,04'1=P2 6_p8C $4-VJ)/# 0(5Bݸ@TBh'R,:m, 1 ==" 759M G)*%$$/''+2&#"3!##"'73274'&#'7&76766I -4T#Rm(2p\H -1f' LUE)! 8R] FEI)8J@@'G"53#5#'&'&=6'&+73232=3]]X"/Q9$( 1^9 38Z9E)"0!"3uF831V''%!#3%2#"'&'7327676'&'&#"56']].F4 H'H  2.!' T"-0+ $D  I &-%03#5#"'&547&'&767632&"#;#"76]](Tr<&G/ ',CW$$(m>ji>p9?, EZ!6#17#'4$ G -6C43!(;2#"'&547627656'&'&'&5&7672&#"&#"'&'7# $  G $X)3O(<0.'7SVLnf f,8UI/L"2n   #&!  .PL2=h%.5''#&%#"'&'#7327676'&+732#"'76767':2g2 /0 H!&4 a+4/`M7G& " F>99"W! ('3A;#"327#"'47676#"'&767"'&5476;#"27654'&#" < :/r4 7'a DKs% H+(s=3%  3J# I 2 izU+r*6_FMb7%63!E, /I(T47"'&5476327'&'&547676'&#"3276'E($#;`W@ 8B2*#ME 't  K ~B#('72767#"'&54765&'&#"76397 0*a1i+*7%@" %WW086M<L$2P*#$S C0;1( 374767&767672&#"#"'&27656'&'&'&(=/b!'5&":HE-[ ]-7> <%J#^E'$%3#5#&'&=6/#7323767276^]] A E- K( +  Eo1!(F&%(63%2#"'#'&'&'7767676'&''7&767632&  )3`)3sY/#H9A$*" D[L6DQD !K&.S in 7   &( .T9D> &X"7276=33#'&747632&'"8 \a` /G-F *")/=2GG6$$W-Ck) ?is(.+23#'&'&76354'&'&&'&5476G0#ZY+*F1  " D*Y51#,1I1+M3( ,AA8'%/DA=$(l67"'&54354'&#"56323#@R 0jZY1l5 Q07 I `WH'6'&1"7673#'#"'&5476;27654'&#"7676U:$. &5^:^] "54WDK V( ARH1 \PU8=6? C EU 38R  )V' !'75&#76767'&'&547637654'&#"#&547632ZX/%(6%bc_! 3U! ,&Q*; %D&'L_"  R(H !,,$7#!'%7"'&547676&#"3276753#5#5Z<3E4D[ T.]] K?Sc@/C N't I EE(R)&#&'&547632&#36765476;#-@0 1_6'=&4, W5 A)]a ~,V>O4@YE:&E'%#"'&547676&3276753#mHH'S#-()%* l'*]]r3d$.^&B  4Z E'8!#3#&'&'&+'327676'&'&7'&'&547632]])- kD1'A")%  'F T"i4 {*._G6"6   6 0KA'' %'3276753#5#&'&576'&+73~, 3( ]]%BD2% &mΘ. 5E /$*F'(53#5##0;#"/#73276'&'&+532]]s{& ;" & {A" -E ^ F)F"*F4 %&A%4'&#"3767#"'&'&767&54&'&#"'&3576KX/,AD5BhrBD9*C#?%5V" A)*!8#/BB*) L!9:_P.FB  5LD ()%#"'&'73276/&'&'&'&76232#"΂!'UI.@+73r)$d/++_I'sP+4t1@#/>"75 E,,F3#3]]E."#476'&$R!^X-@V0 PALH )E6D'$#KM3#4'&'&#&7632^''#  IwOFDU:* $2nXUWP27654"#'?6'&'7@ :/!DCDS(/R7%(%/B9 21.O476324'&'&765'&O[!)jO-@)7F4;8 MF%M O++-5E*4 #476;#"327#"'&5(b/ b)4&7RJ12C&CL%C$()#'3@P|u'7#'7aVMC ;f#'3#3P|]]gK '7#'7#3!aVMC]] ;uCIt2#"'&5476'&'&'3767#"'&'77676'&'&#"#"'"7532?6%"'6#"'&'73276/&+73276'&   4f; \([cB*=H/ $6*# !#,L  % B&CC%'.4 T18g$,^I/ Q 9FR SR1&  9 ])"RM~}?*H % 5R%-)X0Cw6998 DlZ1_ C+/W>% H<& '!7476#"'&276'&'&'B5EY6(54NO670+  + X9-E3CM7776 <<6)/A;(,2767'&='&'&7676"7676=4'&W*$ X.*"  1 #(I,% "1$  S8z  /L4#*F,+&  M&#2327#"'&5&5632654'&#"'6g>/,"0:+X$qG;-S6"26E8+<##KD"$HDLC1B'0%#"'7767656'&707676'&#"'6M-;ZY-C:O_)0 C+#/$R.k+  SM':?07 9G(  C:"$ )"'&767&'&/776'&'&#32R-g5.,:(#A#:$  Y$78$0MK"^!r?o*5,H* R7''!#'&='&'&576'&+73232753;Q%2&K&  B( ' ,\ ^3$pF&#  'j72&'&327'&/2765&/&'&76767&'&5476WH8 \/ /q# L:9L/'I}B  DR   (B]? $-6. ^ '$277676'"'&767623'&'&'&76776/&36t0b &EU&r'6%  A + :!/ A, "E%13^ 8" .j-)/ ("'&54?327a6#8>225>7=(8K,B(/DR'%#5347632&#"727#"'&PBX&!B. 9)4'(fC7D$eA6 I 6&0M/"NL@OR#"'&5476324'&#"3276R+4 ,'%  #1,4 '# ! #+:7#"'&54767&'&5476324'&#"64/3276="I"(! *6 (MM&.*1 * L&& &1 4wR!:%/:3,6,D&>$FM1>: .'. ?-4)*8$=0G727653#5#"'&5476767654/"#5&'&#""'&547632632Q;/..&T%"d:)b+3$" - & A /+06 .-F*(1'2`Q2 ;*:R2 )0GB& $ )1959(S 57 5K!#327653#5#"'&5476767654/"#5&'&#""'&5476326324+-Q;/..&T%"d:)b+3$" - & A /+06 .-F*1'2`Q2 ;*:R2 )0GB& $ )1959(S 57 <L\#'7654'&#"76327632'&/#"'&=7&5476324'&#"3276'4'&#"3276+K8K%R=RX51(<3*UOGPjOZ  " } !  " _;usE0*m@/84I."#M^8!$:bdB8@I= <.A ,"B>> (B"'&567&547632#'67654'&#"73276=4'&''7Y03TLXmLZ+K8L% T;RS>>B1 4$E!B"",22@(45TbB:@KNFtw%Hw?,56E"A2%@"2 C  %5C*,<L%#'3254'&'654'&#"632#"'&547&54763227654'&#"2 47F O$ +::KL46 &4A(: (@( PRCY_FH + %- '8'v?+%OK1177D(#7#*J&6#+&0QgC8?>_#+p+- *4 !#3#"'&547676767??C3  *J3 5z  #" !:E%#"'&5473327654'&#"'76327654'&'&#"&547632M.;- P:" g3#$#$&K $ /1";"LV+5BzpNEDDB *%9/  !8!8!'*"& $<L%"#5#"'&=7'&547632'674'&'&#"7632632#5&27654'&#"(-" GQBXhIN+I3A N98,,5. ' *# ! 5K %-'gB7FIo ^>+33A0)44A +48H!##"'&5477632#"'&547&547632232767534'&#"3276.86K6 V!$G$1!(G(USBX- '( .,1 .> B743`,:(A+9#,[kB5L 1 '?q5*;; ,<!#4'&#"67632#"'&547&547632534/#"3276-I6HR4&,G$1!(H% PA@^;5>--- (4t$1$A1=-:(A+=Kq:)6 3B!#5#"'&'#"'&54?&54763253276=332?&'&#"367-"' 9%U_;QU]/0#" =Ga7%+$a$ "-!+) mt9#IB! QP$%%$" +@*:(#%BQ( -='674'&#"67632#"'&5&'&5476324'&#"3276  0)2?kL>A8?C%8 '@',A[PUqMO', '- +$:/GG>N44DP- <6 (D%3 '<[`E;MK. ', 'K747632#5&#"#"'&547'&'&547632'674'&#"63'"32767&8:%.$, H># *PCYo 1 I>SY8*#0 '&%'= " (<<%+*-fC9l0 "\>5A1@* #.19%?CS4'#"'&=7"7632'#"'&547&547632"32764'&#"3276!R 6!)O$ !$C'uv#%G(U^=S',4 +/ ,7&*D A(@!) j% ,7")2.19#,\q9& (0 -6)95&6253#54'&#"672#"'&547&54764'&#"3276sE..I0>Z9)d=A&6 'L"tUD'- &/ A?]I)4%4I27 (C%>' -:e]4*k- )- (#"'&547632327654'&#"DCfkE9@DenE:Y?2H]8)?4K^5& jUT^OflOS\LfmC6V?QgD9W>87"'&547&'&547632'7654'&#"67676732753#5E!F M@TwK=- 99[H71 `':!--%;$D dB8SD_H)&T==;3A# .D* AC%5253#5#"'&54747&'&54763276754'&#"6&oU-/5DT73E X>:#*=7+ D7GT71$%(" YRL %0,9 =h:(:"." %/%2.?5 "s'7T25367632#"'#5#"'&547&'&5476"327654'&3276754'&#"63&oU.# 2*-0;N T73 F V>!  Q:#*=7-D7FT72$%(! YR( 2 5"*LC0,9?f:*0& ,%:".&%/%2-@5 " &%A253#5#"'&547"'&5476?&54763276754'&#"6;&4kY.05DT73\($ $f:X>:#*=7+ D7GU34$%! YRL %0,98 ' +<Vh:(:"." %/%0.A5 "+;"632#"'&=7&547632#'654'&27654'&#"S8- &4A(9!)@( QQDXhIUDI8LN^3j+ (- %?3@(#7#*G'6#+&0QfC9?IFWqvVE9?+2 *1 4B#'67654'&#"7632672#5&#"#5&'&'&#"#5"'&'&54763247I9?f )(83  3  0#jC\L@ s /(%ZBJ!  )   ;=&`Ro'-+@"67632672#54'&#"#5&/&#"#5&547632'654'&f6$! '%83  3   1Y[?ZjON.?>O6I/$ )  ;dC/GFi,0 2P==8H!#&#"/"3632#"'&5?&5476;47632534'&#"3276-Qe+ *AB $)8B'8!)F' dO4!,MG-'. '. sw"&!%:3) &8#*F&7")RXK)?Va0 +1 - ,9253#5#"'&54767&547654'&#"'32732?'oU.. FON0!WOBG7C7_$&>!N=-s#YRS +4#.!$!NdC7%/% /3% ~1 03L!!#%7&/4763253&#"32?/nJ@TN4//6nK437 #SeX`d81, !T90275 :!>"6767;2753#5'%7&'&'&=&5&'&547632'654'&S.0>+,+'7Gx! *N:JjE>, F29&3  !-#7'p@4+&5_  :[9+F@XF4V4%A7#3@+-&A&'&#"'67632G =PN: !LVeB`7* "B- 3#'7.]>"k5#*#"'&'#"'&547632532767&'&#"32')<*;@ ,!3+F(:3%912Ki-  1,=%476353'"3276532?#"'#"'&0!+*%& 4(A-;& -(#@"3<"!4':<.L8!3674/"?2#"'&54767"v)J! 7MC"*%&(%#''?-#2#).R*%#"'&547632&#"7324'&#3276R0#-l=/P4MF&'@E+/>`CD1==?1 ?,!gNfG./ &K6>@87D6'( 4HX2##'327654'67654'&'"7654'&#"632#"'&=7&547627654'&#"lF= !# 54X#! 93I5BL46 &4A(9!)@( QQD2+ (- %G=X**%1P# * T4%77D(#7#*G'6#+&0QfC9+2 *1 #"'&5476324'&#"3276>>XU><<>UV??"56HE3421II55sPPQPrpNMMNp[AA?@^_CDDCe/.47632#"'&'&'&'&'&%4'&#"3276H*7P1"<)7<1(5]"?< G  4 ? 2";"e0<)6T2#,&%4 /4!#4'&#"#&'&#"3274'7#"'&547632632.,-- ,;!0%% F%TC'6?-.CT' (!D "E(-v%(51 rw7 /7=-3"2#"'&5476?&'&'76767674'&'3276-m)8//EW/: "? 4M[C Ie'84!C ^S/>>L,-C+9B< U] A,hkEG #87A 8 -/;G%&/#"'&54767&'&'7'&547632'4'&#"64'3276 11! ="+N'-WS #Bd:%.H(0 &`+ 14 >u3Cu-J"3.N&<",20J  U!%&H*:$,=, "# <.H.$A44E8 @89#52767654'&#"#"'&'7327654'&'&547632޸Jx9+6(/8 68 $:/ '#)+ 7 !B$,c6$wu. 1NOoE0#$ 5) %C#K2051@476325276767654'&#"7632#"'&4/"32760F?QfC6  27654'&#"72#"'&54767 /: 4D/9+2E/#9+F0= 2B:!"E.#:*2E0#T />O_327654'&#"327654'&#""'&5476322#"'&54647632#"'&4'&#"3276T68 *<6</ApD/#-.;=\0.<,..-;<..\9*4D/.-;;../= 2: BD1+3 ID5? 88*4=-/\=:..//-=;-..-;=\G/":!#;-..-< 4@ 1 ` G"327654'&!32764763233#5##"'&543!654/&#"#"'&<# '" kMThP5CmD555Q{B*& ,G+aQ.YF^20Tn6#2=d1-:S> 5OQs d327654#"!3276"'&54;#3254/&#"#5##"'&543!654/&#"#"'&54763233632  &6   kMTf2< +7$G+]?7771 n6#2=d1-:S> 5C"@#K-&YF^20TR<'[Zdq4'&#"3276676767&547632#4'&#"67632654'&##"'&547632#"'#"'&&#"676327654327&"1/ 2#( ?Cb60Swml8RF!*(3T,_Ki??AT2$>[9#LX?:{}T&!9b+&+ *LA)2#"'&5476!2#"'&5476###!#  D  p=<u  #   # X< 0<"5476;27654'&#"2#"'&547632+"3!"327654s940'K",6)55@ I=Td<.C=Ns66`& /# T9*"'\$6=1Y+%E5GK417k# /! 0-^jt676;####54'&#"632"'&547632!"5476;27654'&#"2#"'&547632+"3'27654#"3254#"6 27%Y7;&!(.?9 5%15P\-ks9:.#K",6)55@ I=U_=1J'#+7 .=.%#7#"632#"'&54763!#4'&#"3276CY;.,_]'2+3f<-UGb'3!2B A3BAC",E/(T@SrH>='#+7 . iy%4'&#"#54'&#"632#"'&547632632#!"3276=3327654/4763#"'&'#"'&54763!276%"327654'&3)6J(7<-9C)J&>$+@("Q=R33o`;.T5L_*<%*L9079&,A(+L5B^8 8s7!g5DRR.8/1*N:.B)3N4() >#,E%9.5m?/bbUBV@(0 :"4+7)=(/%! 58Q0"=]D(9a)I/0 :- 7 aq2#"'&547;#"#"'&547632#&#"32767"'&547632327654'&#"632#"5476"327654'&}V'<(8O  12 (BB!./N|;;< \C!15-+?*) I ;LZE0(N 2 '{gJ0 *1">Wc8&7:B'6,D ,UC' K4L G*-?345+1h 1E4NA">'ǍNB",& $  w727654'&#"27654'&#"2#"'&547;#"#"547632676767"'&547632327654'&#"632#"5476;)3"r;!1V'<(8O  12 (BB!./N5!@ #.15-+?*) I ;LZE0(N 2 '{g;) *& $ <..>Wc8&7:B'6,D ,1/4 &L G*-?345+1h 1E4NA">'ǍNB -7%676;####4'&#"632"'&5476323254#"2#"'&547;#"#"'&547632#&#"32767"'&547632327654'&#"632#"5476"327654'&b 27%Y7;&!(.?9 5%15P\-' 3;2*V'<(8O  12 (BB!./N|;;< \C!15-+?*) I ;LZE0(N 2 '{gJ0 *1"87se D"-1 D <*+T@GA ( /8>Wc8&7:B'6,D ,UC' K4L G*-?345+1h 1E4NA">'ǍNB",& $ y735"32="'&5476;5!#32#"'5327654+<,+ww_>2&n@&>'0 $#C`VP)&1&sB?2E7"6='.E)=+[[W&#!#63233!536765&'&#"###",G/!765:/,7665&.[*7@. "\)Rs!%"'&5476;5!#3#75#"32#3_>2'P)C$ <,+w?2E; 67[W&B+ 1&w 327654'&#"4'&#"3276"'&547632632!"32?632#"'&'47#"'&54763!27654'&#"#54'&#"632T- 2(.,701P^ Q=R33o`;.h#)!_*?#)%PPYI'9=!L;U;1g5DRR.3)6J(7<-9C)J&>$7 $ -# ^3- 3(nS )m?/bbUBV70 >!3`49!*?" 7!"1:/?a)I/=N:.B)3N4() >#,E%P%327654'&#"%632#"'&54?2327654'&#"##"632#"'&54763!#2? '2!(8b+zN &Ch|+#.&=Z;.2Z]'8'2e<.LLh7 -'#*,!X/=XJw~amqk@L5)1A3BAD!,K0!S@TiHG=3!!6AS7"IXdp26763!###"#"'&547&#"#"'&547&#"632#"'&547632676"3254'&327654''327654tA<@:J' *0R+P'T.(ka]LAR ,"0_+.'!.`a`)*!)#6RRb8'L0+'zg7;G"'&5476;5!#32+"1#4'476;27654'&'"+35##"325_>2'+`1q%.B4:0/E+P)_$ ?'-w?2E; 6O1A<91Z a$/h [W&#+ :#s)!#632#"#'&76;27654'&#"###'!R(W=$].^ f (Q('R3?N#"'&547&#"632#"'&5476326763!###"327654254'&#"6d9 &L,^5>J' *0R+P'T.(ldYK2O ;<`6\`)*!M_+,"0Rb8K1+'z`0#;'3!3!67S3347632#!%4'&#"32766Y `D=D*B50EC 4 S._cXf~/bID"&D 327673!3!5#"56%7&457`?U.5@S7'K 1 !#57## ǐ66XBR88#"#'&76;27654#"#4'&#"#47632676325H7?/n;*,7+# 67)D)1-Q^p 4=M"632#"'&5476321327654#52#"'&74576'&'&"327654'&F?=3JU,C)3S1/HGm^KM-#`+G6Pa) 9?5B (=TnQPHK\!O!S-;6wF5A/<73.;1: /3! @/?!###"#4'&#"632#"'&5476326764'&#"3276<7C3 7wVVFJb;1Q$)Z:.2? 1=  1>(m%327654+%"327654'&%"37674/&!"632#"'&54763237"'&54763232+#7!567654'&*bst: 1< 0.,? ),#N?--'Q+B%/e-OOydOQN@K0 +*242%P<"M 1Q$)Z:. IY2327654'52#"547676'&#"#4'&#"632#"'&547632676327654'&#"\c&M@+ `8*C3L*'A 7P+4F?=3JU,C)3S1/HGmlC :"5B (?Q)6*HQ<@7\EWL:F J";/J"=TnQP0. : /3!1]m"632#"'&54763234763267632#!"#'&763!27654#"#4/&#"!567654'&"327654'&'N?--'Q+B%/d-PQvdOQN7)U$ 3.-+7+ # wSG8: 1< 08(1C)4S(U.>wVVFJb;Q*H3?R^p4%-^ hLg-L6 /1Q$)Z:.2? 1=   !#### 766RRL4'&#"#&547632X#.P1!%CZ9L1 7/7%1441! NW$ 82( !!5#!35ۤ ' %547632#4'&#"67632#"'&%"327654'& ZM|5 7X,=w@50 F!)b A$-C, 9 : *'{n^,$* ~2vathS"V (O&a5H,< a<L"327654'&&547632#"'&547632#"'&547"7"327654'&-7> .|8?*4A4)^>PnlhhiA1L!L+9UPOV4 2B -+<., 8DN-8,2e5"uupq=.B\& >'1E/le^e1 9 2-#8FR"632#"'&547632632'67654'&#"#"'&547&"3254'&327654'cJ-(1Q,P']/lb_GIFpJF`7GCBW'$d:'6L+`7? 0a-). b_@'7A'2c! O1AVO,)YSs}H<\V9;Rd8%K2;R4; `21M*?)(sGQ  /?!####47632#4'&#"67632#"'&%"327654'&*76ZM|5 7X,=w@50 F!)b A$-C, 9 : *'6RR}n^,$* ~2vathS"V (O&a5H,< <LV"327654'&&547632#"'&547632#"'&547"7"327654'&%!####-7> .|8?*4A4)^>PnlhhiA1L!L+9UPOV4 2B -O76+<., 8DN-8,2e5"uupq=.B\& >'1E/le^e1 9 2-#6RR ` 0@fv!###"#4'&#"632#"'&5476326764'&#"327647632#4'&#"67632#"'&%"327654'&\7C3 72't:3WTDM&6RR;)-%3#'3#"'&5476;5!#!!'32=#"%#3<<<<_>2(QN):,-w$  ?2E)!#67[V&1&sB+ k,!###"632#"'&547627654'&#" _T[.&"*8 25!####&'&#"#476OC3nNP')N * B9\\V4 q-' !/%#"547632'3254+"";254#2#"'&5476'I$F$\! g&&g ''g4]! D)GbB dA 4-)*,*++*;6d)!B Y7"3#53&547632#"'&547632'654#"327654$6"Q#hNkQR..= Hb.=u*! *2- :"."#9'0A)=Bfo>7+ e', +O 5<J47632632#4'#"'&54763267654#"#54'&#"&'&32767&'&;$+Y/:PQ$0;U_^4+#*+>5! T6 CO E3=* 92= r0&"c322U,8*?J 61"&UGq #8) # 4 LU"!4'&27654#"72#654'##"'&'#534767#5!27654'73&54762765!C, 3+K!E4;Y(2V RZG4C1 = g684 xX8!<>#BA"7) )88HW#)$+L \1c9+s%/:/G 8;#7J[#@P'.E}6!*S PM47632327654'&'7#"'&5474#"#"'&547632'654#"327654'&`)5 pp %G7 u+z~ Q2CrIH6#1 ;H.24Ye !o'hwR(A!::#`&%Z(6&#V)$d1OOra5#V! (;Z=@Q" v%27654'47632#"'&54763"3276'&'&#"#"547654'"#"'&547632'654"3254'&5476UZl8KyD2c (` F% 6- \ 2Ec' |V  ]>@+&9B+4 98R$ DE$&}2WA\+ ?M 3" ! 5',=&(3 f9 )*PMs\1,*! /dn$)C,,b ? x#,727653723654'&'&'7'&'#"54767"2 C!&.,+4$;!oE?/D+ 4?9AJI ?^"B/A!@ H&>"'&53327#"'&'#"'&547&#"327653327654'&'M D4,'k,="G,*^M&y 12 CX/ ()0 qI(5+H14 c%$F=#.Q"G &1kH+CE#>"#4'&#"&547632632#"'#"54763"32765332=4- 40E;C!&L<"XH'A i!1WJ*V2 CXC## +*3 @@<$.c @@P9 H1ftVq/;"'&54767654#"&5476323253327654'7#"'_ (I(3H45 #^ (K(/XC: 4##C7$i!1L%,(<;- *,77%7%0 VI ! 98U&@@1I"&547674'&5473253327654'7"'#"'&5476767414$N(K((E(1XC85  #5Bi!(`P&&A '  *,* 2;+A$(7(41VB$8Eb @@?"-)&4 ;kp"[+53254+5!2"53254+"'&'#"'&54?654#"&54763232533254'7* / 0&)zF*NP (`U$(L&3N/5 #^ (K(VXC8FD&%$+!1H[/p7gk& @B!+*%; ;$%,77%7%HVB9%1JD$&1%4'&#"23676'4'&+5!#3##"'&54767#5323-2 BAe(4pF"+QE+'" ~-/ 'R/ ?<89(I0+:-)0K 9;C23254'&'#53#"'#"'&547632654/&#"&57676327&#"W-*s(CO6<])7yL/\H,'-+CFE 'EE"&WF13DWK.>Z4:UQ1EMi.F/"&+!JF' .%++*%#654'&#"#&547#5!#E#<3>>1<$E#ffDSJY58VrC::Cr2\2\f=[Rq M2#"'&54#73!5!#"'&'#"'#"'&54767"32765332765'573275"! TE#Z[2$'D 6'5V$?IM'SN22 EV,r7 BV   (r=8) 5\9(99=#.E":F(1f=i26rLZ2#6/"3276533254'7#"'#"'&54?654'&#"&54763262#"'476V+ N<'$2(/O(`KK4K0>(g4AWh%-S-( W7@).W/<7 $ =6(()="!Q>0 ?!"?<X&77Q",/'=$)5 1 /1JJ 3SC732533254+535#533##"'#"'&74?654#"&547632`1XCVEM=WW>]VL"/i$.W7),(L&3M 25 #^ (K(1VVHW:r9$:,F+ @@')>0$8!;)  ',74(9 ?K27653#"'3253327654'7#"'#"'&54?654#"&547632qN G=&%-%;&A!XVE4- #*8%n3V[!&F%*A><$'4, *q&4+,&7 8V> F4M#FFI'1#6#1  +,& C x%2767&'&2#"'&54764'&#"#4'&'#"'&547632654/"#5&"#&5476326763247632'6 -#Ci? S$8$D4E HeT2-#*!-64+6 CPG"3EC 'g! <>) 1'*T-&*3> (,9C7,Y[*:  9"&U-UF  .*)(K< .$;+#;(*&55B<Dr^476;#&#"32'654'&#"327653327654#5327654/&+532'"'&'#"'&547&)#P 1%C : )< @+1 b"$)  H%FL C. 5MJ+PA.E+&2# ,3QL!(% +5,;E:"+;1.9hy # 6J2AD8&"327654'&%3'&547#47632#"P'M#d 7#uC=;\M`))*Q")p# ]$O/K;L`j>>TX' h "<2"'#"'&54767#5!4'ᒆ#"325332 <w D?*;nEg -'g5  WDWD)@8T 9( =+4fX#;;+ +0_a-9  VV o "A%4/ᒆ'&'&#"325332737#"'#"'&547#5!'^_6# WDWD#3w D?*nnEg# )%  +2 0P4C# VVrr3 9( =+4_;;%KAJ"#4'&#"3"3273#"'&547&'&547632632#"'&54767327654'&3D* V>"(qNWW\E]*1@,D. W)4jQ4xw=#66O]! I1L2 40)7FV9+A0G (!_+W"^^\5I _:<6@ 9">).H40-4'&#!5!#"'&767327654'&+5327696^ &DHEa%"4U2->!!F G' ;; 22B;&$5! 2,N2:0  o '+B74767#5!#"'#"'&%#"'&547632#73727654'&'&#"3253 ?v,]N / )v0W3!"/    D#h286AN;, WDh^';;Ci,+E+==(&   Vrc3X69L9B< VV  ,73253327654'&#"%#"'#"'&547#5K) WDW' A5IO96 IO4% \0W3!"vvAVV/cA6ID;?x%'D->=(&@N; o *.72533276'&'&#"%#"'#"'&547#5!3#WDW*)4MV9'/ )v0W3!"llT?Q#DDVV=b)9O5C]HE+==(&@H;;Ls"r -7476323254'&'#5!#"'&'&'&#"& 8,4. -M+-C%U-B%2?, "> = 6)!L(t9>D;Y/I%l2I5?%):!#"'&54767#5"3254'&k, 99ZZ9:+]M'++;9"'4O"f?@B@c+06;KC'2I..V, ' .KY%'&''&'&7676323&5432'27654'&#"4'!5&'&'7673676%3254'&#"& (H9%(WQ'# >SS[{$   !# ) /&/5" (M;(#A ?  :1U2'rjcs+Ay y%#   4HT.? ;/SA3)5(w92$4 S*4'&'3#"'&54763'654#"3276M2^OwoU_01A@ #4/CX9Oc@<d36QAE:AJvS;:&8Q*h6#;7 ?aS_327#"'&7676#"'&54767"'&547632#"'53254/"3254'&#"3254'&'&y5+EW" h%.6#@#b04&.Y>   4 !%- <>= "  <>4\)K *.'#H+-D/98EL:8"Q_@ELGQ[XrZ2@ 3&5432#!5!254'&#"8 xm+~*6'CT 9Osr8J+FB11O )47"'&5432654'&#"'6323653#"'&5'"3254'&E"x4=-)$F|E4M?!;&(+,) %X'X-V465= TcJ2 I 2 $$ !;%274#""'&54767&'&5432#65&5#"367654'&'3.34*8"  Z7(yH(UO:<)CD/38831& 6&.k . 5%A&7?4"C @ EO72765"2#654''&547674'&#"#47630767'476"6767&4> + EKDU#( -&H-::A"4)", D6(#-)  "''12:4T8!.)5-#&6--,FO.6H2 +##@+73!!"'&547'72#"'&'74'&#"3276=_/gE u0 >9"2K4$! 3FB&4m@rx7#/E ` "#4323!!"54?654( H|C":j83%ۛ;l;d,;0E&& 9p;*;!%3@/476;#"#"'&547632'4'&#"327654'&b+U-L44CA[8"!3F= 3 I+'+,q0 8 A>(L68f5JA&'8 !B("0!63P/%4#"32'2#"'327"'&547&54763!!"6B=O*K4A 3:@ @!(e<>##M=A@4o,+ %89-,C8)JI8<!<h 2#"'&547627654/&#"U3$10FR4&=.;A%33%&2@-;F24?/=Q3%5 )?# #"3A%2 0@72#"/4764'&#"3276#"'&'45476324'&#"3276i:(* +j((% +.+<4),.)H6b+ +$"7 9.3- ( {lGVg#"/27"'5#"'&54763224/"#"'&5476721676737&#%27654'&5747{,%?&8 [xXavLl :*'$" A!'*0f 6C7G "T-s! /4 *"(;@kA+&$$ 8( N/* &Z<0I0." 2/,<$$c'&/"3767654'&'&/&'&'57237676767654/&'&/"32?"'&547632#"'&5476767633#"'&'&5476324'&#"3276   2  ?l- Zh51C N !%R.h.$B'?#Z!L 3.$-Z"a*BGd!I '3"V(>%&9:%-4 G )    '5")\@A# e5  4"-O E'L1 2E  %:H2D"A ,J'0'% HF0!,j Y|47632#"'&74'&#"3276476?676?676?2322#'"'&'&'&7276767676754'&'&+"#"'&5476724'&#"3276[&1'+    # By EQ#  .DxX  $A*)(  3a:JL<.b&G3V@>;(3;k^;'  '+ 1   # / ) , ' $  T [-O$ & 1!0 9  o1*>l!& C05.? F03  ,:5*h, ')  $   [R"'&/6762#'"3276767674'7#"'$476767676?4'&/"+ c'(4[0< -,X.3-!AT a1Q* L*,),8 )E6@ :&_6D1B>Hm<  # '*'C[Y?`=$'"Y -&T , #+. :"32?4'&4'&#";27676765276767#"'&'&'#"'&5476?2327654'&'#"'&547632#"'&5476654='4'&'&'&'&'&""'6;2'&" 8 44E="  "'D #+ ( 5" . 1km;*W#". n" !<3H5+J-8h7# (!S:6: A3vx&S6#6E !)(  ! +  J3RC./Fa- %&! ArRo> 2 &> P !"*4 3*4G&7"1"\". U!"+  A< =T\T0PB #Y %27654'&/0;6767657"/#"'&'&#"'&'6767674'&'&#"#"'&5'47632676326+"/3276767654'&#"2Cu:/7H*76E1 5 B#5V. ,*# HX*:  '=#33D 8 2(?9k ,1,' #7! NMoA6IPXE"*N3 /5E`, . -F&r3#2"3\,,5^/  B46 #&$S4A\6A"$C )IpTS(-.3:\%4'&#"32767#"'&5476323767676767#"#"''?67654'&#"6767632%654='4'&'&'&'&'&""'6;2'&&&2# (\,BBf@) &#,+70 ', ( `*(Y@K A  2}a5  '  (!S:6: A3vx&S6#6E !)( e+ .%3d;MgQPS6M.12$  / )Jl_:@AC ))U5 ,/m"\". U!"+  A< =T\T0PB ?\n47632&'&;676765&'&'476767632#"/7?2767674'&'&'&#"672/&'&'&'&?]Fk& (I4< *(&S-I& "4G9wNE*68M(!/ %9 Q!4]2I) 0I fB6 ,R>  `)7P3  'J  (*)%ZPp4 +#G&$  @iM'K, C< #*?1DH6:!`"327654'&76367674'&27"32?67673276767#"'#"'&'454767#"'&54763654='4'&'&'&'&'&""'6;2'&_  #  < |Dk["H),9'W(+ "#(B#$) ( 2/hkJ2d T804 $gk(g (!S:6: A3vx&S6#6E !)(    +!   I%%9P  $!%  F`Y_ZG@O T5 %I "\". U!"+  A< =T\T0PB # :U7676?67676731#"'&'&'&'&767676767'&5474'&#"1"'&547672#"%&'4'&'&'&'&'&""'6;2^:W &C / 'hFd8.390,. !Y(3 !  /"6)GI(B"r (!S:6: A3vx&S6#6E +"Fq-  &F! (5UD+ 211$&#  * %!*)V& U!"+  A< *W!_ g%%"32?4'&2674'"322'476726"'&5476?6234'&'"#'&'47632&+" 54/&'"#"'&'#47676767476n8+= * ]5 '% W$ $=y  ;: bTUuU#w 2 /!  @$&0!(  ]2%?bi>A# FD=|, " C !0/ !!W' #9 !@-)KqG3KT[, 6   % .'2+k"yP @80-85 1*  K" 274'&#672#"'&'&54732#"'&5476?623&'"#'&'47632&+"27654'&/476?6?672n0 5 )E/1#  A;!!B{puU#w P/!  @$&0!  ]2%?bn.';? :D,+4",  "  %( ) 1+,+~NFKT[, K   % %9 2+k"y1']3~ 0a!%27654'&'&#"67227676767267672672&#"72?#"'&547676376&/&#"#"'&'&5&#"2#"'&5#"'&'&#'67674'&'&#"'&547667677276?"'&'&7676B#]4*!tW  = @#- O\.GSVOa?33/(r J64 6I^;# M;"-!Y:  ['% =&% F !%E >*#(*)  8Eaj96 B <J9pdA& $$0!-% h4;  7 %%P6*`D.  (*3 ('&0a4'&/"4?6767676%2&#"72?#"'&5476763672&/&#"#"'&#"#"'&547632;27654'&47632667677276?"'&'&7676I!G,/ I .WI /)*( U*< 6I^;# M4cm# H<  >;"A>W:)1/, %E  :*#(*)  8Eao78  B <* <:O GjB7Z\{p[eP.!E/6/&5"WO $WD.  (*3 ('+:1a!276767673"#"'&=747676;&#"%6'&'4'&'&'&/&'&'&""'6;2\ Q:&0'# / ' shj .^(/;0!s  $*:6: A3vx&S6#5G $ : $/3-$D@s8CcBk   !/4  /.   A= !;H@(*Xi7"'&/476767"3276765327676=&'#"'&'&547&'&/#"'&'3276767&'&'lA [(2&#*!2AR,B;  $!#S1 5*#)$."' "x30K-, 7$6*%(6a8"$D| m5C*yH  1 *@ $ :!*9!$VA 81;B*DRR_P$43 FMHV>:M%#"'&54767#5!4'&'&'&#"#"'&547632'"2765;7276767#"'&%654='4'&'&'&'&'&""'6;2'&@*1S9:0HF !$  H3 | 5 8B#$) (88,2%#"'&57#"'&/&'"'#"&'676?&747632%67632632#"'&5732765'54'&'&/"4'&'&#"6324'&#"3276%47632#'&'&'&'232767654'&'&'&74'&'&#"32767&'"0 ;"!  BZE:'?3"  G[F?^:?C.[~68;&`/ $D;(*2!H  =  96 1+ $->$,**" 4#71-#2G61L7 3E#." #!"?2\p08,# a& ((J; , 60 O60!) 70 &T #;.q@ O&6l ;Z! F !"*)2!1"- - - 39#/OF2*;%%%E  $ %! ?!. !!Rf~"#"'&5476763267672322+"/3276767654'&'&'&#"2#"'&/&''676?674'&2327654'&'&!3"+Q+ /59A,!% 4OA #:$'V%&(0B)Bs)$9EpeN:?T > !!*!3q-GT. D 071<0>$*{B;9._9A-  !2*@TN`; 2* jIY#0\, Av+%':G47'&'#"'&54767632&'"327654'&'#"'&'&327&'&'0 UF0GQ* L*,),8 )E6@ :&_6D1B>Ho4?g-;" / (*)  8Eam9G B< !;* (D.  (*3 (' :6i727673276767#"'&/#"'&547637#"%654='4'&'&'&'&'&""'6;2'&k? ""$B#$) ) /e%!"'$W88P5]"-$ :( (!S:6: A3vx&S6#6E !)( I .F4^2Y $3JJ`@)y$,O0!d"\". U!"+  A< =T\T0PB Wt7676?6765'&#"#"/4767676;6767672"'7;6767674'&#"72#"'&'&'&'&;27676765&'&'x7   +# -0 1  * $A"J_]x2  L - 4QU$I"@I$  ? M G8" / 5n< #J]/F Q~@-39L%8#   -17'21 -Q* L*,),8 )E6@ :&_6D1BCKz3  # '*'C[Y?`=$'"Y -&T , #+. :e%4'&#"32767+'3767676767#"'&'&'&'&?727654'&#"47632#"'&'&'456767632654='4'&'&'&'&'&""'6;2'& #"#M .,2:.- ( " GbD%%'7?(RC@B'8 .'2/ B^mIA (!S:6: A3vx&S6#6E !)( a$ # !_ =W(: X ,' 80 #"G1 +4 !?It??C;m"\". U!"+  A< =T\T0PB s^_#"'7127654'&/""'&547#"'47!4'0'&'&##"'&547632"327654#47632s!'%G"#N/"['5!V1!..o)3.hNPbP 2  " .?'---/GDdb6"\4?k3#, " K6E> 3"/ %\j-NObx;  %.499F3$%+&=kUh964'&#"37676"'&'47632#"'&5676?4'&#"327676?671"#"'&'&'4767632327654'34'4'&'&'&'&'&""'6;2( " (K9I#%K  3(B]?/  _SSQ:&0' 3 ' sWpx 4("R#*o0G  (!S:6: A3vx&S6#6E +"32( ' X7d ;))+%,  ,5, ?-( $B! D@sCHS8DjN'  ? <(+> )*[ U!"+  A< *W!D0:4'&#"327637676767"#"'&547?674##"#"'&54763232765&/#"'&547632#"'&'&767654'&'&#"327654'&5476?227654='4'&'&'&'&'&""'6;2'&! * %?!- ( 5)() 0'($8'./7s9&D/G0&UN)+7 O8)G,61/0  a ?.'"# - 1% (!S:6: A3vx&S6#6E !)( " 0'# Ga)$$4  4"$yPnN7)9 T(2 4 + 7&=;vI816D./26+* (5  1R,&!_,<-P $N*&6H:;} &   $# [X!"s 7fV,.JA *)#> OG-*7!/R:5 )'*:O|32767676731"#"'&=676767676374'&#"1"'&547672#"%&765'4'&'&'&'&'&""'6;2\ Q:== / ' shj 21&z3 !  /"6)GI(=x (!S:6: A3vx&S6#6E !):2$@! D@s8CcG5* %!* 69  U!"+  A< =T\mXz%67&#732"2+&'&/&'&547676?632&'"32?4'&'&47632&'&#"&'&54767632674'&'&#5 =0(%4@>P? %5151*B<3J, >P/Q'' 1?Hi? R '% = .'(98'=50  S3I)+  /44DI344 # #1 E% H#L,# --/9-)6 H $?#:4Dj7&W$ '/Bhhz4'&#'47676322#"'&/#"'&54767#&767!4#""'&54767632#";276767653276'67674/&#"32;#-F"#_& ( !"I_)#; M '5<  %*$$? _# 3gkSQL1)3M4,0f^v2/"#327676'476#'"'&'4'6327654'&'&76#"'&5476?676"'&'767324/&#"Ę4 i$!o3 HJXWA? & ]hFW   'eOvu I`, O"df[+'  f> )1 A %. P00GEg b? KQ0%g=I 0/  3'kkB -Ee L /({RK2+'/527676754'&##4''&'&#"7"/&'&547632676r> D) 4-44!#./<4&'&/3O> "($G(,I7 CIm=0jOz.9+-M,   &/EM>? ,\ $3> #1: @xX^{e"+45&'&'&7676263'&'&1367&'"z$->(  !&(`   ;4  /23P]947632'&'&'&'5327676?4'4'&'&#"3#, s  *F5!    8% >'qB+6&    '21*~"!37#&'&'&54?67#'&7076# 9T 7*#D&U)W&/ -#%J:xAL49  7"'&'&'&5476767#57'&'&'4?732?6.X(S J!B\_^+5$ ) E  48$+*(K#* h t'219a+ ! *4'&/&#'""/&54767632/7276 !|~3" 2 6)$WoI*`<$42 ?&  4# "+ 0(Q""&/ :"7654'&#"'&547&/#""/&5476723322$)   F- "#V2E0.2 6):/: W-%Mu* $<0 ".  # "+N'2(#;27632;7!"'&54763/"E)T*!C!"9!=% : 7")%H9#)E  % (+3276327&'&#"#"'&547632&#" 6BNQ@';/' VW&37+N. ;++' 0%u8 %$  B %1"/)  oZ4E2674'&'&#"'6767632'&#"&'&54767667&'&#6720G&D1 7*+(3 4)*-! <|3TA)P+.A-W 6@ t7t <$505Wn>'0*#!inAR47632#"'&'&547632'&#"327654/&'&##&'&74'&#"3276D*4d61XSs~Y'a`Y:B3)qSR[CZj>, $ %0_ /$00 [I)&4MiEA\)23A^`"  RTj_8):*:W!1:D&0 4/*BYO27654'&'47632#"/&'72767654/&#"#"'&5476372#'"9)D ]XXBDZF+ !, E!* .K-0$   *\'\ RRmbb<  3 5/  P+<'3D&  @"G&h:0&r:G&:0G&:G&:0G&:G&m:0&m:&&!''?' ' 'q'q&V>'w&`> &>'&> &>'&>vf'@Pf'Jsf'=Cf'=sf'=Cf'=J&r @J&s@J& @J& @J& @J&@J&e @J&w @gq'1!Aq';!dq'.!4q'.!dq'.!4q'.!q'q!q'q!&B8&Bm'7B8S'<Bm'7B8S'<B&B&Bk'5#EV'?#h'2#8'2#h'2#8'2#'q#'q#&hH"&rH&H"&H&H"&H'g)2'_)'y)s'm)')')&WN(y&aN &N(&N &N(&N&\N(t&\N'.'.'.'q.'R$'R{&ER$&JR{&ER$&JR'R$'R'h2*'r2'k2q'k2'2'2C'q2'z20G':0G&O:''>'&=>J'@J&b@&B&ǠB"'H"&OH('N(&>N$'R$'RG&r0&rG&r0G&rG&r0G&rG&r0&rY'Y'!Y'Y'?Y'Y'Y'Y'&&&&&&&&gA'AA'dA'4A'dA'4A' A' A' '4$ '5{ '6$ '7{ '8$ '9 ':$ ';'<*'='>q'?'@'AC'B'C0G&n:0G&qo:0G&iD0G&i:0G&Ei0G&r:0G&i'g'q&&dzY'X5Su6Gcl^d@o'j&H&@&IJ&m@\h'KYCf'-Cf'4q'!4q'!AA'!6G'6G'6GDt'&B&qBz&Bh&B&Bt'S '#g'q#8'"#8'#G'G' Gt'(&]N(&q^N(z&`N(k&LN8&}J98'J(&aN(v'cT'.g'q.'.'.Np'H+d('$jd3z'jPC$ 'P$ 'R$ &Q$'R$ 'y'c)'\)w'a2'B2*'2\P-vG.8#58HH18!518HH8!58HHA #547673]L 00en&S@ 356745#@]Q-0er&B @h 73#56745#A]T00het&F@ #&'&=0 R h: &d e0+ #547673#547673]L 00]L 00en&Shen&S1. 356745#7356745#1]Q-0]Q-0er&B her&B /,h 7356745#7356745#/]Q-0]Q-0her&B her&B 1. #&'&=3#&'&=0 R 0 R h: &d eh: &d e&O ###5353XXRUR&O#3##5#53#5353XXRRR3R2,2#"'&5476B%5!'@&4!6 )?%4!(@&F,0F}|suh 7#5!#5!#5hhhhhhhhhh #3CSc2#"'&5476"327654'&%3#2#"'&5476"327654'&%2#"'&5476"327654'&L,;(2K-;(21+1,4BuBL,;(2K-;(21+2,NL,;(2K-;(21+2,<)3H.<(3J-<*2*4 F +<)3H.<(3J-<*2+4 <<)3H.<(3J-<*2+4 I/@P`dt2#"'&5476"327654'&%2#"'&5476"327654/&2#"'&5476"327654'&%3#2#"'&5476"327654'&KL,;(2K-;(21+2,NL,;(2K-;(21+2, L,;(2K-;(21+1,4BuBL,;(2K-;(21+2,<)3H.<(3J-<*2+4 <<)3H.<(3J-<*2+4 <)3H.<(3J-<*2*4 F +<)3H.<(3J-<*2+4 1'7U8U$$(vx1 '7%'7U8U$$ U8U$$(vxw(vx1 '7''7%'7`U8U$$U8U$$U8U$$(vxw(vxw(vx1/7%%U7wxv1 //Y7%%U7~7%%U7wxv(wxv1 /%/%/Y8$$U8(8$$U88$$U8wxv(wxv(wxv[j757[jjYzSSSSUj57'5ll=YzSSSSbD /?K47632#"'&72#"'&5&76#&'&547632"'&547636'7'77'b         ݼ         | #'#5#'#5'STj'STRhhqRhhM (%#5#47632#547'7674'&JZ= U~83? Z ZJ> hhh'F1 S$+F;:/7!S BBGRP3#:<:'M)'","M /3#'#5%#5476767674/&#"#47632#5'STZ#J=RU~83? ZRhh_72%!BBF :"@S$+F;:hh| .2#'#5%#5476767674'&#"#47632#5'STZ#J=%RU~83? ZRhh_72%!BBF:"@S$+F;:hh0O 32####0gB7F 0M@R@9QC\kD (LJJE 2#"'&5476"327654o,&C[ZR ߸w6//8735##5>>>>I:jQ #533##=м.CC>; 5d F"#632#"'&'3327654'&#"#7.&.W( D&3R* 8JI:.!4"4w@V*3/G<H#?*"547672#&'"632'"327654'&*/KV 8:R&CQ&?&.?-8 7p;;H<o/= *O)18 /DG #6767#5G&=#K/,v1?4I*:#"'&547&'&547632'"327654'&"327654'&NB%2Z*N4<"+S%#f<.91@3D2"HJ$=(G"" @ 7 -, /) 2/716F-2"#"'&'32765#"'&5476"327654'&*&IU!9:O)?R&?&/85< /n=7F<i/=!)O).0 C/: *E=8{8Ft*Bu8Q)F*?8G*I*F[|0HUa#&#"#"'&53327654/&'&547632%#327#"'&5#5353#!2#'327654/&+gXfRBPvZ4JX!GT 6NwT1D# 2V 'Y GGSu]-/?:Sf O"zT1-F`, /#/.3+]*eqD&FC Dv)7a94RJZ]0NY#&#"#"'&53327654/&'&547632#!2#&574'&#'327654'&+XfRBPvZ4JX!GT 6NwT1D# 2]P) H> qPy& IzT1-F`, /#/.3+]*eax!*b3 (%V` 0GAmRVB <X$%3336767676#&/!#!2W^#)W1  W2Wl< +:V'w L'W!/547#7367632&/"!!3#32767#"'&'&'#7OO?3Fb^ U9k, &6FMYkB ,S9;_KeCP?;;& ]/GHf;!%#"'&54?#"#"'&547672#"'32767+"576?#"'&547654#"+"5476323276?632367632327676;2"6767654JHh L@<.yLoUD\ &!  Pd+HJ VJ3.9  %;  R=:  A?䀦~73G1UIc9>W QR 0g U TkYlC4.&" 1 >YiyW"P  v(  /=@6FyfE3t] D+-P#&367676#"'476'4'&'&767'&'&767676776767454'&'&'&'&'76327676'&'&'&'&76767676767236[3. )%8&,1Z* W,7 *) ++',  O. -B!$0, 2="C!  % %%  )/ % -'K(;o!$5' MY,7   " 3 ,7:2 ,$o+J%(  (9>4!/N  G AI% /. : W76767%4732#"'&547672#"'23276?&'454767676763267654>~K{6<K$+Q B~bR` &!  c Vp/%W5?I1\+Q9/U< iS31MTU  <3<"gC4-%" 4o-5NALY.) a*b)E9@u3~'&/&'&#"&/5&'&'&767676767676'7&76762376'&'&'&76767676#4'&#"'&'&'&'#+&2))  00;  Y+/%&  O /++ J8- " =?  , F-. %#!\1 4';@'G &  [/ / /  +'''E&+6I<?3 3 <' # C* VY&'    Vbj2#"3277632327676;2"'&'+"547672;26?#"'&54767627&#"2"6765&;!EN'%T(3n!Q.bd=dnGEL$ 7\-'Sj fR !\ EWP:V 8(5]2:H@>DL&U/;#3+B ;A6B#U=8N.,2& .:Rz=$/9L)F-$%xC.0L$.#52#"'&5476"327654'&'##3uJ- <#H. <(43,7,iXe}HHX;)3L-;)4J.9+3.4'OTw 267654'327676;2#"'&'&54?6765##"'&547672#"'3276?4767&#"3276?6=472#"'&'&5476763276321#6dQ6+jf! ")4* 9Q#4Q.""JGuZI_ #!  SXv[ <{mrs?7B%#OG 'C,&G8@}qJ/$!((S "K7"m F86'R $*=O2 & q?neA2*""  . !% f,<9.-7 - Wa * D4" %@ O* 1% 7+   J  ;n8G  9?$##5!##33#Dw6FyC^[C~77UjKU*2*(%27654'&'5!##"'&54767#5!pD./.\%%n[Q)%[" L?LjIc^PL&PLM',[NQfse\JD8LP;+0QDt'&'&76767676'"/&#"6'&'&3"'&767637677676'&'&/&#4767675&/6737676767654'&E T.6`K6  !M G# GA   $ "5  ,; "K I,=J *#=W$E7E`S*  &+[-@.@,-I# 0UM>=1" ) &!7!!-   S3,LW*6C-  5 AA1;?!O."32767676=472#"'&'&547676327632#"'&54767632#"32767654'#"'#"'&547672#"'327676767&#"267654'60327&#"K(.' H  8(O2,K7@xoI45m8VOW?! M *++.)3*.3%D5FHvZIb &!  ] WtPRU?yjsr<6'-)%M  $/dA.f*  MN8"9 STN/ (/. * '%?G6+%bfB3-""  2#)XY?':9VL" #;5-(OXw7'&767767675&'&7676767677'#"'&76'&'76767676#"/&#"'&'&'&7676?6'&'&'&7676767&'& %$4 '# p^25  hs!  $3 !C/&, V&LM  HD.  )'#  " +3;6%]$&/   60!v$!   * H/>C ,  Y'( 9'(  *&)V9- * 8~~dF-x47632#"32767654'"#"632#"'32767654'"#"#"567632#"'&5476767&54767632#"'&274'&#"3*& &&-$*r+0()85(?%8&>\584$T,+  7-+g -[>8,37j]T\ a! 6113 R"/.&3" 0 &"F!;P-   "9YM7 )*;>./8 @?3iW9JG/9)xC ! $ =['u'm{['u&tm=_'!_'&tm_'&um_'&m=X'!X'&m=b'!b'&umb'&mb&'m=&{md,d',,d',,',,d'9,9]',9s',',9',',',9d';,;]',;s',',;P/0&Y'K0BLBt'LLBR'L'LLB'YL  Y 'LY h'L'LY F'L'L'LYB'[L ['L[h'L'L[DOFGFP  !&'672y#dd#y281#ww#1-; !#'67&'P81#ww#12y#dd#y21 75!&'7'6712y#dd#y281#ww#1-;x 367&'781#ww#1x2y#dd#y2#!&'&'7'6767!&'&'6767X.%pD %li$%E:X.%%pD %li%E:\> A!`}* `?\>3 A!`}$ `?$%'6767&'&'6767&'&'7\>3 A!`}$ `?\> A!`}$ `?]X.%%pD %li%E:BX.%pD %li%E:Zu3!'7!#7[nuTpoT!!!&'&'6767QQHM)\^&E)M~5PP5b!rZ$zP$!b'7'6767'#'#H!rZ$zP$!b5PP5m)\^&E)MHQQ-'7!5!7'!5!'7)MHQQM)\^&E!b5PP5b!rZ$zP,<z&'&'7373!rZ$zP$!b5PP5)\^&E)MQQH!'7'7!&'&'6767!7'!8L(nD*oR&(LL(nD*oR&(xTToT}_"A'e`-"__"A'e`-"VVVG$@$#3#4'&'&'&#"'632#"'&5476"327654'&%P(;P.6;/1qGi=!#!#idvvd7i=GV@)= !! !!5 8o%Mug`_Jm(  !5  FF2o %##5#53533!5!FFFF@(i7&'&767654#"'&'&76?6/&'&'&'&76765&'&'&6136767676'&/&'&  -&   `, -)   $ 22 &  ">0 `  +  '$0     , GG3"    1&, '7$^P.!It{/<&?'&'&/'&76567667676&767'&z+%- 7 F/ 0H ,'.BU@70>V&(/O# IU( #'=/E0t& ,$& "/&8!!2*C<'1 #)EO#A-#B*|-=67676'&/'&7676&'&'&767677676'&eG! KB6--@VP0?IH.#:@I.5 M$G'/ #/& g<3&!':&G)@!,%@=12P.5=/5B%) . 3@73 ! $:  $$)#;!!) Z%7G!# #GAA^B7,,w@(!#54'&#"#547676327[WqqW[7]_ famOLLOm}`c_[{ (3#"'&'&=3327657]AZ02fa7[WqqW[}`D_[{ mOLLOmd 47632&#"#"'732'4Q! D%%D ^!SO7GS  h88Vd 747632&#"#"'732'47632&#"#"'732'4Q! D%%D ^'4Q! D%%D ^!SO7GS  h88VSO7GS  h88Vd V7S47632&#"#"'732'47632&#"#"'732'47632&#"#"'732v'4Q! D%%D ^'4Q! D%%D ^'4Q! D%%D ^!SO7GS  h88VSO7GS  h88VSO7GS  h88Vd 47632&#"#"'732'4Q! D%%D ^!SO7GS  h88V/747632#"'&%47632#"'&47632#"'&$ ($ ($ ($ '$ ($ (A($ ($ ($ ("l($ ($ 3'&'&'676767%9P$p2)&B/T m73  ' !% ">K 3#"/&#"#67632327659'*b5T u,U ?# E1 '&'&'676767''%9P$p2)&B/T m7q233  ' !% ">_" ''7'7122122112 !5#5#5&hhhFFhhphh5G6/%#"'#7&#"'6327'&#"'63273327#"'327G4MG6RF%()|!%?F%()|.FG6Q G(#%CGߔ3P ](P,b]*b 7#537#5!73#3!'}9L2;9L3oFfFiFfF- %!55% v8CC3EOO- %!55-5v8CCxEOO+ 533##5#53327654/&#"4767232"#"'&'4i66XUw{VSXM`{V95aaddaaddA66{VSXUw{V9XM`ddaaddaa+-!5!327654/&#"4767232"#"'&'4~XUw{VSXM`{V95aaddaadd/6{VSXUw{V9XM`ddaaddaa+ #577''7!4767232"#"'&'47327654/&#"''''aaddaadd5XUw{VSXM`{V9'&&'ddaaddaa{VSXUw{V9XM%!5!3#7777k' , 327654 &#"#"''7&54767632JVt\[Wq\?$[\ed fa%aYed h*FJ\[uI\ Siq#[gkh[b%bfkhY # > ttT887#"'&5476323#54'&8@ 86 T&\2 '2 -7mC88mfWX/ &/&fC+ !$D&/MM3 .U,Pe62#"'&5476"327654'&6.7/- (- (6/ 8/9(. )0 @^7676'&74767676%676'&76767676 %!P M *H$Y V! .W#5 2R*:w* J>R,2 0N!=y.  M;Fa#'%67#&7676737'&/&' YVO~m>G"  73noP  !"B$)Z~s:] <*+ sN2b0*:c|l/%676765&'&'&#"&'&'&54767636yjc^]xzjd[Zwvoea#"zq ec)YSkl]]WSjka_2b[x |mj`Yw%$zmj X 6 '&'&7&76   /"  je   M &7676/&767 ?      W S! X 3#3#22222   3#3#^2222  !2#!#"'&5&547632Z)!   )! g  /%47632#"'#"'&54763   + X^+ "    2 %335#'3##2dKR2d2, 73##533K2dKdRJ 3#] X r~=;f2,3#67676'&'&'&2T  \Oz>=s&&76?6'&/#"'&5'67    # 5  '%'&7676632"''&'&767      )  !  ! BE Y67&&'376"#?23076767'67676'&'&''"#&'&'&767674 5?24 8H  4A 1ly9QI 27&.C&j9r# +]O6TG:D/$2EB>\ eE3L!&xA X+?4)N#:Ae:.@"?$ .F/ T& P5 T\,"0Zu[67&&'376#?27676767'67676'&'&'"5'"#&'&'&767674HJAH 5" Q !@' @Dx" \Z ;7/7&I!+tF|*  #6zQ ?^O= F&9(=RZTn{S?,$9-!E: *'V3 B~B&,2M M`L/KpM[I%7'6'&'&'&%67&'&'&763NAMF?//*9-.E?/~(d< F:9eSXRILO%"h>"0'676'6767676'&'&'"'7767'&'&vKaFQ/=q6ph4H  0$"B%M$-Os/1=' )7WgN$$? "/B)" )9' A V:#1'676'676767676'&'&#&7767'&'&]pR[5Aw Cw6U%   8*(T U05h <:>+ /9]oW,(>%"7L0)1 :- A  1#1;776767627#/&'&76'"''&?&'& 6+A =/"  4= A Q"&|1 ;% A P0b+5776767627#"'&76'''&7&'& KR C)( F3 8t 3 J+灐;1]/@G7r@=(  ; G@B]1 ,1 :+ A (ee7&'7676'&7&'767676'&'&773767676'&'&'&'&'&767674<130Iq ,-3y h>A2t |:q `' >AnO  ?  )!#7  ?M B*06!.6rQ9;)C'7S ,WAc=@]?)V<JYIO,'J33 ?5. w)8  !5K K35U<n i7&'&7676'&5&'737676'&'&7"7767676'&'&'&'&'&76767&F $-2-P% 46E ?@F LÅi.CEsY$ ?1'&> HZ3- H19<". <:%:)8@X 3a @5@f8H PaRV 0+R=   G("=& *+ < $=L U<,wyJ7'7&'&%'&'7767676/7767676'&'&'&'&'676s-Z" *.4 \$#&h>Us? ApC@ &$.A!@' D11 p+7^//Y.C7#@p9= @ ZK@ [T '8&GO/*C"ElY] )g7&'7&''7'7&'&'&'&'7767676''7767676'&'&'&'&'676Y< ; w: = .d).04(&'iFL&!kG@0$ Q( !D *#1E/I"F( K6 , u37d"59!:%" /`= I8'?|??eL @ TRGa\ *,7)JV41Q#LwhH'77&'7676767&767'&'&547676&''&'7767&MI >$6lF&PA0^T61K6.28Iw!<[UKW?NMCTZf"$*&47y- A 9v;" >* =33>/3S;' (!!%&-?0,6>>90 )- @ Jzc7&'7&''&'77&'7676767&"767'&'&5&767676&''&'7767&)=< x8 < ]P%?!F M+_W/n]=7P<41:R&E_`U^CS1E]ds%(8'9<39 "!:""nA <}P,>. E96?/3b<+,&#%) . ?2/8C5/ 1 7. @T;$&'&/&'&7676767676-8f=Y TM/EO!>" Fk Mc C >.9@" +?# Ot 97&'7&'&/&'&7676767676< ; w: = 8h:*` OS/ST%D$ Gm9!:%" 2!J3k@C.DD! !%-E% Qu5b"/'&'77675367'676767&'&76i M"A)_d8 1N1 '@%-@0!]@õ >! 2/# D/>0&8z rlxu Y3D7&'/77675&'&'67'676767&&'&5&768=< t8 X$"A) < +kfD 5A5 +A(0@/%d9 "!@#" X "=#6B,I2=4)> t! ny2F ?'&'&'&77767'&=!~'#z;0[ v ,0RFQ+ @ 52T%@ A ]+57&'7&'767'&'&'&7677'&8=< x8 < w<% )'A4`$k EPXCP9 "!:""_/ A# 77[A A >9'&'7723&'767&'&767'&'&'&'&7676&s& r@FD$^:'L?7I7@ ,9K^!N1/WCRm<@PV##4 @Fh u9 *>* ]lA6G 2=* (!?$ .9DZK) GrO7&'7&''&'7327&'767&&'&767'&'&'&7676&^> ; v;= &- K,'A[J$]d'SF=M?9=@Pf&K=9bDWmDI[c&&H9 !!:#" @Ey vI+?.blr5L 74-**+# @# 0 ; v;= A !WidCV5R.(+tk4& 9 !!:#" #S-I%5$v %u-(?& V Tz6r B&'76'&'7727'7167'&'776767'&'&7676'a;B2" !,p A Z j W C|%1 < FZ:#1!;a9.>2 @@ 2*6<% A !_/ %7K.!9mb"[7&'7&'&'76'&'7763'767/77676767'&'&76764<< v: < lA E9& * @S k ] G07 @#K]@&3 $?dC39"! :!" iE 6"3@K"@".9B' A #`0 )8O4$;#_p]UE'616763&532'"#/&'776'&'"%67'&'&'&'&'4'&76 AA6j *,FOB0P4% 7AEAF|:AX3 D <p-!?5A '"Q^?Tr^7&'7&'"#'76763&7452&#'&'&'73276'&'&7'&'&'&'&5&74L=< x8 < A@XWp8  + . "F_& 24(GX8(  #9 "!:""@MKIG@l8H  <* rO7)E& @ 1'VVR)wa-77676&'&'&767676?'%'#'& MG...R '.n'* GP@?A53: AI?+*B,3J7 1?1| E7&'7&'%77676&'&'&76767'##'''< ; w: =  LZ=34_+  +5w+$:.$1U-9!:%" \A?$A"*B+3I>@)-J=I#V1 ,> (Lfr!<772367/&'&''623&'&%&'7676767'676?^F GE+"(d kC@831_f/ A 3jwI (l7q,(# TA  "S @)>(LAA>#z]v)#tj+*8U7&'7&'772367'&'&''63&'&%&'736767#'67676<< v: < ?#gL LL-)*i :J=:^ GX! A Of~D"*s8r) ?9"! :!" , WA %X'A->, b@]uhc>$f~2#a$"Y~6f<&'7676?#6'&'7767676'&'&'&'76G> {KAbI'&Os6/L77 (-<W<6_;,AiL +A '?8>*&776?6"'676767676'&'&'U WA[90~!f-L& a(<,06kcdQA " XJLtU0 A .IAG5jg;7&'7&'776?6'676767676'&'&'3=< x8 < ?Z ]E`=4 %n,V'"e-?07:qpk}9 "!:""A%#]OSz[4 A 0L%$EM<UZ5$%&'&'&76767; ^O!)*/8G%:EeA@<4+8DV( <' ?!6Ro8/s.a617&'7&'%5$%&'&'&76767<< v: < UN e_%-,"8;O)= I9"! :!" @@?52?L]/ A) ? $:Ww<3|8O"677'&'&'&76767&7457F fZ#'  %_i:, 7"AE-?91*6;?: A MDZ'#S7097&'7&'67%'&#&'&'&76767&7453> ; v;= P pd'+  )hf?/ =%A9 !!:#" _1@<4.<@F@ A OHa*%\9:UAZ%&'&767&'7&&''&'&'&76764'&7676%"'73676767'6766`1)J#lYq73N R,@ ?o o%42Ea8=o !%j^9 @ 3`W&zB8g<%  &A !A ,r_A8?D8== (! nl5&_ A IBR0 6x o**?. %9dB682+? "; > * UlB(_ B*)t'  "V><kMY_%&'&76767767676&''&'&'&76766'&'&/&#5'6?5'76( D% "'2A&)R$df Z'*% :$D-I8.? G ! ; 1R&'UaA.d6 Jf D7)! #  : ?_ t|&6,C86-'KTa\"7h 6~$C\ AUm'7'&'&76767676'67676'&'&'&3676 0f/3?6 > -wZhd0<"=a:(30sJ|]3 & _CCev{T@C2Tj|;/U4>.' Fa7+S* d7: 'Cgh @:  Z5$O ![F=3'PpM^! @)A<9!K  &  6h @ CF#9% @ p:8T71/ 6C J% 2 "!_N5gs"327654'&'2#"'&5476&"#767676'&'77676767&''&'&76767676&7476J    ) %) %S4 8[ ?gh @`Z5$O ![F=3'PpM^! @)AN    $)$+zK  &  @ C@ p:8T71/ 6C J% 2 "!r/;/'677676764'7&''&'&'&76767;%B#d_Cc*#@Xd8F:"1J\u6H=DaA=Q34X/(1 !u{}7D[&) U kD7&'&''&'&7676767#'277676764'77&'B=< TCg9\3%5{c1LAF|>/G$jjLj/&@ 8 < 29 "!3!uȈ;.=a)-A=S>>^"3!+ ) '" U SO"327654'&&''&'&7676767#'277676764'7&7672#"h   C,h9\3%5{c1LAF|>/G$jjLj/&@,")%%    Tu!uȈ;.=a)-A=S>>^"3!+ ) t/ $) @Ys 7?7&'&%'6767'&'&'772767676'&'&7&'&*J(L7M!&8:&(\T!&0,Q9-6+T%M*0 +t0^z$X&.1A.x"w&( f(&09, $,@rWL*  <57 (+<?v+nJ7; (;+LT7&'7&'7&'&%'6767/&'776767676'&'&7&'&<< v: <  +O-P6N*#9>%)a\$)04V ;/;"'b%U,4"! $/}0e$[-&9"! :!" 1F!4#{0'"!j)'390#&,I}\R, C6< +1D C+vQ7<& ; *7X`"327654'&'2#"'&54767&'&%'6767/&'776767676'&'&7&'&    *$*$+O-P6N*#9>%)a\$)04V ;/;"'b%U,4"! $/}0e$[-&   %)%)1F!4#{0'"!j)'390#&,I}\R, C6< +1D C+vQ7<& L'7676&'&/&'&{/b:JRHV`R*HxC$ <,lE<hx` 1NI   G+> 97&'7&''6767676&'&/&'&< ; w: = 0_ =?@K[kX *LI( "C$9!:%" ,gE) mg1QP  O*+B"327654'&'2#"'&5476'6767676&'&/&'&    ) %) %0_ =?@K[kX *LI( "C$    $)$+,gE) mg1QP  O*{lhIS%&#767676'&'776767&''&'&747676&'/776%76~L13T :]IO V5r:@"l4 UB8/%T uDQ!^V@&A;  # 2 @? >$ Se"P7B. :FK  0A t{v_N co7&'&#767676'&'776767&/767&''&'&5&7676'45'7727274%76E< ; U58[ > e! OO 0J./ ):  K :".![F=3'N|JZ!#gT @)A9! B &c A @ G :&?% n]7N!0 4B O  @F "!_N!fr"327654'&#767676'&'776767&'476367&''&'&5&7676'45'7727274%76\   U58[ > e! OO 0J8#&( K :".![F=3'N|JZ!#gT @)A    B &c A @ G'+'$!?% n]7N!0 4B O  @F "!X;#X%&7676763&67&''&'&'&7676'5'&'&765?3567'6rk" 9UI Af e] E\"X"\B>+$;  0X{1/x;:@^$K*  ( *wngAli @y%&p8`(= &3%%%!E % @m=GF306367676767'&'776767&''6767&''&'&7676tj<  R0"'Bhwki"3J&eA `991|& kSh1#/U/ $I FO"M^ A  5] 25s4 $=5(NH 8??`8f 1' #=N5 e7&'&&'&'6'77634'76776767676'7#'&'&767'&#&'&'&7676766"=$;  (?4{g;A:xF %)z58@$d~10#R+/#%7#H>$!! =AUl^^ &>* \-R!) :A X!h7d  >43 <$%`XI6767&'7676&'76?6'6767676'&'&''&'&'&76J<0T L&T 3M @Yi$?X=44A>:1 -}/55'81$8E,,5-r TLT(\e?KCS/ $ b3,q5$;ayT6F A4cO4ScB*)t'  $T}#?OH676727'7676765&'&'7'&'&'&'&747&'7767&'&'7hA5c v4!E IH a58_%w=!=4*E$"-3;PjCw< c8h,+E0L. 27CWH'0=.5+)3. #*/#!;y I%765&'&''&74567676767&'7'&''67&'&'&'76'&]v<(G$0 .P=6 A(?2%?XAC1QKNb6}!h-?1 ;)!BN3Iy4b]LcK*e\ęnOi$8U3l%&sJ- :H7?(%a TV%`sP%76767654'&'&'&''&76767676767'7'&'6'67&'&'76'&e80O6%;'gF< B-@31HX&,@ N:X Q Yo:!1U@ :."0N .b]I}c{W!:q\ȅ14Zn/ gi#7x-.~T3 >O7P-([)g/1$:%&7676'4'&767767'&'&''&'&767676[K23F;A`d# rR)CONX!Pi>E'  ( +&M*6x^?! o*s 3j'Z*( HJz4W'1676/7767676'&'&'&'67&'&A v:vomF(D$4[hJ/"? D,/_:^9>_}>:pc;5wZ BC&1`f5$?A  ,P6'5"M)P$AA5;0  .+/67676'6767676'&'&'&76Q>9 rt4*.* & .WVA*0!9Y$*Y'Vj&@ ; / %M25fJ% 8?& T"_  ". C-(65f6MYM7457767676767'"'&'&76'4'&'&#'?5'76 A&)RjVF H  @ (.3 6"+gA62Jf D7) 0:3|7, E=' k [!&E319 5&V\ A"wf,77676'6767676'&'&'&''&5+1 Ǥ}_4XO%;L :"&o<^(Vj&@ ;MJ)/ZV8) ?& 6B1- o64EV<767676'67676'&'&&5'6?5'762A )E8icN'B ##i8$ (H "UeA7?7AR :0!yJ#;s +*' 8`;3Z8"=7+ 7I)# "cbL=M% H AMY877676'67676'&'&#'6?5'76A&)RXipY,!I'-|C/1T'(ayA%m6 Jf D7):%G*- ?kE;d?(><1")@S4* 'v($C\ A8Oi _%&7667676?'676'&'&'&767676654/&'&'&'&'&7676gE 1V(I8   V!?X+]WJ.&h,X fdI]Qj 6EBg,.26=$)$!aD  y0J?J)5I|" A 28 (b27r[C !7CB EHX:  ay8"0'1NJ,%jk 0~%7&'&%67'&'&767676'&'&66''67/7327676'&'676767'&'&'&'&'&'67&'&76$G#:$W;   fQH$3 _[B)-!%J'Th6z:+{ns]6.Di5 K2, >+H:,%'#<4g#X 6.""HF6  !  '># #9  46(Y&5 A ?w0 $*=T4K2   . 71<% ** 18pP.4+wS&'767767"'67667/&'2&'&'&'&7676767&'676>3d n:!@!g' \)()-9US2 \Q ApE mCQ+'&X .{+ALF@^B (?(;dk"&9! (@5 .9GC i0XLK57676767'&'&'&7&'"'76763676B #5Q1O1 U=P !:O3[;h;Q?,#  h'' "_*]& 6#=G"2C(f 7!I7&'7&'L<< v: < {9"! :!" ,67"#'%3''67676'457w>;6C1._ &$d%)b" "A*CAAJ"#!PIP3M.D?H$6767#52%''67676'&57OxN,5m,*r(i%(A51VAAV$(/^T\ 3T,S5M'67676767#RFOo 5i8 A>N;M3 A '9 }vbG'67676767#]QZx 5q>AHW ;V8I&B?*53!'67676767!#A4>C<>$< A` KQ9 =6)H z#U53!'67676767!#Ad CJsJ+GA9QY@(>=2!W'(N #5!#!!5!P>1_AAAAS !5!!!!5!ZgAA@AAN46"#'%23&'7723#"/7767676'&'&''67676D  A   =.P G   V?;'6>ABrAoJ6 ?3 dIEg 3f;HMhf3"5%'7%23"#/7767676'&'&''67676tA   H2XW#' fII (DEzAAeR>? "A uUUu3vLQw/46'45723'77676767'"#'676DEA$   #6$A> ",{+/o*UiAHdJMm, )=wiqSn,.ro4'7'77%'%v\:_S:uK;k9V%'67676767%3'67676767 1s(s, .,? >,R?%)d!?O>+YW >1HY3X8 E <@^7+e^;V5(-\M:7&'7&''67676767%'67676767[<< v: < 9$4v (u-2/? p,WA*/g#U\>,c_ N9"! :!" :C7L]3Z4K H@d@1ia&<\?*.giJz"!'67676765!#'6767676M(n 1v(@&" .q1&o*0oH~ +H > {DA\#QU$5Q0RK* 87&'7&'!'676767!!'6767676T< ; w: = .x 1,!@X"2z#&v-6Z9!:%" P *R F IAa*#W\ 4W4^5!!5!9AA7&'7&'5!!5!J> ; v;= vd+]9 !!:#" EAA3\^#53533673#'676767##KAA5/v,,p--ASAA!Apcm(0e@ ]}47&'7&'#5353!673#'676767!#3<< v: <  A@81{&,t02AX9"! :!" AH{aAwgt#1gC&'iQ.%%'676767677&'&7&'&V/$_j9d<36d]).F)G@$+&E>84 Q>C2P8 NA.SHeA ;2> /52!!a"U"m2i&2<7&'7&''676767677&'&7&'&<< v: < HT@/fp$9h<:?mb+1L)E)$'M%>87$09"! :!" [=F-"(V#BQM4[L @ ?3:M59 (e!Z'R^^$'67676767'%23&'&'&`0#Qb&zP?5C?4he| 6yIhA@bR+5I4UM4H9`,X69t{nB;(FA0$NV E2&'6767676%7&'&?:'#,KH%A'L? -C".;,%[S=hq26kA'(j"/?)0ea)%n$%/7&'7&''6767676%7&'&O> ; v;= /?>,%/NV%E/"SD v,G!"4;39 !!:#" fXBmv=6pC./t(/A/.sm(!s=)'67676767%'6767&'&'767k. +a&/2?',`F#%ZG!?W6H."SW)0P;Mw{2S3 I  @m5*gn+7f2FN2?7`V E7&'7&''676767676%'6767&'&'767O< ; w: = #.j*d& 15>",cG*.]@"TP5soa*4X?Wp9!:%" s4.IZ2W1L U<?pC5lr&7oGDMS@=e qVf"!5!6'&''6767!!'67676W[ agM \ &,u*&o)A@P "@ N`_)8\=!i'Jk ,]pgN#%-57&'7&''6767676%7&%7&'&^= ; v;= >D,.:OS"E,!XM< A 0e1:(8 !!:#" >biIce28`;')o,]J#)t ,fwQZ3xD!5!!'67676'45!  c 1g AAc:% Uu +vB=fAA9*.7&'7&'!5!!'67676'&5!`<< v: < }o_t  g 2m# N9"! :!" AAl>(#Zz $*}ECl.AAyd#37&'&'&AAy;?f.c03/5)$'f.a  rD4&7&'7&'#37&'&'&z=< x8 < AA@Al .h609 "!:""} ^,')j /h$v7jj#5276'7%23"#'67676rsAB 'l 0e& A]TAuMdy ,p?!"Ec75!5!c(E2AAAAl6-67!5!&''6767"'&/7-?S%i@Fy 1}F.!b>!m/&GUAAV9+87 ar%8|f-/-->02` %7&'&'676767!5!&'&'#uD !;2HR ;sejh+Y@Cw*lFBAAp"&&(e2]+$1P'6767676h?"!$FH#C0@)P XF6hn/7l?,.aN~7&%'6767635]:jC@&e/f#!& A Lk-k=A.p 07&'7&'7&'&%'6767674'< ; w: = 6j;C13T@#(i/n'$79!:%" C&TW LNq-tEF.1 (:"327654'&'2#"'&54767&'&%'6767674c    )%)%6j;C13T@#(i/n'$    $) %*&TW LNq-tEF?%67'&'&'&55367678j#%9g_AX"AS]]_֖\ "@=*VNhqJa"@N_ie?9"! :!" t1[+%@ ?.\ ]VhqJa"@N_ie?    $)$+t1[+%@ ?.\ ]V ; v;= 4u7." ( w*u'}'1 09 !!:#" &;. )![3E  1L@ 9"327654'&'2#"'&5476'67676$'&'&    *$*$4u7." ( w*u'}'1 0(   %)%)"&;. )![3E  1I^b $7&'&%'676767!5!53!!#S;3"#X-[($s? !V,X,A1At02T/W92y47O 0O.-AA(l!,87&'7&'7&'&'&%'676!5!53!!#> ; v;= ;4("`,c+'9> '"Y,a# HALAl9 !!:#" x91^.]=6 @:Q1V86 AA(ly -8D"327654'&'2#"'&54767&'&'&%'676!5!53!!#     *$*$;4("`,c+'9> '"Y,a# HALAx   %)%)Wx91^.]=6 @:Q1V86 AAI$6767!5!&'&'7|92<(K;9|5L0t;.t&dRA9tAAEAU4S,~4(U5GP26%7'6&'&'&7&'&7&'&^ m UX `n@E|rD6DE~xA@A P;K4A 7;4A;;9$7'67676767&'7''q(*3?4,)[0E0m5UZah] 7:L,'sG)A^&'767&''676@@ADn-b::'C))`(A( '7'7%'6767X`;d|1$#"T/c* ;0?-i5g85V-bWY_dRU'7'7%'6767Bq;v2-&+]/p1 z:C9?6{5}5P2P@IAA  U*N,#;.'a)c05C,7VP8BK1E+ [O63676767'A[a +L('kA6+/2026,33 !#!#5 AuAIpAB4>3(#!'67676767Aq 7B}H+5 GKZA.=B2!HHR#!'67676767A =I*rPA"=(.ScJ)=G2)/S)]W#3#5!533#!!#!53JHA3A@AAAAoz%3!!55!'67A{mh =AAAAvH8F@GJ67!5!'6767!5G3.+%PhDv04rAAZ;.aW1;N0TyAg7'676767677&'&^B-\U F.D_-7&'7&'53!'67676767!#L<< v: < uA "IO}O4 L!{A{9"! :!" R9Z`C,=@4!'\&5=] ,H7&5723'77676767'#'6768ru:A 2 94   *s(/b"H A??`%$= eG_Hcy*-e1g5L!#'676767!#'6767676<#d1i ?  (c*'h' , %VJ')'!=$RM 4&X#!5!W  LL?4X#&'&'&/&'"'!5!34W  &9 S2#!  Wzt7 L 2Bw9X-)5!6767676767075&'&'&'&'!5!\N    "jb_7 ()  "5L   .6 'L  4= E/E%%#4767676767475!53!W %q. aW8N:(VVr72@ 9HᕙE3."-?6X )!2&'&'&'!5 UT'3W) 9GX*?5 +3' @%X#&'&'&/&'"'!5!W  &9 >T2#! zt7 L 2B#uX.6+532767676=#5!#&'&'&'&'&/  % AT2)<0! W  &;  ?+L,)LH2@t8 2!5353F FF;:>72;7676767453#&'&'&'&7336767676=3'3# =$/R' 6!W^ @GRG?C-$Wc' W 3RGG52  4&(RfT#?:>R  +#3G;:>72;7676767453#&'&'&'&7336767676=3'3# =$/R' 6!W^ @GRG?C-$Wc' W 3RGG52  4&(RfT#?:>R  +#3G;:>B72;7676767453#&'&'&'&7336767676=3'73#3# =$/R' 6!W^ @GRG?C-$Wc' W 3RGGGG52  4&(RfT#?:>R  +#3GG;:>B72;7676767453#&'&'&'&7336767676=3'73#3# =$/R' 6!W^ @GRG?C-$Wc' W 3RGGGG52  4&(RfT#?:>R  +#3GG:}FX#'#5&76767'367676753#3#0 W9 &f/ W: &fE > %TP =$QM  %TP =$QM ҃uuGG:FX#'#5&76767'367676753#%3#0 W9 &f/ W: &fGGE > %TP =$QM G:6X%&'&'&'&'#533!53# "j^1 () JGGL'6 'L  4= LL GX%#73'&'&'&'&'&'4#3#BuQ > RWF"2XGG˧. L*R "UG&X #!5!3#WGG  LLG?:X"#&'&'&/&'"'#5!33#:W  &9 S2#! WGGzt7 L 2BwUGX333#pWGGXUG(X ##5!3#WWGG  LLG=:XDH"5632#"'&'&'&'336767674767475&'&'&/&'&3#: -*&HL$"  #MHIM!$ W  2 +#    3 2GG R+1AG,!++!4@z8 "18G X3'3#WWtGGX#wG&8X#&'&'&/&'"'#533#W  &9 S2#! GGz<7 L 2B,G9X-13#536767676767075&'&'&'&'#533#㪤N    "j_7 ()  "5GGL   .6 'L  4= E/EUG%! 3##47676767675!53!GGW.[W.G*aEx1+$%)V 5ᕙ<9 $$0:X##532!534'&/&#3#:X:NM5U-#$8GG  L!A-;L+&%G3FX)53&'&'&/&'43#F  4 IMUGGL(7L+.%G=9XBF!"'&'&'4'!2'6767674767475&'&'&/&'"'#3#;IM!(@B $"  #MH+#    &9  2 GG+!:9z"1AG,!+L "18 8 G98 X)-32#&'&'&/&'"'#3/&'&'&'%3#9@? #! W  &9 yB"(G$+GGX!2B<7 4 L$7 G?X9=3#53276767675&'&'&'"+3/&'&'4'5323#87 , ,;5 XB"(G%+LB / $ #a GGL<9* 4 L$: 5?&= !*G3X 67676767670753!5!33#<.   W !"&FdGGU *70" L G>8&X%#5367677!5!#3#,>7h o 0WGG!L*!2LG( IurUG%X#&'&'&/&'"'#533#W  &9 T2#! GGzt7 L 2B,G;X:>72;7676767453#&'&'&'&7336767676=3'73# =$/R' 6!W^ @GRG?C-$Wc' W 3RGG52  4&(RfT#?:>R  +#3G#{X.26+532767676=#5!#&'&'&'&'&/3#  % AT2)<0! W  &; GG ?+L,)LH2@t8 G>333#>WOGGXG:6%&'&'&'&'#533!53# "j^1 () JnL'6 'L  4= LLG9-13#536767676767075&'&'&'&'#533#㪤N    "j_7 ()  "5VL   .6 'L  4= E/EG?9=3#53276767675&'&'&'"+3/&'&'4'5323#87 , ,;5 XB"(G%+LB / $ #aL<9* 4 L$: 5?&= !*GHF5367676753#HW/ W: &fD =$QM #!%)%5476767654'&'&#347632#3  7C5 39/% 888hg 3* N ($+ ))" #;A{hg"Z J,4J HX-\% @ FD$,T Z    J , 4J   H X$$ $H$TcCopyleft 2002, 2003 Free Software Foundation.Copyleft 2002, 2003 Free Software Foundation.FreeSansFreeSansMediumMediumFontForge 1.0 : Free Sans : 29-7-2004FontForge 1.0 : Free Sans : 29-7-2004Free SansFree SansVersion $Revision: 1.27 $ Version $Revision: 1.27 $ FreeSansFreeSansThe use of this font is granted subject to GNU General Public License.The use of this font is granted subject to GNU General Public License.http://www.gnu.org/copyleft/gpl.htmlhttp://www.gnu.org/copyleft/gpl.htmlThe quick brown fox jumps over the lazy dog.The quick brown fox jumps over the lazy dog.navadnoDovoljena je uporaba v skladu z licenco GNU General Public License.http://www.gnu.org/copyleft/gpl.html`erif bo za vajo spet kuhal doma e ~gance.i2  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghjikmlnoqprsutvwxzy{}|~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ softhyphenAmacronamacronAbreveabreveAogonekaogonek Ccircumflex ccircumflex Cdotaccent cdotaccentDcarondcaronDcroatEmacronemacronEbreveebreve Edotaccent edotaccentEogonekeogonekEcaronecaron Gcircumflex gcircumflex Gdotaccent gdotaccent Gcommaaccent gcommaaccent Hcircumflex hcircumflexHbarhbarItildeitildeImacronimacronIbreveibreveIogonekiogonekIJij Jcircumflex jcircumflex Kcommaaccent kcommaaccent kgreenlandicLacutelacute Lcommaaccent lcommaaccentLcaronlcaronLdotldotNacutenacute Ncommaaccent ncommaaccentNcaronncaron napostropheEngengOmacronomacronObreveobreve Ohungarumlaut ohungarumlautRacuteracute Rcommaaccent rcommaaccentRcaronrcaronSacutesacute Scircumflex scircumflexuni0162uni0163TcarontcaronTbartbarUtildeutildeUmacronumacronUbreveubreveUringuring Uhungarumlaut uhungarumlautUogonekuogonek Wcircumflex wcircumflex Ycircumflex ycircumflexZacutezacute Zdotaccent zdotaccentlongsuni0180uni0182uni0183uni0184uni0185uni0186uni0187uni0188uni0189uni018Buni018Cuni018Euni018Funi0190uni0191uni0193uni0199uni019Duni019Euni019Funi01A5uni01A7uni01A8uni01A9uni01ABuni01ADuni01AEuni01C4uni01C5uni01C6uni01C7uni01C8uni01C9uni01CAuni01CBuni01CCuni01CDuni01CEuni01CFuni01D0uni01D1uni01D2uni01D3uni01D4uni01D5uni01D6uni01D7uni01D8uni01D9uni01DAuni01DBuni01DCuni01DDuni01DEuni01DFuni01E0uni01E1uni01E2uni01E3Gcarongcaronuni01E8uni01E9uni01EAuni01EBuni01ECuni01EDuni01F0uni01F1uni01F2uni01F3uni01F4uni01F5uni01F8uni01F9 Aringacute aringacuteAEacuteaeacute Oslashacute oslashacuteuni0200uni0201uni0202uni0203uni0204uni0205uni0206uni0207uni0208uni0209uni020Auni020Buni020Cuni020Duni020Euni020Funi0210uni0211uni0212uni0213uni0214uni0215uni0216uni0217 Scommaaccent scommaaccent Tcommaaccent tcommaaccentuni021Euni021Funi0226uni0227uni0228uni0229uni022Auni022Buni022Cuni022Duni022Euni022Funi0230uni0231uni0232uni0233uni0250uni0251uni0252uni0253uni0254uni0256uni0257uni0258uni0259uni025Buni025Cuni0260uni0261uni0265uni0266uni0267uni0268uni0269uni026Auni026Duni026Funi0270uni0271uni0272uni0273uni0275uni0279uni027Auni027Buni027Cuni027Duni027Euni027Funi0282uni0283uni0284uni0285uni0287uni0288uni0289uni028Cuni028Duni028Euni0290uni029Cuni029Euni02A0uni02CAuni02CB gravecomb acutecombuni0302 tildecombuni0304uni0306uni0307uni0308uni030Auni030Buni030Cuni030Funi0311uni0312uni0313uni0314uni0326uni0327uni0328uni0374uni0375uni037Auni037Etonos dieresistonos Alphatonos anoteleia EpsilontonosEtatonos Iotatonos Omicrontonos Upsilontonos OmegatonosiotadieresistonosAlphaBetaGammauni0394EpsilonZetaEtaThetaIotaKappaLambdaMuNuXiOmicronPiRhoSigmaTauUpsilonPhiChiPsiuni03A9 IotadieresisUpsilondieresis alphatonos epsilontonosetatonos iotatonosupsilondieresistonosalphabetagammadeltaepsilonzetaetathetaiotakappalambdauni03BCnuxiomicronrhosigma1sigmatauupsilonphichipsiomega iotadieresisupsilondieresis omicrontonos upsilontonos omegatonosuni0400 afii10023 afii10051 afii10052 afii10053 afii10054 afii10055 afii10056 afii10057 afii10058 afii10059 afii10060 afii10061uni040D afii10062 afii10145 afii10017 afii10018 afii10019 afii10020 afii10021 afii10022 afii10024 afii10025 afii10026 afii10027 afii10028 afii10029 afii10030 afii10031 afii10032 afii10033 afii10034 afii10035 afii10036 afii10037 afii10038 afii10039 afii10040 afii10041 afii10042 afii10043 afii10044 afii10045 afii10046 afii10047 afii10048 afii10049 afii10065 afii10066 afii10067 afii10068 afii10069 afii10070 afii10072 afii10073 afii10074 afii10075 afii10076 afii10077 afii10078 afii10079 afii10080 afii10081 afii10082 afii10083 afii10084 afii10085 afii10086 afii10087 afii10088 afii10089 afii10090 afii10091 afii10092 afii10093 afii10094 afii10095 afii10096 afii10097uni0450 afii10071 afii10099 afii10100 afii10101 afii10102 afii10103 afii10104 afii10105 afii10106 afii10107 afii10108 afii10109uni045D afii10110 afii10193uni048Cuni048Duni048Euni048F afii10050 afii10098uni0492uni0493uni0494uni0495uni0496uni0497uni0498uni0499uni049Auni049Buni049Cuni049Duni049Euni049Funi04A0uni04A1uni04A2uni04A3uni04A4uni04A5uni04A6uni04A7uni04A8uni04A9uni04AAuni04ABuni04ACuni04ADuni04AEuni04AFuni04B0uni04B1uni04B2uni04B3uni04B4uni04B5uni04B6uni04B7uni04B8uni04B9uni04BAuni04BBuni04BCuni04BDuni04BEuni04BFuni04C0uni04C1uni04C2uni04C3uni04C4uni04C7uni04C8uni04CBuni04CCuni04D0uni04D1uni04D2uni04D3uni04D4uni04D5uni04D6uni04D7uni04D8 afii10846uni04DAuni04DBuni04DCuni04DDuni04DEuni04DFuni04E0uni04E1uni04E2uni04E3uni04E4uni04E5uni04E6uni04E7uni04E8uni04E9uni04EAuni04EBuni04ECuni04EDuni04EEuni04EFuni04F0uni04F1uni04F2uni04F3uni04F4uni04F5uni04F8uni04F9uni0531uni0532uni0533uni0534uni0535uni0536uni0537uni0538uni0539uni053Auni053Buni053Cuni053Duni053Euni053Funi0540uni0541uni0542uni0543uni0544uni0545uni0546uni0547uni0548uni0549uni054Auni054Buni054Cuni054Duni054Euni054Funi0550uni0551uni0552uni0553uni0554uni0555uni0556uni055Auni055Buni055Cuni055Duni055Euni0561uni0562uni0563uni0564uni0565uni0566uni0567uni0568uni0569uni056Auni056Buni056Cuni056Duni056Euni056Funi0570uni0571uni0572uni0573uni0574uni0575uni0576uni0577uni0578uni0579uni057Auni057Buni057Cuni057Duni057Euni057Funi0580uni0581uni0582uni0583uni0584uni0585uni0586uni0587uni0589uni058A afii57799 afii57801 afii57800 afii57802 afii57793 afii57794 afii57795 afii57798 afii57797 afii57806 afii57796 afii57807 afii57839 afii57645 afii57841 afii57842 afii57804 afii57803 afii57658uni05C4 afii57664 afii57665 afii57666 afii57667 afii57668 afii57669 afii57670 afii57671 afii57672 afii57673 afii57674 afii57675 afii57676 afii57677 afii57678 afii57679 afii57680 afii57681 afii57682 afii57683 afii57684 afii57685 afii57686 afii57687 afii57688 afii57689 afii57690uni0700uni0701uni0702uni0703uni0704uni0705uni0706uni0707uni0708uni0709uni070Auni070Buni070Cuni070Duni0710uni0711uni0712uni0713uni0714uni0715uni0716uni0717uni0718uni0719uni071Auni071Buni071Cuni071Duni071Euni071Funi0720uni0721uni0722uni0723uni0724uni0725uni0726uni0727uni0728uni0729uni072Auni072Buni072Cuni0730uni0731uni0732uni0733uni0734uni0735uni0736uni0737uni0738uni0739uni073Auni073Buni073Cuni073Duni073Euni073Funi0740uni0741uni0742uni0743uni0744uni0745uni0746uni0747uni0748uni0749uni074Auni0901uni0902uni0905uni0906uni0907uni0908uni0909uni090Auni090Buni090Duni0910uni0911uni0913uni0914uni0915uni0916uni0917uni0918uni0919uni091Auni091Buni091Cuni091Duni091Euni091Funi0920uni0921uni0922uni0923uni0924uni0925uni0926uni0927uni0928uni0929uni092Auni092Buni092Cuni092Duni092Euni092Funi0930uni0931uni0932uni0933uni0935uni0936uni0937uni0938uni0939uni093Cuni093Duni093Euni093Funi0940uni0941uni0942uni0943uni0945uni0947uni0948uni0949uni094Buni094Cuni094Duni0950uni0951uni0966uni0967uni0968uni0969uni096Auni096Buni096Cuni096Duni096Euni096Funi0970uni0981uni0982uni0983uni0985uni0986uni0987uni0988uni0989uni098Auni098Buni098Cuni098Funi0990uni0993uni0994uni0995uni0996uni0997uni0998uni0999uni099Auni099Buni099Cuni099Duni099Euni099Funi09A0uni09A1uni09A2uni00C1uni09A4uni09A5uni00C4uni09A7uni00C6uni00C8uni09ABuni09ACuni09ADuni09AEuni09AFuni09B0uni09B2uni00B6uni09B7uni09B8uni09B9uni09BCuni00DAuni09BFuni09C0uni09C1uni09C2uni09C3uni09C4uni09C7uni09C8uni09CBuni09CCuni09CDuni09D7uni09DCuni09DDuni09DFuni09E0uni09E1uni09E2uni09E3uni00F1uni00F2uni00F3uni00F4uni00F5uni00F6uni00F7uni00F8uni00F9uni00FAuni09F0uni09F1uni09F2uni09F3uni09F4uni09F5uni09F6uni09F7uni09F8uni09F9uni09FAuni0A05uni0A06uni0A07uni0A08uni0A09uni0A0Auni0A0Funi0A10uni0A13uni0A14uni0A15uni0A16uni0A17uni0A18uni0A19uni0A1Auni0A1Buni0A1Cuni0A1Duni0A1Euni0A1Funi0A20uni0A21uni0A22uni0A23uni0A24uni0A25uni0A26uni0A27uni0A28uni0A2Auni0A2Buni0A2Cuni0A2Duni0A2Euni0A2Funi0A30uni0A32uni0A33uni0A35uni0A36uni0A38uni0A39uni0A3Cuni0A3Euni0A3Funi0A40uni0A41uni0A42uni0A47uni0A48uni0A4Buni0A4Cuni0A4Duni0A59uni0A5Auni0A5Buni0A5Cuni0A5Euni0A66uni0A67uni0A68uni0A69uni0A6Auni0A6Buni0A6Cuni0A6Duni0A6Euni0A6Funi0A70uni0A72uni0A73uni0A74uni0A81uni0A82uni0A85uni0A86uni0A87uni0A88uni0A89uni0A8Auni0A8Buni0A95uni0A96uni0A97uni0A98uni0A99uni0A9Auni0A9Buni0A9Cuni0A9Duni0A9Euni0A9Funi0AA0uni0AA1uni0AA2uni0AA3uni0AA4uni0AA5uni0AA6uni0AA7uni0AA8uni0AAAuni0AABuni0AACuni0AADuni0AAEuni0AAFuni0AB0uni0AB2uni0AB3uni0AB5uni0AB6uni0AB7uni0AB8uni0AB9uni0ABDuni0ABEuni0ABFuni0AC0uni0AC1uni0AC2uni0AC3uni0AC7uni0AC8uni0ACBuni0ACCuni0AD0uni0AE6uni0AE7uni0AE8uni0AE9uni0AEAuni0AEBuni0AECuni0AEDuni0AEEuni0AEFuni0B02uni0B03uni0B05uni0B06uni0B07uni0B09uni0B0Buni0B0Funi0B13uni0B15uni0B16uni0B17uni0B18uni0B1Auni0B1Cuni0B1Duni0B1Funi0B20uni0B21uni0B2Auni0B2Buni0B2Funi0B30uni0B32uni0B33uni0B36uni0B37uni0B38uni0B39uni0B3Euni0B3Funi0B40uni0B41uni0B42uni0B43uni0B47uni0B60uni0B66uni0B67uni0B68uni0B69uni0B6Auni0B6Buni0B6Cuni0B6Duni0B6Euni0B6Funi0B82uni0B83uni0B85uni0B86uni0B87uni0B88uni0B89uni0B8Auni0B8Euni0B8Funi0B90uni0B92uni0B93uni0B94uni0B95uni0B99uni0B9Auni0B9Cuni0B9Euni0B9Funi0BA3uni0BA4uni0BA8uni0BA9uni0BAAuni0BAEuni0BAFuni0BB0uni0BB1uni0BB2uni0BB3uni0BB4uni0BB5uni0BB7uni0BB8uni0BB9uni0BBEuni0BBFuni0BC0uni0BC1uni0BC6uni0BC7uni0BC8uni0BCAuni0BCBuni0BCCuni0BCDuni0BD7uni0BDAuni0BDBuni0BDCuni0BDDuni0BE1uni0C83uni0C85uni0C86uni0C87uni0C88uni0C89uni0C8Auni0C8Euni0C8Funi0C90uni0C92uni0C93uni0C94uni0C95uni0C96uni0C97uni0C98uni0C99uni0C9Auni0C9Cuni0C9Euni0C9Funi0CA0uni0CA1uni0CA2uni0CA3uni0CA4uni0CA5uni0CA6uni0CA7uni0CA8uni0CB0uni0CB1uni0CB2uni0CB3uni0CE6uni0CE7uni0CE8uni0CE9uni0CEAuni0CEBuni0CECuni0CEDuni0CEEuni0CEFuni0D82uni0D83uni0D85uni0D89uni0D8Auni0D8Buni0D91uni0D94uni0D99uni0D9Auni0D9Buni0D9Cuni0D9Euni0DA0uni0DA1uni0DA2uni0DA4uni0DA5uni0DA7uni0DA8uni0DA9uni0DAAuni0DABuni0DADuni0DAEuni0DAFuni0DB0uni0DB1uni0DB3uni0DB4uni0DB5uni0DB6uni0DB7uni0DB8uni0DB9uni0DBAuni0DBBuni0DBDuni0DC0uni0DC1uni0DC2uni0DC3uni0DC4uni0DC5uni0DC6uni0DCAuni0DCFuni0DD0uni0DD1uni0DD2uni0DD3uni0DD4uni0DD6uni0DD8uni0DD9uni0DDFuni1F00uni1F01uni1F02uni1F03uni1F04uni1F05uni1F06uni1F07uni1F08uni1F09uni1F0Auni1F0Buni1F0Cuni1F0Duni1F0Euni1F0Funi1F10uni1F11uni1F12uni1F13uni1F14uni1F15uni1F18uni1F19uni1F1Auni1F1Buni1F1Cuni1F1Duni1F20uni1F21uni1F22uni1F23uni1F24uni1F25uni1F26uni1F27uni1F28uni1F29uni1F2Auni1F2Buni1F2Cuni1F2Duni1F2Euni1F2Funi1F30uni1F31uni1F32uni1F33uni1F34uni1F35uni1F36uni1F37uni1F38uni1F39uni1F3Auni1F3Buni1F3Cuni1F3Duni1F3Euni1F3Funi1F40uni1F41uni1F42uni1F43uni1F44uni1F45uni1F48uni1F49uni1F4Auni1F4Buni1F4Cuni1F4Duni1F50uni1F51uni1F52uni1F53uni1F54uni1F55uni1F56uni1F57uni1F59uni1F5Buni1F5Duni1F5Funi1F60uni1F61uni1F62uni1F63uni1F64uni1F65uni1F66uni1F67uni1F68uni1F69uni1F6Auni1F6Buni1F6Cuni1F6Duni1F6Euni1F6Funi1F70uni1F71uni1F72uni1F73uni1F74uni1F75uni1F76uni1F77uni1F78uni1F79uni1F7Auni1F7Buni1F7Cuni1F7Duni1F80uni1F81uni1F82uni1F83uni1F84uni1F85uni1F86uni1F87uni1F88uni1F89uni1F8Auni1F8Buni1F8Cuni1F8Duni1F8Euni1F8Funi1F90uni1F91uni1F92uni1F93uni1F94uni1F95uni1F96uni1F97uni1F98uni1F99uni1F9Auni1F9Buni1F9Cuni1F9Duni1F9Euni1F9Funi1FA0uni1FA1uni1FA2uni1FA3uni1FA4uni1FA5uni1FA6uni1FA7uni1FA8uni1FA9uni1FAAuni1FABuni1FACuni1FADuni1FAEuni1FAFuni1FB0uni1FB1uni1FB2uni1FB3uni1FB4uni1FB6uni1FB7uni1FB8uni1FB9uni1FBAuni1FBBuni1FBCuni1FBDuni1FBEuni1FBFuni1FC0uni1FC1uni1FC2uni1FC3uni1FC4uni1FC6uni1FC7uni1FC8uni1FC9uni1FCAuni1FCBuni1FCCuni1FCDuni1FCEuni1FCFuni1FD0uni1FD1uni1FD2uni1FD3uni1FD6uni1FD7uni1FD8uni1FD9uni1FDAuni1FDBuni1FDDuni1FDEuni1FDFuni1FE0uni1FE1uni1FE2uni1FE3uni1FE4uni1FE5uni1FE6uni1FE7uni1FE8uni1FE9uni1FEAuni1FEBuni1FECuni1FEDuni1FEEuni1FEFuni1FF2uni1FF3uni1FF4uni1FF6uni1FF7uni1FF8uni1FF9uni1FFAuni1FFBuni1FFCuni1FFDuni1FFEuni2010 quotereverseduni201Funi2023uni2031minuteseconduni2034uni2035uni2036uni2037uni203B exclamdbluni203Duni2047uni2048uni2049uni204B zerosuperioruni2071 foursuperior fivesuperior sixsuperior sevensuperior eightsuperior ninesuperior zeroinferior oneinferior twoinferior threeinferior fourinferior fiveinferior sixinferior seveninferior eightinferior nineinferiorpesetauni20A8 afii57636Eurouni210Buni210Cuni2110Ifrakturuni2112 afii61352uni211BRfrakturuni2126uni2127uni2128uni212Auni212Buni212Cuni212Duni2130uni2131uni2132uni2133onethird twothirdsuni2155uni2156uni2157uni2158uni2159uni215A oneeighth threeeighths fiveeighths seveneighthsuni215Funi2160uni2161uni2162uni2163uni2164uni2165uni2166uni2167uni2168uni2169uni216Auni216Buni216Cuni216Duni216Euni216Funi2170uni2171uni2172uni2173uni2174uni2175uni2176uni2177uni2178uni2179uni217Auni217Buni217Cuni217Duni217Euni217F arrowleftarrowup arrowright arrowdown arrowboth arrowupdncarriagereturn arrowdblleft arrowdblup arrowdblright arrowdbldown arrowdblboth universal existentialemptysetgradientelement notelementuni2210uni2213 asteriskmath proportionalangle logicaland logicalor intersectionunionuni222Cuni222Duni222E thereforesimilaruni223Euni2241uni2242uni2243uni2249 circleplusuni2296circlemultiply perpendicularuni2300 musicalnoteuni3001uni3002uni3003uni3005uni3007uni3008uni3009uni300Auni300Buni300Cuni300Duni300Euni300Funi3010uni3011uni3014uni3015uni3041uni3042uni3043uni3044uni3045uni3046uni3047uni3048uni3049uni304Auni304Buni304Cuni304Duni304Euni304Funi3050uni3051uni3052uni3053uni3054uni3055uni3056uni3057uni3058uni3059uni305Auni305Buni305Cuni305Duni305Euni305Funi3060uni3061uni3062uni3063uni3064uni3065uni3066uni3067uni3068uni3069uni306Auni306Buni306Cuni306Duni306Euni306Funi3070uni3071uni3072uni3073uni3074uni3075uni3076uni3077uni3078uni3079uni307Auni307Buni307Cuni307Duni307Euni307Funi3080uni3081uni3082uni3083uni3084uni3085uni3086uni3087uni3088uni3089uni308Auni308Buni308Cuni308Duni308Euni308Funi3090uni3091uni3092uni3093uni3099uni309Buni30A1uni30A2uni30A3uni30A4uni30A5uni30A6uni30A7uni30A8uni30A9uni30AAuni30ABuni30ACuni30ADuni30AEuni30AFuni30B0uni30B1uni30B2uni30B3uni30B4uni30B5uni30B6uni30B7uni30B8uni30B9uni30BAuni30BBuni30BCuni30BDuni30BEuni30BFuni30C0uni30C1uni30C2uni30C3uni30C4uni30C5uni30C6uni30C7uni30C8uni30C9uni30CAuni30CBuni30CCuni30CDuni30CEuni30CFuni30D0uni30D1uni30D2uni30D3uni30D4uni30D5uni30D6uni30D7uni30D8uni30D9uni30DAuni30DBuni30DCuni30DDuni30DEuni30DFuni30E0uni30E1uni30E2uni30E3uni30E4uni30E5uni30E6uni30E7uni30E8uni30E9uni30EAuni30EBuni30ECuni30EDuni30EEuni30EFuni30F0uni30F1uni30F2uni30F3uni30F4uni30F5uni30F6uni30F7uni30F8uni30F9uni30FAuni30FBuni30FCuni30FDuni30FEuniF639uniF63AuniF63BuniF63CuniF63DuniF63EuniF63FuniF640uniF641dotlessj commaaccent onefittedffffiffluniFB05uniFB06uniFB1DuniFB1E afii57705uniFB20uniFB21uniFB22uniFB23uniFB24uniFB25uniFB26uniFB27uniFB28uniFB29 afii57694 afii57695uniFB2CuniFB2DuniFB2EuniFB2FuniFB30uniFB31uniFB32uniFB33uniFB34 afii57723uniFB36uniFB38uniFB39uniFB3AuniFB3BuniFB3CuniFB3EuniFB40uniFB41uniFB43uniFB44uniFB46uniFB47uniFB48uniFB49uniFB4A afii57700uniFB4CuniFB4DuniFB4EuniFB4FuniFFFD jmnno !HIOP|}}~~ TDFLTarmn&hebr2latn>fracliga liga&liga, " zJT^h- "(MIOLILKOJLIIMOWNW MOLL,ILVAIniL}&Pf " "   0JDFLTlatnkernkernV2@ft F`$H $79:<H $79:<{$7: <$GRUVWYZ\ $7 9:< $7 9:<$79:< $79:<@CH@CH@CH@CH@CH@CH >?@ABCDH@CH@CH =>?@ABCDEH}=>?@ABCDEHL<Xd6d Jdnx      j 8 f N T b x *8FTbp~&&*24789:<DEFGHJRTWXYZ\m$29:< $+.2 $-79:;<$-2DHLMRUX $79:<$&*267DHRX\$&*26789:<X\"ks$&*DR $79:;<yy$-DHR&*2789:<DHRX\ $79:<W/{$&*-269 :<DFHJLMRUVXYZ\m"# $PQSU&$&*267DHJLRUX\m"$$&*267DHJLRUX\m &24DHRX\$$&*267DHJLRSXYmY\MYZ\YZ\KNWYZ[\DHILMORWD\7MDHJRVX\SYZ\7SYZ\7WYZ[\W\FX+DFGHIJLNORSTVWXYZ[\] W6DHKRDFHJRVDFHJRVDFHRTDFHJORV &*24789:<&*24789:<DEFGHJRTWXYZ\m &*24789:< &*24789:<&*24789:<DEFGJRTWXYZ\m&*24789:<DEFGHJRTWXYZ\m$79<$79:<79<79<$79:;<$$$PQSU$$EPQSUYZ\YZ\YZ\YZ\YZ\YZ\YZ\YZ\YZ\WWYZ[\$+.2KN$79WY\$')*-/13 5= DFHLN\,238=?BDGH""J??Krgl/inst/fonts/FreeMono.ttf0000644000176200001440000107372014265301464015414 0ustar liggesusers`GDEF)3vBGSUB"vOS/2ehVcmap(?(cvt !y gaspvglyf:I$headcO6hhea $$hmtxN} locaR (,maxp H name=postʙl(_Fc_<WW" 8ZX| x@.X1 Px PfEd@  8Z"?!MXXXX\XqXWXiXX&XXqXHXXHXXqXqXqXTX`XiX`XXiXqXXXXHX3XNXXiX X+X?X+X+X+X?X5XqXTX+X?X XX3X+X3X+X\XHX(X XX(X3XgXXqXXqXXXHXXTX?X?XiX?X+X\XX?X\X X5XHXX?XTXgX+X+XXX3X3XsXXXX\XXXqX?XgX3XXBXXXX?XHXHXXXXHXXXX+XOXXXXX?XXXXqX X X X X X X X?X+X+X+X+XqXqXqXqXXX3X3X3X3X3XvX(X(X(X(X(X3X+X+XHXHXHXHXHXHX XTX?X?X?X?X\X\X\X\XHX5XHXHXHXHXHXHX5X+X+X+X+X3XX3X XHX XHX XHX?XTX?XTX?XTX?XTX+X?XX?X+X?X+X?X+X?X+X?X+X?X?X?X?X?X?X?X?X?X5X+X5X+XqX\XqX\XqX\XqX\XqX\XX|XTXX+X?XFX?X\X?X\X?X\X?X9X+X\XX5XX5XX5X5XX5X3XHX3XHX3XHX X X+XTX+XTX+XTX\XgX\XgX\XgX\XgXHX+XHX+XHX+X(X+X(X+X(X+X(X+X(X+X(X+XXX3X3X3XgXsXgXsXgXsXiXXX,XX.XX?X?XTXXX:XXDX+X2X\XXWX?X0XXXqX+X?X\X:X XX5X3X3XHXXXXX<X\XgXfXQX+XX+XHX(X+XNX+XX3XgXsX`XPX_XXXTXPX_XXXXX3XXXXXXX|XXX X XHXqX\X3XHX(X+X(X+X(X+X(X+X(X+X?X XHX XHX X X?X?X?X?X+X?X3XHX3XHX`X_XXXXX?X?XXXX5X XHX X X(X5XCXIX XHX1X;X+X?XCXCXqX\XCXCX3XHXSXOX+XTXCX;X(X+X\XgXHX+XoX|X5X+XgXsX XHX+X?X3XHX3XHX3XHX3XHX3X3XXXHX?XXXTXTX?X?X?X?XCXgXgXX?X?XMX4X2X+X3X3X\XXX\X\XX X X XX5X6XHX XpXTXTX4XTXiXTXTX<X<XgXWXWXWXQX+X+X+XXX3XQXsXsX_XXXX?XIXMXSXX?X\X?XXX)XXXXXXX,XXXXXXXXXX,XXXXXXXXXXXXXCC9CC4twCCCCC0zXE C94X<z +> +g53q+ E33+fH3.'Fq3?5+?<=Dz5qF:+|HR]+++Q"+Z+H++pB%PY+++>@\qqT $323 ,+> +\33-9 533+?H2(2I +@ HQlr7? gAAFX4AHATf335` @ lJX??+rJg\\"+F>3>"+l+>r>r>r \g$F$F$F 5R5R?T?THz33(3J`J`J`q $F5RJ` H H +?2K2K \g\g3>3>3H3H3H@J232323I` ))+"":) 4?.)k5!Z=*+@ ) \*A\G3Z 4+!,+}545IG85GBP6[G5] F5,,g5?y iHYd1<<<<<<<<<<<<<<<21<3ZZZGGGGz3~n3iXiM3Vv3Z H+++?T+?+?+?+?+?+?+?+?+?+?+i??5+5+5+5+5+q\q\+?+?+??\?\?\?\ 55553H3H3H3H+++T+T+T+T\g\g\g\g\gH+H+H+H+(+(+(+(+(+  (3(333gsgsgs++3Hi H,s H HYj H H H Htt H H+?dk+?+?+?ky+?+?tsq\3Htt3H3Htt3H3H3H3H?83H3H(+t[(+(+_((+(+3333tt33????????pp#,H8H855555555gWgW Oo~~;:HHHHHHbPw++++++++L=++++++++_R{**)E)Eii*)('+&;9!!!1)+))*J*!!8888 G++q++&&s&&s3qHHHq%&&((8n8(((\\\HHH3\333333335;5;))HN3333######((((((((((((((f7((((H7((,,,<<s#ThTTT<< ",,, ,,221222222222##TTyy##99^_####Y############,#,#,##222222222###2222####22222}}2/<xZ#222&2PP#22222222###vvv@55mx=ll}}--lllkkkkpppppppllllkkkkpppppppp Z<<<<<<<<H3131<<<<<<<<<<<<<21<3<<<<"44 ~3B\mv"(38BDz_djlqVEMWY[]}   " & 7 : > F I K !!! !!!"!'!+!2!5!o!" """"0"5"7"="E"H"S"Z"a"g"l"o"w""""""######*###&& &&&&&&)&.&7&<&B&o'(6<>ADO $AP_ox!'35BDzdjlp1a HPY[]_    % 0 9 < C H K p !!! !!!"!$!*!2!5!S!"""""'"4"7"<"A"H"P"Y"`"d"j"n"v""""""######)###%&&&&&&&(&.&0&9&?&i'(8>@CF}|n]TOKA@76f\Y43(#xie_][YWVUTSQPOMJI8653*)($#"|z]=tsoke\^ )*+,-./0123456789 ;~{utho  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`ardeixpkvjsgwl|cnm}byqz!yVVVV|h"BpB<l :  T  d B6 J6~Ph$t6z2`^  R !v!"p"#f$$$$%D%&"&&'R'v((v(()*6*++,- -../&/60 0,001b12:23(3f344r45678:89h::;B>?|@<@A&AB>BCvDDE6EFGGHVHIJhJKtL&LMNOPpQbRnS<STUnVLVWWXXYZNZ[\J] ]^^_<_`aabhbcd<eefgZhhh4hJh`iijbkkkl,lllmnBnopRqq&q<rrssstttujvvv,vvvwwxxxyVyyzf{ {{|>|}}}~^~t~zB~0<L 6F&.D<Tj2z($T8P`*l,^rJ>Zj0d`f",H\(\@jR~: â*Ĥ@ƪ.DZrLjǠǸȠȸ(ʐʦʼ,BXnp͜Ͳt4LbxϐϦϼ 6RnЄКж6Lb~њѰLծpֆׂ֞ט׮ 6LbzؐئؼؼؼXB\ܰLR.T 0bF\&"$8LF*@Hj,Htfd`pz0n,<L 8dJfZ*<N`b2V 6 H   ^ v        ,   d   ^ zNX8HHDJ  6Lbx(\Lx8hV `!2!"D##2#H#^#t#$ $$$%`%&J&&&'h'(l(|((()Z)*+F+,-- ---.P.`/(/0l1012.2>2N2^22223R444z55~66n77z8 89:9J9:p:;;.;<=>=>d>?L??@:@J@Z@@AhAxABbBCdCD|DEtFFFFGGHHHHHIlJJKRKLLMPMNONO^OPdQ QRRbRSST@UUVWXpXYzYZ[[\ \] ]^ ^_j_z_`Laa\abbzbcpcdxdeXeffgghhiZjkll*m0n>no~ppq2qqqqrr"r2rHr^rsbsxstuvwxyzz{|Z|p||}j}}}}}}~~~0~F~\~r~~(0*N^46ZFl,PBR~.p>D8r ,J>.FnHnRP@vHB"r|pF>zp<* bLzR&j<v F* b”¸JrÚöFhľ$ŰRƤ>hǴ4lȮɲd~ʸ.hˀ˲f,D\t͌ͤͺ.F^tΊ΢κ.F^vόϢϸ*BZpЈРи0H^vюѦѾ2JbzҒҨҾ0F^vӎӦӾ6Nd|ԒԨԾ.F\rՊբո.F^t֊ֶ֠.F^v׎צ׾2H^v؎ؤغ(>Vnلٰٚ6Nf~ږڬ6Nd|۔۬ $:Ph܀ܘܰ&<Tl݄ݚݰ&>Vnކޜ޲(@Xn߆ߞ߶.DZr2Jbz 8Ph "8Ndz.F^v,BZr*@Vl*BXn ":Rj  6Nf~4J`v.DZp.F\r "8Ndz*@Vl2H^t$:Pf|,BXn4J`x,Lbx0*@Vl z0F\r(N,D\r@hx$4$j<hx&  $      `  2  f   X   0BTB\ r2f.LD !^!"#*#B#$R$R%,&&&"&6&'))+,@-N.J/v01364>455X56(6~67d78x8999999:B::;@;x? ?@N@AdAxAB B BBCHCDDDDEEFzG<GH H"H8HLHIIJK KLPLMM^MMMNN*N@NNO OP@PVPlPPQvRRRSVSTTU"U~U~VVrWWWXXYrYYZZ[H[[\6\\\\]^0^_Z___`<`abc@dBeghBhXiijjk:klm4n nvo oop0pqqtqr:rs<st>tu u"uuvv^vvwdwxVxy.yzzlzz{ {D{d{{{||P||}}f}~0~n~DD,PrDd``z<Vv <r:"<VpJz&b"Bb"Bb*T~Dj 6`$Hr@f&VRFv<b8lHxDvT>~ "6Lj4N`r4Nh8Ph(B^z (Vvb6N@Vx@Z>X|>VxBp@(| d.6j0F^8`:NtX~:T~TèVĄĄ:HȐtzˬ"l̨2͊ΆτZbRԴՊl n׼ dfJڂۆ܂ܼ ݈ހߪl tjVN0D><l0Hn0>2D0 zn @FL p *  v 6  d$n*bjVf !v"2"#$%&'v(`)r*^+n,--.\./T/0J01223$34p5*567278V99:\;<<=V>>?@A~BBCDDE\FFGHPI IJKjLNM8NFNOPPQ4QRSTUVxW`XpYZZh[|\]]^<^_`@aabtc.cdefghi&ijkl@m$noopqrstuvwx@xyz{|l}|~: *d"J2BV"R( <<pVx~PNJ"`^^ lHfFf02&!n./<2<2/<2<23!%!!!M f!Xhj"#"'&54763232+"'&5476R . # $  3F   !  ! ;\ 3"'73"'"4"4\$$$$\:>32+#"'&57##"'&=7#"54;7#"54;76323763232+3 PS[WY NQ[Y[ [d~~~qR5432632#"'&'&#"#"=&'&'#"=432327654/&'&'&'4765(2 $C%@0Y 1Q%?19'-X(<1 R%-@#@44<! /5 !CR)ww&O'4:$:G*Wc/?Q%2#"'&5476"327654'&2#"'&5476"327654'&#"'&547%632iB$4 &@%4 &0 */ +B$3 '@%4 &. *- + { 6 (=&5 '@%&*1 *4 7'>%5 '@%&)1 (4 zz i7B!'#"'&54767&'&547632632&#"6732+32#/32-CD,!G-4 '!! !+ ,o+ &qi?.70@<,6T+ J =$  &E:FS+)V:=#;l\3"'"4\$$&\2#"'&'&5476dd en\  7\2"'&547654'&'&5476 end]\" q\-54327632#"/#"'&54?'&547632Q RQ Q +*p pp p*H #"=#"54;543232#@oT 73#"'&547υ H+ !"543!2nvt%32+"'&5476' -& +&t% *$)q #"'&547632 G yH qj$#"'&=476323276=4'&#"L/@_5'M.@`40"@@"00"@@"0_dJ-^FfdI-^):OYhJ55IiYhJ55Iqd32#!"54;#"'&547A  d*Tj*7!5432!5767654'&#"#"'&547672{:vY7(0H. >\R9-VO)$Md4;QL2'>.9S26 (>#3$B&8"*D)7$+G&j#2#"'&547632#"'&547232767654'&/"3276=iL3(B/#-=DM8h09 =++ $ + % )D9;@")D "D%1C." $ " % ip9D%5#"'&547654'&#"327632#"'&=47632#'5"32 L&E.=7"P,/'IF# 9,1W56J3FT. !R$27'L*/G!S;S\F9 KNkL4A /36  O3 $%!32+"54;#"54;32+"54;'#6Ox%LGpl%+3#07#"543!2#!"543327654'&+327654'&'&+|6Z2U?-9_X(7!)E%6,S)<%0I/-dJ.!472"7#?@/5432#"'&'&#"32767632#"'&=4767632@0:[<2I?RYC &LbfON6 Efep4#I>QGaD:F #GONeSTI J+3#7#"54;2+"54;276=4'&'&+h"gD;N@XKL9362L)RHc8uK>D=KIMA2+3)!5432!"54;#"543!#"=!35432#"=:>66ۑwb--+3'32+"54;#"543!#"=!35432#"=66Ƒb--?2@8%#"'&=47676325432#"'&'&#"327675#"54;2#ZaI1? FccC?,6T7< d7MDFѭ4cB_JaL A6[.68S I8 5'33!32+"54;#"54;2+!5#"54;2+32+"54;6-x66x.6q332#!"54;#"543!2#@? TG3 #"'&'543232765#"543!2#C5DNOKIK+( S7+@ D:$.e+<37732+"54;#"54;2+%#"54;2+32+&/&'K66K-vI)"+ 8W@5*ݴ8/h9?3!5432!"54;#"54;2#=``  Q3,%##32+"54;#"54;32+32+"54;#F.J"cd"Ja\23"!#32+"54;#"54;#"54;2+4K"6j1J"13%@2#"'&5476"327654'&,nIBQGakIEQGaZ>8H;MX?9I:@]UzWMZVxWM)QJdsM?PJbyL=+3&732+"54;#"54;2#'327654'&+66_8&H8KQ09'0@,9O1')4"(=&3%@1A632327632#"'&#"#"'&54?&'&547632"327654'&16())*- &#!8T Z_9.QGakIERDcZ>8H;MX?9I:(   AaN^WMZVxVH$QJdsM?PJbyL=+M3)4732+"54;#"54;232+&'&/327654'&+K66T8(7(& 9U7'r^57'-;,5a0%:"@ 2)3$4$\@C5432#"'&'&#"#"'#"=432327654'&'&'&'&'47632<#,R(R+_#=M6Kj?A,8[.-E `(3F1AVg95"E %QV0!Hp;#8 (7 $DN- H3%32+"54;##"=!#"'&=#Aii)IrrI(03)#"'&5#"54;2+32765#"54;2#I6Ha:,"J?)6O/ J b;,I7IQR/>+7Q O3!#"54;2+3#"54;2+ MN D3 3#"54;2+3#"54;2+# z<]8p>m9`>@ps $xp(03332+"54;'32+"54;7'#"54;2+7#"54;2+E>@n+-o 3%3&%32+"54;5#"54;2+7#"54;2#Biio&(n g3)55!#"=!!5432vH]:;v:4\ 32+32#Aa3zq#"'&547632G  H  @\ #"54;#"543aS(qbg#"/#"'&547,   g   d!5dK22@"/&547632r r vd d H(7!5#"'&54763254'&#"#"'&54763232#'5&#"3276Yf_)R6K;M<#,b]@\-6_*3g3 I0AmN +Pgr@/S=V]x [0K/?_3"H 7P;QrA0?G\*32+5#"'&5476325#"543"327654'&6_Go`A7J=QnH6}U5(C1?T5)D0\YiK@UeC7hC2AY6(B2A\6&? +%!32767632#"'&547632!&'&#"`T.:VE HGDnH3H:LhAS2#@-;R2$B,NSl:.65'aI;O`?3^6A-;S3$@.:W2"+'\16763232+"54;54'&#"32+"54;#"543<>Z---&66' -.6\H >",.!  \p32#!"54;#"5437#5@v;OhhFp#"543!+"54;2765#5B'2B ;xCY,6#hh?\)7#"54;#"54;7#"54;2+32+"54;'_66_/- \\32#!"54;#"543@u\  Q>6763267232+4'&#"32+4'&#"32+"54;#"543p*0@!:78 "J"/0"J"27"m""4;GE1?( E<) RO506763232+"54;54'&'"32+"54;#"543;2T."m"&&,7('--"EB :",, ! 2OH!2#"'&5476"327654'&'&,jC7LAWhD8LAWY8*E3CX8+E,9N>VcA9L?UdC8)C2AX6)A2A[6#F#367632#"'32+"54;#"543"327654'&=Jj@ L1` @.;S2%?.;V2#?FG!3532+32+"54;5#"'&547632'"327654'&_66bCqh@2M0[4A%/ S2%@-;V2#T%67632"'&#"32#!"54;#"543j:(%#)7A`Kf`  "*8OgD5432#"'&'&#"#"'#"=432327654'&'&'&'&'47632C"R# &'V,1J4F`=<*4]*'#I\&-D,;UE0) !9C&6 S).# 2;!+3)32+32767632#"'&5#"54;5432=SE KA;e&JJ9!?" w+"!5#"'&5#"54;327#"54;32#TbS"6_,dSJs"BR@&3 Z:!##"54;2+3#"54;2+PF)AD)xO: !# ##"54;2+3#"54;2+2[Y3To5HV3YE2ox@3%3%32+"54;'32+"54;7'#"54;2+7#"54;2+I AD o.0n۲3F%%!#"54;2+#"54;2+32+"54;s46nAxKs!5432!5##"=-$8a$T7`\.#"'&=4'&'&47676=47632B &" 7( . /& 0 & )1-(( <$ @\"542@((A^\054767&'&=4'&'&'432#"54763676&" 7( . .& 0& )1-(( ;$ \\$2#"'&'&#"#"'&5476722761-!*%# 2* ! 8$%J ; *  4 *4(h"632"'&54#"'&5476;2 . # $ F   !  ! qv654322632#"'&'&#"327632#"=&'&547676?):W,@'2J3 8/-Z/E!kj$=/?$0O**qq I.7Y7?BA732765632#!"54367654'#"54;&547632#"'&#"032+#)'h^9%/6, (25cZ)'4?5>U$H+'  1.O#hg_6F7#"'&54?&547'&5476326327632#"/#""327654'&9  8#"7  8,:9-7  7"#7  8/677?%4 (>&68  8/6;+8  7##7  8/6:,8  8#"4 (@&4 'C%3%3@%32#32+"54;5#"'4;5#"'673'#"54;2+7#"54;2+32AVVtn''nv<dd<@\"542"542@((((A N B[;S#"=#"+5432327654'&/&54767&54763'&'#"6767654'&3 /G8s$+ 9"*: L A8 5")d@T# 5}>PAI[mE&!"'>: '>!oG('2$PC2 :#$.+G#-"%1 c2#"'&547632#"'&5476!   !  c    TB)9I54763242#"'&'&#"327632#"'&2#"'&5476"327654'&8%.+.$*91#1) ,8E."|WUZW{xWVYVzoLEPIctLCQJ-H,A 3"'<#/ )9*pYWxWSXXy|WU)QJdmMFSHenLE>'45#"'&54763254/"#"'&54763232#'5&#"32i65C;!)-(0 7(? ?*C' 7,8 ,"  ,D; &  ?'?632#"'?632#"'?          H !"543!#"5|H+TB"-=M32+"4;5#"4;232+&/327654'&+72#"'&5476"327654'&$`A 4 '96?8K(MC|WUZW{xWVYVzoLEPIctLCQJf$$$/3(/$w$*% YWxWSXXy|WU)QJdmMFSHenLE@#"4;2((Z|!2#"'&5476"327654/&,H,:'0J+9(08 /8/|:'0H,<&1F+)/9/8 H#"=#"4;543232#!2#!"4@on-((((d(3542#5767654'&#"#"'47632ۖ$5$-#77"B''+{5$ $ ,- !=d6#"'&5472327654'&#&5476327654/#"#"'47632f:4&5*)+0 - ,&- *> $47  $*   $ . +#"'&54?632r  r Wd  d +8"7#"5#"4;327#"4;32+5#"6_1eRJs"KPe9&(< [((;KO \)332+"'47#+"54;&'&'&=476;2#5>bHaA.HT8OP&;"3H </Q*2%3!v\32+"'&5476' -& +&\% *$)Sy!3#"'&5472327654+&:-$" %./2, d32+"5432#"'&5476?G'A  d$  A"2#"'&5476"327654'&'&-K+ :(1I,:'2; 1!:!2A;!G,;'1G-%0!; 0 =! ?'%#"'&54?'&547632#"'&54?'&5476327          Dd*AE32#"5432#"'&5476#"'&547632#57332+32+"54763=#G'A    ^  9  U )kd  hb   t"$9$ ]=d)P #"'&547632%32+"5432#"'&54763542#5767654'&#"#"'47632  ^ G'A  Q$5$-#77"b   {$  '+{5$ $ ,- !#Dd6H_c#"'&5472327654'&#&5476327654'&#"#"'47632!#"'&547632#57332+32+"54763=#:4&5*)+0 - ,&-*>   ^  9  U )k$47  $*   $ . +b   t"$9$ ]qQ$6%5432327675432"#"'&54767#"'&5476;2>#-:BM8h09$k* $ + % )D:>@ )C "D%1C.! $ " %  O $5%!32+"54;#"54;32+"54;'#"/&5476326Ox%LGplr r %'d d  O $6%!32+"54;#"54;32+"54;'##"'&54?6326Ox%LGplr  r %d  d  O $8%!32+"54;#"54;32+"54;'##"/#"'&5476Ox%LGpl_  kk  %0l XX  O $E%!32+"54;#"54;32+"54;'#2#"'&#"#"'476323276766Ox%LGpl$!4 (#'-%  $ % O $4D%!32+"54;#"54;32+"54;'# 2#"'&547632#"'&54766Ox%LGpl!   !  %     O+ $4D%!32+"54;#"54;32+"54;'#2#"'&5476"327654'&6Ox%LGplc6 ,3,%" %" %F-0+1! $ $ N359%#32+"54;#"543!#"=#3542"=#35432!"54;5#))h%?N((N42Po`]$?S@O#"'&5472327654+5&'&'&=47676325432#"'&'&#"32767632#=:-$" %.>"U6 EfeH@0:[<2I?RYC &AQ 2, E:`STI JEp4#I>QGaD:F #< +):!5432!"54;#"543!#"=!35432#"="/&547632:>66ۑ_r r wb--d d +);!5432!"54;#"543!#"=!35432#"=#"'&54?632:>66ۑOr  r wb--d  d +)=!5432!"54;#"543!#"=!35432#"=#"/#"'&547:>66ۑ  kk  wb--l XX +)9I!5432!"54;#"543!#"=!35432#"=2#"'&547632#"'&5476:>66ۑ!   !  wb--    q(32#!"54;#"543!2#"/&547632@?r r  d d q)32#!"54;#"543!2#'#"'&54?632@?r  r  d  d q+32#!"54;#"543!2##"/#"'&547@?  kk    l XX q'732#!"54;#"543!2#%2#"'&547632#"'&5476@?!   !       31#"54;5#"54;2+"54;32+3276=4'&'&#hMM"cE>LBX")J9552LQIc8oMBC>KJKA22"C!#32+"54;#"54;#"54;2+'2#"'&#"#"'476323276764K"6j1J"D$!4 (#'-1 $ %3%02#"'&5476"327654'&'"/&547632,nIBQGakIEQGaZ>8H;MX?9I:r r @]UzWMZVxWM)QJdsM?PJbyL=d d 3%12#"'&5476"327654'&7#"'&54?632,nIBQGakIEQGaZ>8H;MX?9I:r  r @]UzWMZVxWM)QJdsM?PJbyL=d  d 3%32#"'&5476"327654'&'#"/#"'&547,nIBQGakIEQGaZ>8H;MX?9I:M  kk  @]UzWMZVxWM)QJdsM?PJbyL=l XX 3%@2#"'&5476"327654'&72#"'&#"#"'47632327676,nIBQGakIEQGaZ>8H;MX?9I:@$!4 (#'-@]UzWMZVxWM)QJdsM?PJbyL= $ %3%/?2#"'&5476"327654'&'2#"'&547632#"'&5476,nIBQGakIEQGaZ>8H;MX?9I:!   !  @]UzWMZVxWM)QJdsM?PJbyL=    vd#7632"/#"'&54?'&5472,     7     (0](17#"'4?&5476327632#"'&#" 327654A EBRFaVHB FCQGaZB ;IZ>8l;JZ>83R  WXrXKBS  XSxWMl;QJd[;QJd^(0):#"'&5#"54;2+32765#"54;2#"/&547632I6Ha:,"J?)6O/ Jr r  b;,I7IQR/>+7Qd d (0);#"'&5#"54;2+32765#"54;2#'#"'&54?632I6Ha:,"J?)6O/ Jr  r  b;,I7IQR/>+7Qd  d (0)=#"'&5#"54;2+32765#"54;2##"/#"'&547I6Ha:,"J?)6O/ J  kk   b;,I7IQR/>+7Q l XX (0)9I#"'&5#"54;2+32765#"54;2#%2#"'&547632#"'&5476I6Ha:,"J?)6O/ J!   !   b;,I7IQR/>+7Q    3%&8%32+"54;5#"54;2+7#"54;2#'#"'&54?632Biio&(nar  r  d  d +3"-732+"54;#"54;2+32#'327654'&+66_8&H8KQ09'0Z;@,9O1')4"(=&+\B747632#"'&5472327654'&'#"547327654'&#"32+"543|:&.J+::!+:-0=9=3/ :n)A&;&1<';`34$> 9#-N2((7*MH(7H!5#"'&54763254'&#"#"'&54763232#'5&#"3276"/&547632Yf_)R6K;M<#,b]@\-6_%11$" <0  6A] ": IA5TSL#"'&547632327654+5&'&'45476325432#"'&'&#"327632;:-$" %-@)RS=V]??)2g3 I0AmN 7 <2, C VcA9L?UdC8)C2AX6)A2A[6#d d H!32#"'&5476"327654'&'&7#"'&54?632,jC7LAWhD8LAWY8*E3CX8+E,9Yr  r N>VcA9L?UdC8)C2AX6)A2A[6#d  d H!52#"'&5476"327654'&'&'#"/#"'&547,jC7LAWhD8LAWY8*E3CX8+E,9  kk  N>VcA9L?UdC8)C2AX6)A2A[6#l XX H]!B2#"'&5476"327654'&'&72#"'&#"#"'47632327676,jC7LAWhD8LAWY8*E3CX8+E,9$!4 (#'-N>VcA9L?UdC8)C2AX6)A2A[6# $ %Hc!1A2#"'&5476"327654'&'&'2#"'&547632#"'&5476,jC7LAWhD8LAWY8*E3CX8+E,9x!   !  N>VcA9L?UdC8)C2AX6)A2A[6#    H'!"43!22#"'&54762#"'&5476n!   !   ((    5(17#"'4?&5476327632#"327654&#"B  B9LAWR>@  @;LAWP3BY8*2AY8*#D  CBSeB81B  AAVeB8Y(C2AD&C2AD+"3!5#"'&5#"54;327#"54;32#"/&547632TbS"6_,dSJs"r r BR@&3 Zvd d +"4!5#"'&5#"54;327#"54;32##"'&54?632TbS"6_,dSJs"r  r BR@&3 ZWd  d +"6!5#"'&5#"54;327#"54;32##"/#"'&547TbS"6_,dSJs"ބ  kk  BR@&3 Zl XX +c"2B!5#"'&5#"54;327#"54;32#2#"'&547632#"'&5476TbS"6_,dSJs"!   !  BR@&3 Zc    3F%%7!#"54;2+#"54;2+32+"54;#"'&54?632s46nAr  r xKd  d FN#367632#"'32+"54;#"543"327654'&=Jj@ L1`@.;S2%?.;V2#3F%c%5E!#"54;2+#"54;2+32+"54;2#"'&547632#"'&5476s46nA!   !  xK     O $,%!32+"54;#"54;32+"54;'##"4;26Ox%LGpl%((H@(7?!5#"'&54763254'&#"#"'&54763232#'5&#"3276#"4;2Yf_)R6K;M<#,b]@\-6_+ %A 1 tL86Oxpl3 ) "  /0%He,@O%3232767632#"'&54767#5#"'&54763254'&#"#"'&5476325&#"32766 T+ %A 1 =Yf_)R6K;M<#,b]@\-)QGaD:F #GONeSTI Jd  d T+=5432#"'&'&#"327632#"'&5476327#"'&54?632>*3g3 I0AmN +Pgr@/S=V]r  r x [0K/?_3"H 7P;QrA0d  d ?'G&T&G F?&V\&T-&V F?/B5432#"'&'&#"32767632#"'&=4767632/&5476327632@0:[<2I?RYC &LbfON6 Efej  kk  p4#I>QGaD:F #GONeSTI J@m XX T+>5432#"'&'&#"327632#"'&547632/&5476327632>*3g3 I0AmN +Pgr@/S=V]M  kk  x [0K/?_3"H 7P;QrA0;m XX +#67#"54;2+"54;276=4'&'&+7'&5476327632h"gD;N@XKL9362L  kk  )RHc8uK>D=KIMA2vm XX ?h*:32+5#"'&5476325#"543"327654'&%#"'&54?6326_Go`A7J=QnH6}U5(C1?T5)D0)T T \YiK@UeC7hC2AY6(B2A\6&~ ~3?G\(832+32+5#"'&5476325#"54;5#"54;"327654'&666_FobA6J=RmH6_U5(C1?S6)D0JQaL?UeC7`+C2AY6(A2A\6'+)1!5432!"54;#"543!#"=!35432#"=#"4;2:>66ۑlwb--((?@ +3%!32767632#"'&547632!&'&#"#"4;2`T.:VE HGDnH66ۑ !  wb--  ?c +;%!32767632#"'&547632!&'&#"2#"'&5476`T.:VE HGDnH66ۑ  kk  wb--pm XX ? +>%!32767632#"'&547632!&'&#"7'&5476327632`T.:VE HGDnH3H:LhAS2#@-;R2$B,1@ ;%1R*NSl:.65'aI;O`?3^6A-;S3$@.:W2"' ' 7 2?2&V \*?F2-&V J?2@8H%#"'&=47676325432#"'&'&#"327675#"54;2##"'&54?632ZaI1? FccC?,6T7< d7MDFT T ѭ4cB_JaL A6[.68S I8 ~ ~?F2$4D532++"54;276=#"'&547632'"327654'&7#"'&54?632_6+3Grt@%Bi]>3H:LhAS2#@-;R2$B,T T NSl:.65'aI;O`?3^6A-;S3$@.:W2"~ ~5''G++''GK5'3?C32+32+"54;5!32+"54;#"4;5#"54;2+!5#"54;2+!!.66-x66x)(T(eeeD+'\=5#"54;32+6763232+"54;54'&#"32+"54;#"43|6_<>Z---&66' -.66_(zH >",.! (q&YW,\"&Yq32#!"54;#"543!2#'#"4;2@?) ((\@32#!"54;#"543%#"4;2@vOw((q'U,\K&Uqe313232767632#"'&54767!"54;#"543!2#@$+ %A 1 ? "  /0\ep,03232767632#"'&54767!"54;#"5437#5@ I + %A 1 v; ' "  /0Ohhq'32#!"54;#"543!2#'2#"'&5476@?!     \32#!"54;#"543@vO;3":#"'&'543232765#"54;2#!32+"54;#"54;2#Q#D-]_m,,, & 53 t e|Fp,0#"54;+"54;2765#532+"54;#"5437#5QzB'2B 0;@B8l;xCY,6#hhOhhTG&Gdq-F'#"543!+"54;2765#"/#"'47B'2B s lj  xCY,6#l XX +<37G732+"54;#"54;2+%#"54;2+32+&/&'#"'&54?632K66K-vI)"+ 8W@5*pT T ݴ8/h9y~ ~?\)97#"54;#"54;7#"54;2+32+"54;'#"'&54?632_66_/-WT T  ~ ~F?+!5432!"54;#"54;2#7#"'&54?632=``r  r  d  d \$32#!"54;#"543%#"'&54?632@ur  r \ d  d ?3)!5432!"54;#"54;2##"'&54?632=``T T  ~ ~\\"32#!"54;#"543#"'&54?632@uT T \ C~ ~?6)!5432!"54;#"54;2#7#"'&54?632=``T T  ~ ~\h"32#!"54;#"543#"'&54?632@uRT T \ ~ ~?3&yA/9\&y}O+3/7632!5432!"54;5#"'&54?5#"54;2# <`j  ~` P \ޡ> J\\(763232#!"54;5#"'&54?5#"543?X lW ku\3 >2 =2"4!#32+"54;#"54;#"54;2+'#"'&54?6324K"6j1J"Dr  r 1d  d 50B6763232+"54;54'&'"32+"54;#"543%#"'&54?632;2T."m"&&,7('--"Ur  r EB :",, ! 2Od  d 23"2!#32+"54;#"54;#"54;2+#"'&54?6324K"6j1J"T T 1~ ~50@6763232+"54;54'&'"32+"54;#"543#"'&54?632;2T."m"&&,7('--"T T EB :",, ! 2O~ ~2"5!#32+"54;#"54;#"54;2+/&54763276324K"6j1J"Ʉ  kk  1vm XX 50C6763232+"54;54'&'"32+"54;#"5437'&5476327632;2T."m"&&,7('--"Є  kk  EB :",, ! 2OIm XX 506763232+"54;54'&'"32+"54;#"543;2T."m"&&,7('--"EB :",, ! 2O9235!#32+"54;#"54;#"54;2+#"'&547232765 K"6j1J";'1+  ?1M, 7"5974'&'"32+"54;#"54;67632#"'&54723276&&,7('--"K;2T.;'1+  ?*J, ! 2OEB :",M, 73%'2#"'&5476"327654'&7#"4;2,nIBQGakIEQGaZ>8H;MX?9I:)@]UzWMZVxWM)QJdsM?PJbyL=((H@!)2#"'&5476"327654'&'&7#"4;2,jC7LAWhD8LAWY8*E3CX8+E,9mN>VcA9L?UdC8)C2AX6)A2A[6#((3%'U2Hm&UR3%1C2#"'&5476"327654'&'#"'&54?632#"'&54?632,nIBQGakIEQGaZ>8H;MX?9I:.a  b b  b @]UzWMZVxWM)QJdsM?PJbyL=^  ^  ^  ^ Hy!3E2#"'&5476"327654'&'&'#"'&54?632#"'&54?632,jC7LAWhD8LAWY8*E3CX8+E,9a  b b  b N>VcA9L?UdC8)C2AX6)A2A[6#^  ^  ^  ^  N3&135432!"'&54763!#"=#35432#"='#";RF3Z@[;Nw j7557j \eIlN8q`FChgCF B07G%!32767632#"'&'#"'&547632676323&'&#"#"327654'&A8"!- <+I2 'I B.*;*4A/ &/M'8Y2#0#0$1b2&  -LfKBWhC0G5$L4!A7A4A[9#?5A^8"+M)4F732+"54;#"54;232+&'&/327654'&+%#"'&54?632K66T8(7(& 9U7'r^57'- r  r ;,5a0%:"@ 2)3$4$d  d T%767632"'&#"32#!"54;#"543%#"'&54?632j:(%#)7A`K-r  r f`  "*8Od  d +M3)4D732+"54;#"54;232+&'&/327654'&+#"'&54?632K66T8(7(& 9U7'r^57'-T T ;,5a0%:"@ 2)3$4$~ ~T%567632"'&#"32#!"54;#"543#"'&54?632j:(%#)7A`KT T f`  "*8O~ ~+M)4G732+"54;#"54;232+&'&/327654'&+7'&5476327632K66T8(7(& 9U7'r^57'-  kk  ;,5a0%:"@ 2)3$4$vm XX T%867632"'&#"32#!"54;#"5437'&5476327632j:(%#)7A`K  kk  f`  "*8OIm XX \CU5432#"'&'&#"#"'#"=432327654'&'&'&'&'476327#"'&54?632<#,R(R+_#=M6Kj?A,8[.-E `(3F1AV0r  r g95"E %QV0!Hp;#8 (7 $DN- d  d gDV5432#"'&'&#"#"'#"=432327654'&'&'&'&'476327#"'&54?632C"R# &'V,1J4F`=<*4]*'#I\&-D,;U5r  r E0) !9C&6 S).# 2;!d  d \'G6g&GV\S@^#"'&5472327654+5&'#"=432327654'&'&'&'&'476325432#"'&'&#"8:-$" %/\1A,8\.-E `(3F1AV<<#,R(R,^#=Q02, B <p;#9(7 $DN- ;g95"E %QX/gSc#"'&5472327654+5&'#"=432327654'&'&'&'&'476325432#"'&'&'&#"8:-$" %.T.<*4]*'#I\&-C,;V4<T! '%V,1N%/ 2, B , S).# 2; .E,) !9G%\CV5432#"'&'&#"#"'#"=432327654'&'&'&'&'47632/&5476327632<#,R(R+_#=M6Kj?A,8[.-E `(3F1AVK  kk  g95"E %QV0!Hp;#8 (7 $DN- @m XX gDW5432#"'&'&#"#"'#"=432327654'&'&'&'&'47632/&5476327632C"R# &'V,1J4F`=<*4]*'#I\&-D,;UJ  kk  E0) !9C&6 S).# 2;!;m XX HS3&z7+C3&zWH0%32+"54;##"=!#"'&=#/&5476327632Aii  kk  )IrrIvm XX +h)932+32767632#"'&5#"54;5432%#"'&54?632=SE KA;e&JJ:T T 9!?" w+~ ~H3)32+32+"54;#"4;5##"=!#"'&=#Accii``Q((IrrI+355#"54;543232+32+32767632#"'&=#"43JJ=SE KA;e&Kewwe(~9!?"((0&YW8+"&YX(0)1#"'&5#"54;2+32765#"54;2#'#"4;2I6Ha:,"J?)6O/ Js b;,I7IQR/>+7Q((+@"*!5#"'&5#"54;327#"54;32##"4;2TbS"6_,dSJs"`BR@&3 Z(((0'U8+m&UX(0+)9I#"'&5#"54;2+32765#"54;2#2#"'&5476"327654'&I6Ha:,"J?)6O/ J6 ,3,%" %"  b;,I7IQR/>+7Q!-0+1! $ $+"2B!5#"'&5#"54;327#"54;32#2#"'&5476"327654'&TbS"6_,dSJs"6 *3,%" %" BR@&3 Z-/+1! $ $(0);M#"'&5#"54;2+32765#"54;2#'#"'&54?632#"'&54?632I6Ha:,"J?)6O/ Ja  b b  b  b;,I7IQR/>+7Q^  ^  ^  ^ +y"4F!5#"'&5#"54;327#"54;32##"'&54?632#"'&54?632TbS"6_,dSJs"a  b b  b BR@&3 ZQ^  ^  ^  ^ (e03A327632#"'&54767#"'&5#"54;2+32765#"54;2#/%<, %> 1'`;+"J?)6O/ J Q23)" , .!I7IQR/>+7Q+e,:3232767632#"'&54767#5#"'&5#"54;327#"543" S+ %A 1 )TbS"6_,dSJ 2)"  /0BR@&3 ZD'G::&GZ3%'G<3F%&G\3%&6F%32+"54;5#"54;2+7#"54;2#%2#"'&547632#"'&5476Biio&(n!   !       g')55!#"=!!5432#"'&54?632vH]:@r  r ;v:47d  d s%!5432!5##"=%#"'&54?632-5r  r $8a$T7`d  d g%)55!#"=!!54322#"'&5476vH]:!  ;v:4C  sc#!5432!5##"=72#"'&5476-!  $8a$T7`  g()55!#"=!!5432'&5476327632vH]:Ʉ  kk  ;v:4m XX s&!5432!5##"=7'&5476327632-  kk  $8a$T7`Im XX i\%%32#!"54;#"54;547632"'&#"bXX@'3FE06"J )O=E$ /\8"327654'&%5#"54;32+672#"'#"54;#"543BU5(B1?S6)C06_Hlf@3J=RnF_66C2AW7)B2@[7'+TfM=SgC8hX3 B327654'&+327654'&'&+!2#!"54;#"32#"'&5476X(7!)E%6,S_Z2U?-966  129472"7##<%0I/-dJ.! *6 ,3\/"327654'&'672#"'#"54;#"543!2#BU5(B1?S6)C0Hlf@3J=RnF_66C2AW7)B2@[7'fM=SgC8hX .%N 7327654'&'&#'32#!"54;""'&54?54327272E%6,S, ?-962FJ2"7#̣fJ.!# 0B%3 N>7327654'&#"5672#"'#"54;""'&54?54327272B1?S6)C0?U5(Hlf@3J=RnF_6- AOW7)B2@[7'C2ʓfM=SgC8hX  -C'7 ?@/632#"'&54723276=4'&#"#"=432wHefE: OOebL& ER ^B:F9JT6!EJ>X SfNNG# QJATGcA41#p?xC547632#"'&54'&##"'&'&#"32767632#"'&=4767632(7  @0:[<2I?RYC &LbfON6 Efe1/ p4#I>QGaD:F #GONeSTI JT?547632#"'&54'&##"'&'&#"327632#"'&547632(7  >*3g3 I0AmN +Pgr@/S=V]x 1/ [0K/?_3"H 7P;QrA033 673276=4'&'&+'!2+"54;#"32#"'&5476L9362LogD;N@X"F 22)D=KIMA2)RHc8uK> #*6 :,3GX@\/"327654'&7!"543!2+32+5#"'&547632W5&A2?U6'B1s66_FnbA6K=QjJE2BS7*D2AX6(XhL@VhA4gD4J+3G(3@2@ -%3276=4'&#"#"'47632"'&'&=nF9J[<2I?RYC &LbfON6 EE:  cA4I>Q4aD:F #GONeSTI JJ>X :\@H747675&'&5476325432#"'&'&#";2+"32767632#"=#"'&\Q?F1AV<<#,R('2?0=B,,B*7Y1?jp:$Y(=N- ;g95"1!9D$4$pHE*53/7#"543!#"=!35432#"=#0#"'&547232766Ƒ <+  .@b--^  :Wj532+#"'&547232765#"54;547632#"'&#"A``;'1+  ?``<(3+G wM, 7"WO/ 9?xL547632#"'&54'&##"'&'&#"327675#"54;2+#"'&=4767632(7  ?,6T7< d7MDFZaI1? Fcc 1/ [.68S I8 4cB_JaL A0"3 5%325&/#"54;2+7#"54;2##"'&5476,.0<'+o&(n* 6> ;BO Z$9@9.'X B#AFE\F%&=4'&'&'0#"32+"54;#"54;676332765#"54;0#'&T 4#-.6_$v,>JsI 3#)21;  4 v 3 =#P 3%#"'4;327676#"'&=fD7# %C E xEW( 4 @q3#5#"543!2+32+32#!"54;5#"43?dd_A((+f3L32+&/&'32+"54;#"54;2+%#"54;2#"'&547632765&'&'I)"+ 8W@5*QK66K-v0 /  8/h9I' 7  ?j7747632#"'&#"7#"54;2+32+"54;'#"543<(3+G /-._)O/ 9'\\ 5#"54;32#32#!"54;5#"43ub ba:(:&f<7473'""'&54?'#"54;272722+"54; 32+"'": NP^U HJn85n 86 87  1 40 T Q3=!5#"'"'&5#"54;32767#"54;327#"54;2+32#*0@!:78"J"/0"J"27"m""4;GE1 /( E2) RT3+7#"'&547232765#"54;#"54;2+# <+  .6jJ"4)^  : B5H06763232+"54;4'&'"32+"54;#"543;2T."m"&&,7('--"EB :",J, ! 2O3%@3U9"327654'&327654'&#"'&547632+#"'&547632,Z>8H;MX?9I:B: 21BQGakIEQGaPQJdsM?PJbyL=  #*6 UzWMZVxWMHN;"327654'&'&7327654'&#"'&547632+#"'&547632,Y8*E3CX8+E,9z? 214LAWhD8LAWHC2AX6)A2A[6# #*6 =TcA9L?UdC8R~>"327654'&763232+"54;4'&#"#"'&547632i,D+>c.G*)fVWF 3M R5Kr;)T5M!r=SF,j?VD)II=  3n#%M2nLjP3T:"327654'&767232+"54;4'&#"#"'&547632E&8"*E&8"$7Y:..3 <.?@0;M3+B.;+J1A_4G1?a5 ;2!?< ..J?TqC.3 9327654'&+"32#"'&5476;2+32+"54;Q09'06 22_8&H8K6 4"(=& #*6 @,9O1'FjA7327654'&#"47632#"'&#"67632#"'32+"543C0?V5'D0>W5&)<(3+G =Jj@ L1`$S O"'<$/P);?(4C%9D$4$pHE*8N( 1>!3ggC6323276=472#"=#"'&547676767654'&#"#"=4324Ub0.#S I#)@'3Y,=`n72,VW 9 )^.4"0 $1)S 6:!)7# * 0 EfAQj8"327654'&#"'&547632327632#"'&54%" %" O*3,L-3  +J+I $ $5/+1>)5rF  <(3&+93;%#"'&5#"54;543232+32767632#"'&547232765KSe&JJ=SE ;'1+  ?!?" ww9!cM, 7"3."32#"'&54763!#"'&=#32+"54;q 22ii  #*6 rI+j932+32767632#"'&5#"54;547632#"'&#"=SE KA;e&JJ<(3+G -9!?" -O/ 9H93&327632#"'&5##"=!#"'&=A3  +J+ F  <(3:IrrI(u=#"'&5#"54;2+32765#"54;27654'&#"'&547632#I6Ha:,"J?)6O/ J 21 b;,I7IQR/>+7Q #*6 +>5:32+5#"'&5#"54;327#"54;27654'&#"'&547632"KTbS"6_,dSJs 21xBR@&3 Z #*5 N;F"=336767454'&'&/53"=#+&'&54767675#cI!5 ) \632 " 8+8' ) ZE17]}$8Q@/ !;CR2 ea ,;[M>% 47d;ae+)3###"'&5#"'4;2+3276532) 451K!7&&^xQ ?%397#"54;2#32+"54;5#"32#"'&5476;2#(nii 22o   #*6 3Fj59 32+"54;7#"54;2+#"54;27654'&#"'&547632#AGs46n 21xxK #*6 g3!!5432!57#"4;75!#"=!32#6:vMj]Q;(v:(s%7##"=!32+!5432!57#"43(x^}GjM7`$(8a$(`34!2+632#"'&547632327654'&#"'&76?##"5p?&,Z3$M5JOJ. IW]-?"-?? 3 I3Fp=+1 CJ,;X)!  7P3GyC@_bG0@X#G%'3767672'&'67665&/#"0/&76?#"'47!2+32c%&P F+<1 <,2U//O&,9, -   |l$ ,7- .:M o;   ~HTj632#!5432!57#"4;67654'&#"#"'&5476725 ]J:vWM 7(0H. >\R9- %-<$M<(L$<)6 (I?1<0*,P30!2+632#"'&547632327654'&#"#"'5#"'4hGI;Z3$M5JOJ. IW]-?"-??-3I3Fp=+1 CJ,;X)!_8"543!2+6232#"'&76762327654'&#'&'&5z *y& B$2a1 $Cc @),! xyO$V'= ,U L 3G<3@F *%654'&#"32+"54;#"54;767232I7V0Mb66_3In W;G8   Y66_m XX ƶ{-*O7`$8a1/ p1?" O4:35432#"54;#"54;2#!#"'&'5432765#"54;2#qY((Ys/$ 9 _ 74;:eFGp/335432!"54;#"54;2##"54;+"54;2765#5``QzB'2B 0; CY,6#hh|Fp,#"54;+"54;2765#532+"54;#"543QzB'2B 0;@B8xCY,6#hh O3<!#32+"54;#"54;#"54;2+7765#"54;2+#"G2+f&Z*u" 8/z"U8Q(3$N#eFGp"8<!#32+"54;#"54;#"54;2+#"54;+"54;2765#54K"6jJ"QzB'2B 0;ACY,6#hh FGp5KO6763632+"54;54'&'&#"32+"54;#"543#"54;+"54;2765#5/W+"m"9  --"QzB'2B 0;E@ >!*' )  O)CY,6#hh O&Hq$H^&HDq&Hq,\l&H3%&Hq2H^&HR(0&Hq8+^&HX(0I'q +&ql(0'v7+'v(0'H7+'H(0'C>7+'C6?"+7!&'&#"#"'&547632#"'&'&%!3276?T.:VE HGDnH3H:LhA_67B 3Grt@$zA-;S3$@.:W2"J aI;O`?3^Sl(64(?2&H q*?F2^&H J+<&Hq.?'HN3U%@&X2HU&XR3U%&qCHU&q`&H~y_bl&H0F^&#"543!+"54;2765'&54727632B'2B !  jl xCY,6#m XX 13'6!#55##"=335432#"54;2+"54;2=4'&'&/&+1껀л\\;&x  ;v:48IN%& 93%435432#5##"=#"54;2+"54;2=4'&'&/&+*s\\;&x  $8a$T7`8IN%& )\ 9"3654'&##"=335432!5#"'&547235#"54;|:" X2{ޯ  > Y66_{-*O7`$8a1/ p1?" ?2&vq*?F2^&vJD5D32765#"54;0#'&'&=#32+"54;#"54;2+35#"54;2#i,>JsI 3#6-h&&h g3 =#P 2F<*763232+"54;#"54;654'&#">IqpMb66_C4!\;,3FUMɆCC5 %2&C6q15^&C<Q O'viHR'v N&vq B^&v(0'v5&vCO&lq$IX&lD OgU@$H}gUg@D1&lq(;X&lH+gU@(?}gUg@HC&lq,CX&lqgU@,\}gUg@C%&lq2CX&lR3%gU@2H}gUg@RSM&lq5OX&l U+MgU@5T}gU g@UC0&lq8;X&lX(0gU@8+}gUg@X\@CS5432#"'&'&#"#"'#"=432327654'&'&'&'&'47632#"'&54?632<#,R(R+_#=M6Kj?A,8[.-E `(3F1AVCT T g95"E %QV0!Hp;#8 (7 $DN- _~ ~gDT5432#"'&'&#"#"'#"=432327654'&'&'&'&'47632#"'&54?632C"R# &'V,1J4F`=<*4]*'#I\&-D,;U>T T E0) !9C&6 S).# 2;!~ ~H3-%32+"54;##"=!#"'&=##"'&54?632AiiT T )IrrI~ ~+3)932+32767632#"'&5#"54;5432#"'&54?632=SE KA;e&JJT T 9!?" w~ ~o@B'&'&76?67654'&#'&'&76?654'&#"#"=432632V"  8F '<$/P)!3g;?(4C"|A%'&'&76?67654'&''&'&76?654'&#"#"=432632K@; K ,  9 )^4Ub0#$GB.%V V+!(I  f* 0 E.4",5'&Hq++''HKg93()55!#"=!!5432#"'&547232765H]:;'1+  ?;v:4M, 7"s9&)5##"=!!5432#"'&547232765-^;'1+  ?$T7`$8M, 7" O&V\$H-&VD+S3&z(?C&zH3%I'q H&ql3%C'qH&ql3%&V\2H-&VR3%'qH}&q=3%&qP<3F%&q\H(7632#"'327632#"'&5#"543327654'&#"Yf_)R6K;M<#-a]@\-6_f4-[T|7@%547632"'&="'&'&5476325432#"'&'&#"765&'"H6Jl9%S=V]?>*3g3 I#-J>8DK ;gb` S7HrA07 [0K/?`3><=?9\8"327654'&7327632#"'&=#"'&5476325#"543U5(C1?T5)D03  +J+Go`A7J=QnH6C2AY6(B2A\6&zF  <(3iK@UeC7h?j8%4'&#"3276=47632#"'&#"32+5#"'&547632D0?U5(C1?T5)<(3+G 6_Go`A7J=Qn\6&C2AY6(B2O/ 9[YiK@UeC7? )74767632#"'&547632327675&'&#"?(`$(lC5PE]TN1 6[l9S'.e69)\ K;PiE;&+ O)6)`%I"+?"+7!&'&#"#"'&547632#"'&'&%!3276?T.:VE HGDnH3H:LhAW2"A-;S3$@.O/ 9:.65'aI;O`?3^?F2"327654'&5432+"54;276=#"'&547632S2#@-;R2$B,n+3Grt@%Bi]>3H:LhAA-;S3$@.:W2"8SC:.65'aI;O`?3^M6%#"'&=47676325432"'&5&'&#"3275#"'6732OU?"=>WT;<#+L/: &;>uv&S.?7M90( C$ %/D6x\47(&.%3#"54;2+#'&747#"54;2+274+2o%)%o1%S{J3% 2LL-!!2&3?632#"=&'&#"#"'&547&#"#"=432632632327654 E5H*!? H4F, !V@@V"<# 'S$/ZA#?[/ S99uPw5,w+E'1#"'&=#"54;2+3276?#"54;2+32#<>Z---&66' -.6H >",.! 3'j?747632#"'&#"6763232+"54;54'&#"32+"543|<(3+G <>Z---&66' -)O/ 9sH >",.! 39jF#"'&5472327654'&#"32+"54;47632#"'&#"67632;'1+  ?&66' -.<(3+G <>Z-#M, 7"J.! O/ 9sH >"\p$#5#"54;5#"54;32+32#!"54;>;vphhX%#"'4;327676#"'&=fD7# %C E x W( 4 @32!"'476;#"'67!2AwyyxO\\527672#"'32#!"54;5&#"#"'&5476725#"54;@.$% 1-'*# 2*%u#%4 ;#*  4\\+85#"54;32+32#!"54;5#"'&7&7664/"#;u26 ,/ 2/4 e5 /" 9\327632#"'&5#"543@3  +J+u\zF  <(3c Q=!5#"'"'&5#"54;32767#"54;327#"54;2+32#*0@!:78"J"/0"J"27"m""4;GE1 ( E ) R  FQ=5#"'"'&5#"54;32767#"54;327#"54;2+32#*0@!:78"J"/0"J"27"m"";GE1 ( E ) R  9J#"'&5472327654'&#"32+4'&#"32+"54;#"54;67632672:'1+  ?"/0"J"27"m""J*0@!:78 CM, 7"i( E<) RO4;GE197#"'&547232765#"54;6763232+"54;54'&'";'1+  ?"K;2T."m"&&,7(&M, 7"EB :",, ! 599327632#"'&54'&'"32+"54;#"54;676323  +J+&&,7('--"K;2T.'F  <(3P, ! 2OEB :"6$!#32#"'476;#"'673#"'6732#1@-] ?kOBH!2#"'&5476&'&#"!3276,jC7LAWhD8LA H/9Y8#t G/;X8%N>VcA9L?UdC8V.C*5(S0 B* K&2)"'&7&763!#"=#35432#"=#35432%#;KE+_<]5KK$( l-= W7Ls4 q`\Ix(p6!f)532+#5#"'&=476;53#";276=4'&'#_5U%-#P"-5U%-(K"--6* #"1-6* +&1>(8->(8-+++-TUqT[q49C3327632#"'&=#"'&5472327675#"543!2#3  +J+j:(%#)7 ><x^F  <(3`  "*9TF%67632"'&#"32#!"54;#"543j:(%#)7A`Kf`  "*8i i9.327632#"'&5#"54;67632"'&#"3  +J+Ktj:(%#)7AF  <(3f`  "*8T)"54;5476;2+"32`B'2B Y,6#TGZ@<-8732#"'476;#"'673232#&'&/3276'&'&+?--P0P6$2J5!qaO05!M1%)5rF  <(3Qj627654'&#"76547632"'&#"#"'&547632% % l;'1+  ? <(33,3cA4F  8 A2=P. A+%567654'&#"#"=76723232+"543>#-=DM8h09 =-)9;@")D "D%1C.AG1m@3G13@?6@/5432#"'&'&#"32767632#"'&54767632@0:[<2I?RYC &LbfON6 Efep4#I>QaD:F #GONe TI JI%07#"'6732#!"'47637327654'&+327654'&+-U+Kp:'0V]BN/$L)O28!!K8"/ 1 - *MuJ547632#"'&54'&#"'&5&'&#"3275#"'6732##"'&=4767632(7  <#+L/: &;>u OU?"=>WT 1/ C$ %/D6x\v&S.?7M90S 7%#32#"'476;#"'6732#35#"'4732#32#"'476;-{%j--j&|-ěOF"p$3#5+"'&5676;#"543!32+";2767;gM$% G'C!Dm2% 0!phh!Y+3"DO!#( .?\N\\\35432!"'476;#"'6732sSSxlO?FjA%4'&#"327632+"54;5#"'&547632547632#"'&#"D0?Y5B1?W5')6bCqh@2M0[O/ 9A9%#"54;567654'&#"#"=76723232+32+"54;ii>#-=DM8h09 =ii--Q9;@")D "D%1C.6oAG<m@)9\5"7654'&3'335432!5"#&'&547635#"54;"(51tN4!3"P6_B2Bc:H0>g6O)$8a1<M>S>?b=\b"7654'&7!2+32#"/&7676327654'&'&#"0'&76?#32+5"'&547635#"54;"(=1t Q,7-@IK  <+ 9&1- &O[6 3"P6_B2Be9R+9g6~P2>cA4F  8 A2=P. 1@O>S>?3'#"54;543232+327632#"'&51JJ||3  +J+xwwF  <(3Fj973276'&7632#"'&#"#"'&=#"54;543232+4<#9,9+B #7,7J+JJ||H 1$AG0% 1%A0&<(3wwv#7632KPW v3#"'75&PW v"/K* W,27654'#,&" 8 * $!./,"'&54763",3/%! !*6 !!$#"/#"'&547,  kk  l XX '&5476327632,  kk  m XX @{ "=472@cbb@qv@Cs 32'&/&76"74?6#d6 6 6 6 p p _p p  s 32'&/&76d6 6p p ,uE,uF #"4;54232B(B(BB(o 32+"=#"4֬B(Bo(BB(54232+"=#"43(BB(BoBB(BB(@#"4;2(l23276763#"'&541@ ;%1R*l' ' 7 2^c2#"'&5476,!  c  2#"'&5476"327654'&,6 *3,%" %" -/+1! $ $e!32767632#"'&54767:+ %A ; !)"  /4!] 2#"'&#"#"'47632327676$!4 (#'-[ $ %y##"'&54?632#"'&54?632#a  b b  b Q^  ^  ^  ^ &'&767676'&/'&'&767/  // //  //  X/  //  // //  3#"'75'3#"'75nPW fPW CCevCeG9o]YCe@q@!"43!2RL(CelUcV4ucjt1(#"'&=476765&'#"'&54762. +6/6 # + 238 /! w1WCeyZCeH{I${ 0#"=4720#"=472 xcb bbbCey#&547632#"/&547632#"'  b   b  Q  ^  ^  ^  Ce'V@UCelGUV@0x5!4'&#"'&547632+"'&5476;276B 21BB #*6  9##"'&54723276=o;'1+  ?0M, 7"*9!327632#"'&=3  +J+*F  <(30zS!zeYXEgA#"4;2( '!"43!2P(C0%""'&54?272g    5%""'&547%272 -  9o] 2#"'&#"#"'47632327676$!4 (#'-[ $ %4u}9!327632#"'&=(3  +J+*F  <(30K62/&747+  8       -62'"'&7'2#"'&547632#"'&5476C  8  M!   !    P    OA'| v\y@'I'@'I<@'I$%@'I%@'I@'Iz&} O3 $%!32+"54;#"54;32+"54;'#6Ox%LGpl%+3#07#"543!2#!"543327654'&+327654'&'&+|6Z2U?-9_X(7!)E%6,S)<%0I/-dJ.!472"7#>3732+"54;#"543!"=!66()b O3)"54;#"54;32%!#4x%x)+3)!5432!"54;#"543!#"=!35432#"=:>66ۑwb--g3)55!#"=!!5432vH]:;v:45'33!32+"54;#"54;2+!5#"54;2+32+"54;6-x66x.63%@)9%"=##"'4=67235432'2#"'&5476"327654'&snIBQGakIEQGaZ>8H;MX?9I:--00]UzWMZVxWM)QJdsM?PJbyL=q332#!"54;#"543!2#@? +<37732+"54;#"54;2+%#"54;2+32+&/&'K66K-vI)"+ 8W@5*ݴ8/h9 O3 732+"54;#"54;32+"54;#lOx%L) Q30231E3 '5&'5!#"=!"=##"'4=67235432!5472!54t|2dd--00ee3%@2#"'&5476"327654'&,nIBQGakIEQGaZ>8H;MX?9I:@]UzWMZVxWM)QJdsM?PJbyL=33-%+"'&54;!32+"54;#"'&543!2#3256  ,-" "+33fA)57'5!#"=!!5432|ʨ4<:yH3%32+"54;##"=!#"'&=#Aii)IrrI3%3&%32+"54;5#"54;2+7#"54;2#Biio&(n .*3 8C#";5#"'&5476;5#"543!2+32+32#!"543327654'&#"R0:'/2._8%H7K us e<)E3D.s2I+=,75!(=&YA+9O2&<!,/8?&+@'1rT"'5F+4'&'"32+"54;#"54;6763232#&&,7('--"K;2T.", ! 2OEB :",Hqj(#"'&=47632!3276=4'&#"L/@_5'M.@`4)0"@@"00"@@"0_dJ-^FfdI-^):hJ55Ii?hJ55Ii%#"'4;327676#"'&=fD7# %C E x W( 4 @F(3#"54;#"54;7#"54;2+32+"54;'_66_/-O:&f#32+"54; 32+"5473'#"54;2n85n G^U 9T+Z)7#"'&5#"5673327#"54;32+5#"4^0UQJq#JPXE&] VcA9L?UdC8)C2AX6)A2A[6#R%!2+32+"54;#32+"54;#"54m~""x--w!"OOB0%#"'32+"54;'47676324'&'&"3276K:Qn@b6M,668F )+ &%?C.=T4%h?1[`cF (S"B2 &%?JV4$B/]m5&#6'"'&54763676'6'&''&7&762432#"52:T"']&#N:* 9S;9|=M;1P0d'*I  97V:#E+.%4'&#"3276#"'&'&'&5476763!2A,;T2#@-V5&12BsP1<%<+ [A '+)#327676#"'&5#"567!2.D7# %C E wW( 4 @$+)%+#"=#"4;327676=#"54;2)54^ $91-1(3!0 QF\ K3276=4'&'+";32"+#"'&=#"'&'&=47672;547632;6* +&Y6* #"1(5=#&-!0"5=#&-!0"y+-++ &9?&&9?&F)-+32+32+"54;7#"'&54;7#"54;2)-4L)5( @1"F-\6%3276532#+#"'&=#"'&=#"4;;47632;*3 V-:()+K#)R" -(.M%= )((" +(O+#"'&'&'#"'&'&547#"4;2+3276=472327>54'#"'4;2!6 0/ #M' 7m1:"  $$:2nS_@6N  , F9>^S(P]8-6 *+ ^6ZRZ;&j+);&jHt&I+)h&I+(h&Ipf (43254'&+"32+"'&5476;2#;27654#ET* A,9x3@2RW.B#O DQm!P"$"MS.N`XF<'7ly.> DBj?32+"'&567632#"'&'#"'&5476;23276=4'&#"$ J.=`4L/@^5 !,"f@"00"@n d# D+^):JdJ-\,:5IiYhJ5 %6!&2%"+#5#"'&=#"54;;3254'&'#3276!-!0"--V&2 $\ 2b=#&-'*16)"?&<'*y&9+PmT2'#""#"'5327654'&#&'&5476;TK\^U /  d##o ([ B[a! e( )O$1[7Ym&#"#'#5327654/&'&54763<^b!O9a*732+"54;#"543!"=!7#"'&54?63266(ƺr  r )bd  d @@432767632#"'&=4767632542"5&'&#"!2#jI?R\F &MafOO6 DfdJ((@1:Z<2aD:L #GNOeSTH JEp4#I>Q\@6q3,q&j\,TG3-H34?32+"54;##"'&=43232765#"54;2#327654'&#T(e=*F4Dst6$ (:K+=+6 A,:P1$B5 5 '<' H37B32+"54;5#32+"54;#"54;2+35#"54;2#327654'&#K1e=*F4D\[[CK+=+6 A,:P1$5 '<'C69673232+"'54;54/"32+"'54;##"'5!#"'5)O !x6k!C.6x|t QT ItrL$43E732+"54;#"54;2+%#"54;2+32+&'&'#"'&54?632J66J"v~D>"8X6$:r  r )"E?fCd  d 3%3D 32+"54;#"54;2+5#"54;2+32+"54;"/&5476326-x66x.6r r zD \d d 2&%=732+"54;7#"54;2+#"54;2+%23276763#"'&54@jn*.p1@ ;%1R*)'' ' 7 23%3-7!#"'54;2+32+#5#"'54;#"'54;2+6-0.6)PP O3$,3*2#!"54;#"543!#"=!327654'&'&+9/ <.;66B&,,SCf!I0%b3$3%+3%>3732+"54;#"543!"=!66()b 63%70765#"543!2+3#"=!#"=;#Yc<)bbb1+3(P3P2+7#"54;2+32+&/&'32+"54;5#"54;6767'#"54;2+5#"543^VQ&+8%>#dP')8K2V3(7?v?%;?B\@H#"'#"=432327654'&'&+"54;27654'&#"#"=432632< XM6Kj?A,8[.-)-=0?2'<$/P)!3g;?(3&33 32+"54;#"54;2+5#"54;2+32+"54;6-x66x.6zD \3&K23276763#"'&54 32+"54;#"54;2+5#"54;2+32+"54;1@ ;%1R*6-x66x.6' ' 7 2wD \-<33732+"54;#"54;2+%#"54;2+32+&'&'J66J"v~D>"8X6$:)"E?fC9'3.7367#"543!2+32+"54;##"'&=432b!+Q.66#P !B5 Q305'3+3%@23%3%!32+"54;#"543!2+32+"54;6-.6 +33?@&H372&3%732+"54;7#"54;2+#"54;2+@jn*.p)'J3 8C#";5#"'&5476;5#"543!2+32+32#!"543327654'&#BR0:'/RN_8%H7K@us@e<)E3DNsRI+=,75!(=&YA+9O2&<32+"54;#"54;2#32+"54;#"54;2+327654'&#ee7e<*F3DeJ,=,6 @-:Q0$5 '=&+2 &327654'&#'32#!"54;#"54;2+J,=,6e<*F3D66v"5 '=&)@-:Q0$@@4!"543!54'&#""=42632#"'&547232765F8JU6!((JdfD; OOfaM& GW^B:cA42#pEJ>X SeONG# TJATU@+<67632#"'&'#32+"54;#"54;2+%"327654/&P6M{8#M1@w9#JWZe.F*=a/K!9I2yJiR%uHcm>TF*g?VC /3 25#"3##"54;6767&5476;2+32+"54;B,B1?rB3$79N*A3@66K$0$7#)G1e)0aG0%HDQr!1&67632'&'6767635432"327654'&&| 53%f@3JV nBAoH> gJ73277654'&#"#"=432632#"'#"=432327654'&'&'#"540O 9 )^4Ub0.1J4F`=<*4]*'75D * 0 E.4"0  !9C&6 S).#A3%5#"54;2+32+"54;532+"54;#"54;2# -x""x--w!"xx3+OA3K%5#"54;2+32+"54;532+"54;#"54;2#23276763#"'&54 -x""x--w!"x$1@ ;%1R*x3+O' ' 7 2F(3#"54;#"54;7#"54;2+32+"54;'_66_/-OX,725#"543!2+32+"54;##'&'5432"M""x-"$ A7O/ 4%,32+32+"54;##'#32+"54;#"54;k""m"}~(nbwOOA3!5#"54;2+32+"54;5!32+"54;#"54;2# -**--w!"xxOHRA%!2+32+"54;!32+"54;#"54\""x--w!"OOFSTFf!#"=#32+"54;##"5f-.[P[3F%\F`=*7B5#"'&5476;5#"54;32+32+"543";3#327654'&Fg@3M2C&1 P3%S?.;V2#3%[5')"54;#"54;2+!#"54;2+3#"5r"-- "m"8OO`3367675#"54;2+32+"54;5#"'&'5#"54;2#E;$"m""m"%AZ"xx$ P3%3#"54;2+32#!"54;#"54;2+3#"54;2+A"m"! j""m")OOO L5)"54;#"54;2+3#"54;2#3#"54;2+3#"5# k##k!"!k!>OOO@(32+32+"'476;##"532765&'#@%N V#p›F ]B\OZ) Q N5>%#"54;2+32+"543#32+"'476;#"54;232765&'#-x""x*N VpBF ])OOB\O) Ql&#32+"'476;#"54;232765&'#%N V#%q=F ]xB\O) QJ1%!"543!&'&#"#"=432632#"'&5476323276 N+7V/=_tA1Q=TgO, Nld5`-.[ 7RPjC7LAWhD0Y8+E3DW9*F(Ob<0N>VcA9L5B3AW7)B2@[7X*5%#"'&5476;2+32+"54;532+"54;#"2;X^MP"$r$.F S@ XO'M?l&C6H?'&jH+i\H2+"54;276754/&#"32+"'54;#"'54;5#"54;32+676?Z,&3A@B % 5F4-.666_<><"-D3& 6!@,>6_H r^+#"=#32+"54;#"543!'#"'&54?632--"Mtr  r [Od  d J17327632#"'&5476325432#"'&'&#"!2#t K-9lN ,Ogs@/S=V_=>*2g4Z+H 7Q:QrA07 [0L'2gV\pL\-&jFpM"60;32+"54;##'&'543225#"543!2#327654'"+`\MP$"& "VF SJx@ XO/ 7' M<7B32+"54;5#32+"54;#"54;2+35#"54;2#327654'"+^dMP$ !cc! ^^F SRx@ XO' M+'\D"32+"'54;#"'54;5#"54;32+6763232+"54;54/&:F4-.666_<> Z,--% ]>6_H <"-,F^(:3#"54;#"54;7#"54;2+32+"54;'#"'&54?632_66_/-вr  r Owd  d >^3D%5#"54;2+32+"54;532+"54;#"54;2#7"/&547632-x""x--w!"x/r r x3+Od d 3F%K&U\>-!#5#&'54;#"'54;2+!#"'54;2+32D0""x--w!"PPOO<@O547632542#"'&#"32+32767632#"'&=#32+"54;#"54;2+8:`p( sd,B4D6/ &3/fD:DWZ9 jGJEpr_4EfD5.  )6 VKaP459'&763!232+&'&'32+"54;5#"54;676737#n  &nO%#8%@ 7dP')8KT(^< '31U@ %;?A,P37;AE332+&'&'32+"54;532+"54;#"543!2'#6767#737#dP&)8%@ 7dP'"WY-#L}(^='9>t@ %;5aV. E3<%6=32#32+"'4;5&'&=#"'&54;#"'&5473+AK#X/?ii+"Js+0 w:__ w-9Մ V "F-\+3'232+"54;#"4;5#"54;2+32#327654'&#e<*F3D6666J,=,6G@-:Q0$j(OO(p5 '=&l2732765&'#'5#"54;2+32+32+"'476;5#"43қF ])%q%--N V#-)) Q++(8B\(+3:674'&+327'&7676'&/+32+"54;#"54;2;9'0> fA I(466_8&*+9=& =  g@  J@,9OFG%654'&#"327'&7676'&/#"'32+"54;#"54;67632?D0>W5&C0?,$D h? D2!32+"54;#"543!54266( br5432!32+"54;#"543--"[O>3$32+32+"54;#"4;5#"543!"=!6556((@(ybr%5#"543!#"=#32+32+"54;5#"43"MNN--*!W((>03732+"54;#"543!"=!32#"'&54723276=4'&#:66(Ƭe=*<'1+  ?=+6#bA,:kL- 7"e<'rD9732+"54;#"543!#"=#32#"'&54723276=4/"#--"MVq*<'1+  ?J&ěO&L- 7"DnP3Q%#"=#&'&'32+"54;5#"54;6767'#"54;2+5#"54;2+7#"54;2+P*%@ 7dP')8K2VdVQ&+)w@ %;?B(7?v nMW%#"=#"54;&'&'32+"54;532+"54;67'#"54;2+5#"54;2+7#"54;2+MU%h #o#o* e/c#o#c0)wH> => nBAo\S@c#"'&5472327654+5&'#"=432327654'&'&+"54;27654'&#"#"=432632< XM2E:-$" %.X5A,8[.-)-=0?2'<$/P)p;#8 (7!1>!3g;?(gSe&'#"=432327654'&'&'#"54;277654'&#"#"=432632#"'&5472327654+M5<*4]*'75D0O 9 )^4Ub0.1K/?:-$" %./ S).# * 0 E.4"0  !9D&2, $n535%3#"=#&'&'32+"54;#"54;2+%#"54;2+SI6$:J66J"v~D>)wC"E?Fn*%3#"=#"54;'#"54;#"54;7#"54;2+Iu_66_/)wO$43A32+&'&'"=0'32+"54;#"54;2+35427#"54;2+{C8X7n(5J66J8(v1()3=IZa;F4%32+"54;'"=##"54;#"54;35427#"54;2+-(_66_(l/֭~AYObFl$43?32+%#"54;2+32+&'&'32+"54;#"4;5#"54;2+QQ"v~D>"8X6$:J6;;6J(g"E?fC(3F432+7#"54;2+32+"54;'#"54;#"4;5#"54;++/-_6@@6_U(=(#435!2+%#"54;2+32+&'&'32+"54;##"5J"v~D>"8X6$:J6c3"E?fC[ *37#"54;2+32+"54;'#"54;##"5 /-_6cO[5n'35%#"=#"54;5!32+"54;#"54;2+!5#"54;2+'~66-x66x)wRn5%#"=#"54;5#32+"54;#"54;2+35#"54;2+i--w!"x--x")wO5k35#32+"54;5!32+"54;#"54;2+!5#"54;#"5Ac.66-x66 RV5#32+"54;5#32+"54;#"54;2+35#"54;#"5,c"x--w!"x--xOd3E32+"54;#32+"54;#"543!2+32#"'&54723276=4/&#\.66-R\\2<'1+  ?6#9#+L- 7"2 DIE%32+"54;#32+"54;#"543!2+32#"'&54723276=4/"#I"x--w!">"Tq*<'1+  ?J&ěOOE&L- 7"D?@&TF?e@G#"'&=47676325432#"'&'&#"3276763232767632#"'&54HfON6 EfeH@0:[<2I?RYC &,8:+ %A ONeSTI JEp4#I>QGaD:F #) !)"  /0TeD#"'&5476325432#"'&'&#"32763232767632#"'&54I r@/S=V]?>*3g3 I0AmN +*6:+ %A P;QrA07 [0K/?_3"H  !)"  /0Hn3%#"=#"54;##"=!#"'&=#i)wIrrIzm%#"=#"54;##"=%#"=v.tdt(wO[[3%3&%32+"54;5#"54;2+7#"54;2#Biio&(n 9:'#"54;2+3#"54;2+32+"54;)AD)23#Oe{3%30%#"4;#"54;2+7#"54;2#32+32+"54;^^o&(neeii( (:132+"54;5#"4;#"54;2+3#"54;2+32#B23aO)AD)P#(sO((n035%#"=#"54;'32+"54;7'#"54;2+7#"54;2+0u>@n+-o)w3n%5%#"=#"54;'32+"54;7'#"54;2+7#"54;2+%uAD o.0n)wn&3+#!#"54;2+3#"=!"54;##"=!#"5d6.JfdD w[ +#3#"54;2+3#"=!"54;##"=!#"5"d"m"8"cDxO[O[Jn35%#"=#"54;5#"'&'5#"54;2+23275#"54;2+~6=h%x6eK)6x)w !15`n5%#"=#"54;5#"'&'5#"54;2+367675#"54;2+^"%AZ"x-E;$"m")w$J3=%675#"54;2+32+"54;5"=&'&'5#"54;2+23542<=#6x.6>(k x6 Z(- ZY0.j`;%"=&'&'5#"54;2+23542675#"54;2+32+"54;5B(X "x-K(8"m""m"87 99J336763232+"54;5&'"#"32+"54;#"54;2+=h%x6eK)6x.vB !15`3%5&'&#32+"54;#"54;2+63232+"543E;$"m""R%AZ"x)O$@ D%54'&#"#"'&547632";5476762!32767632#"'&5[F9J[<2)&1/ &6 EE: EI?RYC &LbfON3 cA4I>Q5(7  TI JJ>X :aD:F #GONe A7!&'&#"67632!32767632#"'&'#"'&547632"3hvQ)1i5) R;KqC `T.:VE HGDnG61/ ['N#a6(Q,6f/(N:O(7  e@ \%54'&#"#"'&=#"'&547632";5476762!3276763232767632#"'&54[F9J[<2 fON&1/ &6 EE: EI?RYC &*3:+ %A 3 cA4I>QONe(7  TI JJ>X :aD:F #' !)"  /0e Z7!&'&#"#"'&'#"'&547632";67632!3276763232767632#"'&54hvQ)1i5nG61/  R;KqC `T.:VE H:+ %A ['N#N:O(7  a6(Q,6f/(  !)"  /0q3,POg2+7#"54;2+32+&'&'32+"54;5#"54;6767'#"54;2+5#"543'23276763#"'&54^VQ&+8%@ 7dP')8K2VJ1@ ;%1R*3(7?v@ %;?B' ' 7 2 MKUm!#"54;532+"54;67'#"54;2+5#"54;2+7#"54;2+32+"54;&'&'3223276763#"'&54do#o* e/c#o#c0e%h #1@ ;%1R*=> nBAoH> K' ' 7 2$3C32#"'&54723276=4'&+32+"54;#"54;2+%#"54;2+Kv7<'1+  ?J$0J66J"v@H)6kL- 7"eM!FD;7#"54;#"54;7#"54;2+32#"'&54723276=4/"#_66_/#q*<'1+  ?J&OE&L- 7"D593:#"'&547232765!32+"54;#"54;2+!5#"54;2#;'1+  ?6-x66x M, 7":R9:#"'&54723276=#32+"54;#"54;2+35#"54;2#;'1+  ?-w!"x--xxXM, 7"OJm37%275#"'&'5#"54;2+23275#"54;2+32+#"5K H=h%x6eK)6x.}( !15w`n5%5#"'&'5#"54;2+367675#"54;2+32+#"=%AZ"x-E;$"m""^)$w O&$UqHY&DU O&$j\H;&Dj N3 B+&(Uq?Y&HU2@ -%3276=4'&#"#"'47632"'&'&=nF9J[<2I?RYC &LbfON6 EE:  cA4I>Q4aD:F #GONeSTI JJ>X :K(%&'&#"#"'&547632#"'&=!3276 K-8mN +Pgr@/S&2tA1 S+8g3[,H 7P;QrA R nBAoH> -    \HXh#"'#"=432327654'&'&+"54;27654'&#"#"=432632%2#"'&547632#"'&5476< XM6Kj?A,8[.-)-=0?2'<$/P)!3g;?(    g;JZj73277654'&#"#"=432632#"'#"=432327654'&'&'#"542#"'&547632#"'&54760O 9 )^4Ub0.1J4F`=<*4]*'75D!   !    * 0 E.4"0  !9C&6 S).#D    \@H#"'#"=432327654'&'&+"54;27654'&#"#"=432632< XM6Kj?A,8[.-)-=0?2'<$/P)!3g;?(gJ73277654'&#"#"=432632#"'#"=432327654'&'&'#"540O 9 )^4Ub0.1J4F`=<*4]*'75D * 0 E.4"0  !9C&6 S).#3%3; 32+"54;#"54;2+5#"54;2+32+"54;#"4;26-x66x.6zD \2((>3;%5#"54;2+32+"54;532+"54;#"54;2#7#"4;2-x""x--w!"xx3+OQ((3%3CS 32+"54;#"54;2+5#"54;2+32+"54;2#"'&547632#"'&54766-x66x.6!   !  zD \    >-3CS%5#"54;2+32+"54;532+"54;#"54;2#'2#"'&547632#"'&5476-x""x--w!"x!   !   x3+O    3%&2jiH;&Rj3%@!2#"'&5476&'&#"!3276,nIBQGakIEQG0L6EZ>2aJ8FX>4@]UzWMZVxWMuE1QBX(qF4PBH!2#"'&5476&'&#"!3276,jC7LAWhD8LAI/:Y8$t F/:X9#N>VcA9L?UdC8X0C+8(R.B)3%&j\H-&j@&j\J-&j2&&qC3F%&q2&&j\3F%-&j2&&Zq3F%X&ZI&&j\`-&j Q&j\ N-&j)nD33'&'#"'&5#"54;2+32765#"54;2+13%0p:#K>)5S1L":i}`1;NU/L).NX:r)7C0%#!32+"54;4763232+"54;54'&#"!27tL#G6Jd9(#fT!)R-mOb<-L6I99b.B*6+FD!1%+32+"5473'#"'&54763272'4'&#"3276FJ6fCoi@1P;PpA)JF/=Z4#E/=[4#mZL:Pj>.Z:AY2!C-)6T1f#I4Hn;YmOR0 K%299f;*`1:"030#!3276=#"54;2+#"'&5#"54;2+!20u>)5S1e"H5Hp:#KU/L).99e<+a1:Nd"6B!1#"'&547632!"'"=423!24'&#"3276&VF`xI;VEaxI;7+((!Av8M:Mf?0M:Nh>.HvI:TE`wI:UDW#t8(Hg=.K9Nf>.L9:3#"/!"54;#"54;2'#!!3 F__4&Q ; Ed)Q )1C)+"54;54'&#"!2#!"54;47632321fT!)R-~6#G6Je9'#21b.B*6Ob<-M6H1 T?8E236#'#"'&5!6'&'&'&#"32+"54;47676#3276'41dD2(+.H_5/U \7'K#K2 %2/&?D2B6W(Bh$cE H D1A;^D @ +*T4<3"0+#"'&'&7676;5#"54;2+325#"3276<_H5Hp:, 29`"_R0 >)5S1me<+`-?I3ǝ>)6S0 L);35%+"54;54'&'&#32+"54;#"54;2+67632;f<"+ E2AA":c\;.#%P0;'+QI9J%?2)"54;#"54;2+!542;bbb* 5P39+#"'&=#32+"54;#"54;2+33276=#"54;2PH(8b0n#f[)9T" $ft5\#EdM"3R9.&< )!"43!2#"'&5476324'&#"3276s0VF`xI;VEaxI;(M:Mf?0M:Nh>.'(vI:TE`wI:UDag=.K9Nf>.L9)133+32+"54;5#"'&=#"54;2+3276=#"54;21##:ap:#K>)5S1-yL`1;U/L(+Bk;)%"=4'&'&#"54;27654'&+"54;2(8"c#%#!"5432;276767654'&#"32+54767632632&#"Av5.2  4,+ P9Nc-o P.6fLM"$-?#GYK!=  P4&Bo<+L+9(&#*Q'FGcVM M,V#! EC)%#'"5434'&#"32+"54;54763232E1T!)R-$p#J5Hd9(JOb.B*611f;*L6I!94$-)"54;#"54;676;2+"3232'54/&+%!:JK9: v[<1>z+_wU\"(ED7H)(LK40"54/&+'&'&5#"54;2+32765#"4;2K(D3D92 #K8(4S/L_>`=.) +DNM2$Y+N*Z]9%+"543!276'&'&+"4;27654'&#"#"=426320 *A0q \_>)<$)Y. (>OV6'A1EC+R;(*!:!7^0.9)7>/ :3)"'&5#"54;2+3276=#"54;2+BY9+X%7)2O-M"56J9INJ3&O**bbP=?=d;%#"'&'&547632'4'&'&+"4;2#"'&'&#"327632QnmG: RE^bM) .S#6+8IK; !K@SaN l ZG:6$1oG N5H+J#3#"'%&54327"'&5476324'&#"3276C $lGW$nB5P?VnB5)H2B^7'H2BW8-g^B /_'dO>VmB4O>V]6&F1B^6&A4?C:%+"54;4'&'&'32+"54;"32+"54;54763232?V*F#o#S-$o#f+Jn:#O5:'ZE(499{8N&1@H4-8%#!"'"=432;2767&#!"=4;232'654'&+!2Hg1* '=BA A&Dö9 $3`O:K.2&)] $.f\2)V) S06Y4& NC2#32+"54;4'&#"32+"54;476763232:P#KS!)Q.L"D,6h8"POa/A+6O\> S3E1)13)+#"'&5#"54;2+32765#"54;21"H5Hp:#K>)5S1Le<+`1;NU/L).N '42%+"54;5#"'&=#"54;2+327675#"54;2+32'^>__:+-pS$"G2!"e.TL:K&&i-;',*\@6*2C++"54;54'&#"32+"54;4767632322o#S"(Q."D,6c9(#21d,A+6O\> M6H1AR2B%+"'&5432;27654'&+"4;&'&=47632'27654'&#"42FD .* C6"+q3K+8_-;zC&< 'J#9"O-f #WH*(6Q)@$2D0 .=/$A 2"<#\3#32+"54;#"54;2+32GGFG3)2;32#!"54;7&'&547675#"543!2+4'&'676R6Hnnd>/C8Voni<+)J)4W0 Z0F,h;(I8JX?5''K6IY0@*oKB*6T0KE&6%!32+"5435"4;5476#"'!2&'&'&76767do6\\S:Nj;&O6JqB]Z$Z3&E/9c*sJK(k9(H/>e8'X(` :*:G)A&3%@2Z=+4=%#5&'#"=4325&'&54767632+%5"4'&'676R0>)Y9I!&{ 4&A!WXNVZ7 (=D=U)[/:r?#=#23& 'F%C 7 Q4%+5#"'#"'&5#"54;327#"54;327#"54;32QL54@ 69,##L# 45#L" 28"K#)8DD&+ .S/S4B-5%#!32+"5473#54;67676"=4'&'&!2-56_1!O6  59/%dW,"9 *Rk!# ;/2+BF#3%+36+"54;5#"'&54763232'4'&#"3276FJ6dCoi@1P;PpA)JF/=Z4#E/=[4# ZL:Pj>.Z:AY2!C->8 /."K5"&Y.[I : T*A5 E#$,0<&232+5#"'&5#"4;!2#!32754#LRaS"7`l/cR;KA&*; [+CG)##"'&547632532+324'&#"3276GtCoi@1P;PnC`8KF/=Z4#E/=[4#!ZL:Pj>.ZK*sY2!C-ME"$B'0%#"'32+"54;#"4;632&'&#"!3276O;PnD88aJg<)E.:\4 ` E+3T6i>/Z*KZl10T0D)6(K(@#4<<++#"'&'&7676;532+325#"3276<_H5Hp:, 29K#`R0 >)5S1me<+`-?I3Ǟ>*6S0 L)5B=-%+"54;54'&#"32+"54;#"4;63232n": 1(*."KMOZ-#A 3A*ME"$IB#!"54;#"54;!2jXVB==6%+50#"'&5#32+"54;#"4;332767#"4;32=L%S"d/."K/!!7`#3A&*; 1*GT</7476;'&54;2+32+#"'&%4/#"3276GJBW'  EED\ZDG34WP:0F4BW9,^C=o (n( ;p[?>?AXc)*@5AR5(?18B <0+"54;5#"'&5#"54;2+32767&'&54;2 IRY-#n"9 @1 - L3KD"$p? 2 ! 5<-%+"54;54'&#"32+"54;#"4;63232n": 1(*/.!JMOZ-#A 3*ME"$GOa):<%+5#"'&54767'&54;'&5432+32'4'&+"3276'#OLEwnB5R/UoB% H = FQ=R[7(D3C\6'F1BBR.+"54;4/&#"32+"54;#"54;63232R+5 =3(..#LMKV*U= 4.T=ME# =P<'%#!"54;#"54;&76;2+"3254'&+BAA%(?NZ:+(U! PUN*(mL:Ih.6)=/476;2+"32+5#"'&5#"4;3275'&3"  c7`ROS"7`/PSb, P 5-%+"54;54'&#"32+"54;#"4;63232n": 1(*/."KMOZ-#A 3T*>ME"$]B2#!"54;#&=42;2w0D(&DFF$ I BQ>+"54;5#"'#"'&5#"54;327#"54;327#"54;2+32Q^54@ 69,##L# 35"L" 28#o##8DD&+.S/SFB0%32#!"54;7&+"'&5&76324'&#"326/ &wV:8Q?VoC3)I1BN7!=#O8&<,nB4P>V_6%6!3+ B/5 3%+"54;7654'&#"32+"54;#"4;6763232 P;9&//."K6,&Y.PU4 6T*>6 ?  , %+5#"'&5#"4;327#"4;32LSbS"7`/dSKt#ME"$?F2Jy%#!"54;'"54;2XXS BP<@"32#!"543?#"'&5#"54;327#"4;6763232+4/&((nn42,##L# 35"L0)-##L#,1;&+.S*4&+D.i e,#"'&#"32+32#!"54;#"54;547632 P,LdYYD&/8D#C /?T?H$ HRYB=4=F%32+"54;5&'&'&76325&'&54767632+'5"4'&'676S/'"+"'&5476;67676765#"'&54763!6#"'&5&'&'&'&#"!<$$*Z%/*  ' >#"  5 (G%6 Z'#"'&5#"'&54763##"'&5#"'&54763YPY44Z'#"'&=#"'&54763!#"'&5#"'&54763YTY4Z'#"'&=#"'&54763##"'&=#"'&54763YPY;r\3"'^<4\$$;\ 3"'73"'^<4^<4\$$$$ #377@{/v#"432#36p#FP{/xG##3+}gO{G ##3#3+}BgO{G##3#"'&547632+}|   gO{d!    G#32#4'&+#3+}1.  1gO/J#{ #3'N{2 #3'7"42i<<N{2#F '#3'X{/w'#37'7sZZdsZZd[F{ENYEAEN ''#37sZaRZdYEAL@{EN #3&X{/w%'#'55'553'onnnnooox///q %'#3'qoooox{/q #575573qoooog//#57557377noooonnnX///#5755737noooont// '7'#3ͯ-{t>%'7›t/#'#3'g{#37{#"54327#37 !{#&547537'$$  / - -+F # # 33F  g]]CF$).8#"'#&54736374'&'676'&"'2/F > jk #" lkPA//=  !"""$!0= K gLRLLTMLK k(MO#b8n99WM$ /#3'{0 #'#33g {H #5'#335'g:{%'#57'537oojinnijy/{{.Y.{{t#&'&547673t% &$ '^2q ,1d+ %'#'53onnox/:q%'#3qoox{:%'#&'&547'5673X $>P(Chd*J/_ q +O:#3:g{t#&'&547673t% &$ '^2q ,1d+z %'757'5<››/!/.3% #553'#%N렠2 #5737noonX/[q#573qoog/ '#'53onnoc.L '#37'7b{/㛖 #'5537nn|-Ҭ~ %577Û/l/#3g7G:3:\#"'&5473\# ""&% * g '737ooS '#573nn<L-#573gM/#&'&54767573% $$ '20)1y/[ + %#37'7'[υ{ݚq #377qoooo/{x/ +%#37'7'7#"'&547632#"'&547632[υ2     {ݚ!  !  "   "   #3^[{|in #'#373gO{#'57'#373jCWWCj~~gOO/gg/O{3%#&'&5336765%MB[jF=J8OcsNSq=COtoUBgb`![[ ߥ=G9Gpdn #'#3735#'5'5#'~~~~j(j~~~~j(jg{͕͕~~3%#4'&'##47673%K8Kd=0EFbkE:etN:[H[uUVU `R:3:4%#'5573'7rnnnnrrr--/݈#3gPV%##5#53#53533#3[ZZ\\YY[ tt !hh!Lk#"'&547632k!(!(-)-)k'c8c9 '#75'37oNooNo8]v '##73'0٧s3%+#4'&'##4767&'&53367653%K8Kd=0EFbjF=J8OcH&C>q3%'vH&vq+&vq3F^&vS+&V\3F-&VS+M&V\5T-&V U+{M3'V|5T{'V |U+{M&qCT{&q +M3'q5T'q U\&V\6g-&VV\k@'Vl6gk'VlV\'V>g 'V\'V>"g 'V#\k&V\gk-&VH&V\7+&V\WH{3'V|7+k3'VlWH3'q7+3'qWHC3'GY7+33'GIW(k03'jl8+k'jlX(p03'Yl8+p'YlX(303'GI8+3'GIX(0q'v*+&v`+(0b'j,+&j\- O&YW9:"&YY {O3'V|9{:'V|YD&C>q::^&C>ZD&vq::^&vZD&j\::-&jZD&V\::-&VZ{D3'V|:{:'V|Z(0&V\;3%-&V[(0&j\;3%-&j[3%&V\<3F%-&V\g&Gq=s^&G]g{3'V|=s{'V|]g3'q=s'q]+'\'qK+&j\W:~&WZ3F%~&W\H&EDi'VA {O3'V|$Hk'VlD,OM'f$s&fD O'vSH<'v O'C>SH<'CEYO"'f]j'f O'Y9H'Y {O&GqHk^&G O'v@H'v O'C>@H'CEtO'fJty'f O'Y&H'Y {O&UqHkK&U+{3'V|(?k'VlHdM'f(k&fH+&YW(?"&YH+'vS?<'v+'C,S?<'C6k"'f]y'f+'Y9?'Y+{&Gq?k^&GtM'f,s&fq{3'V|,\{p'V|L3k%@'Vl2Hk'VlRt%M'f2t&fR3%'vSH<'v3%'C>SH<'C>t%"'f]t'f3%'Y9H'Y3k%&Gq1Hk^&G23U'vbH'vYc3U'CRbHN'CYc?U'fb8N('fcc3U'YbH'Y?c3kU'VlbHdN'Vec(k03'Vl8+k'VlXt0M'f8[&fX('vq+q'vsr(u'Cq+>'Csr_u'fq(>B'f}r(H'Yq+{'YYr(du'Veq+d>5'Ver3%&C>q<3F%^&C>\3{%3'V|<3%'V\t%M'f<tF%&f\3%&YW<3F%"&Y\?G&?G&G?G&?G&)?G&?G&*?G&?G&+O@'O@'GOA'pOA')OA'pOA'*#OV'Q,OV'+Q&&G&&)&&*@'@'GHA'x8A')pHA'x8A'*p5F&5F&G&5F&5F&)5F&5F&*5F&5F&+ '@''@'Gg'A'W'A')g'A'W'A'* 'V'Q'V'+rQ&&G&&)&&*O&o&+@'@'GA'~A')A'~A'*;V'Q:V'+QH&H&GH&H&)H&H&*%@'%@'Gb%A'P%A')%A'w%A'*+)&+)&G+)&+)&)+)&+)&*+)&+)&+%@'GL%A')=%A'*u%'Yd+(&+(&G +(&+(&)+(&+(&*+(&+(&+@'@'G_A'RA')A'{A'*<@';J@'+;?G&;?G&F&; &F 5F&;-5F&F-&;&FH&;H&F+)&; +)&F +(&;+(&F?G&{_?G&{`?G&{a?G&{b?G&{c?G&{d?G&{e?G&{fO@&gO@&hOA&ipOA&jOA&kpOA&l#OV&m,OV&n5&{{5&{|5&{}5&{~5&{5&{5&{5&{'@&'@&g'A&W'A&g'A&W'A& 'V&'V&+(&{+(&{+(&{+(&{+(&{+(&{+(&{+(&{@&@&_A&RA&A&{A&<@&J@&?GY&U?G&q?G&{?G&{?Gh&{?G0&?G0&{ O&U~ O&qPOA'; OA'F  O3&9!327632#"'&=(3  +J+*F  <(30T27654'#&" 8 * $!./] 2#"'&#"#"'47632327676$!4 (#'-[ $ % 0@2#"'&#"#"'476323276762#"'&547632#"'&5476$!4 (#'-!   !   $ %x    5&{5&{5k&{5F3&53&{A';A'F'A';'A'F5'3&!'&/&767627654'#m8 8 &" 8 *   $!./#62'"'&747'27654'#  8  &" 8 *     $!./'jY&Uj&qϿ\&9Z&:`0&Z&q&U~q&qP A'; A'F!'&/&7676"'&54763"u8 8 K3/%!   !*6 !!$#62'"'&747'"'&54763"  8  23/%!     !*6 !!$'G+)Y&U+)&q+)&9+)&:B&B&G+)0&+)&3%&U~3%&qP%A';%A'F@'G 0'&/&76762#"'&547632#"'&54768 8 N!   !  O     -62'"'&7'2#"'&547632#"'&5476C  8  M!   !    P    K'&/&76768 8   +(&{+(&{+(h&{+(0&+(0&{?%P';%Q'FA';A'F#F 3&K62/&747+  8      T"'&54763"T3/%! !*6 !!$+ !"543!2H. !"543!2nW. !"543!2< W.J#d!5!5dpK22`22W\ #"/F \:T\ 3#"'&547υ \oT 73#"'&547υ W\M]W\ #"/##"/F \F \]W\ 3#"'&547%3#"'&547} } \] 73#"'&547%3#"'&547} } ]W\Q|\4?3543232+#"5#"|d|\&4?3543232+32+#"=#"54;5#"|Q2#"'&5476.3.6/Q-6.63%T/72#"'&547632#"'&547632#"'&5476d!  !  !    !  T  !     "4f/?O_o2#"'&5476"327654'& #"'&547%6322#"'&5476"327654'&72#"'&5476"327654'&;!0":!0", ', (L v ;!0":!0", ', (;!0":!0", ', (f2#9!1":""'. '0 z  z 2#9!1":""'. '0 "2#9!1":""'. '0 Rf/O`q2#"'&5476"327654'& #"'&547%632672#"'"'"'&547632672327654'&#"4'&#"32765'4'&#"32765;!0":!0", ', (L v y!<;!0";"%8;"%8:!0";"!<;3', (, "), ', ), ', f2#9!1":""'. '0 z  z 32#9!40401":"43o, '0 '0'. '0'. 'W\ 3#"'&547} \]W\RWW\  3#"'&547'3#"'&547%3#"'&547} } } \W\ #"/FF \]W\GRX@WW\  #"/!#"/!#"/GF EF F \?8?632#"'?     %%#"'&54?'&547632     pj"3E#"'&54763232+"'&5476 #"'&54763232+"'&5476 . # #   . # $  3F   !  ! F   !  ! AE%32+"'&54767&5'&54763267654'&#"#"=767232#"5+ $ + %   l >#-=DM8h09 =U" $ " %   4; @")D "D%1C.){d!5d222% #"'&547632A    \-3#"'&=4767&'&=47632B*/ " 6&/& 9* (.). 0& :$ B\054'&'&'432#"54763676=&'&#&47674" 6  &/& -- 9).0 & :$ +(*&Hj"GY#"'&54763232+"'&5476%#"=67654'&#"#"=76723232+"'&54762 . #  #  >#-=DM8h09 =++ $ + % 3F   !  ! )D9;@")D "D%1C." $ " % 'j"GY#"'&54763232+"'&5476%#"=67654'&#"#"=76723232+"'&5476r . # $  I>#-=DM8h09 =++ $ + % 3F   !  ! )D9;@")D "D%1C." $ " % O \Gx\@!#"'&=47632276=4'&"7?7>@@:b(D&1:c(D&53<  <3<  f37332+32#"'4735#Ojj7   `'? >>c+67232#"'&5472327654'"#"#"'532) 8 8%/* *3>A. ?b4$H# '5Kt"1"'&+"632"'&=47632;2765&'"D',3G#&[ >.? =&<#Z>,97D.!b$+Z9, K* W#f0'&7#"'53` ^@,8n'7#"'&547&547632'"327654'&"327654'&X@0!; @;/8g7 -* * *5;7/:33-4p- ' . (.* "t ,&#&376&'&747672#"'&76765G'%% )3@ #&\ >&2 7G6.S+ =)(4?!.!e%,[:# 8/GAE#'&=#"'472;547236= SSS `  `VV "'472;6 "'472;6'&7&76;2#    I u61&'&7676c P & T+  ;F >CQ'&576'&/6 Y(Q &t@>u@=v@>w@#'&=#"'472;547236= SSS  `  `VV "'472;6  =7"'472;6'&7&76;2#    I &u%61&'&7676c P & T+  ;F >C&Q7'&576'&/6 Y(Q &L*V  .! / & (  U {& (   5  .:'B%)$B<E%47632+4763232767676'#"'&=&'&'&'&+#"'&532"!?*i + ~L()I@!!9’6 ]#'J @E!2!!2!32767632#"'&'#"'4;5#"'673676325432#"'&'&#"j O7BYC &MafNC  T@OfG@0:`;"_<b7'F #GNCX<oA1Ep4#O->u);cp5472"'&'&#"327632#"'&547632'#"'&5476325#"'&54763254/"#"'&54763232#'5&#"32 < QFG-3?N'=$.:  ^ 65D;!)-(0 7(? ?*C' 7=.KX- %?&0U,b   -8 ,"  ,D; &  3^9F #"'&5476325#"'&54763254/"#"'&54763232#'5&#"32  ^ 65D;!)-(0 7(? ?*C' 7b   -8 ,"  ,D; &  ?@+1732767632#"'&=47676325432#"'&'&#"7>YC &LbfON6 EfeH@0:7-)<>%F #GONeSTI JEp4#fxAYGVBP2#"'&5476"327654'&5432#"'&'&#"32767632"'&=47632p6 *3,%" %" ;'3_4"D6L?, &@;iG?F=[I< -/+1! $ $yp;!T9KGiB4(! #< UKbSqJ@3 MP!K]2#"'&5476"327654'&'&5472"'&'&#"327632#"'&547632#"'&547632K+:(1I,:'2; 1!:!2 < QFG-3?N'=$.:  ^ ;'2G,;'1G-%0!; 0 =! 7=.KX- %?&0U,sb    MP!K]2#"'&5476"327654'&'&5472"'&'&#"327632#"'&547632#"'&547632K+:(1I,:'2; 1!:!2 < QFG-3?N'=$.:  ^ ;'2G,;'1G-%0!; 0 =! 7=.KX- %?&0U,sb   \@R!;337#"54;2+35#"54;2+32+"54;5#32+"54;3f26x.62)(0 0/8>%'&'&76767676?67'&'&'&'&7676327676@7'L-H+'  1.VB632765632#!"54367654'&/&547632#"'&#"9#)' 9%/6, (25WF(hG'4?5>&.j H+'  1.ux=676/"67632327676#"'&'&767'&'&7676u93<*M$O:8Q.? $=- 5O 0/ ;QItRrT [MD .O h /01 .\8"327656/&3#"54;67632#"'&'!"54;#"54;,/O+6_ 0xD&*"<%N,N7#"54;32+##"'&=43232%#"4;2'2#"'&5476"327654'&q6j4<$ ɈT1 (0 (" " P&rC ((*- *. " "TB$4D#32+"4;5#"4;2'327654'&+72#"'&5476"327654'&E?$`A + q8K(M&|WUZW{xWVYVzoLEPIctLCQJf$$$/(*% YWxWSXXy|WU)QJdmMFSHenLE4j2>%#"'3327654'&'"#"'&547&53676324'327682Sm($\$Glh= 0=..(  Yd%(X-C0yNFU p28|# ,T,""K JWeCoR 0X3AYRC@>+3#(732+"54;#"54;2#&+32?65466_8&H8KA )8@,9O1' (8<3%@1>C632327632#"'&#"#"'&54?&'&547632'327654'&#"16())*- &#!8T Z_9.QGakIERD+4X?9I:M3,)H(   AaN^WMZVxVHCPJbyL=]Mtr#M3 48327654'&+"543!232+&'&'#32+"54;3D^57'-kT8(7(& 9U7'V(0$3$4$;,5a0%:"@ 2M3'wL5V3F32#"'4735#"'53"'5+"'4;5#'32#"'4;5#"'4;732#3265GU%R S%U ;SQ< IjjI1'375#!#"=!!5432!5U8!: H)#v:4;N;M#5676767654'&'##543235&'&'&547676;235432+676\05: }X 70BZ%&5K  KK@!4 Q8!ea4y d73 L % fB aeN;J"=##&'&54767675##"=3;67674/&'&/5G 3+ZD27U}B5 " . \662%;ea )Q!$ %K) 47d=ae8Q-$ !CHS2+<3. O++3)33^3%32=#"4;'&/#&32+5476;'&7676HaPzLd !? `M"C [@(h\  ' p^ g Od5G_%#"'&5472327654'&#&5476327654/#"#"'47632#"'&547632%32+"5432#"'&5476:4&5*)+0 - ,&-*> ^  ^ G'A  $47  $*   $ .+b   {$  Of&\n3542#5767654'&#"#"'47632#"'&5472327654'&#&5476327654/#"#"'47632#"'&5476324$5$-#77"b:4&5*)+0 - ,&-*> X  ^ )'+{5$ $ ,- !#$47  $*   $ .+b   Xd+=U67232#"'&5472327654'"#"#"'532'#"'&547632%32+"5432#"'&5476) 8 8%/* *3>A. H  ^ G'A  9b4$H# '5Kb   {$  Xf&Rd3542#5767654'&#"#"'4763267232#"'&5472327654'"#"#"'532'#"'&5476324$5$-#77") 8 8%/* *3>A. H  ^ )'+{5$ $ ,- !#db4$H# '5Kb   Xd6bt#"'&5472327654'&#&5476327654'&#"#"'4763267232#"'&5472327654'"#"#"'532'#"'&547632:4&5*)+0 - ,&-*> ) 8 8%/* *3>A. H  ^ $47  $*   $ . +b4$H# '5Kb   Dd6H_c#"'&5472327654'&#&5476327654'&#"#"'47632!#"'&547632#57332+32+"54763=#:4&5*)+0 - ,&-*>   ^  9  U )k$47  $*   $ . +b   t"$9$ ]Bd)IW #"'&547632%32+"5432#"'&5476632#"'&547632'&#"327654'&#"  ^ G'A  L)3Y "^ >/>7D(E#0 ( b   {$  a6_.  i#*[:+>)5@R) N 2Bd+=]k67232#"'&5472327654'"#"#"'532#"'&547632632#"'&547632'&#"327654'&#"I) 8 8%/* *3>A.   ^ o)3Y "^ >/>7D(E#0 ( @b4$H# '5Kcb   6_.  i#*[:+>)5@R) N 2Hd'7Ia%#"'&547&547632'"327654'&"327654'&#"'&547632%32+"5432#"'&5476@0!; @;/8g7 -* ) *5  ^ G'A  ;7/:33-4p- ' . &.* "9b   {$  Hd'7n%#"'&547&547632'"327654'&"327654'&#"'&5472327654'&#&5476327654'&#"#"'47632!#"'&547632@0!; @;/8g7 -* ) *5:4&5*)+0 - ,&-*>   ^ ;7/:33-4p- ' . &.* "$47  $*   $ . +b   Hd+CScu67232#"'&5472327654'"#"#"'532#"'&547&547632'"327654'&"327654'&#"'&547632I) 8 8%/* *3>A. @@0!; @;/8g7 -* ) *5  ^ @b4$H# '5Ku;7/:33-4p- ' . &.* "9b   8Hf(8HZ0'&7#"'53#"'&547&547632'"327654'&"327654'&#"'&547632` ^@0!; @;/8g7 -* ) *5  ^ @,8O;7/:33-4p- ' . &.* "9b   3d) #"'&547632%32+"5432#"'&5476  ^ G'A  b   {$  q332#!"54;#"543!2#@? 1'3#3!2+32#!"54;#"54wkkAkk  !73!2+32#!"54;#"54#3#3#<KK!KKgggg3)%33 $76#!"54;#"54;26;2' #s956" fc '$(u)  (E*+,332/&'"#&54;26#$ /," 3(E*%33#"'&56;26;2+32#!"5673#e- $' cf "659D)  *G( .3#'%3#32#!"56"'&56;26;2+#9s_- $' OR "(*) *G(G3'+73##32#!"56"'&56;263!2+3lq) UK(' ;> " H(() *G(J32732+7#"54;2+32+"54;'32+"54;#"5437'*,xx(n"2xx4**pB3)(03;E32732+32+"54;'32+"54;7'#"54;2+7#"54#38++3xx2"n(xy-BB3)J37;#;2#!"54;'32+"54;7'#"54;2+7#"543!2+#||! ddp"||Zdd!)1 ?3/?@&+3' Q30)#"/7632!2#b    `T6  mm 5& #"/&54?1#"/#"56  ln  4b     `6!"543!'&547632#"/&547T`   5 mm  & %43276320'&54?6324 nl  V`    ?*#"/7632!'&547632#"/&54?b    `6`   b6  mm 55 mm  6,*#"/&54?"/7632'&54?6326  mm 55 mm  6b    ``   bpg'&'&/'"/'&' > i ck >  ze'&'&5'&7637'#&?'&'&767vk =     >h  wm%'&7676'&76'&7562t   ?  i =m?67674722  h >   = (0/'&'&76?##"/763237632#- $b   `. %hZ H6  mm 5[ I(003'&547632#"/&54?#'&'&76?#"54;76`   b- $x. .5 mm  6Z H[ M v-/#'67676763#&'&'&#&'1  b Y(  '$  6=""e    ,&8'M v6'&/&'&#"54767676676?"'&7676767'&7)"=    $"  % (Y!b "+'!   &  ,   (0/#"/76323763232+#"/b    `N  `b  6  mm 5X 56  Y/#"/&54?"/"/#"=#"/&54?6  mm 5X 56  Yb    `N  `b  (0X2X2))##"/763237632#"'Yb    `   6  mm 5X JJ  >/GX@*6!!#"/7612!5432#"5 b     `j6  ln  4a !%#"/&54?1#"/32+"5436  ln  4a)mb     `*6!#"=432!'&547630#"/&54?Tj`    bca4 nl  6&2!7632'&147632#"54;2#@6  ln  4a b     `k, 432+"54#"/&54?"/7632'&54?632~6  mm 55 mm  6 b    ``   b).!2767&+"'&5476;2#!#"/7632 :A&&G *)b    .$1036  mm E7G`@)-:547636+#"'&=##"/7632;2767&/T0= '&9b   `9/!3.$? ./EE6  mm 5 &.E7G`@?C/?27676767767'&'4763"'4?'&'&'&#'&b  `$# !`   b/  $ 6  mm 5#( 5 mm 6X@'&'&76?##"/76323763'&547632#"/&54?7- $b   `. %`   bZ H6  mm 5[ I5 mm  6476776'&76?d΁ T}Q "  4\/2I  i#"'&5##"/7632b   `F6  mm 5GX@iG@X* 7632'&54?632!"'47634 nl  6`   bF)  %!#"/7632!47632 `   bE{5 mm  6F( 947676762"'4'&'&'&&7632/472 &(8,"*  &  6 ln 4.*' ''!1,.*$( %%!b  `' ;763'&56?6324'&'&'&&#&'&767676364 nl 6 !+   *",%& `  b!%%($*.,1!' ' '*+g0; ("543!2/&'&''"/'&'1  *  i k  >  &69>!#"/?2!5432#"'#"'5432!'&7470763#"'4? b     `jDj`   b6 ln 4aca4  nl 6;!-&/#'&//"'&'4723676P >  iB \2FuE3I7Ff-W6k  >%J >!ZAU];.X/9-276563#&'&54767'&'&?/"56?J)7W<3HCa4H i  >: s6B8LiFAo7J`; >k'0!7632!2#!"54)  `T:m 5 !/&763!2#!"')  ` 5 &#"/"542,l  6(  `&A6#"5#"'&547-5  :T` !G1@1 /GA@%G;@&AG;@)147#"/7632!2#'&54?632#"'&54?!"543b    `T:b    `u6  mm 5H6  mm 5+/F@)1GZ@)47#"/7632!2##"/7632!2#b    `Tb    `Tu6  mm 5 6  mm 5*&. 5#"/&54?1#"/#"5#"/&54?1#"/#"56  ln  4 6  ln  4b     `Vb     `J1GZ@*&. G2@!a '%#"'&54?!"543!2%7632!2#!"54  `  `T:m 5 m 5 !a GA@8 H%*32+#7##/?237332+3u.l&    $(w,&"   !HH/437'#73'&'4763"'4?##7##/?23737#8g"   &.n&    $(*!  ""   !&8H)37'#7"'4?##7#"54;7#"54;733'&'4763o &.x(i$ n "&! 8 !2#!#/?2!2#!|&    $T"   !&'#"5"'&5?"/#"5@"  "@$   &8 7'!"543!'&'4763"'4?!"543T$   &!  "& %432763/47632432@"   "vg&    $?H"(&'4763"'4?!#/?2!7'!   &&    $F*lw  ""   !P$"(#"'&5?"/763/476327'7 ""   !P   &&   $5)z O37#"54;2+##"54;2+#3;N9M9qw )GF#5"'4'47632#"'&547632&'"#"327654'&'& 3BQ$A KBXeD6"4@"0+5IiYSGL ]JsdJ-'W gKwdI-~S%5IiYN+-333%!+,:3(+-3!#+,3 '&-;2+"'&5476;2+"!2#QL/?nE9MA^v2l3 VG^rI>^)6&FM#7;2+"'#"'&54?&'&5476;763232+32#'7#"M }V##1 0U MA^s8 0ReYY`v2l4 h g.b')rI>x g(^)6sn ;2+"'&5476;2+"!2# 8^'>%5]J Q'1_/^ &G>@&@GK?#"'&5476;7&+"'&5476;27632+#"'&54?#"'&5476;2767#73&ZT$+'? ?VKC^e, $`Sm5`MF  3g oJB] LW-;̤psnGC@3A-+"'&54;!32+"54;#"'&543!2#3256  ,-kk kq3'!!76;2!"=47&=43!2+"'ܮ4W rM H. !2#!"54cn.H%32+#"=#"4;5432'"43!2#@((c((H\%%32+#"=#"4;5432'2#"'&5476@!   ((  qv\yt32+ #"=437TB5X$it6F#"'&5472327654'&#&5476327654'&#"#"'4763232+ #"=43:4&5*)+0 - ,&-*> R7TB$47  $*   $ . +X$it*#57332+32+"54763=#32+ #"=439  U )kY7TB"$9$ ]X$i%*132760'&#"32+"'&'#"'&5476326;2+"0N<74 ..K 86E2 =OR-@(3P<$R g0N@D0747632!2#!&'4  &22!# #32-- 2&2 #32 -2(!#4'&#"#47632+^0@r:$+VG^rI>x1L1E,nE9MA^(3327653#"'&5(+^0@r:$+VG^rI>,x1L1E,nE9MA^.6'&'&/'&'&'&767636765476" @25  0+ MM :  + RA"8#O"'&/367654766/&/'&''&'&'&76763676547636m @  07" @2/;5  0+$ M  + R8- MM /1:  + RA"KBTf636/&/'&''&''&'&'&76763676547636636&'"#767654'&'"#767654%" @2 1%*5  0+$ % @ 0h@ 0 MM :  + RA"  & M+ R& M+ R&n@IT547636'&'&/'&'&'&76763676=&'&547667654'&/+$" @S/C)425  0U2#E,9L)<$VJ%=$ gA" Mg G/7W7"|M :  + {F0=X7#8?&.N/4 @$+N08#JS\n~54763666/&/'&''&'&'&76763676=&'&547667654'&#"'36765547"'&/63&#"327+$7" @)3:+2/;5  062;0+'5#'=9"!  0 @#2. !%tA" - Mr !6JP6M /1:  + 5KP7,7672#"'&/"'&54767&547&'&547632654/ EE    FF  $$#% )~x*  -{-" z`cc`baaH &N&!>(%632#"'#"/&54?'&547632&   !     Z   >GTX@3q7"'&54763!2#!"3!2#^'>%54Z4#4qQ'1_/X'N#3q%!"543!27654'&'!"543!24H G4](?%qC"bQ(1_/3 &7!2#!"=47"'&54763!2#!"3!2#a]^'>%54Z4#4%LQ'1_/X'N#3GXM@?!'#"'&547632&'&'#5#6765#?VOnxQKWOnvQL+|!&*ө$ w$xQJUOowQKUPY/ *ӎ2?!#"'&547632&'&#"!3276?VOnxQKWOnvQL+V!0! *9?0$   !3N$   '#' : '5!#''%7!~>/0(D7P%A! T|*~+; T8M 3!73%57 '!R)0>"%M{TY;," AN3#3^)j,)BX !5X PPX5!5X5PPXT!5XTPP#Xs%!5XsPPX@!!X@(XT!!XTP8@ 3#(( 8T 3#PP X@ 3+53#53ddddd@((((XT 3+53#53dddddTPPPP8@  #=3#5@(((pd8T  #=3#5TPPPpdX@ #5;#!#53#53тFAAAA(((((XT #5;#!#53#53тFAAAAPPPPP8@  #5#553#5@(((((;gggg8T  #5#553#5TPPPPP;gggg8X@!!#@(@( 8XT!!#@(TP48X@!!#TP@( 8XT!!#TPTP48@@#!5@(@(8@T#!5@(TP8T@#!5TP@(8TT#!5TPTPX 3!( (X 3!(4PX 3!P (X 3!P4P@ !5!3@((@ !5!3@(PT !5!3TP(T !5!3TPP8X 3!!( ( 8X !!#3@((TP48X #3!!#P( ( 8X 3!!#(P@ ( 8X #3!TPP  (8X #3!!#P(4P48X !!#33@P(TP48X 3!!P4P48@ #!5!3@(((8@ !5!3#((P8T #!5!3@(P (8T 3#!5!3@P(@(8T 3#!5PP@(8T #!5!3@(P4P8T 3#!5!3@P(TP8T #!5!TP P8X@!!#!X(@( 8XT !!#!5!@(@@( P8XT 5!!#!5@(@P4(8XT!5!!#X(PP48X@#!5!TPX ((8XT #!5!!TPT P(8XT !5!5!!#TP(P48XT!!#!XPTP4X 5!3!(( (X !5!3!@(P (X !5!3!!((4PX !!5!3@(TPPX 3!!5P@ ((X !5!3!TPP (X !5!3!!P(4PX !5!3!XPP48X !5!3!!#((( ( 8X 3!!#!5((T ( P8X #!5!3!@((4(4P8X !5!3!!#((P4P48X 3!!#!5P(@ ( (8X #!5!3!TP( ( (8X !5!3!!#PP( ( 8X ##!5!3!T(P4P (8X #5!5!3!!#P((4P48X 3!!#!5!3@P(T( P8X 533!!#!5(P@4P4(8X !5!3!!#P(P4P48X !!#!5!3@P(TP4P8X #!5!3!TPP P (8X 3!!#!5PP@4P4(8X !5!3!!#PPP4P4X@#53#53X(((XT#53#53XPPP8@ ##@((( >>8h ##hxxx >>X|!!5!!XX((8| 3#3#((x(( 8X| !!!!@D(P(\8X@ !####|(P(@(  8X| !#+!!T(P(|(\D(8@| #!5!5!5@(|(P(8|@ ####5|(P(@ (8|| ##5!5!(T|4(4(X %3!!!(D\(P(X !3333X(P(  X  33!!T(TT\((D@ %!5!5!5!3@((P(| !53333|(P(( |  !53;!5!(P(TT((8X 3!!!!(\(P(\8X  33#+3T((P(( ( 8X  3##33!(T(((\\(8@ #!5!5!5!@( (P(8|  ###533|(P(( (8|  #30!##!53|(((4D4(8X| !#!=!X(X(\(P((8X@ !#####X(P(@(  8X| 5!##5)##0 X(T(T((((\X  %!5!%5!3!XX((P(\(X !533333X(P((  X  !!0!53!133X|((D4(4\8X !5!3!!!!#!5!((T(\(P(\(8X ###533333##TP((P(( (  ( 8X ##50!##0330)533(T((((4(\\((48X@ 3#"#476ddv%(Y1@(=(O,-8@@GX@@ XXX GX@.i*X".i*GX@.i*  ' 7 C&""&"",((,@!!,@(,@ 3#(( ,X@,8@, ,T!!,TP,T 3#PP ,XT,8T, XT!5!5!!,,,(P8T 33#(P, XTG"X@8T G#X@,X !!X 8X!!XK}8X25!!X28X5!!X8X,!!X, 8X!!X8X&!!X&8X!!X8X !!X 8  !!  8 !!> 8w !!w 8, !!, 8 3# 8 3# 8K 3#KK ,8X !!,, 8& #'+/37;?CGKOSW[_cgkosw%3#'3#'3#%3#'3#'3#3#'3#'3#%3#'3#'3#3#'3#'3#%3#'3#'3#%3#'3#'3#%3#'3#'3#%3#'3#'3#%3#'3#'3#222222222222,222222222222,222222222222,222222222222,222222222222222222222222222222222^222222222222222222222222222222<8X #'+/37;?CGKOSW[_cgkosw{%3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#22d22d22d22d2222222d22d22d22d222222d22d22d22d2222222d22d22d22d222222d22d22d22d2222222d22d22d22d222222d22d22d22d2222222d22d22d22d222222d22d22d22d2222222d22d22d22d2222222222222222222222222222222222222222222222222^222222222222222222222222222222222222222222222222222222222222222222x8X  #'+/37;?CGKOSW[_cgkosw{ #'+/37;?CGKOSW[_cgkosw{%3#'3#'3#'3#'3#%3+3#'3#'3#'3#'3#%3#3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#3#'3#'3#'3#'3#%3#3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#'3#'3#'3#'3#'3#%3#22d22d22d22d2222222d22d22d22d2222d22d22d22d22d222222d22d22d22d2222d22d22d22d22d2222222d22d22d22d222222d22d22d22d2222222d22d22d22d222222d22d22d22d2222222d22d22d22d222222d22d22d22d2222222d22d22d22d222222d22d22d22d2222222d22d22d22d222222d22d22d22d2222222d22d22d22d222222d22d22d22d2222222d22d22d22d222222d22d22d22d2222222d22d22d22d222222222222222222222222222222222222222d22222222222222222222222,22222222222d22222222222d22222222222d22222222222d22222222222d22222222222d22222222222d22222222222d22222222222d22222222222d22222222222d22222222222d22222222222d22222222222d22222222222X !!X } 8X 3# KK  ,,!!,,, X,!!,,,,,N%,N XM!!!,,M XN%%,,,,C XM!!!XM XM!!!XM",,XN%,,N XN%%,,,.D XM!!!,,,!2&3!2 2&3!%!!24\ (1&87&'076767!00!0'&73!0767650'&'&'!00R 8$! 8$! (  *" 8"# 8$!/ ("  )2& 753!%!!4\}} (2& !5%!5!!5%!5!!Z\\\\(YKK(KKK(K 2& 73##!3##!!KK(KYKK(K (\\\\(2& #'+/37;?C%353535#35353535#35353535#35#3#35##3!@KKKKKKKKKKKKKKKKKKKKKKKKKKKKKsKKsKKKsKKsKKsKKKsKKsKKsKKKsKKsK(KYKK(K 2& !!5+5%332 'ު\ުx ̥x2& !#75373& ͥxޥ (ުƪx 2& !$'+%3'5'7'35'7'7'?#'?#'!!E(D}UUUUUUDDDUUUUUUrDD`ED lD`DDUUUUUU9DDEEUUUUUUrD`DaD( 353735#53ת((2&,3!2,2&,3!%!5!24\,(3!, 3!%3#, (?,3!22,?,3!%!7!22:&\,(#5)5 #5% ! (N()7%'!7mAA(jj(T 5 T %5 y %充 %'7]n;{@y % y%'%uSCH#5 5:#5! l v:%'%#7'mAj99  99W    ?充757n@{;^ 7%^_75%HC#5! ,    #5%7' ,  8  #5 %'77' ,    #5!12#"'&54767"327654'&'&'2#"'&5476.3.6/gD9L@UeC9J.=nMJSLjsNHUMl-6.6~K?UgD8K@VcD* (RMjrNITMjrNGY? 77+Ҝ?&#5!"327654'&'&'2#"'&5476/gD9L@UeC9J.=nMJSLjsNHUMK?UgD8K@VcD* (RMjrNITMjrNG #5-9CQaq}2#"'&54762#"'&54762#"'4762"'&5476'"'472%"'&54763247632#"'&%47632#"'&%472"'&672"'&47632#"47632#",|X7X2j|Pl#5$-2#"'&547667&'67654'&0nMJSLjsNHUM{'$#P'$$LRLM IRMjrNITMjrNG)@Ch)h=d hCc:` bC#51A2#"'&5476"327654'&'"327654'&'&'2#"'&5476.?%4!(A%6!'1 *0 )gD9L@UeC9J.=nMJSLjsNHUM5!'@&5!(A%()1 )/ K?UgD8K@VcD* (RMjrNITMjrNG#52#"'&54760nMJSLjsNHUMRMjrNITMjrNG#527654'&'2#"'&5476-eB9KAQnMJSLjsNHUM>K@VcD:(RMjrNITMjrNG#5"32#"'&5476+aCOhD5,, qKBRIc a@5L;O# 0##567673/ f?# (VG^M+5 qK=, 9'3#5&'&'&#-sK>(O3B(UF] d?*#0 %#&'&'53/sK>(N:K((UF] d?/,9 %3676753#- f?/(VG^(M9J qK=# 55&'&#"#567632 L>OhD5(VLgmNF a@5L;O qKBRIc #53#"'&'5332767 (SKbvOE(N?SaC6 oKDTGc c@3K_=*SKitOHSLjqOI)a=/M@VdC0N5#5#2#"'&547632767#7&'&'0nMJSLjsNHUMSc<.L@UdD2 M5ARMjrNITMjrNG) N3"'&7476323276=47632676320/&#"0'&#"0'&#"0'&#"4$!V;CpK%!!!-2$S[T.L%/     P& '7'7PTT=;R~ڔ x%%'65472#"'47j ( JZ+!5472#"'473'7!#"'&5!2 I J+#5 04763#"'&7"327654'&'&'2#"'&5476(gD9L@UeC9J.=nMJSLjsNHUM   K?UgD8K@VcD* (RMjrNITMjrNG2&G2&3!%!!62#'&767624\ !\  (4   2&.3!%!!'&/'&'&76?'&76767624\     (҈    &&!+5@K3&547#"'&54763!53#5#"'&547&547!"3!35#"";5#";P$I+ 0$f+ $$#dd\4 + 8( (+  4  _7(7_23 *4>H#37##3!2+'!27654/327654/##327654'327654/PP$*f$/ *I$ܤd\ 4 9 ((+ 9  47_7^7P`S76#"'&=/&76?5#"'&5476;5#"'&5476;54763232+32#@T hT hXXXXZ1 <1 <TNNTP`=#"'&5476;5#"'&5476;54763232+32+#"'&5XXXXZTNNT:S%##"'&54763235#"'&54763!2+3547632#"'&=#32#!"'&5476;҂,҂,҂#5#'2#"'&5476'67654'&'7550nMJSLjsNHUMSS'K8JΦc<.A8TRMjrNITMjrNGYuY8GcD3ԋ N2D9%/H+9&/E+x2@U7*C2BV6)(6@#"'&5&76324763266=1,.& - @,%#"'&56/&'#"'&5&7632476329J 6=13G) [04 .& - 'F)2#2$5<!#"'&5&7632#"'&5&76326=1R6=1.& - R.& - '5<!%#"'&5&7632#"'&5&76325%5%6=1R6=1.& - R.& - aMam| 4'&#"67663247632f#+>U]WWGp<)`yl! %A<$D0ED!hxY[ #53%++=+7m793=V\575375377#5#5577YY++YYYY++YY+W(!((!(>!8l\ 32+32+32+32+bbbbSzl\ #"54;#"543##"54;#"543bzbS((}[0 #&' 672 > S df}[63 "'4'4767 &'&'6 > SAC -+[/0 #&' 6720 #&' 672( >  > S df df-+[/63 "'4'4767 &'&'6363 "'4'4767 &'&'60 >  > SAC AC l2#"'&5476&!$ !% $l2#"'&5476'$! "# ! %l2#"'&547672"'&5476& $ & $! =" $ $!#! %k2#"'&5476&!$ ! % $k #"'&5476322#"'&5476# $! &>&!$ ' $! !% $k!2#"'&547672#"'&5476&!$! &! $ :!%! %"$ $k0#"'&547632'2#"'&547672#"'&5476# $! &>'$! &!$ ' $! "! ! &!% $p2#"'&5476& $! !$! %2#"'&5476#2#"'&5476' $! &" $ "$! %" & $ #"'&54763272#"'&5476 # $ &&! $ ' $!" $ $ 02#"'&547672#"'&5476'2#"'&5476&!$ &! $ '$! =!% $" $ $"# ! %#"'&5476322#"'&5476 " $! ''$! & &""! ! & 1#"'&5476322#"'&5476#2#"'&5476 " $ &'"$! &!$ ' $""& &!% $ 0#"'&547632'2"'&547672#"'&5476 " $! '>& $! '$! & &"!#! %"! ! &!1B#"'&5476327#"'&54763272#"'&5476#2#"'&5476 " $ &"$! &'"$! &!$ ' $"$! &!"& &!% $p2#"'&5476&!$ ! % $2#"'&5476'2#"'&5476' $! '$! >"$! %"# ! %!2#"'&5476#2#"'&5476&"$ & $! "& $!$! % 02#"'&54762#"'&547672#"'&5476'! $! &!$ '$! >"$! %!% $"# ! %2#"'&547672#"'&5476' $! '$! :"$! %"# ! %!2#"'&54763272#"'&5476'2#"'&5476 " $ &&! $ &!$ ' $""$ $!% $/2#"'&547672#"'&54762#"'&5476' $! '$! &!$ :"$! %"# ! %! % $!2C#"'&54763272#"'&5476#"'&547632'2#"'&5476 " $ &&! $ o"$! &?&!$ ' $""$ $?$! &!!% $p 2#"'&547672#"'&5476&!$! &!$ >!%! %!% $/2#"'&547672#"'&5476'2#"'&5476' $! & $ '$! >"$! %" $ $"# ! % 02#"'&5476#"'&54763272#"'&5476&! $ o# $ &&! $ =" $! $>' $!" $ $ 0@2#"'&54762#"'&547672#"'&5476'2#"'&5476'! $! &!$ &! $ '$! >"$! %!% $" $ $"# ! % 0#"'&54763272#"'&547672#"'&5476 " $! '&"$ '$! & &""& $"! ! &!1B#"'&54763272#"'&547672#"'&5476#2#"'&5476 " $ &&! $ '"$! &!$ ' $""$ $"& &!% $ 1A#"'&54763272#"'&5476#2"'&547672#"'&5476 " $! '&"$ & $! '$! & &""& $!#! %"! ! &!2BS#"'&54763272#"'&5476#"'&54763272#"'&5476#2#"'&5476 " $ &&! $ o"$! &'"$! &!$ ' $""$ $?$! &!"& &!% $p2#"'&5476&!$ ! % $ #"'&5476322#"'&5476" $ &&! $ ' $"" $ $2#"'&5476'2#"'&5476'! $! &!$ :"$! %! % $!12#"'&5476'2#"'&547672#"'&5476&"$ &$! &! $ ]"& $!" ! &" $ $2#"'&5476#2#"'&5476&! $ & $ " $ $" $ $!22#"'&5476#"'&5476322#"'&5476&"$ p" $ &>&!$ ]"& $>' $"!% $/2#"'&5476#2#"'&547672#"'&5476'! $! ' $! &!$ :"$! %"$! %! % $!2C2#"'&5476#"'&5476327#"'&547632'2#"'&5476&"$ p" $ &"$! &?&!$ ]"& $>' $"$! &!!% $p #"'&5476322#"'&5476# $! &?&$! & &!!" ! & 0#"'&547632#"'&547632'2#"'&5476" $ &" $! '&! $ ' $"u& &"7" $ $ 02#"'&5476'2#"'&547672#"'&5476'"$! & $! '$! ]"& &!$! %"! ! &!1A2#"'&5476'2#"'&547672#"'&5476#2#"'&5476&"$ &$! '"$! &! $ ]"& $!" ! &"& &" $ $/2#"'&5476#"'&5476322#"'&5476'"$! p" $! ''$! ]"& &?& &""! ! &!1B2#"'&5476#"'&5476322#"'&5476#2#"'&5476&"$ p" $ &'"$! &!$ ]"& $>' $""& &!% $0@2#"'&5476#"'&547632'2"'&547672#"'&5476'"$! p" $! '>& $! '$! ]"& &?& &"!#! %"! ! &!2BS2#"'&5476#"'&5476327#"'&54763272#"'&5476#2#"'&5476&"$ p" $ &"$! &'"$! &!$ ]"& $>' $"$! &!"& &!% $p!2#"'&547672#"'&5476& $! & $! :!$! %!$! %!1#"'&547632'2#"'&5476'2#"'&5476" $ &>& $ &! $ ' $""$ $" $ $/2#"'&547672#"'&54762#"'&5476'$! '$! &!$ :"# ! %"# ! %! % $!2B2#"'&547672#"'&5476#2#"'&547672#"'&5476&"$ &! $ &$! &! $ ]"& $"$ $!" ! &" $ $/2#"'&5476#2#"'&547672#"'&5476'$! ' $! '$! :"# ! %"$! %"# ! %!2C2#"'&5476#"'&54763272#"'&5476'2#"'&5476&"$ p" $ &&! $ &!$ ]"& $>' $""$ $!% $/?2#"'&5476#2#"'&547672#"'&54762#"'&5476'$! ' $! '$! &!$ :"# ! %"$! %"# ! %! % $!2CT2#"'&5476#"'&54763272#"'&5476#"'&547632'2#"'&5476&"$ p" $ &&! $ o"$! &?&!$ ]"& $>' $""$ $?$! &!!% $p 0#"'&5476325#"'&547632'2#"'&5476# $! &#$ &?&$! & &!' $! !" ! &!1A#"'&547632'2#"'&54767#"'&547632'2#"'&5476" $ &>& $ N" $! '&! $ ' $""$ $~& &"7" $ $ 1A2#"'&547672#"'&5476#2#"'&547672#"'&5476'"$! &"$ & $! '$! ]"& &"& $!$! %"! ! &!2BR2#"'&547672#"'&5476#2#"'&547672#"'&5476#2#"'&5476&"$ &! $ &$! '"$! &! $ ]"& $"$ $!" ! &"& &" $ $0@2#"'&5476#"'&54763272#"'&547672#"'&5476'"$! p" $! '&"$ '$! ]"& &?& &""& $"! ! &!2BS2#"'&5476#"'&54763272#"'&547672#"'&5476#2#"'&5476&"$ p" $ &&! $ '"$! &!$ ]"& $>' $""$ $"& &!% $0AQ2#"'&5476#"'&54763272#"'&5476#2"'&547672#"'&5476'"$! p" $! '&"$ & $! '$! ]"& &?& &""& $!#! %"! ! &!2CSd2#"'&5476#"'&54763272#"'&5476#"'&54763272#"'&5476#2#"'&5476&"$ p" $ &&! $ o"$! &'"$! &!$ ]"& $>' $""$ $?$! &!"& &!% $l72#"'&5476'$! "# ! %l7#"'&5476322"'&5476" $ &>& $! >' $" g!#! %l72#"'&54762#"'&5476'! $! '$! Y"$! %z"# ! %l 07#"'&5476322#"'&547672"'&5476" $ &>& $ & $! >' $" "$ $!#! %k72#"'&547672#"'&5476&! $ & $! 5" $ $!$! %k 072#"'&547672#"'&54762"'&5476&" $ &!# & $! |" & $!%$z!#! %k/72#"'&54767#"'&547632'2#"'&5476'! $! N# $! &>'$! Y"$! %~& &!"# ! %k 1A72#"'&547672#"'&547672#"'&547672"'&5476&" $ &!# &! $ & $! |" & $!%$"$ $!#! %%#"'&5476322#"'&5476 # $! &&! $ =& &!f" $ $/%#"'&5476322#"'&5476'2#"'&5476 # $ &&! $ '$! >' $! e" $ $"# ! %/%#"'&5476322#"'&547672#"'&5476 # $! &?&!$ &! $ =& &!! % $" $ $/?%#"'&5476322#"'&547672#"'&5476'2#"'&5476 # $ &?&!$ &! $ '$! >' $! ! % $" $ $"# ! % 0%#"'&547632'2#"'&54762#"'&5476 # $! &?& $ &! $ =& &!"$! $z" $ $/?%#"'&547632'2#"'&54762#"'&5476'2#"'&5476 # $ &?' $! &! $ & ">' $! "$! %y" $ $!$$ 0@%#"'&547632'2#"'&547672#"'&547672#"'&5476 # $! &?& $ &!$ &! $ =& &!"$! $! % $" $ $/?O%#"'&547632'2#"'&547672#"'&547672#"'&5476'2#"'&5476 # $ &?' $! &!$ &! $ & ">' $! "$! %! % $" $ $!$$ 72#"'&54762#"'&5476& $! &! $ Y!$! %z"$ $/%#"'&5476322#"'&5476'2#"'&5476 # $ &'$! '$! >' $! "# ! %"# ! % 172#"'&54762#"'&5476#2#"'&5476& $! &! $ &$! Y!$! %z"$ $!" ! &/?%#"'&5476322#"'&54762#"'&547672#"'&5476 # $ &'$! &!$ '$! >' $! "# ! %! % $"# ! %072"'&54767#"'&54763272#"'&5476& $! N" $ &&! $ Y!#! %' $" "$ $/?%#"'&547632'2#"'&547672#"'&5476'2#"'&5476 # $ &?' $! '$! & ">' $! "$! %"# ! %!$$0A72"'&54767#"'&54763272#"'&5476#"'&547632& $! N" $ &&! $ o"$! &Y!#! %' $" "$ $?$! &!/?O%#"'&547632'2#"'&547672#"'&54762#"'&547672#"'&5476 # $ &?' $! '$! &!$ & ">' $! "$! %"# ! %! % $!$$/%#"'&5476322#"'&547672#"'&5476 # $! &'! $! &! $ =& &!"$! %" $ $/?%#"'&5476322#"'&547672#"'&5476'2#"'&5476 # $ &'$! &! $ '$! >' $! "# ! %" $ $"# ! %/?%#"'&5476322#"'&54762#"'&547672#"'&5476 # $! &'! $! &!$ &! $ =& &!"$! %! % $" $ $/?O%#"'&5476322#"'&54762#"'&547672#"'&5476'2#"'&5476 # $ &'$! &!$ &! $ '$! >' $! "# ! %! % $" $ $"# ! % 0@%#"'&547632'2#"'&547672#"'&547672#"'&5476 # $! &?& $ '! $! &! $ =& &!"$! $"$! %" $ $/?O%#"'&547632'2#"'&547672#"'&547672#"'&5476'2#"'&5476 # $ &?' $! '$! &! $ & ">' $! "$! %"# ! %" $ $!$$ 0@P%#"'&547632'2#"'&547672#"'&54762#"'&547672#"'&5476 # $! &?& $ '! $! &!$ &! $ =& &!"$! $"$! %! % $" $ $/?O_%#"'&547632'2#"'&547672#"'&54762#"'&547672#"'&5476'2#"'&5476 # $ &?' $! '$! &!$ &! $ & ">' $! "$! %"# ! %! % $" $ $!$$%2#"'&54762#"'&5476'$! &!$ "# ! %! % $/2#"'&5476#"'&5476322#"'&5476'! $! o# $ &>'$! :"$! %' $! f"# ! %02#"'&54762#"'&54762#"'&5476'"$! &!$! & $! "& &!%! %z!$! %/?2#"'&5476#"'&5476322#"'&547672#"'&5476'! $! o# $ &?&!$ '$! :"$! %' $! ! % $"# ! %/%2#"'&54762#"'&547672#"'&5476'$! &!$ ' $! "# ! %! % $"$! %/?2#"'&5476#"'&547632'2#"'&54762#"'&5476'! $! o# $ &?' $! & ":"$! %' $! "$! %z!$$/@2#"'&54762#"'&54767#"'&547632'2"'&5476'"$! &!$! N" $! '>& $! "& &!%! %~& &"!#! %/?O2#"'&5476#"'&547632'2#"'&547672#"'&547672#"'&5476'! $! o# $ &?' $! &!$ & ":"$! %' $! "$! %! % $!$$ 02#"'&5476#"'&5476322#"'&5476&! $ o# $! &&! $ 9"$! $& &!f" $ $/?2#"'&5476#"'&5476322#"'&5476'2#"'&5476'! $! o# $ &&! $ '$! :"$! %' $! e" $ $"# ! % 0@2#"'&5476#"'&5476322#"'&547672#"'&5476&! $ o# $! &?&!$ &! $ 9"$! $& &!! % $" $ $/?O2#"'&5476#"'&5476322#"'&547672#"'&5476'2#"'&5476'! $! o# $ &?&!$ &! $ '$! :"$! %' $! ! % $" $ $"# ! % 1A2#"'&5476#"'&547632'2#"'&54762#"'&5476&! $ o# $! &?& $ &! $ 9"$! $& &!"$! $z" $ $/?O2#"'&5476#"'&547632'2#"'&54762#"'&5476'2#"'&5476'! $! o# $ &?' $! &! $ & ":"$! %' $! "$! %y" $ $!$$ 1AQ2#"'&5476#"'&547632'2#"'&547672#"'&547672#"'&5476&! $ o# $! &?& $ &!$ &! $ 9"$! $& &!"$! $! % $" $ $/?O_2#"'&5476#"'&547632'2#"'&547672#"'&547672#"'&5476'2#"'&5476'! $! o# $ &?' $! &!$ &! $ & ":"$! %' $! "$! %! % $" $ $!$$02#"'&54762#"'&54762#"'&5476&"$ & $! &! $ " & $!$! %z"$ $/?2#"'&5476#"'&5476322#"'&5476'2#"'&5476'! $! o# $ &'$! '$! :"$! %' $! "# ! %"# ! %0A2#"'&54762#"'&54762#"'&5476#2#"'&5476&"$ & $! &! $ &$! " & $!$! %z"$ $!" ! &/?2#"'&5476#"'&5476322#"'&547672#"'&5476'! $! o# $ &?&!$ '$! :"$! %' $! ! % $"# ! %/@2#"'&54762"'&54767#"'&54763272#"'&5476&"$ & $! N" $ &&! $ " & $!#! %' $" "$ $/?O2#"'&5476#"'&547632'2#"'&547672#"'&5476'2#"'&5476'! $! o# $ &?' $! '$! & ":"$! %' $! "$! %"# ! %!$$/@Q2#"'&54762"'&54767#"'&54763272#"'&5476#"'&547632&"$ & $! N" $ &&! $ o"$! &" & $!#! %' $" "$ $?$! &!/?O_2#"'&5476#"'&547632'2#"'&547672#"'&54762#"'&547672#"'&5476'! $! o# $ &?' $! '$! &!$ & ":"$! %' $! "$! %"# ! %! % $!$$ 0@2#"'&5476#"'&5476322#"'&547672#"'&5476&! $ o# $! &'! $! &! $ 9"$! $& &!"$! %" $ $/?O2#"'&5476#"'&5476322#"'&547672#"'&5476'2#"'&5476'! $! o# $ &'$! &! $ '$! :"$! %' $! "# ! %" $ $"# ! % 0@P2#"'&5476#"'&5476322#"'&54762#"'&547672#"'&5476&! $ o# $! &'! $! &!$ &! $ 9"$! $& &!"$! %! % $" $ $/?O_2#"'&5476#"'&5476322#"'&54762#"'&547672#"'&5476'2#"'&5476'! $! o# $ &'$! &!$ &! $ '$! :"$! %' $! "# ! %! % $" $ $"# ! % 1AQ2#"'&5476#"'&547632'2#"'&547672#"'&547672#"'&5476&! $ o# $! &?& $ '! $! &! $ 9"$! $& &!"$! $"$! %" $ $/?O_2#"'&5476#"'&547632'2#"'&547672#"'&547672#"'&5476'2#"'&5476'! $! o# $ &?' $! '$! &! $ & ":"$! %' $! "$! %"# ! %" $ $!$$ 1AQa2#"'&5476#"'&547632'2#"'&547672#"'&54762#"'&547672#"'&5476&! $ o# $! &?& $ '! $! &!$ &! $ 9"$! $& &!"$! $"$! %! % $" $ $/?O_o2#"'&5476#"'&547632'2#"'&547672#"'&54762#"'&547672#"'&5476'2#"'&5476'! $! o# $ &?' $! '$! &!$ &! $ & ":"$! %' $! "$! %"# ! %! % $" $ $!$$p%2#"'&5476'$! "# ! %%#"'&5476322#"'&5476# $! &'$! >' $! f"# ! % %2#"'&54762"'&5476&!$! & $! Y!%! %z!#! %/%#"'&5476322#"'&547672#"'&5476# $ &&!$ & ">' $! ! % $!$$ %2#"'&5476'2#"'&5476&!$ ' $! 5! % $"$! %/%#"'&547632'2#"'&54762#"'&5476# $ &' $! & ">' $! "$! %z!$$ 1%2#"'&5476'#"'&547632'2"'&5476&!$! o" $! '>& $! Y!%! %~& &"!#! %/?%#"'&547632'2#"'&547672#"'&547672#"'&5476# $ &' $! &!$ & ">' $! "$! %! % $!$$p!%#"'&5476322#"'&5476" $! '>&!$ =& &"g!% $/%#"'&5476322#"'&5476'2#"'&5476# $ &>& $ '$! >' $! e" $ $"# ! %/%#"'&5476322#"'&547672#"'&5476# $!&&!$ &! $ =& %!! % $" $ $/?%#"'&5476322#"'&547672#"'&5476'2#"'&5476# $! &&!$ &! $ '$! >' $! ! % $" $ $"# ! % 0%#"'&547632'2#"'&54762#"'&5476# $! && $ &! $ =& &!"$! $z" $ $/?%#"'&547632'2#"'&54762#"'&5476'2#"'&5476# $ &' $! &! $ & ">' $! "$! %y" $ $!$$ 0@%#"'&547632'2#"'&547672#"'&547672#"'&5476# $! && $ &!$ &! $ =& &!"$! $! % $" $ $/?O%#"'&547632'2#"'&547672#"'&547672#"'&5476'2#"'&5476# $ &' $! &!$ &! $ & ">' $! "$! %! % $" $ $!$$p %2#"'&54762#"'&5476' $! &!$ Y"$! %z! % $/%#"'&5476322#"'&5476'2#"'&5476# $ &>' $! '$! >' $! "$! %"# ! % 1%2#"'&54762#"'&5476#2#"'&5476& $ &! $ &$! Y!$! $z"$ $!" ! &/?%#"'&5476322#"'&54762#"'&547672#"'&5476# $! &>'$! &!$ '$! >' $! "# ! %! % $"# ! %0%2#"'&5476'#"'&54763272#"'&5476& $! o" $ &&! $ Y!$! %' $" "$ $/?%#"'&547632'2#"'&547672#"'&5476'2#"'&5476# $ &' $! '$! & ">' $! "$! %"# ! %!$$0A%2#"'&5476'#"'&54763272#"'&5476#"'&547632& $! o" $ &&! $ o"$! &Y!$! %' $" "$ $?$! &!/?O%#"'&547632'2#"'&547672#"'&54762#"'&547672#"'&5476# $ &' $! '$! &!$ & ">' $! "$! %"# ! %! % $!$$p!3%#"'&5476322#"'&547672#"'&5476" $! '>&!$! &!$ =& &"!%! %!% $/?%#"'&5476322#"'&547672#"'&5476'2#"'&5476# $ &>' $! & $ '$! >' $! "$! %" $ $"# ! %/?%#"'&5476322#"'&54762#"'&547672#"'&5476# $!&>'! $! &!$ &! $ =& %!"$! %! % $" $ $/?O%#"'&5476322#"'&54762#"'&547672#"'&5476'2#"'&5476# $! &>'$! &!$ &! $ '$! >' $! "# ! %! % $" $ $"# ! % 0@%#"'&547632'2#"'&547672#"'&547672#"'&5476# $! && $ '! $! &! $ =& &!"$! $"$! %" $ $/?O%#"'&547632'2#"'&547672#"'&547672#"'&5476'2#"'&5476# $ &' $! '$! &! $ & ">' $! "$! %"# ! %" $ $!$$ 0@P%#"'&547632'2#"'&547672#"'&54762#"'&547672#"'&5476# $! && $ '! $! &!$ &! $ =& &!"$! $"$! %! % $" $ $/?O_%#"'&547632'2#"'&547672#"'&54762#"'&547672#"'&5476'2#"'&5476# $ &' $! '$! &!$ &! $ & ">' $! "$! %"# ! %! % $" $ $!$$p%2#"'&547672"'&5476& $ & $! 5" $ $!#! %/%#"'&547632'2#"'&54762#"'&5476# $ &>' $! '$! >' $! "$! %z"# ! %0%2#"'&547672#"'&5476'2#"'&5476&!$ '"$! & $! Y!%! $"& &!$! %/?%#"'&547632'2#"'&5476'2#"'&547672#"'&5476# $! &>'! $! &!$ '$! >' $! "$! %! % $"# ! %/%2#"'&547672#"'&5476#2#"'&5476&!$ '$! ' $! 5! % $"# ! %"$! %/?%#"'&547632'2#"'&5476#2#"'&54762#"'&5476# $ &>'! $! ' $! & ">' $! "$! %"$! %z!$$/@%2#"'&547672#"'&5476#"'&547632'2"'&5476&!$! '"$! p" $! '>& $! Y!%! %"& &?& &"!#! %/?O%#"'&547632'2#"'&5476#2#"'&547672#"'&547672#"'&5476# $ &>'! $! ' $! &!$ & ">' $! "$! %"$! %! % $!$$p 2%#"'&547632'2#"'&54762#"'&5476" $! '>&!$ &!$ =& &"! %! $z!% $/?%#"'&547632'2#"'&54762#"'&5476'2#"'&5476# $ &>' $! & $ '$! >' $! "$! %y" $ $"# ! % 0@%#"'&547632'2#"'&5476'2#"'&547672#"'&5476# $!&>&! $ &!$ &! $ =& %!"$! $! % $" $ $/?O%#"'&547632'2#"'&5476'2#"'&547672#"'&5476'2#"'&5476# $! &>'! $! &!$ &! $ '$! >' $! "$! %! % $" $ $"# ! % 1A%#"'&547632'2#"'&5476#2#"'&54762#"'&5476# $! &>&! $ & $ &! $ =& &!"$! $"$! $z" $ $/?O%#"'&547632'2#"'&5476#2#"'&54762#"'&5476'2#"'&5476# $ &>'! $! ' $! &! $ & ">' $! "$! %"$! %y" $ $!$$ 1AQ%#"'&547632'2#"'&5476#2#"'&547672#"'&547672#"'&5476# $! &>&! $ & $ &!$ &! $ =& &!"$! $"$! $! % $" $ $/?O_%#"'&547632'2#"'&5476#2#"'&547672#"'&547672#"'&5476'2#"'&5476# $ &>'! $! ' $! &!$ &! $ & ">' $! "$! %"$! %! % $" $ $!$$p0%2#"'&54767#"'&547632'2#"'&5476' $! O# $ &?&!$ Y"$! %' $! ! % $/?%#"'&547632'2#"'&547672#"'&5476'2#"'&5476# $ &>' $! ' $! '$! >' $! "$! %"$! %"# ! %0A%2#"'&547672#"'&547672#"'&5476#2#"'&5476& $ &"$ &! $ &$! Y!$! $" & $"$ $!" ! &/?O%#"'&547632'2#"'&547672#"'&54762#"'&547672#"'&5476# $! &>'! $! '$! &!$ '$! >' $! "$! %"# ! %! % $"# ! %/@%2#"'&547672#"'&5476#"'&54763272#"'&5476& $! &"$ p" $ &&! $ Y!$! %" & $>' $" "$ $/?O%#"'&547632'2#"'&5476#2#"'&547672#"'&5476'2#"'&5476# $ &>'! $! ' $! '$! & ">' $! "$! %"$! %"# ! %!$$/@Q%2#"'&547672#"'&5476#"'&54763272#"'&5476#"'&547632& $! &"$ p" $ &&! $ o"$! &Y!$! %" & $>' $" "$ $?$! &!/?O_%#"'&547632'2#"'&5476#2#"'&547672#"'&54762#"'&547672#"'&5476# $ &>'! $! ' $! '$! &!$ & ">' $! "$! %"$! %"# ! %! % $!$$p 2D%#"'&547632'2#"'&547672#"'&547672#"'&5476" $! '>&!$ &!$! &!$ =& &"! %! $!%! %!% $/?O%#"'&547632'2#"'&547672#"'&547672#"'&5476'2#"'&5476# $ &>' $! ' $! & $ '$! >' $! "$! %"$! %" $ $"# ! % 0@P%#"'&547632'2#"'&547672#"'&54762#"'&547672#"'&5476# $!&>&! $ '! $! &!$ &! $ =& %!"$! $"$! %! % $" $ $/?O_%#"'&547632'2#"'&547672#"'&54762#"'&547672#"'&5476'2#"'&5476# $! &>'! $! '$! &!$ &! $ '$! >' $! "$! %"# ! %! % $" $ $"# ! % 1AQ%#"'&547632'2#"'&5476#2#"'&547672#"'&547672#"'&5476# $! &>&! $ & $ '! $! &! $ =& &!"$! $"$! $"$! %" $ $/?O_%#"'&547632'2#"'&5476#2#"'&547672#"'&547672#"'&5476'2#"'&5476# $ &>'! $! ' $! '$! &! $ & ">' $! "$! %"$! %"# ! %" $ $!$$ 1AQa%#"'&547632'2#"'&5476#2#"'&547672#"'&54762#"'&547672#"'&5476# $! &>&! $ & $ '! $! &!$ &! $ =& &!"$! $"$! $"$! %! % $" $ $/?O_o%#"'&547632'2#"'&5476#2#"'&547672#"'&54762#"'&547672#"'&5476'2#"'&5476# $ &>'! $! ' $! '$! &!$ &! $ & ">' $! "$! %"$! %"# ! %! % $" $ $!$$%2#"'&5476#2"'&5476& $! & $! !$! %!#! %/%#"'&547632#"'&5476322#"'&5476# $ &# $ &?& ">' $! ' $! f!$$0%2#"'&5476#2#"'&54762"'&5476&!$! &!$! & $! Y!%! %!%! %z!#! %/?%#"'&547632#"'&5476322#"'&547672#"'&5476# $ &# $ &?&!$ & ">' $! ' $! ! % $!$$ 0%2#"'&5476#2#"'&547672#"'&5476&!$ &!$ ' $! 5! % $! % $"$! %/?%#"'&547632#"'&547632'2#"'&54762#"'&5476# $ &# $ &?' $! & ">' $! ' $! "$! %z!$$ 0A%2#"'&5476#2#"'&54767#"'&547632'2"'&5476&!$! &!$! N" $! '>& $! Y!%! %!%! %~& &"!#! %/?O%#"'&547632#"'&547632'2#"'&547672#"'&547672#"'&5476# $ &# $ &?' $! &!$ & ">' $! ' $! "$! %! % $!$$/%#"'&547632#"'&5476322#"'&5476# $!&# $! &&! $ =& %!& &!f" $ $/?%#"'&547632#"'&5476322#"'&5476'2#"'&5476# $! &# $ &&! $ '$! >' $! ' $! e" $ $"# ! %/?%#"'&547632#"'&5476322#"'&547672#"'&5476# $!&# $! &?&!$ &! $ =& %!& &!! % $" $ $/?O%#"'&547632#"'&5476322#"'&547672#"'&5476'2#"'&5476# $! &# $ &?&!$ &! $ '$! >' $! ' $! ! % $" $ $"# ! %0@P%#"'&547632#"'&547632'2#"'&547672#"'&547672#"'&5476# $! &# $! &?& $ &!$ &! $ =& &!& &!"$! $! % $" $ $/?O%#"'&547632#"'&547632'2#"'&54762#"'&5476'2#"'&5476# $ &# $ &?' $! &! $ & ">' $! ' $! "$! %y" $ $!$$0@P%#"'&547632#"'&547632'2#"'&547672#"'&547672#"'&5476# $! &# $! &?& $ &!$ &! $ =& &!& &!"$! $! % $" $ $/?O_%#"'&547632#"'&547632'2#"'&547672#"'&547672#"'&5476'2#"'&5476# $ &# $ &?' $! &!$ &! $ & ">' $! ' $! "$! %! % $" $ $!$$0%2#"'&5476#2#"'&54762#"'&5476& $ & $! &! $ Y!$! $!$! %z"$ $/?%#"'&547632#"'&5476322#"'&5476'2#"'&5476# $! &# $ &'$! '$! >' $! ' $! "# ! %"# ! %0A%2#"'&5476#2#"'&54762#"'&5476#2#"'&5476& $ & $! &! $ &$! Y!$! $!$! %z"$ $!" ! &/?O%#"'&547632#"'&5476322#"'&54762#"'&547672#"'&5476# $! &# $ &'$! &!$ '$! >' $! ' $! "# ! %! % $"# ! %/@%2#"'&5476#2"'&54767#"'&54763272#"'&5476& $! & $! N" $ &&! $ Y!$! %!#! %' $" "$ $/?O%#"'&547632#"'&547632'2#"'&547672#"'&5476'2#"'&5476# $ &# $ &?' $! '$! & ">' $! ' $! "$! %"# ! %!$$/@Q%2#"'&5476#2"'&54767#"'&54763272#"'&5476#"'&547632& $! & $! N" $ &&! $ o"$! &Y!$! %!#! %' $" "$ $?$! &!/?O_%#"'&547632#"'&547632'2#"'&547672#"'&54762#"'&547672#"'&5476# $ &# $ &?' $! '$! &!$ & ">' $! ' $! "$! %"# ! %! % $!$$/?%#"'&547632#"'&5476322#"'&547672#"'&5476# $!&# $! &'! $! &! $ =& %!& &!"$! %" $ $/?O%#"'&547632#"'&5476322#"'&547672#"'&5476'2#"'&5476# $! &# $ &'$! &! $ '$! >' $! ' $! "# ! %" $ $"# ! %/?O%#"'&547632#"'&5476322#"'&54762#"'&547672#"'&5476# $!&# $! &'! $! &!$ &! $ =& %!& &!"$! %! % $" $ $/?O_%#"'&547632#"'&5476322#"'&54762#"'&547672#"'&5476'2#"'&5476# $! &# $ &'$! &!$ &! $ '$! >' $! ' $! "# ! %! % $" $ $"# ! %0@P%#"'&547632#"'&547632'2#"'&547672#"'&547672#"'&5476# $! &# $! &?& $ '! $! &! $ =& &!& &!"$! $"$! %" $ $/?O_%#"'&547632#"'&547632'2#"'&547672#"'&547672#"'&5476'2#"'&5476# $ &# $ &?' $! '$! &! $ & ">' $! ' $! "$! %"# ! %" $ $!$$0@P`%#"'&547632#"'&547632'2#"'&547672#"'&54762#"'&547672#"'&5476# $! &# $! &?& $ '! $! &!$ &! $ =& &!& &!"$! $"$! %! % $" $ $/?O_o%#"'&547632#"'&547632'2#"'&547672#"'&54762#"'&547672#"'&5476'2#"'&5476# $ &# $ &?' $! '$! &!$ &! $ & ">' $! ' $! "$! %"# ! %! % $" $ $!$$/%2#"'&547672#"'&54762#"'&5476&!$! '$! &!$ 5! % $"# ! %! % $/?%#"'&547632'2#"'&5476#"'&5476322#"'&5476# $! &>'! $! o# $ &>'$! >' $! "$! %' $! f"# ! %/@%2#"'&547672#"'&54762#"'&54762#"'&5476&!$ '"$! &!$! & $! Y!%! $"& &!%! %z!$! %/?O%#"'&547632'2#"'&5476#"'&5476322#"'&547672#"'&5476# $! &>'! $! o# $ &?&!$ '$! >' $! "$! %' $! ! % $"# ! %/?%2#"'&547672#"'&54762#"'&547672#"'&5476&!$ '$! &!$ ' $! 5! % $"# ! %! % $"$! %/?O%#"'&547632'2#"'&5476#"'&547632'2#"'&54762#"'&5476# $ &>'! $! o# $ &?' $! & ">' $! "$! %' $! "$! %z!$$/?P%2#"'&547672#"'&54762#"'&54767#"'&547632'2"'&5476&!$! '"$! &!$! N" $! '>& $! Y!%! %"& &!%! %~& &"!#! %/?O_%#"'&547632'2#"'&5476#"'&547632'2#"'&547672#"'&547672#"'&5476# $ &>'! $! o# $ &?' $! &!$ & ">' $! "$! %' $! "$! %! % $!$$ 0@%#"'&547632'2#"'&5476#"'&5476322#"'&5476# $!&>&! $ o# $! &&! $ =& %!"$! $& &!f" $ $/?O%#"'&547632'2#"'&5476#"'&5476322#"'&5476'2#"'&5476# $! &>'! $! o# $ &&! $ '$! >' $! "$! %' $! e" $ $"# ! % 0@P%#"'&547632'2#"'&5476#"'&5476322#"'&547672#"'&5476# $!&>&! $ o# $! &?&!$ &! $ =& %!"$! $& &!! % $" $ $/?O_%#"'&547632'2#"'&5476#"'&5476322#"'&547672#"'&5476'2#"'&5476# $! &>'! $! o# $ &?&!$ &! $ '$! >' $! "$! %' $! ! % $" $ $"# ! % 0AQ%#"'&547632'2#"'&5476#"'&547632'2#"'&54762#"'&5476# $! &>&! $ o# $! &?& $ &! $ =& &!"$! $& &!"$! $z" $ $/?O_%#"'&547632'2#"'&5476#"'&547632'2#"'&54762#"'&5476'2#"'&5476# $ &>'! $! o# $ &?' $! &! $ & ">' $! "$! %' $! "$! %y" $ $!$$ 0AQa%#"'&547632'2#"'&5476#"'&547632'2#"'&547672#"'&547672#"'&5476# $! &>&! $ o# $! &?& $ &!$ &! $ =& &!"$! $& &!"$! $! % $" $ $/?O_o%#"'&547632'2#"'&5476#"'&547632'2#"'&547672#"'&547672#"'&5476'2#"'&5476# $ &>'! $! o# $ &?' $! &!$ &! $ & ">' $! "$! %' $! "$! %! % $" $ $!$$/@%2#"'&547672#"'&54762#"'&54762#"'&5476& $ &"$ & $! &! $ Y!$! $" & $!$! %z"$ $/?O%#"'&547632'2#"'&5476#"'&5476322#"'&5476'2#"'&5476# $! &>'! $! o# $ &'$! '$! >' $! "$! %' $! "# ! %"# ! %/@Q%2#"'&547672#"'&54762#"'&54762#"'&5476#2#"'&5476& $ &"$ & $! &! $ &$! Y!$! $" & $!$! %z"$ $!" ! &/?O_%#"'&547632'2#"'&5476#"'&5476322#"'&54762#"'&547672#"'&5476# $! &>'! $! o# $ &'$! &!$ '$! >' $! "$! %' $! "# ! %! % $"# ! %/?P%2#"'&547672#"'&54762"'&54767#"'&54763272#"'&5476& $! &"$ & $! N" $ &&! $ Y!$! %" & $!#! %' $" "$ $/?O_%#"'&547632'2#"'&5476#"'&547632'2#"'&547672#"'&5476'2#"'&5476# $ &>'! $! o# $ &?' $! '$! & ">' $! "$! %' $! "$! %"# ! %!$$/?Pa%2#"'&547672#"'&54762"'&54767#"'&54763272#"'&5476#"'&547632& $! &"$ & $! N" $ &&! $ o"$! &Y!$! %" & $!#! %' $" "$ $?$! &!/?O_o%#"'&547632'2#"'&5476#"'&547632'2#"'&547672#"'&54762#"'&547672#"'&5476# $ &>'! $! o# $ &?' $! '$! &!$ & ">' $! "$! %' $! "$! %"# ! %! % $!$$ 0@P%#"'&547632'2#"'&5476#"'&5476322#"'&547672#"'&5476# $!&>&! $ o# $! &'! $! &! $ =& %!"$! $& &!"$! %" $ $/?O_%#"'&547632'2#"'&5476#"'&5476322#"'&547672#"'&5476'2#"'&5476# $! &>'! $! o# $ &'$! &! $ '$! >' $! "$! %' $! "# ! %" $ $"# ! % 0@P`%#"'&547632'2#"'&5476#"'&5476322#"'&54762#"'&547672#"'&5476# $!&>&! $ o# $! &'! $! &!$ &! $ =& %!"$! $& &!"$! %! % $" $ $/?O_o%#"'&547632'2#"'&5476#"'&5476322#"'&54762#"'&547672#"'&5476'2#"'&5476# $! &>'! $! o# $ &'$! &!$ &! $ '$! >' $! "$! %' $! "# ! %! % $" $ $"# ! % 0AQa%#"'&547632'2#"'&5476#"'&547632'2#"'&547672#"'&547672#"'&5476# $! &>&! $ o# $! &?& $ '! $! &! $ =& &!"$! $& &!"$! $"$! %" $ $/?O_o%#"'&547632'2#"'&5476#"'&547632'2#"'&547672#"'&547672#"'&5476'2#"'&5476# $ &>'! $! o# $ &?' $! '$! &! $ & ">' $! "$! %' $! "$! %"# ! %" $ $!$$ 0AQaq%#"'&547632'2#"'&5476#"'&547632'2#"'&547672#"'&54762#"'&547672#"'&5476# $! &>&! $ o# $! &?& $ '! $! &!$ &! $ =& &!"$! $& &!"$! $"$! %! % $" $ $/?O_o%#"'&547632'2#"'&5476#"'&547632'2#"'&547672#"'&54762#"'&547672#"'&5476'2#"'&5476# $ &>'! $! o# $ &?' $! '$! &!$ &! $ & ">' $! "$! %' $! "$! %"# ! %! % $" $ $!$$o#"'&54?632gT T a~ ~S\-[32+"54;#"54;547632"'&#"32#!32+"54;#"54;547632"'&#"32#HSMM0 &% %(HHSMM0 &% %(HxO;E& ,;O;E& ,; Ip-@D32+"54;#"54;547632"'&#"32#732+"54;#"5437#5HSMM0 %& %(HKM9a;xO;E& ,;)Ohh K\,?32+"54;#"54;547632"'&#"32#732+"54;#"543HSMM0 '$*& HMM9xO;E& ); K\'N#"54;543232+327632#"'&532+"54;#"54;547632"'&#"aJJ||3  +J+HSMM0 &% %(xkkF  <(3UMO;E& ,3'#"54;543232+327632#"'&51JJ||3  +J+xwwF  <(3sI"%2"'&5476#"'&=#"'&54763,Y2u#67676"'&'&'&76762R $8  %"O   Zq%9732+"'&5476#"'&=#"'&54763!#"'&=#"'&54763 YTYF<.7#"'&5476;3676767#"'476;'"#!"'&54763B]I85 "V( ,K)I NT+<8%676=#"'&5476;'&'32+547'&7676z`5^x | d5^| %1~a5| %7~f4| <!"'&54763!2##"'&5Y]<2747632#"'&#"'&5&'&'&/!"'&54763!6_ %%/*&%7  0<3!#"'&5476;6767676=&'&'&'&+"'&5476;6'"L6  ) .*"+M ) 7  -OL',<i%/&76?676=!547632! I  ~u-<*!&'&'&'&+"'&54763!6!&76767hi ) %-*Eh 6  2J< #"'&5&'&'&/!"'&54763!6 %%/*9%7  0>'"+"'&5476;67676765#"'&54763!6#"'&5&'&'&'&#"!<$$*Z%/*  ' >#"  5 (G%6 H"54;543232#c3BWH2#"'&547632+3276767#"'476;!32+3#"'&5476%\2Q7 "2`' 0L^52WwrMR*r1:WH2#"'&547632+3276767#"'476;!32+3#"'&5476O\2Q7 "2`' 0L^52WwrMR*r3BWHW2#"'&547632+3276767#"'476;!32+3#"'&54762"'&5476%\2Q7 "2`' 0L^52WwrMR*r1:WHW2#"'&547632+3276767#"'476;!32+3#"'&54762"'&5476O\2Q7 "2`' 0L^52WwrMR*r<J32+"'&54767676=#"'&5476;'&'32+547'&7676`5^x | d5^| <%1~a5| %7~f4| <$S#"'&5476;2##"'&5676=#"'&5476;'&'32+547'&7676.0c`5^x | d5^| ec%1~a5| %7~f4| <8G%676=#"'&5476;'&'32+547'&76762"'&5476z`5^x | d5^| %1~a5| %7~f4| <0-<%4'&'&/#"'&5476;232#!"'&5476372"'&5476+N)+Z4)7%+M5C%54'&'&/#"'&5476;6#'&/'&'&74?676'2"'&5476 #!II1+$  V$.9 &*$57  *M  M  0/<)!"'&54763!2##"'&5'2"'&5476YY]<2A747632#"'&#"'&5&'&'&/!"'&54763!62"'&5476_ %%/*&%7  0w@"2"'&54767#"'&5#"'&54763tY4'2"'&54767#"'4763!2##"'&5M}$~]H%2"'&54767'&'&76?3#'&'&745#"'&5476;;27676765LHs ~"0Lj/+5^ % j7͊ L'* (M6 ) @ !2"'&54767#"'&=#"'&54763Yfz<%"1"'&5&'&'&'&+"'&5476;62"'&5476 ' /)96  'J1<3B!#"'&5476;6767676=&'&'&'&+"'&5476;6'"2"'&5476L6  ) .*"+M" ) 7  -OL',<i*%/&76?676=!547632!'2"'&5476 I  ~u-2<6E73!"'&5476;&'&'&'&+#"'&5#"'&5476;2"'&5476}?") ' eh:ku&'J6 h02"'&5476!"'&54734'&'&'&+"'476;6,( $$.+7 +M<BQ;7676=&'&'&'&+"'&54763!2'#'&'&'7&7672"'&5476h ( I ) %K'* P-*!h n6 I 7 "0LO 'Nu%&^<%6D32+5&76?#"'&54763!6#"'&5&'&'&'&#2"'&5476h!K%/* ' h:%&K 0L7 }<HV32+5&7676?#"'&54763!6!"'&547!2767676=&'&'&'&#2"'&5476h K%/*#0L$7 ' h  :K 2JL(** 6 u2172"'&5476?5#"'476;!"'&547!55#"'476;Y5YMUTR"C1% );2"'&5476'&'&76?676=!"'&54763!%#"'&547632@ ],   8K$< /#"'&5&'&'&/!"'&54763!62"'&5476 %%/*9%7  0w3:H2"'&5476'32+3276767#"'476;!32+3#"'&5476\2Q7 "2`' 0L^52rMR*rM2"'&5476''"+"'&5476;67676765#"'&54763!6#"'&5&'&'&'&#X"!<$$*Z%/*  ' >#"  5 (G%6 @W !2"'&5476#"'&5#"'&547632YWw4<0E?32+"'&54764'&'&/#"'&5476;232#!"'&54763Ň+N)+Z4E7%+M<EE32+"'&5476#"'&5476;6767676=&'&'&'&+"'&5476;6'"ɇ6  ) .*"+ME ) 7  -OL',<EZ32+"'&547632+5&7676?#"'&54763!6!"'&547!2767676=&'&'&'&#)h K%/*#0L$7 ' Eh  :K 2JL(** 6 <i(547632676=#"'&5476;'&'&<`5^x | Ỉ%1~a5| 9"354767674'&#"3672#3 e##* ,9g( 2/ '** ]   /$?mD%1\  0'&/&76762#"'&547632#"'&54768 8 N!   !  O    Y2Z V>4n HX-\+^ Fh$,x H^]Ho HH#mH Z    V > 4n   H X  K HY x  H/  y H \ /H=H@ #H 7^  H  9H K H  H j G H  H  gH u$ $ $H W$T * *H-Q-Ha   H H  [ Hi   HCopyleft 2002, 2003 Free Software Foundation.Copyleft 2002, 2003 Free Software Foundation.FreeMonoFreeMonoMediumMediumFontForge 1.0 : Free Monospaced : 29-7-2004FontForge 1.0 : Free Monospaced : 29-7-2004Free MonospacedFree MonospacedVersion $Revision: 1.10 $ Version $Revision: 1.10 $ FreeMonoFreeMonoThe use of this font is granted subject to GNU General Public License.The use of this font is granted subject to GNU General Public License.http://www.gnu.org/copyleft/gpl.htmlhttp://www.gnu.org/copyleft/gpl.htmlThe quick brown fox jumps over the lazy dog.The quick brown fox jumps over the lazy dog.Normalhttp://www.gnu.org/copyleft/gpl.htmlZel de grum: quetxup, whisky, caf, bon vi; ja!oby ejnhttp://www.gnu.org/copyleft/gpl.htmlnormalhttp://www.gnu.org/copyleft/gpl.htmlStandardhttp://www.gnu.org/copyleft/gpl.htmlZwlf Boxkmpfer jagen Victor quer ber den groen Sylter Deich.http://www.gnu.org/copyleft/gpl.htmlNormalhttp://www.gnu.org/copyleft/gpl.htmlJovencillo emponzoado de whisky, qu mala figurota exhibes.Normaalihttp://www.gnu.org/copyleft/gpl.htmlNormalhttp://www.gnu.org/copyleft/gpl.htmlPortez ce vieux whisky au juge blond qui fume.Normlhttp://www.gnu.org/copyleft/gpl.htmlNormalehttp://www.gnu.org/copyleft/gpl.htmlPranzo d'acqua fa volti sghembi.Standaardhttp://www.gnu.org/copyleft/gpl.htmlZweedse ex-VIP, behoorl3k gek op quantumfysica.Normalhttp://www.gnu.org/copyleft/gpl.htmlNormalnyhttp://www.gnu.org/copyleft/gpl.htmlNormalhttp://www.gnu.org/copyleft/gpl.html1KG=K9http://www.gnu.org/copyleft/gpl.html G0I08681K; F8B@CA & 4, =0 ,M:75<.Normlnehttp://www.gnu.org/copyleft/gpl.htmlNormalhttp://www.gnu.org/copyleft/gpl.htmlNormalhttp://www.gnu.org/copyleft/gpl.htmlnavadnoDovoljena je uporaba v skladu z licenco GNU General Public License.http://www.gnu.org/copyleft/gpl.html`erif bo za vajo spet kuhal doma e ~gance.thnghttp://www.gnu.org/copyleft/gpl.htmlArruntahttp://www.gnu.org/copyleft/gpl.htmlNormalhttp://www.gnu.org/copyleft/gpl.htmlNormalhttp://www.gnu.org/copyleft/gpl.htmlNormalhttp://www.gnu.org/copyleft/gpl.htmlNormalhttp://www.gnu.org/copyleft/gpl.html2   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghjikmlnoqprsutvwxzy{}|~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~                           ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~          softhyphenAmacronamacronAbreveabreveAogonekaogonek Ccircumflex ccircumflex Cdotaccent cdotaccentDcarondcaronDcroatEmacronemacronEbreveebreve Edotaccent edotaccentEogonekeogonekEcaronecaron Gcircumflex gcircumflex Gdotaccent gdotaccent Gcommaaccent gcommaaccent Hcircumflex hcircumflexHbarhbarItildeitildeImacronimacronIbreveibreveIogonekiogonekIJij Jcircumflex jcircumflex Kcommaaccent kcommaaccent kgreenlandicLacutelacute Lcommaaccent lcommaaccentLcaronlcaronLdotldotNacutenacute Ncommaaccent ncommaaccentNcaronncaron napostropheEngengOmacronomacronObreveobreve Ohungarumlaut ohungarumlautRacuteracute Rcommaaccent rcommaaccentRcaronrcaronSacutesacute Scircumflex scircumflexuni0162uni0163TcarontcaronTbartbarUtildeutildeUmacronumacronUbreveubreveUringuring Uhungarumlaut uhungarumlautUogonekuogonek Wcircumflex wcircumflex Ycircumflex ycircumflexZacutezacute Zdotaccent zdotaccentlongsuni0180uni0181uni0182uni0183uni0184uni0185uni0186uni0187uni0188uni0189uni018Auni018Buni018Cuni018Duni018Euni018Funi0190uni0191uni0193uni0194uni0195uni0196uni0197uni0198uni0199uni019Auni019Buni019Cuni019Duni019Euni019FOhornohornuni01A2uni01A3uni01A4uni01A5uni01A6uni01A7uni01A8uni01A9uni01AAuni01ABuni01ACuni01ADuni01AEUhornuhornuni01B1uni01B2uni01B3uni01B4uni01B5uni01B6uni01B7uni01B8uni01B9uni01BAuni01BBuni01BCuni01BDuni01BEuni01BFuni01C0uni01C1uni01C2uni01C3uni01C4uni01C5uni01C6uni01C7uni01C8uni01C9uni01CAuni01CBuni01CCuni01CDuni01CEuni01CFuni01D0uni01D1uni01D2uni01D3uni01D4uni01D5uni01D6uni01D7uni01D8uni01D9uni01DAuni01DBuni01DCuni01DDuni01DEuni01DFuni01E0uni01E1uni01E2uni01E3uni01E4uni01E5Gcarongcaronuni01E8uni01E9uni01EAuni01EBuni01ECuni01EDuni01EEuni01EFuni01F0uni01F1uni01F2uni01F3uni01F4uni01F5uni01F6uni01F7uni01F8uni01F9 Aringacute aringacuteAEacuteaeacute Oslashacute oslashacuteuni0200uni0201uni0202uni0203uni0204uni0205uni0206uni0207uni0208uni0209uni020Auni020Buni020Cuni020Duni020Euni020Funi0210uni0211uni0212uni0213uni0214uni0215uni0216uni0217 Scommaaccent scommaaccent Tcommaaccent tcommaaccentuni021Cuni021Duni021Euni021Funi0224uni0225uni0226uni0227uni0228uni0229uni022Auni022Buni022Cuni022Duni022Euni022Funi0230uni0231uni0232uni0233uni0241uni0242uni0250uni0251uni0252uni0253uni0254uni0255uni0256uni0257uni0258uni0259uni025Auni025Buni025Cuni025Funi0260uni0261uni0262uni0263uni0264uni0265uni0266uni0267uni0268uni0269uni026Auni026Buni026Cuni026Duni026Funi0270uni0271uni0272uni0273uni0274uni0275uni0276uni0278uni0279uni027Auni027Buni027Cuni027Duni027Euni027Funi0280uni0281uni0282uni0283uni0284uni0285uni0286uni0287uni0288uni0289uni028Cuni028Duni028Euni028Funi0290uni0291uni0292uni0294uni0295uni0296uni0297uni0299uni029Buni029Cuni029Duni029Euni029Funi02A0uni02A1uni02A2uni02A3uni02A4uni02A6uni02A7uni02BB afii57929 afii64937uni02BEuni02BFuni02C8uni02C9uni02CAuni02CBuni02D0uni02D1uni02D2uni02D3uni02D4uni02D5uni02D6uni02D7uni02DFuni02EE gravecomb acutecombuni0302 tildecombuni0304uni0305uni0306uni0307uni0308 hookabovecombuni030Auni030Buni030Cuni030Duni030Euni030Funi0310uni0311uni031Buni0321uni0322uni0327uni0328uni0333uni0335uni0336uni0337uni0338uni0342uni0344uni037Atonos dieresistonos Alphatonos anoteleia EpsilontonosEtatonos Iotatonos Omicrontonos Upsilontonos OmegatonosiotadieresistonosAlphaBetaGammauni0394EpsilonZetaEtaThetaIotaKappaLambdaMuNuXiOmicronPiRhouni03A2SigmaTauUpsilonPhiChiPsiuni03A9 IotadieresisUpsilondieresis alphatonos epsilontonosetatonos iotatonosupsilondieresistonosalphabetagammadeltaepsilonzetaetathetaiotakappalambdauni03BCnuxiomicronrhosigma1sigmatauupsilonphichipsiomega iotadieresisupsilondieresis omicrontonos upsilontonos omegatonosuni03D0theta1Upsilon1uni03D3phi1uni03DAuni03DBuni03DCuni0400 afii10023 afii10051 afii10052 afii10053 afii10054 afii10055 afii10056 afii10057 afii10058 afii10059 afii10060 afii10061uni040D afii10062 afii10145 afii10017 afii10018 afii10019 afii10020 afii10021 afii10022 afii10024 afii10025 afii10026 afii10027 afii10028 afii10029 afii10030 afii10031 afii10032 afii10033 afii10034 afii10035 afii10036 afii10037 afii10038 afii10039 afii10040 afii10041 afii10042 afii10043 afii10044 afii10045 afii10046 afii10047 afii10048 afii10049 afii10065 afii10066 afii10067 afii10068 afii10069 afii10070 afii10072 afii10073 afii10074 afii10075 afii10076 afii10077 afii10078 afii10079 afii10080 afii10081 afii10082 afii10083 afii10084 afii10085 afii10086 afii10087 afii10088 afii10089 afii10090 afii10091 afii10092 afii10093 afii10094 afii10095 afii10096 afii10097uni0450 afii10071 afii10099 afii10100 afii10101 afii10102 afii10103 afii10104 afii10105 afii10106 afii10107 afii10108 afii10109uni045D afii10110 afii10193uni0464uni046Auni046Cuni0470uni0471uni048Cuni048Duni048Euni048F afii10050 afii10098uni0492uni0493uni0494uni0495uni0496uni0497uni0498uni0499uni049Auni049Buni049Cuni049Duni049Euni049Funi04A0uni04A1uni04A2uni04A3uni04A4uni04A5uni04A6uni04A7uni04A8uni04A9uni04AAuni04ABuni04ACuni04ADuni04AEuni04AFuni04B0uni04B1uni04B2uni04B3uni04B4uni04B5uni04B6uni04B7uni04B8uni04B9uni04BAuni04BBuni04BCuni04BDuni04BEuni04BFuni04C0uni04C1uni04C2uni04C3uni04C4uni04C7uni04C8uni04CBuni04CCuni04D0uni04D1uni04D2uni04D3uni04D4uni04D5uni04D6uni04D7uni04D8 afii10846uni04DAuni04DBuni04DCuni04DDuni04DEuni04DFuni04E0uni04E1uni04E2uni04E3uni04E4uni04E5uni04E6uni04E7uni04E8uni04E9uni04EAuni04EBuni04ECuni04EDuni04EEuni04EFuni04F0uni04F1uni04F2uni04F3uni04F4uni04F5uni04F8uni04F9uni0531uni0532uni0533uni0534uni0535uni0536uni0537uni0538uni0539uni053Auni053Buni053Cuni053Duni053Euni053Funi0540uni0541uni0542uni0543uni0544uni0545uni0546uni0547uni0548uni0549uni054Auni054Buni054Cuni054Duni054Euni054Funi0550uni0551uni0552uni0553uni0554uni0555uni0556uni0561uni0562uni0563uni0564uni0565uni0566uni0567uni0568uni0569uni056Auni056Buni056Cuni056Duni056Euni056Funi0570uni0571uni0572uni0573uni0574uni0575uni0576uni0577uni0578uni0579uni057Auni057Buni057Cuni057Duni057Euni057Funi0580uni0581uni0582uni0583uni0584uni0585uni0586uni058A afii57799 afii57801 afii57800 afii57802 afii57793 afii57794 afii57795 afii57798 afii57797 afii57806 afii57796 afii57807 afii57839 afii57645 afii57841 afii57842 afii57804 afii57803 afii57658uni05C4 afii57664 afii57665 afii57666 afii57667 afii57668 afii57669 afii57670 afii57671 afii57672 afii57673 afii57674 afii57675 afii57676 afii57677 afii57678 afii57679 afii57680 afii57681 afii57682 afii57683 afii57684 afii57685 afii57686 afii57687 afii57688 afii57689 afii57690 afii57716 afii57717 afii57718uni05F3uni05F4uni16A0uni16A1uni16A2uni16A3uni16A4uni16A5uni16A6uni16A7uni16A8uni16A9uni16AAuni16ABuni16ACuni16ADuni16AEuni16AFuni16B0uni16B1uni16B2uni16B3uni16B4uni16B5uni16B6uni16B7uni16B8uni16B9uni16BAuni16BBuni16BCuni16BDuni16BEuni16BFuni16C0uni16C1uni16C2uni16C3uni16C4uni16C5uni16C6uni16C7uni16C8uni16C9uni16CAuni16CBuni16CCuni16CDuni16CEuni16CFuni16D0uni16D1uni16D2uni16D3uni16D4uni16D5uni16D6uni16D7uni16D8uni16D9uni16DAuni16DBuni16DCuni16DDuni16DEuni16DFuni16E0uni16E1uni16E2uni16E3uni16E4uni16E5uni16E6uni16E7uni16E8uni16E9uni16EAuni16EBuni16ECuni16EDuni16EEuni16EFuni16F0uni1E00uni1E01uni1E02uni1E03uni1E04uni1E05uni1E06uni1E07uni1E08uni1E09uni1E0Auni1E0Buni1E0Cuni1E0Duni1E0Euni1E0Funi1E10uni1E11uni1E12uni1E13uni1E14uni1E15uni1E16uni1E17uni1E18uni1E19uni1E1Auni1E1Buni1E1Cuni1E1Duni1E1Euni1E1Funi1E20uni1E21uni1E22uni1E23uni1E24uni1E25uni1E26uni1E27uni1E28uni1E29uni1E2Auni1E2Buni1E2Cuni1E2Duni1E2Euni1E2Funi1E30uni1E31uni1E32uni1E33uni1E34uni1E35uni1E36uni1E37uni1E38uni1E39uni1E3Auni1E3Buni1E3Cuni1E3Duni1E3Euni1E3Funi1E40uni1E41uni1E42uni1E43uni1E44uni1E45uni1E46uni1E47uni1E48uni1E49uni1E4Auni1E4Buni1E4Cuni1E4Duni1E4Euni1E4Funi1E50uni1E51uni1E52uni1E53uni1E54uni1E55uni1E56uni1E57uni1E58uni1E59uni1E5Auni1E5Buni1E5Cuni1E5Duni1E5Euni1E5Funi1E60uni1E61uni1E62uni1E63uni1E64uni1E65uni1E66uni1E67uni1E68uni1E69uni1E6Auni1E6Buni1E6Cuni1E6Duni1E6Euni1E6Funi1E70uni1E71uni1E72uni1E73uni1E74uni1E75uni1E76uni1E77uni1E78uni1E79uni1E7Auni1E7Buni1E7Cuni1E7Duni1E7Euni1E7FWgravewgraveWacutewacute Wdieresis wdieresisuni1E86uni1E87uni1E88uni1E89uni1E8Auni1E8Buni1E8Cuni1E8Duni1E8Euni1E8Funi1E90uni1E91uni1E92uni1E93uni1E94uni1E95uni1E96uni1E97uni1E98uni1E99uni1E9Auni1E9Buni1EA0uni1EA1uni1EA2uni1EA3uni1EA4uni1EA5uni1EA6uni1EA7uni1EA8uni1EA9uni1EAAuni1EABuni1EACuni1EADuni1EAEuni1EAFuni1EB0uni1EB1uni1EB2uni1EB3uni1EB4uni1EB5uni1EB6uni1EB7uni1EB8uni1EB9uni1EBAuni1EBBuni1EBCuni1EBDuni1EBEuni1EBFuni1EC0uni1EC1uni1EC2uni1EC3uni1EC4uni1EC5uni1EC6uni1EC7uni1EC8uni1EC9uni1ECAuni1ECBuni1ECCuni1ECDuni1ECEuni1ECFuni1ED0uni1ED1uni1ED2uni1ED3uni1ED4uni1ED5uni1ED6uni1ED7uni1ED8uni1ED9uni1EDAuni1EDBuni1EDCuni1EDDuni1EDEuni1EDFuni1EE0uni1EE1uni1EE2uni1EE3uni1EE4uni1EE5uni1EE6uni1EE7uni1EE8uni1EE9uni1EEAuni1EEBuni1EECuni1EEDuni1EEEuni1EEFuni1EF0uni1EF1Ygraveygraveuni1EF4uni1EF5uni1EF6uni1EF7uni1EF8uni1EF9uni1F00uni1F01uni1F02uni1F03uni1F04uni1F05uni1F06uni1F07uni1F08uni1F09uni1F0Auni1F0Buni1F0Cuni1F0Duni1F0Euni1F0Funi1F10uni1F11uni1F12uni1F13uni1F14uni1F15uni1F18uni1F19uni1F1Auni1F1Buni1F1Cuni1F1Duni1F20uni1F21uni1F22uni1F23uni1F24uni1F25uni1F26uni1F27uni1F28uni1F29uni1F2Auni1F2Buni1F2Cuni1F2Duni1F2Euni1F2Funi1F30uni1F31uni1F32uni1F33uni1F34uni1F35uni1F36uni1F37uni1F38uni1F39uni1F3Auni1F3Buni1F3Cuni1F3Duni1F3Euni1F3Funi1F40uni1F41uni1F42uni1F43uni1F44uni1F45uni1F48uni1F49uni1F4Auni1F4Buni1F4Cuni1F4Duni1F50uni1F51uni1F52uni1F53uni1F54uni1F55uni1F56uni1F57uni1F59uni1F5Buni1F5Duni1F5Funi1F60uni1F61uni1F62uni1F63uni1F64uni1F65uni1F66uni1F67uni1F68uni1F69uni1F6Auni1F6Buni1F6Cuni1F6Duni1F6Euni1F6Funi1F70uni1F71uni1F72uni1F73uni1F74uni1F75uni1F76uni1F77uni1F78uni1F79uni1F7Auni1F7Buni1F7Cuni1F7Duni1F80uni1F81uni1F82uni1F83uni1F84uni1F85uni1F86uni1F87uni1F88uni1F89uni1F8Auni1F8Buni1F8Cuni1F8Duni1F8Euni1F8Funi1F90uni1F91uni1F92uni1F93uni1F94uni1F95uni1F96uni1F97uni1F98uni1F99uni1F9Auni1F9Buni1F9Cuni1F9Duni1F9Euni1F9Funi1FA0uni1FA1uni1FA2uni1FA3uni1FA4uni1FA5uni1FA6uni1FA7uni1FA8uni1FA9uni1FAAuni1FABuni1FACuni1FADuni1FAEuni1FAFuni1FB0uni1FB1uni1FB2uni1FB3uni1FB4uni1FB6uni1FB7uni1FB8uni1FB9uni1FBAuni1FBBuni1FBCuni1FBDuni1FBEuni1FBFuni1FC0uni1FC1uni1FC2uni1FC3uni1FC4uni1FC6uni1FC7uni1FC8uni1FC9uni1FCAuni1FCBuni1FCCuni1FCDuni1FCEuni1FCFuni1FD0uni1FD1uni1FD2uni1FD3uni1FD6uni1FD7uni1FD8uni1FD9uni1FDAuni1FDBuni1FDDuni1FDEuni1FDFuni1FE0uni1FE1uni1FE2uni1FE3uni1FE4uni1FE5uni1FE6uni1FE7uni1FE8uni1FE9uni1FEAuni1FEBuni1FECuni1FEDuni1FEEuni1FEFuni1FF2uni1FF3uni1FF4uni1FF6uni1FF7uni1FF8uni1FF9uni1FFAuni1FFBuni1FFCuni1FFDuni1FFEuni2010 afii00208 underscoredbl quotereverseduni201Ftwodotenleaderuni2031minuteseconduni2034uni2035uni2036uni2037 exclamdbluni203Duni203Euni2043uni2045uni2046uni2048uni2049uni204B zerosuperioruni2071uni2072uni2073 foursuperior fivesuperior sixsuperior sevensuperior eightsuperior ninesuperioruni207Auni207Buni207Cparenleftsuperiorparenrightsuperior nsuperior zeroinferior oneinferior twoinferior threeinferior fourinferior fiveinferior sixinferior seveninferior eightinferior nineinferioruni208Auni208Buni208Cparenleftinferiorparenrightinferiorlirapeseta afii57636Eurouni2100uni2101uni2102uni2103 afii61248uni2106uni2107uni210Duni2110Ifrakturuni2112 afii61289uni2114uni2115 afii61352uni2117 weierstrassuni2119uni211Auni211D prescriptionuni2124uni2125uni2126uni2127uni212Auni212Buni2132alephonethird twothirdsuni2155uni2156uni2157uni2158uni2159uni215A oneeighth threeeighths fiveeighths seveneighthsuni215Funi2160uni2161uni2162uni2163uni2164uni2165uni2166uni2167uni2168uni2169uni216Auni216Buni216Cuni216Duni216Euni216F arrowleftarrowup arrowright arrowdown arrowboth arrowupdnuni2196uni2197uni2198uni2199uni219Auni219Buni219Cuni219Duni219Euni219Funi21A0uni21A1uni21A2uni21A3uni21A4uni21A5uni21A6uni21A7 arrowupdnbseuni21A9uni21AAuni21ABuni21ACuni21ADuni21AEuni21AFuni21B0uni21B1uni21B2uni21B3uni21B4carriagereturnuni21B6uni21B7uni21B8uni21B9uni21BAuni21BBuni21BCuni21BDuni21BEuni21BFuni21C0uni21C1uni21C2uni21C3uni21C4uni21C5uni21C6uni21C7uni21C8uni21C9uni21CAuni21CBuni21CCuni21CDuni21CEuni21CF arrowdblleft arrowdblup arrowdblright arrowdbldown arrowdblbothuni21D5 universaluni2201 existentialuni2204emptysetgradientelement notelementuni220Asuchthatuni220Cuni220Duni2213uni2214uni2215uni2219uni221Buni221C proportional orthogonal logicaland logicalor intersectionunionuni222Cuni222Duni222Euni222Funi2230 thereforeuni2235uni2237similaruni223Duni2241uni2242uni2243uni2244 congruentuni2250uni2251uni2252uni2253uni2259uni225A equivalenceuni2266uni2267uni226Auni226Buni226Cuni226Euni226Funi2276uni2277 propersubsetpropersuperset reflexsubsetreflexsuperset circleplusuni2296circlemultiplyuni2298uni2299uni229Auni229Buni229Cuni229Duni22A2uni22A3uni22A4 perpendicularuni22A6uni22A7uni22A8uni22A9uni22AAuni22ABuni22ACuni22ADuni22AEuni22AFuni22BEdotmathuni22C6uni2300houseuni2303uni2308uni2309uni230Auni230Buni230Cuni230Duni230Euni230F revlogicalnotuni2315uni231Cuni231Duni231Euni231F angleleft anglerightuni239Buni239Cuni239Duni239Euni239Funi23A0uni23A1uni23A2uni23A3uni23A4uni23A5uni23A6uni23A7uni23A8uni23A9uni23AAuni23ABuni23ACuni23ADuni23AEuni23AFuni23B0uni23B1uni23B2uni23B3uni23B4uni23B7uni23BAuni23BBuni23BCuni23BDSF100000uni2501SF110000uni2503uni2504uni2505uni2506uni2507uni2508uni2509uni250Auni250BSF010000uni250Duni250Euni250FSF030000uni2511uni2512uni2513SF020000uni2515uni2516uni2517SF040000uni2519uni251Auni251BSF080000uni251Duni251Euni251Funi2520uni2521uni2522uni2523SF090000uni2525uni2526uni2527uni2528uni2529uni252Auni252BSF060000uni252Duni252Euni252Funi2530uni2531uni2532uni2533SF070000uni2535uni2536uni2537uni2538uni2539uni253Auni253BSF050000uni253Duni253Euni253Funi2540uni2541uni2542uni2543uni2544uni2545uni2546uni2547uni2548uni2549uni254Auni254Buni254Cuni254Duni254Euni254FSF430000SF240000SF510000SF520000SF390000SF220000SF210000SF250000SF500000SF490000SF380000SF280000SF270000SF260000SF360000SF370000SF420000SF190000SF200000SF230000SF470000SF480000SF410000SF450000SF460000SF400000SF540000SF530000SF440000uni256Duni256Euni256Funi2570uni2571uni2572uni2573uni2574uni2575uni2576uni2577uni2578uni2579uni257Auni257Buni257Cuni257Duni257Euni257Fupblockuni2581uni2582uni2583dnblockuni2585uni2586uni2587blockuni2589uni258Auni258Blfblockuni258Duni258Euni258Frtblockltshadeshadedkshadeuni2594uni2595uni2596uni2597uni2598uni2599uni259Auni259Buni259Cuni259Duni259Euni259F filledboxH22073uni25A2uni25A3uni25A4uni25A5uni25A6uni25A7uni25A8uni25A9H18543H18551 filledrectuni25ADuni25AEuni25AFuni25B0uni25B1triagupuni25B3uni25B4uni25B5uni25B6uni25B7uni25B8uni25B9triagrtuni25BBtriagdnuni25BDuni25BEuni25BFuni25C0uni25C1uni25C2uni25C3triaglfuni25C5uni25C6uni25C7uni25C8uni25C9circleuni25CCuni25CDuni25CEH18533uni25D0uni25D1uni25D2uni25D3uni25D4uni25D5uni25D6uni25D7 invbullet invcircleuni25DAuni25DBuni25DCuni25DDuni25DEuni25DFuni25E0uni25E1uni25E2uni25E3uni25E4uni25E5 openbulletuni25E7uni25E8uni25E9uni25EAuni25EBuni25ECuni25EDuni25EEuni25EFuni25F0uni25F1uni25F2uni25F3uni25F4uni25F5uni25F6uni25F7uni25F8uni25F9uni25FAuni25FBuni25FCuni25FDuni25FEuni25FFuni2600uni2601uni2602uni2605uni2606uni2607uni2608uni2609uni2610uni2611uni2612uni261Cuni261Euni2626uni2628uni2629uni262Euni2630uni2631uni2632uni2633uni2634uni2635uni2636uni2637uni2639 smileface invsmilefacesununi263Ffemaleuni2641maleuni2669 musicalnotemusicalnotedbluni266Cuni266Duni266Euni266Funi27E6uni27E7uni27E8uni27E9uni27EAuni27EBuni2800uni2801uni2802uni2803uni2804uni2805uni2806uni2807uni2808uni2809uni280Auni280Buni280Cuni280Duni280Euni280Funi2810uni2811uni2812uni2813uni2814uni2815uni2816uni2817uni2818uni2819uni281Auni281Buni281Cuni281Duni281Euni281Funi2820uni2821uni2822uni2823uni2824uni2825uni2826uni2827uni2828uni2829uni282Auni282Buni282Cuni282Duni282Euni282Funi2830uni2831uni2832uni2833uni2834uni2835uni2836uni2837uni2838uni2839uni283Auni283Buni283Cuni283Duni283Euni283Funi2840uni2841uni2842uni2843uni2844uni2845uni2846uni2847uni2848uni2849uni284Auni284Buni284Cuni284Duni284Euni284Funi2850uni2851uni2852uni2853uni2854uni2855uni2856uni2857uni2858uni2859uni285Auni285Buni285Cuni285Duni285Euni285Funi2860uni2861uni2862uni2863uni2864uni2865uni2866uni2867uni2868uni2869uni286Auni286Buni286Cuni286Duni286Euni286Funi2870uni2871uni2872uni2873uni2874uni2875uni2876uni2877uni2878uni2879uni287Auni287Buni287Cuni287Duni287Euni287Funi2880uni2881uni2882uni2883uni2884uni2885uni2886uni2887uni2888uni2889uni288Auni288Buni288Cuni288Duni288Euni288Funi2890uni2891uni2892uni2893uni2894uni2895uni2896uni2897uni2898uni2899uni289Auni289Buni289Cuni289Duni289Euni289Funi28A0uni28A1uni28A2uni28A3uni28A4uni28A5uni28A6uni28A7uni28A8uni28A9uni28AAuni28ABuni28ACuni28ADuni28AEuni28AFuni28B0uni28B1uni28B2uni28B3uni28B4uni28B5uni28B6uni28B7uni28B8uni28B9uni28BAuni28BBuni28BCuni28BDuni28BEuni28BFuni28C0uni28C1uni28C2uni28C3uni28C4uni28C5uni28C6uni28C7uni28C8uni28C9uni28CAuni28CBuni28CCuni28CDuni28CEuni28CFuni28D0uni28D1uni28D2uni28D3uni28D4uni28D5uni28D6uni28D7uni28D8uni28D9uni28DAuni28DBuni28DCuni28DDuni28DEuni28DFuni28E0uni28E1uni28E2uni28E3uni28E4uni28E5uni28E6uni28E7uni28E8uni28E9uni28EAuni28EBuni28ECuni28EDuni28EEuni28EFuni28F0uni28F1uni28F2uni28F3uni28F4uni28F5uni28F6uni28F7uni28F8uni28F9uni28FAuni28FBuni28FCuni28FDuni28FEuni28FF commaaccentffuniFB05uniFB06uniFB1DuniFB1E afii57705uniFB20uniFB21uniFB22uniFB23uniFB24uniFB25uniFB26uniFB27uniFB28uniFB29 afii57694 afii57695uniFB2CuniFB2DuniFB2EuniFB2FuniFB30uniFB31uniFB32uniFB33uniFB34 afii57723uniFB36uniFB38uniFB39uniFB3AuniFB3BuniFB3CuniFB3EuniFB40uniFB41uniFB43uniFB44uniFB46uniFB47uniFB48uniFB49uniFB4A afii57700uniFB4CuniFB4DuniFB4EuniFB4FuniFFFDuni1FEE :        0JhebrlatnligaligahR4>H- O L IM W W,ILVA rgl/inst/fonts/FreeSerif.ttf0000644000176200001440000355616414265301464015566 0ustar liggesusersFFTMDzXGDEF,:GPOSɆ`GSUB, >2"""Tab~xd74jh0<0T_@wwet w]*sZ"TD@;UZUDx u4JK\HZV'LT8YWWX[[\ rTYWzZZSTYPQU]\\V[^^^`XZYX]SM8LLLL:IMORNNLINNNKMMGL)LJHKLPMKMMMNL LMMMO KKKMMOMLM)JMLMKLKMC,(zJLL>LgPPLYLOMINMNONPMPPw<> $'>F%\ #\?F#v v &F+\\\{!F%\ v F%\ F\v,'>F*v5v/>(| !*EFFTFEFRFFF1FFFTFFFxFxF2FFF{FDFOFEFF+FFgFgFXFXFFFxFOFFFEF1FxF/FQFF=FFF1F1FFFgBI[I[VIFFF  V]Z# G8<8<g<=<<<`<G$MP"MkMNMMMMMJNMLMMML&D1MDGLvMMMMMLMM MNKRMMM!! !u!!!!!!!4!!!!!!! !0!!s!!!!!!!F!!!!GEE0  G EV1211G82d-k1191119q:+..)+;MI.?>=SkC1;qG0RG101G--0G--,G,-G-G-1.1N$1(@@@@?AN@7@>@$AN7       %%%"#%%;;;11:1X8;d11dG7k00Gk l*?]*2?%IHH3+636G//6/G//G(G/*BAB*JA*N*B>>QQ>    k   q  kT @k@77K@4*NN<G<;AdC """ """"&&&&&H&&0 00d%d040d%k+1++%%Q1+%%%4%%%4 ###dd#G' 3N##*%1# dG 1???1>?11??7?q?q?* ?4?c?FG6F8FFGF8GFG6FG8FFGF8Z[G""G"AdCII?1*"&&&1 &C1&1.0G:: ; 0002d#LL2GOQOG2%fHG6C1%d2Gk0  ' h    %c c c c c , M      MM """c c c c y  y  y      """",,MMMM,*3,*3,*3,*',*3c c cc       c c c  %M%'%%%'%%%%%'%%%c  c c c  c c MM"'"I""'"I""""'"I"" 'I   'I   'IK)K)K)K)K)K)K)K)AAA AAA))))))y!y+yy ! !      ,,3=yyy ))))))))K)K))) ; ;))K)K)K)K)K)K)K)K)\\))))))))K)K)K)K)K)K)K)L]lyyvu]      MM ed],,))y0y/ |w)))))yy(yy!M'M'MsMOMOMs+-+;:^(^(oSc   M?M0uD55:EM+XXxD D ,,9,,,,,,,2,2,2,,,9,,,,,,,,,2,2,27,    v "<c*#6!6): j 6 &"Ro !!""f2#2-), 87;"$Mv$]  $ c y ,B   6    >.>.>->>>>>>;>.>.E>EHE>-E>->> >>>>>- - ll>>->>->H->>H->H->>>>>>&>&>&>>>>>>D D >>KlK,K,d$44044077|>|>|>|C|C>>>%%%|U4>>>>@P@>>>>77;7V7u>u>Hu>|>O>|>|8|8|86|8|>|>|8|>|>|>|8|8|>|>|3|>|>|>|>|>|>OQO>|>|>|>|>|>|>|>|>|>|>|>|>|>|>|>44>|3|>|>|>|>|>|>|>|>|>|>|>|>|>|>|>|>|>|>|>|>|4|4|4|4|4|4|4|4|4|4>>>|4|4|4|4>>||||||||||=|=|=|=X>X>>>>>L>>L>LL|>|>|>|>>>>rl>>>>>>>*E@u9?0404|>|2|2|4|4>>>|>|>|>44|>|>|>|>|>|>|>|>|4|4|4|4|>|>|>|>|>|>|>|>Ettt 5#>>>>4%HL >>II 7 7 7 7 7L-##########yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyhyyhyhyyyyyhyhyyyyyhyhyyyyyyyyyyyyy|##|#|^|#|^##################0#7#77"###### # %V%##%H%H%CX2X2X2X2X2X2X2X2%C%H%H%H%" 8 777773G07G7% %t%!#A##$*%!"%! a 5  J Z  ` 1  I a r"#S"##S"M7+777By<2d]########%W!#####"N$##;$#####(##A########7##I#7#A#0#?#####"##########:#/###!$##"###$i##########"#$# 8 "########################""#######~########B#i#<####"##s#D#D#c#c###j#j###"a#"x"#x"?#i$##"fP8d&X222}>YF6wX/CaLLffwwmm~qqDDwXcO\yyy?oonPB*MqVyz&kzooxxxxpptt**~tx1vvvsssw vw}y ?xkskFu+  "8Ma23zo[21(((L661]#,, 8#5#3^'^0^0^=^/  ^0rr44{}DDRRjyjyII00E,6,,,6,3,,,XA -~~%%{{44**|}>>z}XXp}TTrrrrHHKK||XX||77%%-&q?|&ZA|BA!!,,yy>>%%yyCCn IIz{#uQfFeKsM MZLLNKGKKE,KVKAI,K@@@KKKKKKKFfOGKKMM(I(I(IKKKKKKJJJKKKMMMKMMMMMMMKKKKKKKMM MIIHMMMMM?M?M?M?MIIIHHHHNzLzLzLH<GHFFFKGKGKGMMMGLGL}HGLGLDLGLIII)L)LMHHMoLoLoLJJJJJJJJJJJJHH/LxKxKxK'HM>M>MnM'JL1LLJJFFFLLMLPPPUMUMEEEM>P7P5PLM'M:MTMTMTMKKKAGGGnJnJnJMMMMHMMMMMMMMMMgKgKgKMMMHHHLJHHHOOONLLLLQiIiIiIKMIKNLNLNLMMMIDL,LGGGH;HKKKIIIMLVHDHAG^H~M~M~M~MKKK L L LGGGH HGGGGGGGGGGGQQQ Y YMMMMMMMMMMUHMMMKMIIIIIIIIIIII J J JdJdJdJMMK-MMMMMMMMnGnGnG&JJM$OHGGH#HJJJHHHHHIIIIOOOIIIHLLLIDHIHFFF,I,I,I6MJJJpIpIpI M M M K K K K K K K K K K K K K K K N K K K K K KHHH K K K K K K K K K KKKKKKKKKKKKKKKKKKKKKKNJNJNJKKKKKKKKKKKKMKKKKKKKKKKKKKKKKKKKKKKKKJJJKKKHJJ%J666MMHIMMLIIIMIJIJIJIIIPEEEMMMOO$OOOOOOOIOOOOOOOOOOOOOOOOOOOOOOOOOJJ[KMMJMMMMI=KMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMLLHaIaIaILLLLLLGIM]J]J]JIJeJDJJMMMMMMM-H-H-HMMMMMMMMMMKKMKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK:T:T:TLLILLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLeMeMeMLLLLLLLLLLLLLLLLJJFKLeKKKKMeJeJeJKKK)J)JFL6J6JMMMF9y(&MMMMMK%C D%KMFMMKBMMMMMMMMMM MMLLLLL Z i\'R=8>o Y2Ud'gCDhUtO'h   8::|rL3wE+\Wq!:!2 imee pp[E'z'$111E##X'I'''t666p%%NL  pck..B&<8>jLUU;%%H$jj;-@BB@/ SL)444z ?U:O ' 'sqOO^C?; j.*NNFCWm":O'* ' 'c  >%ZM+[Mhq{15Ewf;$+*f\e:o .xet ]*sZ"TD@;  M)F S!AE:f@` ;Js91wUZU1bb  ~357Eauz~ :KQikt~    5 9 E I M P ^ p  ( 0 3 6 9 < B H M \ ^ p t   ( - 0 2   ( 9 C H M W a p :[FHMVX]FZ|")EMWY[]}  # & K q | !!!! !$!(!.!3!9!!!!!!!" """/"="K"W"Z"\""""""## #####*#H#P#W#^#$#$i%K%m%%%%%%%%%%%%&&&& &#&&&(&*&,&c&f&q'' '''K'M'R'V'^'g'''00000000A6<>ADNY}ptvxz| &57P`tz~ !AM`kt~      7 < G K P X `    * 2 5 8 < > G K Y ^ f r     * 0 2     * > F J W ` f ?HJPXZ` Ha  ) HPY[]_   & 0 p t  !!! !!"!&!*!0!5!S!!!!!!"""%"4"@"M"Y"\"`"""""##### #)#G#P#W#^#$#$`%%P%%%%%%%%%%%%&& &&&"&&&(&*&,&.&e&i''' ')'M'O'V'X'a'v''00000A0009*8>@CFVzptvxz||kQ?;83210/- hgfcaUP9+('!  yutrhdba`_^\[WUJIBA430/,+*'$!  OE;:98654210.-,*)'&%$#" y" {yxvmIGE20.,}|{zwvtsqoa[WNID(!R|jg]MJEB=:8.- nmkjihedbTQP 3A8 RSTUVW   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a rdei xpk vj s gw  l|cn T m} b :  y XhqdefzigY!yXXXXLl0 `xX4lHx x $ L t  (  x|xDDXx t,T`@P l X !L!" "l##$ $T$$%<%%%&d'('(0(X)()p**++8+H+,,`,,-`--.T..//P/0T0122,2D2\2t223P344444L4d4|445,5D5\5t55556t666667l788,8D8\8t89`9::,:D:\:t::;;;;;;<<,<<==(=@=X=p=> >$><>T>l>?H?`?x?????@@ @@ApAAAAABBBBBBBCC,CDC\DEE4ELEFhFFFFFFGdGHHDH\HtHHHHItIIIIJ`JJK KxKKLLL0LHL`LxMMMMMMNNNOXOpOOOOOPPP0PHQ QQRRS$S<ST TTTTTTUU,UDU\UtVVVVVVWW W8WPWhWWWXtY0Y@YZ@Z[[\\\]]]^0^@^_<_`H`aab bc`cd@dedeeffgh0hiPij\jjklklHlmmn n4no$op$p|ppqDqrDrs stt$t<ttttttttuu,uDu\utuuuuuvvv<v\vvvvwww0wHwdwwwwx\yDy\ytyyyyyzz,zDzzzz{{{{{|||,|D|T|l||||||}},}D}\}t}}}}}~~~4~L~d~|~~d$4Ld| <TlxPdxdtxx @,llDXH<L(<PDtpThHXltLH4L\p|x$h4L44|(Lh @d(p4DXlH\p8Dt T p84(\ \t4\8```,xL\ $<Tl$4DThx €ØDT0Ű$0H`x Ȭ$ɴHẌtάμD`8Ѡ8H $<TlըTlք׼tٌژHt$Tޤ޼hl t\\H88D\hT L <t\ ($xH444lT ($<\L0l<L\t  \ t     X   `|L(@H@,| 8 !!$!d!!"#$T%%&&'4''(0()()*+,-L-./T/01X223834H456(778\99X99:4:;4;<|<=l=>t>?@@xAABCHCXCpCDDDEtEF|GGHHIIJJ0JHJ`JxJJJJJK@KTKlKKKKKLDLLLLLMM,MMMN N$N<NTNlNNNNNNOO,OOPPPQlQRSST@TUVVWWX$X|XXYLYdYYZ ZLZdZ[\\\]]^^_``\`aTabbcDcde,efgDhhxij,jklLllm(mmn\nnnoooDoppqqrrrs\sstupvvwwxxy,yzz{X{|(||}8}}}~T~|~~(xh|(80d, |@x h$h`@H8(d||$8\T< 4,\(\(dLl80|`8PhŴhDǬȘ0ɘɰʨH,ΨXєd lׄ$`xܤppߜld8L|XpLP4X  `L@8\ <(8L(LHp4l @  X  h       Xl(@Xp0H tP,|l$x0PL|L $ l  !!T!!""|"#`#$l$% %l&&&''((()<)*++,./0`02p3(356h7889|:;\<<>@? ?@A(ABBC(CDEF|GHJJJK`KLTM MNOOO4OlPPPQQRlS0TPU(VpWX$XYpZ(Z[|\t\]^$^_`8`ab<ccd8defg@gh`hiTij\kkllmmnopqr|stu8uvwxyz{x||}}~,~ x(\xTt@P@,T ,TDL4H pp4lpT,$hh<0Hh\40,X\D(l4ÄH<48D`τhlP\8ք׼ؠ|(۴܄݌||l@|HDt8`$8x$XpT,4Td<Px0@hX  \  X    dhH\x$dL|8@t4 p!!x!"#d#$%<%&T&'(D()|**+H+,-P.@./001d22t234l5567`789L9:;p<<=|>`>?@tAABCDEFHHJ K(LMxNPQ`RlSTUW(X YdZ[\]^_`ta,abcld4e$fPghiijkl|m|noq4rDstvwxyz{|~(Xt0,\t<l l<8thXt(P0HpTT4`Ƥ<ʈ˸X0άx<0@hԼ| یd, @dDp0x4   <   pX$ "#,$%%&'(t)T*+-.//1d235\678:;l=>@BCEFHIHJJKL@LMNOPQRxSTVWHXYZ[](^h_L`a8bcldf|gi0jl8mo@p<qXrstuvxLy0z8{L|8}@~P\t0D\<xT$4\0`@LX\ddL¤h( Ŕ@Lj< 8Phɀɘɰ(@Xpʈʠʸ0H`xː˨ 8Ph̘̰̀(@Xp͈͠͸0H`xΐΨ 8PhπϘϰ(@XpЈРи0H`xѐѨ 8PhҀҘҰ(@XpӈӠӸ0H`xԐԨ 8PhՀ՘հ(@Xpֈָ֠0H`xאר 8Ph؀ؘذ(@Xpو٠ٸ0H`xڐڨ 8Phۀۘ۰(@Xp܈ܠܸ0H`xݐݨ 8Phހޘް(@Xp߈ߠ߸0H`x 8Ph(@Xp0H`x8Tl,H`x(@Xp $<Tl8Ph,D`x,D\t4Ld| $<Tl,D\t4Ld| $<TlT(@Xp8H`xl@ $<Tl|d|,H4L4Ldddd|HpxP||      , x  d |  0   Hd<Tl tt,@h0DXl  hDp x!!"p##$%@&,&'L(()*D*,D-H-./H0401\1112224$45$6<7789:::;8;P;p;;;;<< <8H>X>?@hA0A@BBCCC$C4CDC\C|CCCCDDD,DDDdDtDDDDDEE$E`EEEF F F`FG GxGGH H H\HpHHHHI0IJJJKK8KhKKKL,LpLMM<M`MMMMNN(NpNOO@OOPP4PlPQ8QQRR<RtRSSTSST TdTU<UVV$V\VW0WhWX`XXXYlYZZxZ[,[[[\$\h\|\]@]]]^^^_L_l__``,`p```a4abcdef@ffgXgghdhiiXiij<jPjkkll|mmn,nooLoop<ppqXqrrTrrssPssttLttu(uuvvw$wpwxx|xyhzzz{${||h|}}t~~<0D|4@h@dhX<Px$d,x0hlHD,\ `0L,(x`x| hlh,x @`4 HpXHD4x | ,Ll ,Ll<h<d 8d,T$Px P@p @p0T|4`HtHxL0x<Xt8Tp,Hd T°$hè8xĤ4hŔżlǔȜȬ(DTʬDϠl<(dל@pج,h٬<x\<lD<tPXtt 8|0|00$\P 8   @ d tp@@,<D lHX  ` ! !"p"##$$%&'()+..002245<67D8X8899L9|99:::p:;,;?@@d@AB0BCCDE<EFLFGH0HIJJKLXLM$MN$NO0OP PQ(QTQQQRRlRRRS`SSSTTHTTTU(UlUUV4VtVWWLWXlXYLYZ Z[$[\@\]X]|]]^X^^__P____`(`X```abLcdteHefdg\hPikllnoqrTs$tDuvtwxzz{P|X}~pL0` D`x,@xP\@P|X(,PDT@üĬŬp<\H͌Ld`Ѵdd$<`l`4dXݤl8\`H$\|t8dX$p TPxd4DLT4       4 D          ( t  hd(H|8p Th`x0H`x 8Ph(@Xphx `!!""###$<%X&@&&&'X''(@(())p)**D*++\+,,,-<-../$/0P001l2 2x23 3p34(4p455\667$78|9T9:;<;>>?d?@P@A0AB BCCD(DE@EFpG GH(HIHIJ(JJK$K`KL@LMMtMNNXNO(OPLPQ$QR RSHS|S|TTUUVpVWXYZ[P[\]^t_abcDdtefhdjkldmopdqsLtvwxz4{p}$~x|<`|t\,8T4ht$ p¬ŀ(ȌX`˼͸H<<(0,hxXPPdHX  , t@|@Ht p!#8$&(*4,-/T1 234x5 56t7@8089h:L:;<=>x?ABDEGLHDIpJLLMO(P0QlRtSTVHW(X`Y|Z\D]^`abdexfhikhln0oqTrtXv0wx,yzH{({}~$LD tL(x,l08dh\xX<  ʀ˰|ϔp | ڈۀ<hLHTX@ $P\,dp@P    ,  0    X P  d l  8    <  8    4  8   , !4 " #` $0 %@ % & ' ( )d *` + , , - . / 1 1 2 4< 5P 6X 7 9 9 : ; < >, > @ AL BH Cd D E F Gx H Ih Jl K L` MT N OD P4 Qd R\ S T U W X Y Z [ ]$ ^ _ ` a b\ c d fT h i k l n$ o p r sP t v w x y {X |0 }H ~  X t 4   8 $ P d , , | h  $  L < \ X  d , $ T L  t \ , @ h  x ɰ ʬ P Έ d Є Ҕ ` ( Դ p   L ܰ  ް ߔ | D t l x p  | x h |  t X ` H  @    \       D   0 ( 8  p     @  " # $ & ' ( *4 + - . / 0 1 3\ 4 6@ 7 9 ;d = >x @( B C DT E G Hx I J Lx Ml N P( Q S T U V XT Yt Z [ ] ^ ` a b c e0 f g@ h i| j k` l m o pt q sD t v x8 y { | } T X ` 8 $  X , < | \ l l   l `   4 t X Ĵ d 4 Ǡ h l  ̼ ` T t | Ѽ @ 4 d L  d L T x  T H ( $ @ h |  8 8 h  x D    (   ,  8 D h  ,  <     T         8    @  d       h D  ! " # $ % &4 & ' ( ) ) *h +( + , -H - . /\ 0 1 1 2 3\ 40 4 5 6 7 8 :$ ;< < =p > ? A B$ B C D E F G H I Jd K` L| MP N< OT P Q RX S U V W Y\ [( \ ] ^ `< a c e f h4 j k m n o q sX t| v w< xT yh z` {p | ~T \ h 4   ` P t   L D P H x t 4 D   T   ` L d  P 8 P 4 | ` ˆ ø Ĝ ń L \ ʈ P δ є Ҝ נ  < @ d D ( L X     p H h P h H h    , 8 p     H   ! ! " #P $ & & ' (| ) *x + + , - .< / / 1 1 2 3 4 5 7 8h 9 : <8 = ?< A< C D` E F HP I@ Jt K L N< O Q R` S UD V XP Y Z \ ], ^l _ al c4 d f$ g g i k l n, p q s u v xl y {d | ~ \ @ < ( P X x H l `  $ ( H p d X d D x <  X @ x  , D l $ < @ H $ t  \  d Ô H h p | < H ʰ  ( @ X p ˈ ˠ ˸  0 H `  ͸ Θ | ( d T  @ ל h t X 0 ܀ L ތ ߀  l p T  , l !n./<2<2/<2<23!%!!!M f!X 7#'.546322#"&4 "5I, l #*P 3 ..MK #&54632#&54632+  #.w(#.w##7##7#537#53733733#'#3m:!:!ktnv::ai&7777,$*046753#.'#5.'53.5654&4ZX"q0 F?(G4a`"?N-RGcOg)ar,@N ?? (o@A,,C,KOWWOI7W-R#2`.9= 5C2#"&5462>54&#"232673##"'#"&546"32654'.16.(3B6B+L)).J"&/)/E('0_4:'wV1EV0a!=f "s83:r)3G:^Li0!/hm $x&Or ]K4_I"U *-8B654&'533267#"'#"&54?&54632>54&#"327&FU*I0:SA[0 #&54632e #.w0O0.54>7$8G6%%2M2! ,6226,-P[EHUO&$:]Y]_<"O'>54.')8G6%%2M2! ,62,B<-P[EHUO&#<]XyV/E I46='5#"54>7'.5463254&5462>2#".'#"&&1 $%Y' R23,!V %E"D'%2.R- #7 "`  WZ'7 2X 533##5#5BBBB8sf#"&54632'654  !".>2 R 3&-T82'3#'?Fd 72#"&546}!" !d" "#DN".5467632" 4&4R0 5+7Ob||eB0JaX+X*4<o"57!5>546$;8'Q[$//>323267!57654&#" !)I.Nk"! 7zN?4?"A+"fKq+ z?N9I+,7232654&'>54&#"'>32#"&546Q["7L6/M"16=1/GYREW*4#QKj  %##5!53#fM:,N@@CW (%4.#"54?3267+#"&5432326e/CS= m &*%9KE#8B+Y;P5R-  Y Uuq;\8$ !%>c" "&547>7>32"32654&e{7iUv/0!VfumD/LB58Gw&#qq`g<;tYR^g ##"'7A)+ ;rT38$2#"&5467.54632'32654&'>54&#""ZAkZUk1QO-lRKa<\<,$F91=*B <3/=:sC[:M\\I3E=ED1DZP>3H,#F0AP=1*?44=8+*J#'>7#"&546322>=4#";rJLQcwYa|WN3dg01, Cz9p[e|e9%"$ %'!68YiQ 2#"&5462#"&546!" !!" !" "" "Ps#"&4632'6542#"&546 !".<4 R,!" !23&-T82" "%5% \ BHx!5!5BBBB5-5\ HHBD*2#6?654&#"#"462#"&546Ll""%2%?-%:&0]L UF$K/-@ZMA@UG2F& 0|S! t)2>"327#"&54632#"&'#"&546327332654&4&#"326~Yk I[5՘nJ$36G%3qS EA'1P)_ 0H0!Đ̩|a(!HA/Z& .zKpoQ'.%#5>54/!3#5>73%3().D%).8t+`u)5m8Q*5%#!5>54&'5! 2>54'&#32654&+"Q3dE>"!?4="-B:T0_FMZV,:9# 87!3 ; :+\#I?;CFy46323273#&#"327#"&@p !  7m-LQ.vi.UE!!⺢WAe=B%#!5>54&'5!24.#"3 6TX9;[W9m,FrI>N-V\C, 67)AYV6+OQ:% U)7;2673!5>54&'5!#.+"32673#.+!Hk\%-7 7 6U @%  &>P3Q!55!C& '8>" "$%#.+!5>54&'5!#.+"32673 (=!:9 7 6U <) =#6!#>5!C& #< ."326=4&'5!#".5463232673#.9X6" z6O9,@-ZbJ1:q  `|)@VO(#8,,0IzN!N]+!54&'5!!5>=!!5>54&'5!/:: 8: 8:::g66D5 "?5 "?66;74&'5!!5>s!@)?#$>?"m7 7D7!  r723254&'5!#"&546; & ==XQ+8l B77^g( "35!!563654&/!5>54&'5!7654&'"431D2' *I9j :; :=N1I"`8i7#>5!7͡H  V%2>73!5>54&'5!3b2L* 07 7;"7'%#!55!!5' _$ ##5>54&'533!5>5$:>#!>8 7; =&mL1/M7 5D5!#> ##5>5.#534&'53 F$:>## %;3+&xL1/M#QL/" !"&546324.#"32>cG+:71N- ,W<=Y-VHpD,*?VO)3bb<54&'5!2%3254&#" #:dB'#;98-TS2"`e06'7!!?6&J:MI"N-##"/.546 4&#"32>%306!=V i/drs_2N. (BE&1M. K7`A6  OGz7"•)?TM(XB)@UP%/2#!5>54&'5>54&#"%+NS2 %8 :88yqY^#J5+46 #>5Mi"[V?Q#"#7!#.+!5>56T949U6">> l.RS-7 !@%73267654&'53#"&54&'5!Ka8Z$:> 5iM{;<dg+$+]K1,L;XO*}876#.'5!#654&'5%'& .) ) ;%B%[o0,# #.'53'.'5!654&'5(S:?''& k!"+ M}&'ߦYF+ R<" FS- 4!563654/#5>?'.'5!7654&'515/()23_w4 ,'*@mF=2.0U*q()!:+LA Og4 v;2 &!5>='.'5!#7654&'5'8+$CD!24" .'-B9!AI? U%2>73!5#"#7!. 3B! P& ) a,$!Xd+ #3#"3+Z12`43# CDN"d 3254+53#"Z-1VӃ,4)#3#\D754#"#"&54632327#"&'#"&75327>%+GY/L*aGR> 'V<.;ZH%"' a&>''=S/AOQ!"'I, - $>32#"&54&#"576732654&#"N.KecDE;'<%0}\k)\S[m.!74632#"/.#"3267#"&X?[" =KWD+>$ '&>!Sko=*.aMVm*4 4 }*'5#"&5463254&#"567327#26=4&#"X0PSfzV63[8&3>(9DL @Cw`j+#+(5#53>32U 9{z =6RRP^-;DYt 87: py#&/=L7467.54632;##"'"'#"&5467.32654&#"4.#"326I>2+aF((MS]? (N7B7TyGf-5JPBUh8Dey,#'9-#(6 :>/D_ '+)EV*:/8-D9(7'(% !(6+0=)2,HY1 *#5>54&#"5767>32#5>=4#",+ D/#D,{)+K3W45 -'4 3j"57#5>=4&2#"&46> 140766!!*&"567#"&54632326542#"&46M-PLVS)52!7jp<>M{<!*457677654&'53#"#53254./#5>54&#"W&%S>5! 6o \z  9:&!  '$567#5>54&#"c<0/ o)(#?567>32632#5>=4&#"#5>=4#"#5>=4&#"HD>0=/ *i)$*567>32#5>=4#"#5>=4&#"J@3;#7?%&I*$&&O0!OG%"/a"+% 2"&54632654&#"`|}{!N?8@P?5Àbhegk`UgV',567632#"&'#5>54&#"32654&#" ?Q@PI^yY + 8,E#6CC8#C MOx]m/'#<,gSWi,'$73#5>=#"&546323276=4#"h6 )5$DYFZ^6>12$]@J  *Jx_l+PC "dgO#"&#"#5>=4&#"567>32(,2"30PD%4j#:+ &!\5)3\1273#.#"#"&#"#5332654/.54632 2+"++l-'S:T   (&-4:@5M;!: C8&+@7%4L '!-!$B*6E C#327#"5#&54>7672e 0HY5 2 /+# L- 6+ t #%'5#"&=4&'533276=4&'533N;++<7B$*.*/"2S++G;#-"&%##"'.'53654'5 x# fc/22/N$ /.'537654&'53"/#"'.'53_!#TZ{ [pc6P) .* 1+',V&2>54'533#5>54/3#5>?'.+53  (3S#[O(r^  +.0)*x" { #E&)2654/&'53654#53#"&54632>,u '  sa0 (O2 *2|O  hl\!%2>7!5#"#7!'.  - [ "#!7vkdK^.=4&'>=4>7^XM#22#.7,4'&88&'46T4..4,7  68>44>86 C3CBNK|"25>=467.=4&'!*.#22#.7,4'&88&'45%4..4,7  68>43?86 (@23267#"&#"'>2~#6"6#2~#6"6@D 0%D 0%a& 3#"5472#"&546 !54 l4($*P : 5vC"+7&5463273"&'3267#"'#7&#"t],#/K& e ,@' &$;!1"Ps=K Be|6 ,89 C ]M6J =H%#"&'#"&54632654'#53&54632"&'&#"3#32>322654&#"'D( =3*%2)lkjY8J,7-2 }yTA"2e##3 -2$##""* -$!k5((4IB,]-##y+  %: Z&'7&547'76327'#"'"2654&b))b2`=BE8b0`''`0b9DA>`?WWzUUl`;CE9b0`''`0b:CB=`2b))bX?>YX@>X47#535'#53'.'537654&+533#3##5>5_)*#A vp'5\ 02(L(J*03(L(I5$%>C33CBBBFlAM4654&#"+#"&5463232654.54632.54632#"4&#"326"$&/"YA38&OA:P"+(/6LL6B1 <(M>7ID&'1)%&" ' *qJQ5C1;&9F:*$"*# =5:T03D2<(6D8*4w&2x( <n 2#"&54632#"&546Bn((&%12#&#"32673#"&54672 &546"32654&"V^CHJB-8]+[ozJɒyvuFY[TS]'/L iUZoˏȐ*~{|z*4#"&54632327#"&'#"&54>754#"26=L =/i 0+('+$ 5&q   &`s ,&*M*!-7#"./7>7632#"./7>7632q O4A W (Lq O4A W (L I-;Q ' 9^ I-;Q ' 9^l%5!5!JlB'& (4@%".'##5>=4&'53232654#72#"&546"32654& )0 %% %4?O9'%+!$GȍȏvvsA c  ! 2*H O6].+O˔Ȑ*|{x #BY!! 7Y69W 2#"&547"32654&xST=:S+==*+>>S=323267#57654&#"2:I&.Vy %bQ+6 - -;/%D-U UkW2-F#%4&+5>54&#"'>32"5462326?4+$?.-?5^dcn:9::>86@\mbW65!"??[_TF6 2#"&546}!" !6" "4)73632#"'732654&#"b)# (.C:-'% ccA% '- 9#5>54#"57 %v&  70 2#"&5463254&#"@QXA?RU ,%G-$ 'K;?UO<@Ok=QW9H(,!-747'&5432#"'47'&5432#"K6  7( AfD K6  7( AfD *]A 6";XD ]A 6";XD% #%##5#53#5# #5>54#"577F/F>1 %v9ZZ1 N  73 # #5>54#"57>323267#57654&#"X>1 %v2:I&.Vy %bQ+6 N  7  -;/%D-U UkW2-F 7%##5#53#5# 4&+5>54&#"'>32"54623267F/F>1?5+$?/-?=Wo4%9ZZ1 N,)%!3,0#'+#N:N2'%&x(4>7332654&54632#"&2#"&546-8; %?-$;&0]ELl ?-V>i;O?@UG2F& 0|SUY,! z#\$z#[$v#X$R#h$C#j$#f$_:=%.+;2673!57>=#3#5>7654&'5!#.+"32673%3$71LQI+,-@D!  )14ELWoG77-%0R!15}!. 0)#>F?)y7327#"'632#"'732654&#"'7.546323273#&#"-LQ.vi-U  (.C:-'% %}@p !  7mRWAe=B4% '- Y!!⺢ Uz#\( Uz#[( Uv#X( UB#j(;z#\,=z#[, Bv#X,<C#j,-#!5>=#5354&'5!24.#"3#3 6TX9SS;[W9m*CwN>N-V\C, 6,7)AYV6'IT=), R#h1"y#\2"z#[2"v#X2"R#h2"C#j2& 7'77''00000000"!)7.5463273#"'# 32654 &#"+XWH1X,[TO1Obs;"B_91k D^:2tl54&'5!32%3254&#" #:dB(#;98<Px"`g _06(47!!?6#< bMH 3#"&546323254'&547654&#"#5>54>32hK+6@ _0+'/&%I4N\9y#Rq)   vAJ:1(r2LC$SE6?%"\8D%"[7D%"X8D%~"h6D%k"j9D%"f:D&x5BI"&54632>32!3267#"'#"&546?54&#"'.=2673.#"(\DA4"3"LL  3+A$ '_?Q03@%3AEPV ( [:'8J=%(+( .>-VaJC,5UJI*=1-C!$?1%54!2-$3$A;:)674632#"/.#"3267632#"'732654&#"'7.Y?[# =KWD+>$'V= (.C:-'$ &L[o=*.aMVm*4 OI7% '- [ y"\8H"[7H"X8Hm"j7H"\#"['"X  n (2#"&54632#"&546"57#5>=4&; 14n((766!(#"&54632.''7&'7732654&#"}c]}zZ$4& *,{!y>G*1A&_![N@9?P@5A~de#7K-A@, 20jaVfV~"hTQ"\TR"[TR"XTR}"hTRk"jSR%!5!'2#"&5462#"&546!" !!" !B" "a" "'"7&5463273#"'#3264&#"}`{a,09'Ab_/.A% #/8?ޟ%+5ANyfm}Fzh{*b0$VFf "\?X "[TX "XGX m"j@X&"[T\',567632#"&'#5>54&#"32654&#" ]4AOI^yY + 8, E#6CC8#CoNx]m/',gSWi,&q"jd\#Z$%>"Z:D}#d$%"d: D[#g$%[:G2327327#"&547&'#"&54>754#"#"&5465327>R> +5;*6V<.;+GY/L*aZH%"' OQ!$L, .++I''=S/A!>, - yz#[&"[LFyv#X&"XGFyC#e&n"e6Fyv#Y&"YLFw#Y'W*>'5#"&5463254&#"567327#26=4&#"#"&54632'654X0PSfzV63[8&3>(9DLe  !".>2 R @Cw`j+#+((9DL>-" x"c#4@Cw`j+("ZDH Ul#d~("dD H UC#e(n"e8H [e#gl([&,3267327#"&547#"&54632%3.#"a010G$6."+6;*5Weu\LT *.Z?[-09*G'1$L, .* xho[\ A2 Uv#Y("Y:H u#X*&"XHJ k#d*&"dTJ C#e*&k"eDJ .B%4&'5!#".5463232673#.#"3265#"&54632'6549,@-ZbJ1:q  `W9X6" z6O   !".>2 R8,,0IzN!N])@VO(# 3&-T82&/=L`7467.54632;##"'"'#"&5467.32654&#"4.#"3267632#"&5467I>2+aF((MS]? (N7B7TyGf-5JPBUh8Dey,#'9-#(`   !".>2 R6 :>/D_ '+)EV*:/8-D9(7'(% !(6+0=)2,HY1v 3&-T82#X+ z#XRK+/!5>=!!5>54&'5!!54&'5!!5f 8: 8:::/::k/)D5 "?5 "?66==6^^ 24#"#5>5#5354&#"57673#>32#5>5K3,+pp D/ss#D,{)+,j"456 6t-'4 3KJ#h,.r"h B#Z,$>"Z;}#d,"d [#!327#"&547#5>54&'5!; $+5;*6?"!@)?#$>.$L, .+ 87 7D7![#."57#"327#"&547#5>=4&2#"&46> 1!++5;*64076*$L, .+6!!*;C#e,"57#5>=4&> 14766!#-M,&#ML ~#X<-&2"X "#T.#TXN8#"&#"#'&+#5>54&'533267>32) %"26"}" 66C)0$+51 9b  '' HF& V#[%/&~#[O V#Tp/#TO V/%2>73!5>54&'5!3#"&54632'654b2L* 07 7;"7  !".>2 R'%#!55!!5' 3&-T82\(567#5>54&#"#"&54632'654c<0/    !".>2 Ro)(#3 3&-T82 #y,/#y(O V#%2>73!5>=5754&'5!73b2L* 07 WW 7;"7'%#!52125!!5Y1Y54&#"#5677#5>=5b c<MM0/Nj#5,5)(6, |#[1"[TQ #T1#TSQ t#Y1"YTQ"Q1T &.26=#5>5.#534&'53#"&54632b$:>## %; 4N)52>MCxL1/M#QL/3+tf<&02654#"#5>=4&#"567>32#"&54632$I*$&&J@3;#7?VS)52>Maa"+%O0!OGjp<"#Z2>"ZTR"}#d2"dT R"z#i2"iTRu0=23!#.+"32673#.+;7>73!"#"&54>4&#"326V t+F =b3*hF9'4|/A&, (?UR/4[ca\5/C&%=;(8GO|K172/!+23267#"&'#"&54632>32%"3254&354&#" 5'$;# 'R:.;C3[sqY.D&:)=^C-@xg;-"P*?J)(0QD,33,dg"**"QfIWpx|*7#[*5O"[U#T5O#TUv#Y5O"YU*|#[p63n"[1V*v#Xq6%\"XV*)G.#"+632#"'732654&#"'7.#"#'332654.546323273c<.:DOcXuU  (.C:-'$ $!O %bC7DB^]BgF*b XT4)(H,5g>Mi3% '- X[V?2/I47V9L_""3)\J273#.#"+632#"'732654&#"'7.#"#5332654/.54632 2+"++l-'S8  (.C:-'% ' 6   (&-4:@5M;!: C8&+@7%4L7% '- ] '!-!$B*6E*w#Yp6'^"YV)Q0!632#"'732654&#"'7#5>5#"#7!#.+B (.C:-'% )> 6T949U6">A% '- c!@.RS-7  )C3632#"'732654&#"'7&5#&54>76723#327 (.C:-'% &B5 2ee , 7% '- \m- 6+ t /+# FQx#Y7 ,/#"&546323#327#"5#&54>76723'654   !".R%e 0HY5 2R< 3&M< /+# L- 6+ t82Q#53#"#7!#.+3#!5>5rr6T949U6rr">> :-.RS--7 !@ C##535#&54>76723#3#327#"5F995 2eeee 0HY-b 6+ t b-/+# LJ#h8 r"h/X#Z8 >"Z.X}#d8 "d. X#f8 "fBX|#i8 "iTX[473267654&'53327#"&547#"&54&'5!Ka8Z$:> &;<+6;*34,~{;<dg+$+]K1,L[[12,$L, -) ~876 [0%327#"&5475#"&=4&'533276=4&'53; L+5;*++<7B$*.*/"$7+$L, i++G;#-"&%#w#X.:#XZw#X<&"XW\C#j< U{#[="[8] UC#e=k"e7] Uv#Y="Y8]".#"!5>5#53>32U 8 =6 P^-;DY287: py#,5354&#"57673#>32#"&532654&#"F C1N.KecDE;'<" x"%0}\k)\S[m.Q+8C%#!5>54&+"#"&543! 2>54'&#32654&+"Q3dE>"9 $3<4="-B:T0_FMZV,:9# 83#25)!3 ; :+\#I?;CF'`# +32654&#"7.+>32#"&54!:'>DE;'<  N.Kec#576732#!532654&%=9 #&66!(ee:KqA( 3gF/#g,> !BjHH &51<=%,-(Y#>32#"&54&+57632654&#"N.KecDE;'<%0}\k)IqCB\S[m.y"&#"#'332654.#"'>32*@p !  7m-LQ.vi.U!!⺢WAe=B&6*2327432#"&#"#&#"327#"&546k?r  )52#7m-LQ.vi.U!!<3$WAe=B*:174632632#"&#"#"/.#"3267#"&X1& x)52#" =KWD+>$ '&>!Sko<3$3.aMVm*4 4 }34.#"3 #!5>54&+"#"&54;2@,FrI>m6TX9/ $3<[W9G+OQ:%)-V\C, 61#25))AYV'`&74>;#"#7!"3!"&7327&#"'<{VF~<%&;q{\L&##3J&!<>%s':9<&h^IX%-/ .726=4&#""#7!"327'5#"&546325%4>(9DL .!0PSfzV63**(=#"#5 $A U6 7 7-%\k4, >& 9& &C!5D5!Q3 ">%.4>3235##"&#"327'#".4>;5"&8,i1Ro!/$iJEg,= &K4g^!7-dO! $?'Xm a41600!M4"+23254&'5!#.+"32673#.+#"&546 & 7 6U <)  (=XQ+8R B5!C& #<=#^g( &&>32#".#"3##"&546323265#5gP_-;9zzVS)52Rqx#&%Yt ^jp<;P  06;%4&'5!#".546323265432#"&#"#.#"32659,@-ZbJ1:q )52# `W9X6" z6O8,,0IzN! <3$N])@VO(#%0#"&54>7&'5!7654'534'321E9VH=I(, %m{=X!.(K [T(BGPM>!C3.'({(6(2 >#".6.#"#5>54&567363232>54.546322X89D%%67,,"i%9W2:*(.J#%%4g[8.IXYI.?1"2! R/L\\L/Th,(#82F%#"&54567327F+T<)OmD4!BLD;oZ#K5354&'5!3#!5>=r!@)?#rr$>?":-7 7-7! 8"6".74#"7!5654.'!5>54&'5!7632"<;:*>8qh"8;#7:"^P/h  5:1% d6!%=6 8XK8"&#"7654&'53#"#53254./#5>5>32A79%S>5! 6P^-<DKYz  9:&!  'ppy#5673##5>=#5354&#"c<cc0/aa o-)(-#/%#"./##4&'57&#"#54632732673C:Uyp2$$(" e[\ [e'S,MZ5*?5 E,> % =%2654&'5!327'5#"'#"54/5!3274&'5!Y8W"0 3"YQ LH(a ]i4 5(4O5$4458#"2[,"[9$fflD4K:J8(3&%4&'53##"&546323265.#538%; F3N)52# L/3+&tf<;Py#8*567>32#5>54#"#5>=4&#"J@3;#7?%&I*$&&O0!OGS%"/a"+%"24.#"32>4&54632#"&54632326>+:71N- ,W<=Y-d<lX?U3AHHpD,*?VO)3bb<54&#" &632>763274."2>* .M,DڴD}-Ji$3-:@/WtW/.WvW.(24:Y(41 T'B/%9'86g_99_g67f_99_f'"3#5>54.#"#"&546326324.#"32>* E'_byx`w>MUv(u;';; ;),8+$93H`daTTY&$KK/^>&QU6>L 43254&#"#"'!5>54&#"#"&54;2"`eT #:dB'#;96$3<-TS2OMI06'7!!?3#25)&J' 132654&#"7"&#"632#"&'#5>5>32E#6CC8#C78@PI^yY + 8,P^-;N,gSWi,KYOx]m/'Epy# .72654&#"723#!5>54&'5!\E6D,dbSz%8 :8!@)?#<(#7K/V"4T6 #>7 7g*/"#733263232673#.#"#"&54>54&73#&7 T:S'-l++"+2 9";M5@:4-&$  L4%7@+&8C E6*B$!-!'  2B@%#"&5#"&463232>324&"2@29If)>7672e 3N)52 ,Y5 2 /+# Btf<;P=- 7+ tQ!#.+!5>5#"#"&549U6">> !6<S-7 !@&25)^ "&#"3#327#"5#53>32479{z 0HYRRP^-;DKYt /+# L- py#4Q2>2#"&5#"#7!#.+ (8+QX6T949U6  (g^s.RS-0B:P373267654&'532654&54632#"&54&'5!Ka8Z$:'0<C6;#5iM{;<dg+$+]K125)4<+H;XO*}876 |1%'5#"&=4&'533276=4&'532654&546323N;++<7B$*.*/$3<y"2S++G;#-"&%#25)v #! #'&54&'5332>'.'.7>!9Q]O=. "0 $/'8+ I87 I^cs - 5Bj#+!5>='&#"#"&546327654#53# 8(??&A/,o42YE(!&; ;_ 30J6+!&6#".#""&5463232654./&'53"7632 %= #28- / ?#r &  s<>s(WF*# D#y!8G ( U %2>73!5#53#"#7!3#. Tt3B! a& ) +- ,$!-%2>7!57#537#"#7!3#'. Vtk- [v_}y "#-!7v-"327#"&54>3!#.+^BW5vi.UXyD1 5$GJYDBe=Bx^&NA',A(/j467'7!.+32632#"&W[/#WR20a(;EaMx u#uH2G<8*p.3#"&54>54&#"'7#"#7!63232>32AH=a-AA-(,Sм .V 7L5LL54$ +>:*?'!*,!=5,D*&1#"("$%!5767#53654&#"'>323#32677z7^uMB9=kWMh/a$$ :2,73ANC?ZmhLDK,%D&%#"&'73264&+54&'5!#."#"32D`U=eyMmmMZ"5(2 9\_xCDpcc5!!+ I$+#"&5463232654'.'"547327&+'zj4^ B78 nY Ui{..!)!eH {D+%#"&#"#5332654.=#&5476763#{W:M 6<#./BC/5 9,ee+l**w9H CI&#-#'@)P 8Vt ..@5'&3#5>54&567>324&#">9be9$4**IGf5V2,'E\9>zfO"&1()3L,>>*=C_CM#__/)f%##5#535#53533#3)22222'v#?'t#@'#@G #-c/ &%#Mc/&#MO D#-1 &#M1&#MQv#Y$%"Y,D @v#Y,$"Y"v#Y2"YNRr#Y8 "Y:X#Z8#s!8 "Z@x#sXc[0I%#s!8 "[Sn"j@XcY63Z#s!8 "Y@n"j@X#s!c\1)+8 "\/n"j@X HB#s $%"Z7x"j7D#Z8"$e%"Z7x"De-_-#Zf&xY#o 3232673#&#"326=#5354&'5!3##".546v>j ??a7|)`EE!70;;F3`cH.!ӫ7\m<t,4$4,:1NR &;GNR23263##"&#"3##".547#5367.54>7&5464&#"326.'!2 _1$ S_@ $ .N4E+B8;&+2 #(]b51%&2'&#hO0$:"'*2@S172,3> ( ,# .! )YJ]7k3NF;8 +,8 v#Y*&"Y7J"v#Y.v#YN"[#22[#R"[-#2"2Z[Y#"RZL#Y}y/j"Y 1&$567#"&5463232654#'37M-PLVS)52}>|"yz7jp<>M{<gg'#='t#]'#]G *&"[7J="57#"=!!5>54&'5!!54&'5!326=4& ,O7 8:::/:: &>77'9@)r5 "?6666*.Na! z#\1"\TQ%_z#[f&x#[""[Uz#z$#zkDl#|$%#|D Uz#z(#zhH Ul#|(#|H;z#z,5#z ;l#|M,#|/"z#z2#znR"l#| 2#|Rz#z5O#zUl#|5O#|JUz#z8 #z\Xl#|!8 #|X*.B23273#.#"#"&#"#'332654.546#"&54632'654*b c<.:DOcXvV2g %bC7DB^]Bgx  !".>2 R""XT4)(H,5g>Mi"[V?2/I47V9L_ 3&-T823\1E273#.#"#"&#"#5332654/.54632#"&54632'654 2+"++l-'S:T   (&-4:@5M;!:C   !".>2 R C8&+@7%4L '!-!$B*6E 3&-T82Q+#"#7!#.+!5>5#"&54632'6546T949U6">> D  !".>2 Rl.RS-7 !@ 3&-T82 C/#327#"5#&547>7672#"&54632'654e 0HY5 8   !".>2 R /+# L- >* t 3&-T82v#Y+v#YKB#e$%n"e-D )U#z()"zBH"#s#Z82"ZLx"jSR"#ZB#h2"ZLx"hMR"B#e2n"eSR"#Z8#e2"ZLx"eSR-#Z<&Y"Zc\B-7#"''674#"#5>=4.#"567>32764#"326B7M{< D&%'5#".54632>77'54#"3268SX,9N~a3> #`FA=-,;$S%1F`8c# #McvL,P?$ E (32654&#"7"&#">32#"&5>32:'>DE;'<79N.Kec7.54632#".#"6324#"326}?9+ >?|d2c ?B10T:;&+L%U=d[ HrGf7.""oC:cx4e/&[ 1726=4&#"7#"&5463254&#"56732632#"&5%4>(9DL0PSfzV63[825)SV**((9DL790PSfzV63-<**(32327.54624'3260" ;'&|dI=-L/BJ~T99/4  &"'1?Bw,2$7 @--4Jf0F1- HD61KYK 3),o))6?32654&#"#"&5463232654&#"#"&54>32#")(Z3<-$ .  1#(*# "61AhE*/GgCl ]>3%45 +9$#=<(5A.@E)3V#".4654#"#"'732654&#"#"&5463232654&#"#"&54>32>2327.54620"\ E*/GgC+(Z3<-$ .  2#(*# >A!S0 m& &"w,2$7 i !(5A.@Ev ]>3%45 +9$ ( ({KYK )0%#"&546324&#"#"&543232654&#"326=L'WmnV'L=G//G\-$ . " . $-+)J]\K)+k(8ZX8(.AA%44%+=}MN=&5673##"&54632326=#534M-PL??VS)52eeW jp<>M- .<&m.<"&#"#".54632326?#"&546325>323276=4#"C79/\@2)+7DYFZ^.2P^-;>12$]@JDKY'GD(CHmJx_lpy#+PC "dg& /73276=4#"".5463232657#"&5463273n>12$]@JZ2)+8DYFZ^6=6 /\+PC "dgCHmJx_l$ 7'GD('%#"&546323273#&#"32=4&'53saQ*j*?"SSK&!~r`t&AH(Vl#m% +9#"&54>7&'53>54&'534.'32'p&<=42  !>D'  !:*!ET@XT8("%!0JmmOB7$!(#8) ,.#"#".547&#"'6326324&'32>)g6V@-0 , /BJ~!#~/.,.'/ 5R<+k`9TLX=1- 8a32#5>=4#"#5>5>32879#D,{)+K3,+P^-<DKY-'4 3j"45\py# &4"&#">32#"&5463232654#"#5>5>32879#D,{VS)52K3,+P^-<DKY-'jp<;PYj"45\py#"L0"57327#"=4&>  0HY7/+# L!7#5>=4&'534444f66664+56732673#"'#5>5&#"#>3254&#"c< 0)0/# 5%  o 91)( .14#!+##5>=.5463254.5673#.#"`,+"""#b=`!!0*) !) &i32632#"&54&#"#56725)SV c<*P;<pj4#/-4&'7!#5>54&#"#567!#"&432326SV0/ c<>[WaF:(a/32Hu)(# xMZp*80=/ *i)$$&E4&#"#5>=4#"#5>=4&#"567>32632#"&54632326n +B+++B:(*HD>0=/ *i)$K/TTjp<;&04&#"567>32#5>=4#"#"&54632326PJ@3;#7?%&I*$VS)52-%O0!OG%"/a"jp<;&[4%32632#"&=54#"#5>=4&#"567>3225)SVI*$&&J@3;#7?P;<pjMa"+%O0!OG##5>5.#5354&'53, -~-/l !0- / /?%"#"&54632;#."32673#.+6:>74&#"326BBVjsh^)5Y()Y )! (#1 7)'rrXj b '( !()E="(XM)7%#"&'##"&54>32&"32>54&543232>54`R9??9R`\Kuu '",/.+1WI;;IWMy=.546754&'53>54.'kcj0/kj0/EQG5TGPQ |aiy k)(hyj^~ w)( zI*PH g nPKxE UJE J&172326=4&'5332732632#"&'5#"&546",2"30E25)QW%4X#:+ &!BP;<kg\5)8O#"&#"#5>54&#"567>32(,2"30PD%4j#:W+ &!\5)&S)"&#"32632#"&54&#"567>32(,225)SVPD%4j#:P;<pjN!\5)".#"!5>=>7>32V 9 =6 L/-;fY87|B:$"'#:"#"&54632!5>=4Z;-/L 6= #'"$:B|78Y &2;#'##5>54&'52654&#"bSzr t(*$ %H?/7K/V""i,) .3%>&"8  3&\>273#.#"#"&'32632#"&=332654/.54632 2+"++l-'S:Q25)M4 (&-4:@5M;!: C8&+@7%4L5P;<dr '!-!$B*6E&>32#".#"#"&546323265gP_-;9VS)52qx#&%Yjp<;P )".#"3#3##"&546232=#53#53432$<{z{{"B$'2325)SV5ce1P;<pj  t " X '%"&54635#"#53"26545#4&+2`Hl:?ZZ@: hHa[XX[H^ N;BXXB54#53%f*,Y+e,# 0'+v,% ?35&U"%2>732632#"&5!5#"#7!'. 25)N3 - [ "#P;<ft!7vk&%+'>7#5#"#7!36324&#"326c7I * '  /[9m@"S!7*S6WE C&2vkX2A/j4&'7#"'7!#"&432326$SV#0[WaF:(a/32Hu#u xMZp*8&.DU:6D/0CP@F *3_VX6EsW5&%63'%2#5>=232654&#"#"&546ZdP0/ DWK= "[n^|z)(mVMa.*='&2#"/.#"32>3#5>=.546?[" =KWD /0Pd=*.aMVm()z|^n' 4V#4632#"/.#"3267#"&5X?[" =KWD+>$ '&>!Sko=*.aMUl*4 4 |a"y{RD) 2#"&#"#&#"32=4&'53#"&5463246321a*j*?"SSK&sa'.xa";k<xt&AH(Vl#m%!~r` bO[ $.#"&54632##"&5434.#"5673#"325 RS4'/DOMS'#0'9xS(8C#D/sN7 0#3 N45"32>73!5265h /2# }/ i,)(7 "|''n 173276=4#"%"&#"#5>=#"&546325>32n>12$]@J79)5$DYFZ^01P^-;+PC "dgKY=  *Jx_lpy#'-23##5>=#535232654&#"#"&546ZdPff0/^^ DWK= "[n^|:1)( 1mVMa.*='.2#"/.#"32>33##5>=#535.546?[" =KWD ^^/0ffPd=*.aMVm1 ()1:|^n#+:%".'5##"&5463254&567!3267#"'54&#"326|z *WY]vY:0&V=LE-k0$V?(,;B1==@]\+%k(E(0(M%#".546232654&#"'7#"7'5##"&5463254&567!54&#"326hC:* DAH@, ϰ/"(*WY]vY:0&V=FWeQ?(,;B1= fq, \G@F /(4=@]\+%3_(7#"'5##"&5463254&567!3632'#"%4#"326%54&#"326 c7I * ' *WY]vY91&V=L9m@"0$E$6Z7*Se?(,;B1=6WE C =@]\+%k(04 A(76763#;2654.546323273#&#"W:\5 :]]3#./BC/S9=  T.0FE0w9H-Tt T&#-#'@)8B {$1#&< "-4".#"#"&546232=#"5#'>76763432#32"$<"B$<,<\5<p"Bp3 n&%Yt@&%Y8-VtUU DCL%#"''>7&'#"5#'>76763#32>7&54632#".#"6324#"326}?9+ G 2X\5<ee3  |d2c ?B10T:;&+L%U=d[ HHq-Vt S  (/f7.""oC:cx4e/&M".#"327>32#"&5463232654#"#5>=4+!5>5#53>32A 9{e"3;#7?VS)52I*$&&=z =6RRP^-;DYt O0!OGjp<>Maa"+P87: py#55673254.546323273#&#"#!5>54&#"c<0iQ/BC/S9=  T.0FE0V;/ o)?-#'@)8B {$1#%<(8@(#!567!32>7!5>54&#"#"c<K'. / ݊, ok "#(#P/_77.'537654#53#"/#"/&'537.'537654#53#"/#"/&'53~3; *2 PP  ;I  Ru3; *2 PP  ;I  Ruzw!ir  $ yzw!ir  $ e%#"'7!.#"'7!.l((((V6%326754&'53327'#"=4#"#"&54632K3,+ Q""E,{21;"#8# j"45)  0-'c<5'H'&@%32754&'5332632#".4&7#"=4#"#"&54632M85--21;",  :X|21;",  j?0#!1Bc< $'))*Rc< $')))1%#5>=4ȷ632#5>=4#"[ 0,+4P 1#w   3`h^?/,"&#"632#5>=4#"#5>=>32 $%+4P 1#% 4=&`-6h3`i_?&x CH q567#"&54632326=4&62"&4S,9n"     $%.MKL &#"32632#"&54632"&'/4=<*%#-*;4*> T 732654#"#"54632#"T #&' / 4<;*&#-*;4*>L #"&54632#"&#"32%*<=4/'&"0 >*4;*-#f632#"'732654&#"f*99*!"  ;R: ++X&#"327#"&4632 "!*99*++ :R; B#'#73B"zy"|>gg B#'37B}>|"yzgg #BY!! 7Y6]= #7632(  #'&54>;2( a  gBqD2 #'&54>;2( a 3 7>;23 ؔ a A533!56ȷ66 bAO#5!##7666%}' ##5#5353'f6ff66ff6ff BO!! 7ɱ63 3#"&'3326|8Q 50,.FW2/(v n 2#"&546n(C  2#"&546"3264&);;)*9;)'&'';R::*(;"&6'&6'@[#"&5473325;*6.,IL, .+#"K~3#"/&#"#>32326.0) 1# 4&$" ~91 .14 y#7632#7632(#(# a  \[X~h#YZ#Y!!"Y6d) ne nj #4654#"#"54632%( )37&U0 $!&Hf,iY7{ #&54632  #&54632#&54632[  ,3'&#"3'&#"(#6(# a 3#"&=332>'4632#"&7:P_& NJa"!  3&#"3>327|8Q 50,.FW2/( S T U!"#"&54632'>54&$ R ,&<)/Z ; #'&54>;2<( a  7>;2 ؔ aJ#5353#g666J#3366ˁ76#5#5066M}42654.54632#"'5"0 & #&/K53i% #9/5J" |&#"327#"&4632e "!*99*++ :R;533!56ȷ66bO#5!##7666} ##5#5353&f6ff66ff6ffO!!7ɱ6:.!#5367"&5462326590 -B."  !.- 0.!327.5462"&=73 ".B- 0 -.! ( 4632#"&!  4632#"&74632#"&! ! | 4632#"7"3264&9*);;)**"!'&R;;R:++&6'#"&54632'654  !".>2 R 3&-T82)z[g7{} #"&547 O##5!#B676vg+32>32654'&5432#"&'#"&54632    ,K9(AK%=*2))1)?<X5$*6*$5Y[#'37 }>|"yzggZ#'#73 "zy"|>ggf3#"&=332>7:P_& NJa"e.#"#546327 &_P:"aJNQ3#"/&#"#>32326 (2'4.#) .(= O!!7ɱ6O!!"6O!!!!""6663#"/&#"#>32326  (2'4.#) .(= %3#+%%!!%D+1mP-1n'V2%V:Q:|632#"'732654&#"*99*!" ;R: ++53!53B66vvJO5#'!!\6["2.#"#".'"&#"4632>]!/%   5 % (/ % !(% 8+)(, 7'77'QQ%RR$PP)MMPQ'RR(PO%MM4&5467'64/; 5446 55/& 7%#!!5!!""Y66UL#"&#"#>323267L6'T%6*U)8+++6+-"&462'#.5462"&462((RU((q((D"`" L3m((4#"=33265%]JLXOc.ND23267#"$#"'>C J;u8?;$30?q+uTA'1C! TF"]DH.#"'>32DGuG-9qR\DgU}*6& 32 @2<".! #"&547 @2<"(#"=33265(]JLXOc.NPsX- #7>2S(  < "1j"B`"&462"2""22""2"~U#&#-;#h#x#I#Y "$Q% "#.+"!5>54&'5!"+)( $79!6%,6"';5!v)3 v6 # U( U=+. &6 4."32>#4&+"#53;26=3[2oo0&5N.8\8\HeeH*UP>%9[j-#(*!;,".!!#532>54' 3#5>73D5  1O*=H   _0 1=; !-#4&#!"#5!#4+"#53;2654'3!533!26=3;&/0b; %bVC"&/,'4IB""I[1#"2)5>5!!5>54&'5!:"6: 87!"6&<5"&<7 6D5"32) !#.+"!26=32L dB IS]1#)LI@RMRZ2#Q7)=4.#"#"&54632>32#"&54654&#"3!52>53)&$"9$-N7% #7K,$9"$"S/+"%KyI2 )!7 %324+5!&#"6324&#26"a^S ,' W q!8IO(T *1# 3bT4jkU^bYcZ55 (/^xl+J3#X)11U7Uc|mm^X ;LQ4.'53234.'5!27>76;#"';!526=#"&'.546U 4%$/+&= ZA"+.##7$?`;+ ;"#A 2n%($/  ?P^SC Y@ BQ^P@   *C;Kdq &%!q"U: 8!-#32673!5>54&#"!53;5"&54>32ɑk$SbhczaTk7^sBDvh<l9(VhdW(9lEi=:k;)#"&462"&462!5>54&'5! ((|((;&&;):((: ((((99 8D8  'P"&462"&4624.#"#"&54632>32#"&54654&#"3!52>546((((/1$"9$-N7% #7K,$9"$"S/+" ((((oR$ )!7 %.9 d:Zks\AJ  T#+<-$2 9,.<ku#!8H\^cG{r<B~,UF0LD"+OAOZH79%#"&'332>54.#"#"546232>54&#"#4>32gW,G8'4 / &)$ 51#/R,R9HeTcXt0)'@K&:9$! 061J!<5"dU5\U1IEd/ _ +4>54&#"#4323>5>32#"&t1K-*&^^5[9 ='/?bB\\tn |H*+,%3%#"&546327.54632#.#"4.#"32}db{xU( =,/>15YG*(0GTG0]@0@> :'ya}^Rs $,/8C2(6)&;AdM-M:T@#EC))6%#"&54675.54632#".#"32632#"&#"327+CgG/*EhA16" #*(#1  . $-<3Z(lvE@.A5(<=#$9+ 54%3>]'>?#"543232654#"#"&547.54632&#"632#"'32632yIC'C5W9 dSn0[N1 (; @W#Q&6/.12( ( @<-FO&)7ch8*,)$0?3O1> . ##4#"#4.#"#4323>32T>U*[$ F='4 &c@gd",,D`27%3)".54>2"#2>5 .PhP. 0L`L0 \-:-U0WbG//GbW0+VZD,,DZV"!*M5775M*; %#"&5332>=3 /97/To;>;9Y # '>32#"&#"3#5254.'#4ȷm*+0f%,06?H%-\>O'^?AKQ-&)%#"./##.#"#5463232673C:U $$(- b [e'4 *5*@" &P/M?^o^?83;O/hN.". $4K&P][z\2D)$bxoM(455$ / !-5 :M2)!H?7^/4M68$''+3*.2?A(0A&#- ,R#(0+32653#"&5##".6'3325#"#>32327(*6*i21f R24  BP11#< EN*@3A#$%$0L-,#*%#"'#>54&54>324.#"32>wfE6 T1V8ct\ 8&| :%!/ h+ST/ " 665_P/$IN1"IE,!89':2654&#"#"&5467632#"&#";72632#"&54632E)cI`U52L$;"C6 O&6 "D,#. 0*!~an(  .8+=V!3(6@-") "#"'#"&546323274.#"32 5/"*2x]b}~h~2 ;*=4yS _4^bh (JQ1gD %#"'3253#"&5&#"#>3232740: (+=00;%%"9(w(+6+!=9$#"&54654#"#463232654&54632HP#0(610$2=F=?1XI$$9\:FO4|6@g@($ )42#7.54632.#"&54>4.#">(: zhT4L<+TK'(-)QQ $: +]\i'@A"l "4_=V!iKdB,FV@867"/-#"./#'.#"#&54632733273 + +Y- 4$# /{W"+Y+9Byu$N#)?)?>F+S }C0#7.54654#"#54323>54&54632 ^ _w!2d/2D?EV3 -X h^s8_O1x?G5 rH( *";lgF)@%#"&'##"&546732>54&543232>=4.'5`R9>>9R`j]*  #",/.+1!+ &]jWI;;IW_#9(  8&(0323>324#">4#"32|cqn4'R$5Nkn!%fBawP7E^]F '8 GAduhOh#"*?Rm>Ji;)dB1k$>@%Dn93@#4##".546=4#"#4>3232="546322/.#"9A3D *'#"-"kQ:$2' &$BU!!"@B.LTV#*;:+ 2 &22Ѹ:L88XF9 !b?#"&54654&#"3!52>5465&6.'.54;2>32b"$"S/+"/)"2kQ! (4 $9? 7!) L$$'T9EGF;-  LB',!*B*+<b",bC"j+ U@%#7.546?34&'>UoFojjTZPJXPZWJlzzlg~ss~gRuc|tSM| J##"&'##"&5467#>3!54.+"32654&543232>5m66`R9>>9R`33#* K)] %$ #1,/.+1!+qBWI;;IW@o/S 5!# "2! 8&(W6"t88s7V*L6&!nE%#"&542327#"547#"&54>7654#"#54>3267>32327GK$<3 f%W`* #"? &Z5Q$]?2 Dsq p'&H+ "%?6j- 4,!"1<67OM6iKF3"5463232654'.'&546323273#"&#"id/K H_bY_^n/  -;JOZTbbR 9&=- KGGLs ?<fN(/83+3&Yc>2"5463232654.'&54>323273#"&#"NJ)E4MPA &X<X% */:GV=MN;'6' 97AxW1.bG+'!'OX+'. #"67'.#"'#'>554&/  +3!!;9!:*#=   H!5!,? 7 1#"&#"6323273#"&#"#"54>32327 (/</ ;H' (/ 6#$2*$N:W& 2-+%:&=Q2-3% *68fP;9:!>"&54?654#"#!>?>54.'&546323263![P# $ (&.. !I## +% . ?,"7 %0C& F$%4 &0(- ;:1>?>7327"3263!+657654#"#;&( 'U7# +%%/ $ ( %0:T &08+P 054''&'"#"547.+"&#"&5467>3232#>*w !A" %a J$ ~F;BNH* ` ;  ɟ>14! J<"#"'632&54654'654'#"54>?654&'"&7>7.0):M%   l[,]! $'Z]4 !! L8$ e5"JIU,g99B4\GJg$ .PH -+5!=%#"547#"&54>7654#"#54>3267>323273 !W`* #"? &Z5Q$]?2 +'&H+ "%?6j- 4,!"1<67OM6iK) !2%#"&'##54.'&546324.#"32>wfDh 39>8.+EKN0qpct\ 8&| :%!/ hRA#39D4. 64gu$IN1"IE,!89)%#"&54632.#"3267=kb}~hd=;1t - 2=LVbhV( !+F*!) Us"(C$f >4632"&74632"&4!#.+3253#4&+;2673!5265&&-&..-%6%"A!&ƱZ(6!KI$8@#&$$#"##$%F, , d52=G-F&7"&#"32>54.#"5323'!3>;!5.=>322;#Lo18Z6/<*6U99T6 >$>".#8X*M< pT8r`="--SR. @! 7S{B "s!7!5>54&'5!#.+"7#7632!:9 7 6U (#m6!#>5!C& z y!3267'#".'!5!>323'##"&#"U.iv EB=e '=hD,!!*6;, ;+",j r-0;%#!5>5##"&546322676=4&'5!3232654#"3ST,:%E.)< ( ,:;#EBd:# e`"3K&"?4suL$#b6!7'60IM3>%#!5>=!!5>54&'5!!54&'5!3232654#"3ST,: 8:::/:;#EBd:# e`"3K&"?5 "?666!7'60IM.%!5>5#"#7!#.+>32#5>=4#"d">> 6T949U648"7?%&I*$m7 !@.RS-1 OG%"/a""s=F#"&#"3#'.+!5>54&'5!3267>32%#7632$> C1(X  :; := 7YI1X(#\"P?]C' &7#>5!7YCY;>j s+4754&'5!!5>5!5>54&'5!%#'&5432/:: 8: 8:::("0'66D5 "?J%5 "?66ae/<732>7.'5!654&'53#"&5463#"&'3326  &0u)73+KC(7c|8Q 50,.oc7>$9*7 =gSE#FW2/(I'!5.54675!!4675!!3547: 8: 8::$8"65 "?5 "?O6   3!5254/!3#5>73&'H 4=I!$z,0w .'5Z'`%4!#&+32#!5265%4&#"326%<~FHm>' o;&]Sa##&K];:'s'6/Th&4.#"326RA<2D 5pPB"#ACf;$ s^G!:)4#*T9,'J[1W .7'":;".EF,%3.AR <10 R*_4!#.+!5265)9.CY,8<&@8$5=$(: @!*4!#";#.+"#5>265#):A('#3 noEL!% 8V-" n;8)$/&0-lT',1<bo!$$(4!#.+3253#4&+;2673!5265"A!&ƱZ(6!KI$8@#*F, , d52=G-F`%;!526="#52>767.#""&5463232754!32>7632#"&#"3#.#'W 3/ 0T)F-G # -A(0'>G<6 02.8* 0;'!(2*@%# !"$'/D/ fT!0-)M4.+526f8,i1Ro!/$iJEg,= &K4g^!7-dO! $?'Xm a41600!M#/%265;!532654&+5!#"4&+5!";!5/! /(*+, 1OT)*212!2-.]++(3/!PZ/$!/!.-#s'd*#:"32>7632#"&#";#'.+;!53254!H+*/E) +V[&C 5@)T*?B. &7&RV225%0(BDH98$!< Y;Z?7(KU0"%72>=4+5!"3!5>5##"54632#W =3/*85/V";D6[^3P!,*'!.!?(+$4&'533"3!5265##5265'=B""BC" @C!&;7 ,F[F--F@EF+,G#+%>=!3!52654!"!54!"3!E!#BA""A4B#R!E6B"#A*GF..EF,-EH*,F[F-% #"'&5476 2654.#"SNTejiff fgf{ 1R4@\/xY[48ghjjhh**RYB+=df7#"%265!;!53254!#";!5,+S03 1%T/,,/V.#+)JI"#"'3!5>54!24&#"326I|b=H$CB !A%{|[B$&4!CONnF-+FF,kYHV Q)"23273#.#"3267#"&5463Q1  U%EE2 6WW,M"d.bb.IxMV~@M; ɔ7265#"#7!#.+3!@#Y9.] ,)]%@.E)%/F-$72327.#5!#"654+53#"&54A$(1#$ CŒ; F)?{(1]-H0%' R$ )[C!2'?(7G4!32#"'3!5265#"&54>34.#"32>%327&#"}0325.0Sz>.*9:)0 y+AjD#<@#7P))P725'L." ..LL)o1&%2p!?@0;V,b)DF%%FD) -K5!"7654#53"3!5254'.'#5>?'.'AEuD%,<3o# "C\B%A(4>2& 'B<0$ %#"$30I+%@-%;#.#!52654&+5!#";2654+5!#"%2 nn10()1&(!!P1/!p5)lT(9-"*6(%"O***4!"32754!";!5326=#"&5u213;)2?Af(<321T+*x]bMM-"('3:).)"2M'39UN$>6%3!5254+5!";2654!";2654!"'2ZP 4#!!+,4#!!+,.+h*,OU-/7%-/4(%7$@>:.#!5254+5!";2654!";2654!"3,nmZP 4#!!+,4#!!+,.+'2mSOU-/7%-/4(%7(*,,7>5#"#7!#"32#!%4.#"326B @', ,);[>4gF%P9!#)J\,E2'(:$<=#<<%,0X&,@4.'5!#"32#!53265%4.#"3264&'5!3!5>5 0T;Jq@) "5[:)*]":="#&L\!G,50U:\>3gF/#]%=9 #&66!F4 F#><#<<%,-Y,> !B""#"'#3>32!!#"'326&#-Q4  Tl-wb 4;X0.be+ #1%4&,&>"367632#"&'&'#3!5>54!4.#"32>R6*_`efT03'91/00,_)86.6+%(BF'6<-&3̓bcϔfgZLQc-,$0/#JsF- 0DiAYB )Bt$,"323263!5.5467354632"Ed3/I0  ! @+? 7 MWD$)"8:-:;BF++FC-=W('42327#"'#".54674&#"#"54653276Z='=3=WL+-~<"+',do%$!@U0*LTT7+>\0^:%  **5?/,! 1!-"&546763273#>32"32654&f}SS,UH5VZ7G< FM*/B5&EEh0K^:.NSA'?w_;O 0W8jKLNeoUae(4Ȕ+5>574+324&#"32>h +^`Zu,# >J(#3 s'$5DM['*U|&8 $.+3#52654!  #2/ !.T  8'),&|$4&+"#5>7654&'5!"3'265#?Ix 0 .,JU|0L|5,"Z`)((4E!]j 327#"&54632!7.#"c!G.a$^MXlp^Oa5-. =J4kIhlpfT'7@+"Y7.#"#"&54632;545"32>32#"&#"#'&#"#5>=&#"#56?6 % (1,$%(#,1' $  6&'$0~e)' e}0$&+ 2.$ #+=>+q)!$&q+>=+ B QF@8&")8@FU%4&#"#7332632#"'732654Ȏ7*^ D'MZ{lRiJ OM.==G0Gh)2@5Ri>KV =;0)?,+?4.'53#5>=#5>=4&'53 %%&&&&%%%"/$"//"%"daJ82>32#"&#"#'&#"#5>545"%0/$"$  % 3"{I, -$% +==+  (3&$S"$G$$*'#.g#4&'5!"3#5265##"546323250- '&."89@ # /l+$))1%'5BqW8##453"3#5>5##5>5b**I) &,o('_(5I#$%1#&-*"3545#526=##56545"! "+#&(*I+,ss* $%- #&'!H("-%#"'&546322654&#"FGbYDBgYDB9FWE2LYgOODBc`DEfSdSbd4!#5265##565b++#&(*Is)"$&- #&U'!H- !14&#"'73632#"'3#5265"32>54&d FZ'6+FFXC.%12!?6%--LB0&7jj 0V5sGJ+7&&7B95)P7Vl327#"&54632#".#"jXJm"o?\re$;"#$;H]pqWdem%+%_.+#5265#"#7! K&%-K T *')N ||,%232?&'537654'53#"&546X 5,%!+  qM.~(R9)od(gJ$N *Gi]$-w*2;;#526=#"'&54763254#"'73632#"'27&#""3254u$%&$+4A0100B1. ,4E]]E2.+)"`G$('#bv* !/.FFigFG.3=.jl. +O,Z,+-37654'53#5254/3#56?'.'&*0$4?1N39+BU,,9YO,! CF ]I{R7/i~U{/%`#%#.#!5>54&'5334&'5390%%&%&@`% %"/L%"//")45"327545#5>=#"&5U&'!/2:'*,(&B`A)t%%$&S){&$#&($)),?74&'53"3!5>54&'53;26545";265z!#($" & ++!]"!(#Vv',9)*%"',#$ )--$:%3#&#!5>54&'53;26545";2654&'53"(& +)!]"!(#V!#(b/!|*%"%.#$ )--$$',9("#7!"32+52654&#"326/2#8GU_p,"C, 5D ! |(/`!*8R&#U5, 8%9"32+5265454&#"3264&'53"3#5265 3#9FXC"(P''&(ZD,!6D,-&&&%'0`!+2A ,+5, :*%(('')"32+5265454.#"3263#9GU# (P''&(Y$#!!A8'0`!*0 ,+) @>32#3#"'32654&#"#"'#J# sQDMh[xwY!L  B/P hli&4"3>32#".'#3#52654&'57"32654&-qw_]FI_4R- q%&&&$(6B%7++MS$,oWhiJL)9H1('-!cQGh0Wdf &7>=##532?&546;#;5&#"*(t rzSb% $T?H7/),i""V/K%3. V&>8$3267#"&54632%3.#"7#'&5432a010G$nGVeu\LT *.Z("?[-09QVygo[\ A2La  .64632#"&74632#"&327#"&54632!7.#"b&&!G._&`MXkp^Oa5,(4}%%=J4kGjlpgS'7@20 '9"&#"32654&#"535#5'632#335.=>32U25)SVA8,D#ss] pp+,3I<pj6FO'-"w "W54"aP;#.+#5>=4&'57#7632} -v%&&o(#}7!%"//"2 %"32>7'#"&'35#5463232654&ZkS$?(#$>+5##"%3267654'&# # & 0FV iu&K1B0&+B +o8/" O -3Q"/:xn (@3A%+5>=##5>=4&'53354&'53"32%3267654'&iu&%&&%& 0FV 0&+B3Q"/u%"//"%tb/" O ) (@ 24#"#5>5#5354&#"57673#>32#5>5K3,+pp D/ss#D,{)+,j"45" w"-'4 3&[/L&\zJ,&dTU~'%#4675#3376735.54675#T%&&( %%&%L%"//"[ 67% %"/AD4&'&'5#"'#"&54>54'5732754&'5!32>$Y!&!9#!T)&9`=J&!@)=%$T=`9&4r '  ! 2bEۣ6!ۨF^1!  )w3%IN;&89"4F&;NI)/43232654&'5#"'##"&546732654&,/...10*AYncOnnMel[%-a-0I86?Ndqfae]_d @92O> 32=4#'.'5!3#.#72#!5>5"#7, Ů16"8WEBd:# 1RU.6T9K"&M3'504J& 32N/A7>5#"#7354&#5673#.+32+%4&+32737>=x 4,  w 60GW(:l323273#'.#"!!#3767+S`Gi#BO"A4C"j;M_F?s!  kMk|/%"2C=!eaq=AfVF.(7 @(,DMwB* !!HY},Ch<' \;%>32+.#"3#32>7#"&'##56545" L<^=K Q?),[>YcX'I*&`n:-&)"`M%BX UG`~*E)!"'w #&35>73/#56=46=#3!$"%#2M+2K$$OL8J!:BD#v0- ! P1%(35>7632/#6?4>=#3  x) .' !  #,i)S&"A1.\ Pr\; *zu9i CF%6=#56=4/#4&'5!!3!5>?!!5>5%3'$OL8$K)2M+ 8 0W A!78 ȜR N1! bv0-14  m'+"3"#?'3=@45"37632!5>?##565%>54/>=#7'b*&I x#6 ((I# . "-*(t)!"'1# M% eg*Ei\4 rzuii8C%26="#52>7>73'.'5!"33#.#;!4&5!765[20 1S"8/&8 fF1(8$' k!"" "V Qq(2 ,+O#BEa#iE2% .Tc1@O&+5!#"#"#;#'&'##5>='#"#56?636;?>=2='## ,2  '!$0~e(' e}0$&3(!\U ' 9N&%;@6)* 8@Fa~  KV%26="#52>7!!5>54&'5!!'.'5!"33#.#;!4&5!76520!1S)F-O!!78 8F1(8$' k!"" "V Qq(2 ,*O;M.3"#?4 #iE2% .Tc1Wk45"!.'5!#"#"#;#'&'##5>=&#"#"'#56?67!#5657>=2='#Z*&rP7 ,2  '!$0~e(' e}0$ 'IBU t)!"'w|C 9N&%;@6)* "@;:*E7i~  1@P26;#".546;2327654&+52654&#"#5332632#"3#"&=332>S +%EC(OT+I#cRad=9f5PrFWLiU/2!+1# ,U@-2'/K'6##(75#"#675!3"'5.6.'&+3'&'37#!5#"&=332>769D /$!BX)0o+#&4; #?Sq04,&6CPA % L'  2EQ.3> \> 2+[^ZC  A9gh2>r2'q ;'! }H2#&?54&#"354323'>=&#"#3QJ5,d2#ua ^ )C+! B%Du : 6I_8]h$1A32#&#"#73 "D # R"Wz*mCJ(i"= Qv'z  'zZ%5$K#"'&=476 26=4.#"%2327.#5!#"654+53#"&'54&'hjiff fghy 1R4@\/{A#)0'$ AŒ; F)?{$3YOWRofhjjhg*RYB+7>>32>=4&'#"5gY7%FvI6iY75Wh5(6(eP V\^Z 5VL7qgK !6VLJX8Q-@qG yz12#"'.=467>"'>32>=4.'QjeC! MeUH! %6!% &'+!  {Zb{ XUxf L4_}(^@+F; AOW4.5475'+"'54675!2#5#".546?67532>7;>7#5!53!K' %9`=T$%=;&&J=`9% 'K!4  %P PF^1!  ! w3%IN:&F4"'38&:NI%3w !  ! 2bE &$ ΧCNnBb)8@74>753273326=4&'#"&=46=&#"+"5#5!53-%\kcOo_QamZ@+^/--//.`tP P3:?b]e]cb`P=68 54&/&'5#"'+.'54>54'57;2754&'#5!35.+#526=#"#7!=`9% &L!& 9#!L& %9`=J&!>)=%$T  K%&*!K, t&:NI%3w   ! 2bE 7 Χ F^1!   w3%IN:&89"4F  @(!#,<)3||):W%4&=43232754.'5#"/##"&=467;265.+#526=#"#7!C/-..^,"YncO`nMel[%-`-0 K&%*!K,  86?N0?8d]f_d @92N>  @(!#,<)3||g/327!5>="&'5467323273#&/&#""2F=!ze.A ?l ?s!  ! =Xq}RKs@) e2#*F.!!!K' =,%#5>=#"&=46;23273#.#"327",+0.[xwX!L  !* C3QD0"2 kg&5mhP )|7'7'77'77''_6]LU6hqU7ZXb5u)@.w8@=/@4w>@C q!5#!3Q PPXbBn#>3267.#"4R'L3Y- 6WaJ-,M; *-9D8 #53!=98~Q138 !5!53#~89Q83|Y )7ESbr""5462#"432#"&""%462#'&"#"2#"&#""542#"&""54#"&"#"5462#'&#"#"5462%""54632#"&V 0'1" F0 x2 0 #  0 0 n   N< &!! &B: & :  &  $$  &     $VQ (.6;254#"3254#"%3254#""3254"32544"24#"32$24#"I1121551F2112x2U221dd1221Wf51!1221u/12T1134122112332T220d#nw3K%;#'7#53265;!532654&+5!#"4&+5!"$2>32+"&'54632!2z&Y0 0+''0 1OT%.230F0QieTm.-'k--],*,.-#NX-&"-(/((A>*(/n.E7#526=#5654'#5"74#533"&'543232>32|Y&'I$&B(! )zUJ#% % fkk (*E.!)D)+"<(&#*##*#)= .32654#"#!5>5#534&'5!3#632e`23ST,8AA9;#DD'Bd:# KIM3K&6|6>!!7 6v'60 .73267654'&+5>=#534.#53"3#320&+Biu"99770FV ڍ (@V3Q&66& #-327'7654&#"72'#"'!5>54&'5"G+U'U`eN-TS2JO'Z5^'#;98OU&U!2MI3&J4[6O&Z7!!?6'4327'7654&#"4&#"567632'#"&'#5>5E#%e'_C8#CT ?Q@PI^GW'Z-4 + 8,N,e&_0EWi,# MOx]xJW&Z/' "!"!5>54&'5!2673 !:9 7eU6 p 6!#>5!&C##5>=4&'5!2673}%&& - %"//"!7 " 3#!5>5#5354&'5!#.+"ɓ!:9>> 7 6U N66!#>6i5!C& !#.+3##5>=#5354&'k -vNN%&11&}7!{6%"/6=/" &E8"&#"32>54.#"546;23'!!5.=>32~2;#Lo18Z6/<* U6 7 9:!.#8X*M< pT8r`="- &C!5O>#!6S{B&3%4#"#5>=4&'5!#.+>32#"&54632326dc %&&k -v'1+0Dj`#;2%,; p%"//"}7!0 Kg;s <$j%"./.'>7632326=4#"+54675!#"&'.#"32632#37>;!5.=3223$%XE >$X1I]7 =: 7]I1X$> EX   ;9! ",%]?P">;YCY7!5YCY;>"P?](' +>#(9."ށ^32632376;35.=32323'.'.'>3232654&#"+54675##"&'.#"0)  ""./"s" 6 "s,+"/.""  )$0):,6:)0$+51 :_ ' 48{ _: 15+&FF  'tFF&%D>32+32#"'632#"'32654&#"7>54&'>54&#"#"'#`c<.:200@ X/vi+Q& %'-:C.( OfA922eH*b XT4)969&)@e:BY -' %8eI7gW3K`"")cG""'#3>32+32#"&'632#"'32654&#"73>54&'>54&!: 2+#/9#%''<4$)E&-& %'-:C.( IB6$-U C87)$7A)3)57 !#Z -' %8L8'C5&5F">.'>7632326=4#"+54675!!5.=3223'".''C >$X1IY7 =: ;:  $%$#]?P">;YCY7!5O>#7 &%ށ,%;2654&#"+54675#35.=32323'.'.'>32$0)C,66 "},+"62"% )t&FH  '' 48{ b9 15+"@353>7>32#"&#"3#'&'#5#!5>54&'5!"6%8 I1X$> C1(X *6" :; :=l~L1Y;>"P?]C' Dp7#>5!7;#"&#"#'#5##5>54&'53353>32) %"26"n6,666 ('$+51 9b Aq  '' kU:,("C3267>32#"&#"3#'.+!5>5#534&'5!3# 7YI1X$> C1(X  :;KK :=QQlYCY;>"P?]C' &7#>|65 66>#"&#"#'&+#5>=#534&'533#3267>32) %"26"}" ,6??5BBC)0$+51 9b   '6%  6@HF&#?#"#7!3267>32#"&#"3#'.+!5>56T9;# 7YI1X$> C1(X  :;l.R!7YCY;>"P?]C' &7#>I;#"&#"#'&+#5>5#"#7!"3267>322) %"26"}" ,6D- 9 C)0$+51 9b   'K!7} QHF&/%#.+5>=!!5>54&'5!!54&'5!f:>Qh: 8:::/::6H9"?5 "?6666/!23'.54675##54675#35.=3z,+&%&%&&%&48{"/%"/bt%"//"%u/"046;23'!!54675!!5.=!!5.5f U6 ::::8 /:8 N &C666O?" 5?" 5/323'!#54675#35.=335.54b- &%&&%&%!7}"/bt%"//"%u/"%5&@"&#"32>54.#"54675!!5.5!!5.=>322;#Lo18Z6/<*:U::8 /:8 .#8X*L< pT8r`="-66O?" 5?" 5S{B&=%4#"#5>5##5>=4&'5!>32#"&54632326gc %&%&&%'1+0Dj`#;2%,; p%"/:%"//"%0 Kg;s < A^2654.#"4/&=46323'##"&#"327+#".'37#"'4&546=4>32S%Z@AZ%lu/J1 s7k[Fg; R) R4 !$  _ApNUuB A+N73$!!ȗ}_.T 3Fd $  2 -'J0=".#"632#327#".'.54632254&#"n#$?D" ?=z[!1a$bI%5,%%Ib-D!`r1*0@"G%+%cHP7D:Tg !kLd'J0oUq& ^.DN>')y4327632#"'732654&#"'7.546323273#&#"-LQ.viY (.C:-'% #@p !  7mRWAev4% '- U!!⺢)9"632#"'32654&#"7>7'#"&5463232654&ZbN& %'-:C.( 6#$>+DWK= "[̉n]|Z -' %8%)" 4*mVMa.*=Q!23'.5323'!3>;Q>:6U99T6 >9H6-SR. @!%323'!3>;323'.D- ` -De,+&c:!7}}7! 48{"<<#%#5>='.'53654'53*0/h# fc/H)(N$ 2-33#!5>=#535'.'5!#7654&''8+ee$CD!llK3$ .'-B 69!Av6j2<)3##5>=#53'.'53654'53rrr0/qqh# fc/e6)(~6N$  :!23'.'7>75#'&54>35!35.54?"Q>)'140)(q*U 2=FmC(&, 4w_329H+:! 2;v 4gPAL6>54'53#.+5>54/3#5>?'.+53  (3S!+,f[O(r^  +.0)*x {84 { #A'%!4&'5!#.#!5>5#"#7!#.+d 8::>Q:6T949U6,5 "?b6H96.RS-'323'!3>;!23'.=4675#!D- ` -D%,+&&%!7}}7!%48{"//"%-!23'.54675!#"&=4675!327Q>:::LR>S::jSH:9H666=V=66~Uk=?"/7"&=4675#327323'.54675#6%&U+G-&e,+&%&#"$d%"/T9<2c/"48{"/%"/j0/536754&'5!!5>=#5.=4&'5!I86@8:: 8:8@6d::)9T -66D5 "?/ tpjQ~63536754&'53#5>=#5#"&=4&'53!6&%%&6+U&%qe#D@ j/"%%"/c WJ<9T/")%4&#"!5>54&'5!632!5>5S>RL:: 8:HSj::=V=665 "?=kU~66+%4&#"#5>54&'53632#5>=C61#&%%&-G+U&%$"0j/"% %"/c2<9T/"%d@ 5.#".546;2>32!327#"&=4 *K/Vlsa<<6JzIvB/0NP)zh*Q+E3&zd08'76s1CW=7U|?e;D!+36;2!3267#".=47#.546;2;674.'#"5RMK3G!A5N'Q,=W( ,&Y5cw72*FG''!*<'77(="bE,qR@IS327327#"&=47.=47"'. 546;2>32!%.#"'0NP)zh$U)+4< )4=[F3 <6J}IvB/ *K/VlKU|?e5D!$L+ /'.FS '76o1CW= +E3&zd];C6;2!3267327#"&=47.=47#.546;2;674.'#"5RMK3G!7u ,4< ),LUQ,=W( ,&Y5cw72$L+ *&x]'!*<'77(="bE,q;,p'dI('dH"&F%4&+!5>54&'5!3267>32#"&#"#"&54632327>- :; := 7YI1X$>  ( 3XN.o)52 *^l|7#>5!7YCY;>"1BT %;]:<0#d%E2654&#"##5>54&'533267>32#"&#"2#"&#"&54632. 0GJ,66C)0$) %NdV )52fsYk  '' HF&+51x[z<o*7232>=4+5!"3#'7#5>5##"'546E;$W =3/.4y&X40Ul(:`Y.P ,.#'j ."=n+7232>=4&'5!"3#'7#5265##"'546&#  0'&#*z&Y0 6;>O#6,!*%!/,*'k'4CnY5O22325!!5>54&'5!!54&'5!#"&546 & 8:::/::XQ+87 B5 "?6666^g( &1"&#"32654675##54675#35.=3$25)SV%&%&&%<pjq%"/bt%"//"%P;#n3%3#'7#5>=!3!52756554!"!=4!"#Az&YD"#BO"A4C"R#C6B"F-'k+EF.(7 @(,D >'+Eo.45"35453'7#526=##565b*&$(! )z&X%'It)!"'ts'#(+"'j!'*E-!"#7>=#"&=4&'5!32754&'5!VQ>:HSj::S>RL:: 89H6=kU~66=V=66D5 /32754&'53#"#7>=#"&=4&'5361#&%%c,+&-G+U&% $"0j/"%%48{"/c2<9T/"%d+n)%33'7#5265##52654&'533"N#Az&YB# @A#'=B"F-'k-D@EF+-D:8 +En)%>5##5>5453"33'7#) +, )+Iz&Y#"'+#0+$_)3I'kU,%73UYGzke"$d(&dHB+"$j(W&jIB_&x Ue"(d &d:G%#"&'!654.#"'>32!3262sR{g*N=ahYZhĠ$QWe&ZaJ#9'j*W&j`J%?'j0-f&juP" "&5463232675."co^`qpn@6 2"&546;265'.#"`|}{ A:7? K65ÀbhegKkbT6QaVG"+'jW&jS?'j?_&j7_ 'Z5,B&ZTU9'j5,[&jTUt'i5,&i8U:'j9[&j`Y&9'jF=['j]'74>354&'5!3!"&5'"326 #:dBE%982rT9 06'6"#=N;  Y[mGj.8%26=4!"#"'!"&=4>354&'5!''"326*?2/536-Mbr #:dBE%9769 3:3-!%*NSY[06'6"$6d/KUd{U54Y%1<*=@U= 7*^ C)K[D Av_o+((6Rg7*^2%##"5463232>=4!"26=4!"#"&V;$,6=3/43/536-M\ZR>(:`Y.)' ,>D+2Q-!%*MU?t8:7232>=4&'5!"32654'5#"&'#65##"'546%5&#  0'&<)2>62m6;>>O#6,!*%!/:7*^ C)K[KC EnY5#D"26=4!"#".'&=35!3!52756554!"!=4!B"43/536-EX)/+#BO"A4C"R#C6+EdD+2Q-!%*LP9/F.(7 @(,D >'6%".=##56545"354532654'5>7I>'K")&$(!<)2LZJ1q*E)!"'ts'#(87*^ C 1.#"32654!#"&=46323273_2H.v"5E?T>;-QABľ9p &27ElA*RmI. (f?\ !!*%2654&'5+"&=4632#"./"2==(eSVh[OJ ?IU>(0  Rx}_mG !)$bKXk*%"&5#"#7!#.+26=4!"#_F6.6" 4 >>443/536- )(,>^ "*)60'782Q-!%*<;/.+332654'5#"&'#65#"#7! K<)2>62mK, T  B87*^ C)K[KC A)3||J7 (3"&54626"&54632"&54632"&54632"&54632    S J   s   !  !   "&54632'"&54632'53      u  44c "&54632 [c! "&54623"&5462~ u   [ "&54623"&5462"&5462~ n O    t`<53tȠ44C 53#2#"5463CO ! 44;G<D_j .4632  J. "&5462"&5462"&5462m A R   H G  T 7"&546326 43#3444qI+i%.'67.'>7+ C$*+$  ($   % C%'U'% !,HU64&547.546;237"&4632#"'./2+".'.##67632>G%?& aX3K,1:18 1$32#@ (/( s %3H;%$< "dBGE26(2(=/M*4H#>*&>/:.= V"&547;23!7!4&#s((0G6#C#r10!67=Pll.'(V0"&547".5.5##54?>7>54'54&#" 7;   >vx# ' .B   /,Z)Ye. w )T3!2++'"5465!"&545;$  1&T!' < )(8V73!2+#"'"5465!"54#'"#"54654&546324;*  Z4 V!A .V1M;$2 0 =V d0V%2+"&554&#"#"&5467323261 .!!  3&( M E5#8 7 V3"&543##"&54654&54>7"#"&547     17t  !'.% ! + ?/W/1*6('&V#"&567"&5477!2+#"&5!A-';+ (230-1 Ac -7VB!654&#""546763632!65654&54>7"&54674&#F^/T='$X  ,B%  p ++3+P C( K8$)1*#Y0FB)Fi;7 4g#/J) 40!*9:=Aw"&546732632#4>54&#"v " "# )$6 )%4)43!2+#"'"&5!"546> E*&  V4&&8sZ.,# E6V$"547;2#!7!2654&=4&#eF%1+=$B3=W569'EUJSl,8 1-E.K12!2#"54>='&#%"=7>54&543 # 1.X  L[L  K7*A"G0T IGUq " V#2>;#"!4&#"#!"&467"3!:> +  #~/(%36>UN.>B*(45 WF%!267!754&#""&=4&5467.54677>3(@u_,H)  %.( H >P'  Hjy[u&7B4 b#B]6'"/   /"&@A.T=:4"&547+"54654#"z#$U "9 3,0!#m9C%.J 8/V"&547;2#7354&#"$!' 8%+7$#52 -P nbSl %V3;232>54&#!7&547;2+".=4;&?! +A+!/[S#1^Q "I:[E?uH?&=4$ . !<6+F` XH2>57.54>?#"&547;24&#267>=4&&'&54673&P !  !K  ' %'%4*K P "DH' '$N  K4.'U211  =  3172654&#"#"546726;23254/5+"5/.! :* AK!<#)+>& Pf Mj # C$ G(2V772654&#"#"546726;2!!>=4.+"50," 9* &1r#!"A-<#  ,:) $5(ld,CV7'#B$ 32 4E."##"&54654.5467>7>7.5467 C/ (1(9 #-%(= i 0,&Ey 7 /$]> &,-/ . V>4'!67!4'.54654&+"&54677&546q!)!1(L0:G:4!$ '*V &!,# .%2S ## D,#3  N<M.34/F%4.+".'&547;2#"5467>"4654&=4632(0." ".# *GFOlB4!"   >F$ 2 +;M1 /&#() J&(dJ\p#@$ (%+V(2#"'"&=54&#"+"&5473P&& &-* 3 4$=IZ&6:   L.!0<V]"&546764&#65#"&467&#3>54&&'&5467!4&5.54>?Q   * k" !|*@&% 4 75* :  /  1+32?  +%b 6 ,Y ' -8, V<;2#"5#"&74&#"#!+&54632.547"&54G8 #&G / V  S aE&":$2#C5$*K#h?1%9V$K2+"&554&#"#"&546732326!2+"&54&#"#"&5467323260  +$!  0  ('!   3'1M E7": ((N E:#8  !V$A2+"&554&#"#"&546732326"&546732632#54>54&#"1 -""    "!# *3)*#M E5"9 v%5 *$2'Aw8"&546732632#54>54&#"!"&546732632#54654&#"] " "$ ) " "# ($6 )"2($6 *$/2))2#"5467>GL @ $fFz$-Z2#"5467>32#"5467>GM @GM A $gF{# $fF|#b"'6&>7632 9C  "2"  <@ #" ,-6"&5472+"54&3mE# : 5F8,^E.  IIDFE !*4632"&54654&#"#.'&+"5632C7C5"!'@#.,<622CF.$ & #>. Q;#?F,:33UyI"&#"32>767.54673(1# L+6' D08k8F6 4u<0 $$5Z9( eQ23267#"&#&>54'76 "(/7: 10##06 *$7E({KBBCCBBC'P );Z>?# -2.! "'7'?'74.'7!"&547@CC@CCABBWA777F 3*BBCCBBC7CCB8@N?)R*7K~c)&|)-237#"327#&'&5&546767.#">'7JoXJ6'M5p0.-?>^4l62/<544!?fkLQ#A?&./1@? DyHv 0'}553z4*237#"327#&'&5&546767.#">J pYK6(N6n%/-@>^3s42 !"5 >djKP$A=%,.0?; CwHv !pZ)-237# 327#&'&5&546767.#">7'74iT3#G1i}-*:=X2j1/  2c,++;FK <<%;<- ;9>oGn  ,,+r4.'7+"=7~  5"87 $"O )8hCN`&r '7.'7+"=7/977  4!76 997 $!N (7gBM_&gY76?>54'E 16hSEF$EOH H 1 dcR&-WgY'77>7654'F8;;7 +"R CRm? *! k( $Z$e44$"-E&!  A/@e9FH*-MC1H8@D8%|:>BF254'7#.'#"+.5473267654'732=7'7''7'7l1',&$";0-#& )!j( $!/11"/11$/11Y$c42% !7I,9&?f6DG*,LC.H8>E 6&---:..,---(32##"567>54'77674#"23276@$&%FS8QkA\-?",x:1JTPg@ 8'!""B[0oVNHNT!45GIHix7R(372##"567>54'77674#"23276'7@$&%FS8QkA\-?",x:1JTPg@100 8'!""B[0oVNHNT!45GIHix7RI0008"6547632#!'%4&#"!6V? sg&(=9%&a~SE2 @.QO-'88&'76547632#!'%4&#"!6.//V? sg&(=9%&ad../~SE2 @.QO-'8%&467&'=476;&#"32>73.>>W#A8F5D L b. 7kD#Iioh:C54K*>91*8%Q"CK{HL.A$8,%)467&'=476;&#";673.'7B9W"A7E4E M _.wp#Idng:011><0J*>90)8$Q:BJzHI/A$7A000+$.246;2#%.'672326;2=.73275.''7P;,1V+""21!!U8M(e$U'*122;}0/@^B\/K6LN$"0 $ =1'J223i1B'7'7+&5&5473!367654'&#""5476767'#";27254'&'777f877G_3   `8K_(4!p!) &27777777N/8-v `zaFt&I 3 %1;53+l,  y/+%"'&547;!654/&'&546?mk"*N2Ob }= "4[~W3 t*)$2=,'$eW@C@-(MD yA4 $?0~(A@ 2[-y"'72>5&'7#"'"&547;::C[N&(:*HP8 i777'M; `GNF^/jg\aJ:4#"&'&5467'32654&HG 6@:<$EA*4#?4P'2 & (s &P. dI"46;+5>7654'#&57.#"3232@5 Dj;l5w=-"c*- %/AV UpK F5J7)F42fD3'7'72&#"32632#".547$7&+"546ACCACC!!"]P ?YuRv<S 4h^..c_zBBC"BBC V%vO5#;>"ksbS]8A6. 7>77>71:;1:J wJ ,7>7'7>7.9;.9J >J 6 7>71:J 3kn'#67.546324&#"6 2"]G5  3"  ' @$'I   "2)   ,7>7.9J X4#"'#"&5473326732654'7 !  $ #-   2rK'7Kojj|}zN #".'O- >.xAd42>7#"'#".'7,! ",K3    92<00 & &aE~uB^D$e8.326763232=>32&'#"'#"'65&6.'/,  1 M< '  , 8>&2; 11x-&_ra;2DIj?IS-2632+#"'.'732>32#&#"a%' 5H0 !A.0 7)D #' >kգ_C,4,"  .&7"&54767'7#"'32>7632>54&;(*'h4WP;:<3Ea7  6 $%DIGcb9g Ia<5b0Q 6 + 2O'2>7#"5467.546732#"&#" L9TC[?VCu4$+ /.C'/ $- .L :2~" B!/4'77#&546s2q>aH" A0.[Z-m-/ $ 8)  '67:6C$&ClPWdGaV M4$%&547#"&54>32327.#"3%7.21=/0'*!y" 4" '5-oLx>"'l37"&5463267O'#%. 8'90+N-"&#"32>767.54673   !1e%,$$- " !L$"#:Jrv #%'7%4.'7!"&547'?'7455 B,79G 4*4555557743C' @(U+7O}e*&7749774{- 6%'7'7'7237#"327#&'&5&546767.#">>??>??>?? rZM6'O7r%0-A?a6o63""5p??==??===>!?fkMO#A@&-/2 @=CyIv "gk '7''7'77>7654'k455466455 16h ./C&!K221G220221EOH H +7a@65-Wy[/3+%"'&547;!654/&'&546?'6mk"*N2Ob }= "4[~TW3 t*)$2=,'$eW?C@-'MD yA4 "ksbS]8AZ767&Z && &&% %& q%#"&54>732>?32q#   #'+)'" dS   )%2632##"&54?32>?&54632G % *#51&m"% #  #m"& 0 !  J :% $ ?"54?326765.54?6732>?63226732#"'"&#">. +       3 1  R)8K.)R     !1 "  B ,,%"543>?&54?632>3"'2- C.; #M>O1 l &&  *  &2%2#"&54676?64+"6?>#67&H,$(o:?DL9$ ( P:  "% &,'%+*6&H $EH   8l672"32>?"54632?>?6&&/4?>+       ::\G&)  f)*       $& 6" # 3 I 726?632#"&54654'4>' VA, ."- # (:! (y / +72>;2#"/4>?>54#"#"=4?6*!VEH,   O@I#%9C9 ED  & @2*  %%2#"543632?67&546"3"?654*@K[&/) I3S55 ("%(1=T&!  1$)N4(%%"+&54>?2#"&'4>;26765&&)" <"!*  +   "oQ e }p27&67'&46763#"#"&54>?'&,(K ):  KcK"k0x      7 >   D" @%2674&/&'4?2?6?2#"'".4>32;2?67&'6325*   ! / 5W  7J '!O        9 SJ  /# &4D7#"&/463232>?4/&546?632#"/.'"72>54/#"ފ( !  R#5970! ]   *<    IL   S $%#"54?2>7>7#&576?>32 +mK"+#/ 6#@0`) _  274672327474/47>72"+"&  ="&.K7  7u'2    +   M'"/.=7>75.5>?2376323>32"#"/&'#"76?6;2n%!  , $   h  G K&"F  # *&      ?4  (7'&546?#".'74?2722!36?>32#A<  %  A n%j+   " ?Cgh(7>3#/&'4>7/"hX  +&)6i  ]O0E W:    $, }C72>722#"&'";?632'.54>7&54?26 d +   ? H  t/"h..CP #)   4     )  2#;,  ,u:DP%2#';2?672#"&54>?&/&54676?674#"7>32674#" 6 h!(2L-"vQR@86  " -*$*" (+  "2/+ "8  S!  3747326?6;2#"&54?67"#".'>?2?6765&/&'1 00 !' '!,v   >[.&   1 $@ )5 }r =+"546?'&67'&46763#"#"&54>?'&r!  ,(K ):  KcK"k0"#o      7 >   D" #gH74632#"'32?2672#"/&546?>?3232654/".c   50&6\ :rG :   ! .  4- 6'  %5"  N8C2#"&/"/&54?254&54>7>7"36?45 Zk 9)%!. ,#  +3UBU**  /Q 6  $ %;H)4   _ Qa%4632"&'"&546322"&46#"&/463232>?4/&546?632#"/.'"72>54/#"F !   S ! ( !  R#5970! ]   !@ !!*<    IL   S u %%"&546327#"&54>732>?32P  #   #'+)'"   dS   \V %4632"&#"&54?6;2>?32 ! L"!  #&**'" 5  ^dR  m L2#"&5462674&/&'4?2?6?2#"'".4>32;2?67&'6326*   ! / 5W  7J '!m        9 SJ  /# &T 6"&54632"543>?&54?632>3"'" )2- C.; #M>O1  ! &&  *   b F%"&54632'"&546324632"&'&546?#".'74?2722!36?>32#   O   t  ! A<  %  A n% !K  9 ! w+   " ?C 1%2"&46''&546?#".'74?2722!36?>32#! A<  %  A n%3!7+   " ?C Y+2"&46&'&'46;!>?>?2!.'> ! %$ M+ ; /Y! "'  5 *  ( >N4632"&'#"&/463232>?4/&546?632#"/.'"72>54/#" ! 0( !  R#5970! ]   "  :*<    IL   S F >N"&54632#"&/463232>?4/&546?632#"/.'"72>54/#"/  r( !  R#5970! ]     *<    IL   S  54632#"'2>;2#"/4>?>54#"#"=4?6  !!VEH,   O@I#$ !j9C9 ED  & @2*  M 5"&546322>;2#"/4>?>54#"#"=4?6>   !VEH,   O@I#  !9C9 ED  & @2*  v F4632"&'4632"&4672327474/47>72"+"&> !d !  ="&.K7  7u'U ! !    +   V "/".46322#"543632?67&546"3"?654&   @K[&/) I3S55 ( A"%(1=T&!  1$)N4(r*#&=467>7632  \j #&5&>7632463>7632#&5"yA  # >07P$|F2"54>7>  |('V$5    N #% BY2#"5467>"&547672}++>p cq JHC ' r"F/J -('rR 46;2#"&'4>7&#"+"#'&'M&6\2I 1=; ! $2a) ,pO>>32"&54>?4#""74632/"'4'4>7674/#".O0&0U#HC% -_&$"&G0k6 G% 4 #" 0# ( \ !  iW272#"/&54?2]'  72 %# U2  'EP '#On=0#"546?632;263226;2#"57>72%1r:9 s  ' lb w- |C9$ V  ,9` G UlX9"54?3272?63"32#"&#'.5#"?>?";,+ 0"63 "#`"%"$    *V!q"4632"&5654&#"32?632#"&I.=j Q= 5 E%6E/(=M =*z+% $9qI 4632#"7";2654g8&-l.X#0 >;Q+$9P81:!#'5".5437>54.732877k0[;$]3 /57771C>K:$3$/0$#'5877$777t #'5#'5TSSSTSSSSSSSSbZ367>=#"#"&'!2+"&=##".'432>74&##"&'&'&632656&#".7>32W XB C >> @S;K>2mM4  .4) 2$$!Qp%QV.&Uz U % ?? :&;PJaUJ5'( $  d"!"( o238cc367>=#"#"&'!;+.5#"&=##".'432>74&##"&'&'&632656&#".7>32W XB C >9 >R>d@S;K>2mM4  .4) 2$$!Qp%QV.&Uz U % ?? : :&;PJaUJ5'( $  d"!"( o23PbC463235#"&'!2#"&+"&#"2632#"'./#"'&6323267"#"&KIQ&9@   [E>g Be+,4   -8b6 -.0/ hBa|0%E=<*b1"; -^2 %(W(./fPWV463235#"&'!5.54632.#"32+"&#"2632#"'./#"'&6323267"#"&KIQ&9O X3)#W5/&3/? [E>g Be+,4   -8b6 -.0/ hBa|0%E= _+(56; 4",<*b1"; -^2 %(W(./f|bD4.#"#!"&'!2+#"&'.'476326=4.+"#"&54;26p&9C#=%)#4BL]:  ;*32&5&?654&#"#".'.'43232654'&+"&'&'3CO F ?)%,  $H1I)%,  E91^D83EC$Y : ;)$ +;.ERD 6SIM9#  b_25!"#"&'!32#!7&5>32"&#"32632#"&54632'"&=#&7>7.#"'.7>=c9 = ?ϵ U(T $8 9.+V{W.4Y*"A, A#X"%5=^13?? % Ms"857q+.HP  ; G @ {  @ cbe>35!"#"&'!2#!;2>".54>54&#"#"&54654&#"'"'&546323 dIW <3='0'&7:/ ' 2A'(G,*<=*5Q( AT#*5$'A L7),O!J 7.)R2FYo.:s#c62654'%.=.'!2632+#"&5436=##"&'4&# O47x > 9#>W14/!#:)635;B =5@  c#E/78p"A8~y2+.5#"&=##".'432>74&##"&'&'&632656&#".7>32367>=#"#"&'!.'+"&56;23@N>d@S;K>2mM4  .4) 2$$!Qp%QV.&Uz  XB C >\!9S;>U[6m" b<: :&;PJaUJ5'( $  d"!"( o23  % ?-9;#?7"m9 8+.5#"&=##".'432>74&##"&'&'&632656&#".7>32367>=#"#"&'!.'"&#"&'&324&'./.7632328Q>d@S;K>2mM4  .4) 2$$!Qp%QV.&Uz  XB C >Y&H 8 \A:18vY=: :&;PJaUJ5'( $  d"!"( o23  % ?2A5`L([ =^Y<b7K25#"&'!2#!632'.7654&#".546=#"&54>2654&=4&#&:/&9=Z&C 9,W?,P)<3325!&/&2654&=4#"33 =E <= @Y%6,F89<XVF Nz6I7?>#6+6(c-43246=4&=.'&+.'!2632+.5##"&7  7 ; >+2,d47 )u ;C : jNYc?.56&'&'!2632+.=#"&54327>=+"32632#"Y/+  ; >BXQ}O(if  #5 (  )3D#)=) C =.}96 \   %+c<C463235!"#"&'!2632#!"&#"2632#".'4763267"#"&%#'5cJGS<> XG> [FaoR;nG-A sEhiD`877{1&E?@ +b/;I:TM5+R8?e)777c+8.=#"&547#".63!635!+.'!2632+"326=#?H9 !2&<iw<&% >@ >',ibs%.54635!"#"&'!32#!#"&76?>74.'#"&54>&/&5463:'"#&#"32>76"32>72654&5"&#"3 &n9-U=n > W +\# A     It dc:!  #1EP?6&# Vi U96#*8 ' v9+-*AX$ $;&Ub572654&'.'!5!"&'!2+.=##".'432"+"$3,<%= >](/UbZ `3(A)s>? < dT&9*OU  Z_ib>S463235#"&'!2+"&="##"'./#"'&6323267"#"&26=#"&#"263232KIQ&99= A>C# *,4   -8b6 -.0/ hBa [E>)I$3Z|0%E=? :$ != -^2 %(W(./f *cD2>75!+.'!2632+"&=#"'#"&542654&#"#"&'&76323G,(9> AD0) *{?2A & $a*0 >@ ;"2K!rL + #aI!6A c6'4>35#.'&'!2632#!#"32>7>#".7Z[/ a ? -YU58J!,-  l`=oH*0E#s A #D,"    " 60HOc&9'4>325#".'&'!2632#!#".%4&'"&#32>:tO  1a ?[zZ:nJ-$" r"::W(63s(A p2BY/FQ 6WH$ %6,+c<463235!"#"&'!2632+"&#"2632#".'4763267"#"&cJGS<w > XG> [FaoR;nG-A sEhiD`{1&E?B +b/;I:TM5+R8?eb.94>;5!"#"&'!2+#"&54632#".2>54'#JWBH =N&;ECYJ#8^(X./mQe! ?;'p.> $(C : #7":]3fU>!*&c546;5!"#"&'!2632+.=+"#"&'&4C =x > > $2 3 8   I#2Oo?B <'&S7  r%[c4B4327.54632#326=#"&'!32+.=#".74&#"2326 '943( +]H,Qt;M # ?-O9mD) #%\*C($-rKAR o=@ <u';NE )sbJ463235#"&'!32+#"#"&#"&+"32634632#"#"&/4&"#".XZN':; ?  " XW  51&%4 4 9   :iD(V?/Q:@  .>. ,62'#I+3MXc@7"&547&54632"32632#"327>=#"&'!32+.=Q}2Z3=-. '  )3D#(if ;M # >B}96L<*(@+! % \ @ =.c$46;!5!"#"&'!2632+.=##"& %  =x > >%$b6&?B :("_c#Zb(%"&547.'!32+.='26=+"T'T = ?!k8T  / @ ; O9YLN;b2@.=#"'.547.'!2#!632'.54>54'4&#"'26=+"?$C82>' ?Y$B" 0 (/!7U&; 5*W / @ l {K[w  4 Gh-  3!8Y#{ b"0925!"".'&'!32+.=#"&5463654'&#"327TH   1Z = >4]cMY +%#G &''@(? =DC8JZ=)   %B" c/4&'"&'235#"&'!32+"&=##"&546;u(#<aP ;M # A#_4-?Y$81D@ :&8  ]%c#46;5#"&'!2632+"&=##"&735#4< ; A$_?C :%8]Pc%54&+"&'!2632+.=#"&'&56263>26=## G; ; ?2GU&'8 5Qt-V>,?C <u({Z #0%o=5:>T fb,3267#"&5!32#!.'.U0%8/ > 1"@DA- "R,D$ jN>> 'JH-(L81,F.NAQfb":b@4632327>35!"#"&'!2+.=&=4654#".?&XF#l:W < = 35!#"&'!32#!#"&'##"&54632"32>?4&2>54&#"L R)%8F ? !odI;s8T@M?&I4\7N!(K, L(>#&50#F+#A=?   \\E^FdYF\!,ZA2$>K &/# (*24  !wb#Lb"625!"".'&'!32+.=#"&546"32654.'&TH   1Z = >4]c/<(   C[$@(? =DC8JO 6% A@b&%"&547.'!32+.=532>7T'T = ?!"(" / @ ; X<&j c0>267>7#"#"&'!2632+.=#"'#".26=# - )C <> ?A#Gc -RT WbN3u/%R;@@ :%-5za [& ]0 /bG46;5#".'&'!32+"+"32632&54>7&#"&'.547.m3 1N = 3 '[2 @"%:Tv7Qb-2_U#0%@(@ 9q2"F? 1'E7">,- 7-R54./.54>7;2;2#"&+"#"&'4'432%9 " ~`5BV#4)E  > ("1*"&.o7! =57" -j5*> t@K|c.5"&'!;+}>;0 >&: ?? ~(.5"&'3=4632.#"36+}>;U8H3F* X>/K 3&: ? 7:2) 0 +),3V , |~%.5"&'3.'&#"&54632;2+}>;S 6<2R DaJT/@&: ?({9*'>-bn = MC%'4632#".'&54332654&#"+"&D4jG-HZa& !)7X5:22' ( 'b82*+Y=(55%5 ' +:BX#'4632#".#"32632#"&4).t^D (19M(&21  .&=y #)G`T-@@-&  , qbNC4732#32>#"& )06.C]K0 I   jbD6467&54>32632#"#"32636#"&#"32>72#"& 47@ 'BgY/= *O$((X&=& +Y4Rv 4*% ! &#- #()+c:s".5437>54.7320[;$]3 /51C>K:$3$/0a~#".'"&#"&'2 %0@i> <xVi(:;->qa #"'&'"&#"&'2.'#"&'&56323  =agUB1c/e d:8:N< #" x|s"|~%.5"&'3.'+"&56;2;2+}>;S!9S;>U[6m" @&: ?-9;#?7"m9<|.24&'./.763232+.5"&'3.'"&#"&54\A:18vY=>;P&H ?)`L([ =^Y<: ?2A= / .'"&52 %B*'<>k##'5#"&'&'32>=4&5432>32'&'&54>7654#"#".'&632654.'&#"#"&'&>7654&#"#"&54632{877'N>^;3c#&;@0 IV28c<"#$    49_6+6  $)8P#777^2_sb 9"1*?)6$0C@ # -*(  ,67 /5.?< #!?+  9(* > 3C<4b7KR25#"&'!2#!632'.7654&#".546=#"&54>2654&=4&#&#'5:/&9=Z&C 9,W?,P)<35#"#"&'!2+.546=#"&54>325!#".2654&=4#"3#'5 . C => @Y%6,F8>: FS QZGz6I7< J9!0 1g}/xq [6+6(777c-443246=4&=.'&+.'!2632+.5##"&#'57  7 ; >+2,d87747 )u ;C : jNY~777Ub5<72654&'.'!5!"&'!2+.=##".'432#'5"+"$3,<%= >](/UbZ `8773(A)s>? < dT&9*OU  Z_*777|c<C463235!"#"&'!2632+"&#"2632#".'4763267"#"&#'5cJGS<w > XG> [FaoR;nG-A sEhiD`877{1&E?B +b/;I:TM5+R8?e777Ub.:A4>;5!"#"&'!2+#"&54632#".2>54'#'5#JWBH =N&;ECYJ#8^(X./mQ54'4&#"'26=+"#'5?$C82>' ?Y$B" 0 (/!7U877&; 5*W / @ l {K[w  4 Gh-  3!8Y#{ 777,b25!"#"&'!32#!7&5>32.#"32632#".32>2#".5465.54632&'"&=#&54>?>7.#".'.676>c8 = ?ϵ U( 0%>9 0 , +'B+N0H,  A @ / _!:>  822?? % Ms" #:  ! * )95++)90'; I ? c cb>35!"#"&'!2#!;2>#"'";2676;2#"&5462'&54>54&#"#"&54654&#"'"'&546323 dIW <3='0'&7:/ ' 2H! !9=L$9  %*==*5Q( AT#*5$'A L7),O!J 7.)R2FYo.:2 J;26#"&54654&#"&74&#""&5463232>320*%/0C2< - #5 >.1(&3TT9( P= ! *7"T$Ef2.JR"32632#"&=465'&54654&#"&'4654#"#"&54>3232>322>& " *- 4L 2 )% *0+>/#''2T0"  +\=   &>& U$'*e1:  ga 2.=54l >=aB < a 2.=5432.=54 >= >=a?< B < gk 4>32#"&2>54&#""3+G#3+G&: ' 3A)>I)>@"1+$!( '.!b/>"&54?6'4/.'&54?67.546;22654&+ @  W> V$iM 9z?60 8e-"  ,>   ^C N n5KFb)JK4) "8200;$1$i96#"&'.'&"#"&54632;2>54&'&#"#.54632F, 6d $ O'>D2)'/1U=pXgKj771N+J+ = e+izE@%#".'&#"#"&546323654&+"&76;2>5&+"&54;2z '%?E GD "N<)pBs)4 < m4!M(JeZfQ2S&B +'@ '>*7 MK:a!174>7.542?632#.>54.53#" cF  @*R.63oe%S 5% b: > TP&9q%  GJ `9'467367#"&'&=4323267>7432+".'#"&F.#] > &P   > @..*0b=V(C[-&E@=B}=c9"6AA> kA+8<7HiiL%"&547.54>3:"&#"32632#"32676.543#"&'.'"H%P%>9  , oU  !==49*:('G 1 2 'I3+ `,&5   G0  = S*% #B" Bj0 W;a&94323267"&54632#".'4&"32654&5.'& ; +"--)b$RJ-I|Z.@?B5(?6 #R [; R`? $0?G@7wm %8_wfD*,0 F+4.5!2#!&32632#"&7>7"#"&5476!$$6 ? !r9G[( > :t'Oi&5  u(e <@ $)q%eOfb%7"'#"&'&632;>'&/547>322654'"&#"AB3!K5&4  $I J*Dr*N786e/K54$L6k$'u[@6' .2 4>32#"&2>54&#"21=l21=lt.1 . +:s7+:s76(& ~ ##"&'72>72'#"&54632E# +T B !0 ]8"  #%   /V #2654&#"'&/5'&4>32#"&sG*$9!6jfE;))/=7(,C]7-%-$qT}U+:#0L)'GTN# #/732?674&#"72654&#""&54>32#"&54632z$ !"%6D+#31-?3&53;*'IK'Eo7!5-#*FU,+.P)KK531?f.*2!5!#./.'#"&'32654&##"&54>Ql:z[)YQ(M.&!!-1qXeI22<. M y0"'92! ;4'#&/.##"&'32654&##"&54>32!5!632'4&53#'J2 F$]S)M.&&(1Ti: <:b`2H$ZK y0"!?2! sVeI28KrZ324J23!./3267.#"#"'67./#5!7654&#"'#".54;2327?Q%/8 ?CQ@s<>N5^) ?"/k&!!8s-7%)WL3 2 0+j+,.QDD}'110'4(S" 2  /!4(Z67'&547"&'4>732654&#"#"&=467'#5!654&##"&'4?32?6323%+%3VR8>*() B=:(3 !P %+"u} ~!,R  O* XLf 0" H(6-K->-gSVJ UL>) 7S#' )%/'2 <2)I12>0O23!32?632#".'32>54'#"&=#5!?4&#"#".54633()4#z "(6dS*F0'#/O0&;  V*&f' 7-A+? ,7 5$2(.m6Tg -O>c5.B^K5,& #H.#2 (  !7L O23!36?67#./&'2654'#"&=!5!2?4&+"+"&54732>7Ra $  YqX9SA5W/[ .L02 ;9#  '%q426753#/&''./>7'&##"&546J1:)^6B&)4262tt!A7]841 V1+1R?2'20%<2l/W;F5K+O $!&"6L32654&/.'47#654.'"2#"&5464HV>2?ZQL,KjkKK% #$2=.N>>D',=12$ !) +Y@C2@.  ?#-<*3;'.'&#"#"&547326324'632#"&5465 5* HW* 9( >&&1&  $%.39/.ePJ:+7%' l  5  (/"K,?QP'.#.547326324'632#"&5>732654.5>7?4 '(*4!)CO(:#10N %!1(0;*CHffH!axr &1+ 6- $@+P52/-E'h  M5 +8,G+ W$2!=,3 *!>&984632#"&/32654'#"'4632654&#"#"&F7E',RA];"!&9 #.-?8. $,#M3'CUG5@-)?54.5467 +-c/9<+8"W@4]A;%k.9%"%%;2R({^85&&IhiI"! # ,D0 -491=8G6RykBE.&!$ .6&$$+=YN *F(0B54F.+%675!5!#2#"&54>32654&+'.'*Ij+A!|VBy1#)X0 *vRL.(*s#'22&vU(4'3Jpkb03#&/./32654'"&54632>7ST  7S>S=v9f*%0)&"?H'Z=S2 *04! g9)E '-*4C#L *_ 83#'.'632'>54&#"#.5>32&/&=[[2$B*--((6>:I  "Q>[e^# 2-),7*+,!3N&AL )3RgV*1.*27#"'47#5!#/.+"'767#"&26RfA =]q<B+#*:'5 Nlx/:2245KD0 =>2654##".'32654'"&'5&'7632#"'6*<Qw -XB?e:( '4F4 \-J  &W*3I86'A> 29*CQEb|[&5/#"&5#5!A-1!"7EE.<>QP'3-E' )3)"GBp22. 826=/&'%&/&/32654&#"&=#5!!7|G)*FQJV;bt'@710,?(,?F3Hp2$5 ? ! 1I#T:'h& \P5/ ">'22A %5-d.S47#5!!327#"/&47##"&'"3>36323#.5472654&'#"&~HsN82KT'   ;s 5 %K 'K<8V. eS#H *3F{7J229McrMN z@7.H! #(J&;N),[%2674'#"&4633254&#7#.''.#"#"&47.#632#"54>72>7!*"!% 2a ]*":9$-fM\*.>N .K `U]#1S/*B'&.!*X78I'20:)i1(2oHI.( \8d03p8OG65!?J:23!3267#"&54632.5#5!754#"""&'>73?QL+m /1>vO!5JJD  F2[ /G52$k-#!69BM$;20;3   *_?72>54'#".547>54'#535&/&5473!7>#5.!60 J6*>16$ ĥ34;%FV-7+_J0,N3,393I6&80-E'(2  NHA"30)[$2=#.(#"&/5#5!!>7#".52654R& -$F[ !N8;_5$ 3R4@RRF22D"3r5H0Dby^$8ea;N+"I.!7"'#5!!>7#"&54632)/Y1P!%) /9.IOd22 W2'$//+K2&2.=&53#'4&#"3'4632#".'&54632R G^6O:> %-3+ WA;) d} >285c.3)&'1" #CW<$ -D=.+/2#./264&#"#"&546%!!B/I(F'!&4W95!00H)1_A 1$0HJ$2>-DV/?hU>/ O6M2(Wn3$("6-+<^2 13#&#'232654&##"&54>;25+"`# WTzO@, %#*=2+O'<' N2 :2hV4  %(%8 N.'#5!!767'&54?CnCBq5cLWA#+[m>E22,RApvNNqf@'4$32?53#'./7"&'4632#"'FeN}6! }T T;~.8*10 +H@]T&IB2UO^1( 0 .2!5!#'.'#"&546/]W#*7&#*"4LbA 22LwB- #(+35?#p .&#"23#'&''764&#""&5632'5;4 "%!DM2#G+ " 1?t $ 9 2-e .* i^~ r.94&#"'./7.'&/&'#5!!632#"&546323279, -4N+: )#,5J{,b Od/% C!)x(7*S~    22I+gH7X_H(0! ".%675!5!#'.'@]dwJ֗\ #<`9H2qk."22&9C/L'.$(2767#./32654'#"&546'!!$BnnV[- @8C*8NP>,?&6$8#>:./b2. '24.'&/#5!#'.'#"&54>?U9-6A  #]U,'0-%$+wA9+\ ,:226p,4#$. .'#5!#'.+"'>N3 ;[\*WFD1G/D 9"z~W%22NqT+6.""&546;2675!5!#'.'@]eCb%%tX (A`4Jd1R#$UB!22?K30.725!5!#'.#.'"&54632+"&54>3246H%U?b2-".0#7 %(, ;P(" D&+!%221%.++*1 !(,!O@&9 >*93#'4&#"#"&'#"&'67'&+'32>7'5 CZ2C4&, #   L A2m208!'  K 2.?` 5'/@#&3($''=$u .,&'5".'#5!#&/.#'>?67&#"Y&+%&hK; "Y ; D, %2 0-2_z*"B(22'&bX(  .025#6?6&#"/#5!#'5.'"#"/7270 $K]<',e2  '-.)! )<  ?o229! "!!9K# @ .+&/3674&#""&567654'#5!#6~BLeq7@k~ *- 7''n*/1@0J 0D$.G3!; <%22  1e8 #"&=4632 %] "* ./2&/3674&#""&5467654'#521>0nm7@k~ *- 7'!S*.".9,+>{D/.G3!; &82>23222&'3#'4&+Q   .ZX2@D.93ev824{1->7'&#"3#'#53'& %?(X4 TVeDV r2Z^,t  "L= A8[)+2/2/-'23#'#53.#"2#>754#"&54B_ rr2UUa2fO+; F5 {ET-;xL222cj*/2 $1(dN#a6>54'5.#"765656=3.'#"&54> +#8W$#5)'%8 " d  ':* N-%  RK!#"&54632'&#"367?,:!-E  )";r5)('0rQ./?8 Zc)n  \@:j2QN <%%N_H#.''&/&/?'?tn *'  -2b 6)n *&O5N% ;j" j2QN%:. ;&'467#"&547#5!:*E1%' $ 5"L_eF.>oF*> #1mry2 C 923#"&54>32#.547#53654/.5473;|)MS<8\/,?1= +A$iN-@; A D1 2]=LH#" /.>M6f2 &  ,+* 34&+5732&'3#'&'>7#"&547#5!@D1 . UU0Lg)@3)5"N^fF1-293U724avDCX")1td{2J N4&+576;2&'3#'23&#&54632#".'67#53654./&547@D1!7UU0kiWS ,|& m ("7+1F!  _ #A/* 1-295U3240G2<,Et 14>^Cn2   *,^.3#3#66FN3.2 4 64&#"267>54/&/&'4632#"&'" 65 ###Qg%  } ZG': b/D " ))$,) )  e 4+ ?A^*" dO-.( $N4%.3#'#53654&+"&54732632 hh2RR -k^RcDH 262E+!#;". <4632#"&"'5#5!!>3#".'2>54'%(#0<1 2(1fL1R8,%0L/.4$S5* "":W22  *#g9Yt(>VQX8/NZ>. 6$!D. +4672#"&#"/#5!!3>7#"&54632{  1 A."Z/N $*$2(0#?!kAX>22 V1 'H%. -4632#"&'.+#'67&/&/&'#5!#,0<oF#' !~FC:Z #:'b: 5&"qV"$GQqU=C  #22oI26753#'&/&//&''&/?./>7'&##".'4>J1:)^6B&F-272rr n *'2>wB41  ^+1R?P1"-%<2l :2;N%+'HjK+O )!6Lk%#654#"632#"&54>3265654.'5+654.'"2#"&54632654&/.'47+-@@-" 4    #'7(:;. % #$2=04HV>2?ZQL,KjkKeB!4&$ #@   & !$L)$2@.  ?#->D',=12$ !) +Y@4j#6'#654&#"632#"&54>3265654.'467 )+k!A     "'7=JD #N( #$  ! !$K)! (#* w#8o#64&#"632#"&546326754.'467%#654&#"632#"&54>3265654.'467! +!("!   "%&8(:;.1 )+k!A     "'7=JD-  / $ H  %9L*$+2 #N( #$  ! !$K)! (#* 07 4&#"326%4632#".'&~-6Ij8-!$ /A.0G%.- >}"1!&/265&/.54632K?qC$ 1_G"Ec5 "0?'3?EP5&@*/(I+ $!" 0J%$%#".'32654&'#"&54632 )I.1H@>,M2`*E4'$3J:9s/?3$5Sd{U54.#"&'>7.54>2)7[( A&)+N!5'-+<,>(Z>6f C*33#H^E4U. Q(+ %+9&!* K9+6%R:5= G)/7& /& !F #074>7.'3.327#"&5467-%'/F^-=;&e )(?G112)6u^R+G-;"!K#@'FG 1M+'>j_ (4#.'32>54'"&/"&4632>p_$@(;e=, #0G*)<  @!$>! BFv!$:*Lgy[ *I=@/ !1')!,1*""+#A\!$"36=4/.#&=#"&/46322!N !0Pk28q1T-!!(A  DG"=gt7' 64&#"2657""&'"54632>72>7!#,) k  5)e[: 9& 9 & 9C  #dB   73FZ8.Kj73'654&#"#"&54>32Jj  <~NVs/" 1(! 3FUGDBFC"?&3*-!1 c) <>732>73#"&54322332654&"#"&54632#'#"@-"8bC8! !2TQ3L>  8/%0'0?!1'F-DbVe7Zh6FI2!    ')4J5'9 /'7;#"54#632h &(&%9TG&7N-S()"+"=4#6232?>32;#"=4">#%F   % $&O_OO&6HF&2! K8S# 72>74#"'4>32#"&5|+:?!2 0 /(+< Z34S**H(! =V&9 )(=R733&+"467#"54632- '0!%9 Eb  %-6  / /1"*4e '-'J'4$ %0! u20%#"54674&'#"5474&'#53>733##5(19"< MV(262U8 e##8r2@AJ490g nR#+%:AS,9+ U D?3 9#t#m##aD#0 D#0# #mD#-3#"!##"&'.'#5362654'!!!> Ff 9'$_MQ# ++A>$#'CG:9? .BJTrL-<9Y8+*!3H0t#*m&74632>5!5!##&'#"&7267.#"#_L1~@&@B&3L]E7Zs m#-7*>gA(q.2D.G9r#D*J0;`O-9Cu[=+.pfrK-1w#,!!2#&'#"&54632654&#!5#5!.#"32N,15L FIW>_YAs9@+# N)PSVt@3b7!=D548F.39L!85##"&5#463!5!5!3254'!e_Vl83EbK8hweD-89@v @"*3#!"3!2#"'.547&5463!5!5!4+326%;5#"@2--2&,nh<$- :0*2@h^-1&43)/-%9ݕ+B2+D F./#0/;\9]@!%###5##67#&543235!5!2@@8` #!#:\89.0!3267#'#"&5463232654&#"#"/7&'#5!%RJP 1C<;8 KY.W;70>A%z :z'3>.݋?LEK "J*G <&&0/A%@99$#!"3!#3263#"5"&547.5#5!5! )=9G7J? >`&ݚ0 9k9>2DM9a,5'7>32;5!5!#&# 32>;#". )&;*G'' X-+g;43# q9'[O4* 99U^/#?[,F674635#5!#2#"&2654&""BBli9skktHx{99{xHLba%G)9KL8*F3%.#"3223265#"'5!##"54632654&#"#"54Sj)@qFl09b22D5hHS;=u327&'!5!#.'&#"327#". l>0)6&". 5$+-S;,?EzTuX?TVGO3Z99(aG$f$+#5O|Sd #M)23265!5!##"&'632654&#"#"54l09'O>-!4Qz Su?N<)uLFe>;;;h7K2ML> N3)(8-. %5!32'!5!'#5!##5#"&'654TbP_ 2@-CI'i(,T2299#\*Z4:][%#"&'#546;35!5!#!32>3j?gk 8(4nB4 AYu7,G9910 7327!'#5!##5#"&'64jTbP$$i 2@-CI'T?IFA99#z*Z4: $74675#5!##532654&'3?"&]o l^mM#Ir89sJ"MoDiEg99gChG@F;57o o65;H73273##5#"&'64'#53jTbP$r2@-CI'' V.T?I9#z*Z4:+9ReD$"&54;5!5!#!">274#"326@ulT=\vR\&V'E<%&; Y~v99F:>*4715 "&546;5!5!#326=#BR;0h 2VuA*1 Y2?99?Rpo5,~297467&'#5!##"32654&'.'327#"&!>2AS#Ɔ#RBkO20^K'M""N'K^.Nn ]00`3K8j99j6K5F`9F)&M89N%*E9`< <C72"&467467&'#5!##"32654&'.'327#"&!> AS#Ɔ#RBkO20^K'M""N'K^.Nn ]00`< h3K8j99j6K5F`9F)&M89N%*E9`<##!"3!#3263#".'.546;5!5! F^J92BmH9QD2nݚ9;79"N791.;a9%!32#"&4"546?&'#5!##5# 9% H2@ R ,@'T(B99#;8-!3"546?&'#5!##5#9% H2@ R@'T(B99#;8-7325!5!##"&'&546;#"a\H~}2FV/,D54849l199%=:<6D9Tr7#5nrrr##53|@<99*#54&"3###5354632*@!6!<<@22K12J($%,9#9.1FH1###5354&"#5463232@<s1 SZkx  #"54632&#"+"5432.- X gmD$F>&V@%4".Zd< #&+"'3;2D4_08,<@F=7 "&5465337632#524&"3#]v ==\@  @rF9 I)o$"#4H2 &##"543532SW"H@WM -$'##5#"&'654'#53!535!322"&462@-CI'' V*rrTbP#\*Z4:][+9T]}53T4 Z )%5#"32!5!####"'&546;2"&46(%/+$LZ2@zZ=9B8a( //+99#}f=9L;F "##5##67#&543235!5!2"&462@@8` #!#:\89& /23265!5!##'#"'#'&543232654&#"#"54$K.@ )OIHH2!LD@,(3I6&N1]a W/990W0JI1L: $TZ% 2*)")/9$."&54;5!5!#!">274#"3262"&46@ulT=\vR\&V'E<%&; Y~v99F:>*471554&#"76yJ:Nur'3OLv72F5,d$wbA]x6*R9EC8Q-F:74&#"5632#'#"/"&5432654&#"#"#"54632326XS_k;Bdi$:Td( Euj?I 8r W4L[%7!4#EJQ98++?1F&("?)6%$.2654&'52+"&547&54632654&"LF9-I]P8aC,Bb8P]I.8>QFhFIbID+29QCN2)CAUW?C)2NDP93* ",12+&))72653#5#"&'654'32[@@&YMz"B3&$91`;HMDVFG:@%"&#"3!!"&547.54>7&546323"&#"2#"&#"32632d(.#:K9#5/.;'x\3r8)A& r"BX:0 *7%!#9B7G @'- >-;5;F5&$ $&1) (*( &54632#52>7654&#"r jQUqNn_T M87C "!!LZcO9 /V87FA5  ".5#463!!;uW$P9W|+JvT.2hdX9X9EbW3;%!3#".5#4633&54632&#"iU@Vu.\Q/H7QWkV 3C=5]4[lE9"9\dDN2HIeKM97>e#654&#"#&5462( 2 &@V@>0 & #((# %%26;#"/467&'#5!##&#"5!,! l=h?g9#N ,)03C7 .f~7%.`BW2S*[799*.B 5_D)16323##"&'.'#5!.#"!!>2654'! +l 9'$_MQ# uIGe z$#'+A>i[9? .BJTrL-<92OG:C3H0t8+*!+@IQ[#54#"&#"!##"'.'&'#53>32632".54632#"&=%!3>4'#326%4&"26@9uC+20H 1" RBD=1- `D*#Yi)F*@\;?X`B<"&@ !+6n'55B55B5O(c:X595g)7?I5*j_G19OxN0"s,&6HE9l :Wf);,c%0'('( 4>32#"&''9.D-%.! BU.%5 - &$:f[ %3?M%32654&#"#"&'4>3232654&#"#"&'4>3232654&#"#"&'4>32*0" 6!/]>BS'8/BSk*0" 6!/]>BS'8/BS*0" 6!/]>BS'8/BS':A2+;DTf:$5 M>':A2+;DTf:$5 M':A2+;DTf:$5 M2b:8CS32735# &5463!654'&'#"54>3234>32654'"3:>7!!#(0G' NzL4 ;)}$0*I`L6))*!+-5KlW:&8%# :`&&+;Z^elV%/<%cB#>(*$8!3O\FZ .'0I%8)=  $;%/:^iy5463!654'&'#"54>3234>7632#".5463232>54&#"3273#"=# &32654'"3:>7!' NzL4 ;)}$0*I`L6)2EJ\4`\&SQ5?7UB?VG25"++! XG()*!+-5KlW:&8%# %/<%cB#>(*$8!3O\FZ dD/eZ:"@)(%  %1 .S3?/&&gYel4.'0I%8)=  $;%B9lw254'"7#"546;2#"&'#"5467&54>32273#"54.#"632654.'.'3232654&'&#">Y45A !E1gO%&JN:%&)7"2QP).|/lkK;9$G_ZRV@!>   C>n{LJuJ6,{VS$@(=4HNB8;QA@Me.}EV}aFcBsTQ,@2_Z-/Hk/HxLIY 0F(6P(5}Bt$uZ:3SJQ9%.D@R9";,,$3 _]E'8VG^.nk::A"UWC,Z&N $A>$1ZF,$M94<,X!K7237>'&5&57263>54&'#"547!"#32632#"547!32632M$ (i8#5&G8  !2)G!&5$ "2) IYW 0 'r&(MY+.r&)FW 72654'"7#"54>;2!#!"54>7654&'!745? D1%D+%Dj;' =;/J[!AId.6^<<m#'F(9.QN(( .&,>L73M7"!/=4>KIu(p] T`4#"32674&#"632#".54>3263!+"32>?#"5463#"32>7#"5%4'"326#!"54>764&'#"54>;2(R)23/(#=;*C' %[5G\I(<  %6\9p-K4e &EUK &EH43A %3 A-NWf&6]=9/J[*Y+"H52&&2$BE:KY#0<(8G:(621# +5R 7# 1/RF(9.!("8+?t'J8< .&,=L83N6!!X6C4>3!+"3267#"&5463#"632#".32>54#"-BqE V -"!1 1O, 'd &bJ,E$T7)% VHLcR9v1!6M3<.=S3S#;%bn/@O5558(.r.mW6C%#".54>3!+"#"54>5&67#"63232>54#"_`H-G%-BqEV .>9ON 1O, 'd &7)% VH`p.@P5LbR9*0/J+  2B.=S3S#;758(.r.FZ x4&#"3267#"&54632632!"&#"32>323254.5476#"'#"'&54327>54&#"32>3#"=4&#"632(*+014'!JcBGTmuO)2K+ r3c %6/5H  2%'+ `rk?VY=?ڛ!-8&R?,I %DGP*C' $\5G)'0+!G67632.547372#"&54632326'767.546323: 2"/(3+ "?;R,}fYO3*pBSmF\q+SY#'OG-C7)? 19,JE&6L}hF8`u -UFP!7_s\P1( #*>)75 ,"%b;Ka3Q U6hOTE ;pg6ngP6;j>^.$7-$<6.A  R^MM7632.547372#".54>32#326'767.546322>54L/;43: 2"/(3+}9e^/LCC2 *pBSmF\q+SY#'OG-C7)? 19,JE&6L}a4S. 1: *8 / 7.8]!7_s\P ""3 (01( #*>)75!.g^=%8`=OTE ;pg6ngP6;j>^.$7-$<6.A  RTW'/# 2@2%  ! 35:# hN[x  ,"%22Y'4X =73276=!"%547#"".54;547!"#32#"54?>74&+ThMP;)T .@b8# |8  eQPCBEATa=K2Eo-_+):4W 0 'WM  =4GHC[L7#"547!"#>3232654>7#!"54;>54&#"547#32?2.,G8  D-+3#M+)>)#$5G7) #-%*!fMYW 0 '>4#I0Um >,eA6H ,0&%&+*r&X 073276=!"%547#"!+#".54;547!"+ThMP;)T @b8# |8  =K2Eo-_+0):4W 2 'FZy43232654.#"#".54327>54&#"32>?3#"=4&#"632#"&54>32632!"&#"3267632#"&4&#"326t'$H0-S.8MC5T1! ٛ"EFT>0+ &DGP*C' $\8D]HJQ "4^;uO)2K+ r3c %6//M(@6O(%I3Qf(*+014'!;- (9 Pb1+!1A9,m`Zx ) # 6*R'E'2#BE:H\uP5I;*^\ /C;! 1K%?N|352/OF'0+!G6,Xan%.#"3267#"&5463#"632#".54>3!+"632#"'&'&762>%32>54#"J/"-"!1 1O, 'd &bJ,E$-BqE V ;3 .%ԓr F(8J5{sd^>`7)% VHvQDy1!6M3<.=S3S#;%bn/@O5LcR92&D,ՉdE}UJ%D2Mg^v58(.r.\%#!"&54>73 =))2//5  Xt732>54.#"%#".54>3263263!+"3276#"5463#"#".5467&#"#".5467&#">327"32654'&%"32654.Y /% )!, aO+E%Vp_lWnWjATV &"R I (C)2K#=3NXT"hT,F&>8HI;WE7[5 &"GG8)@n K 7&.> & '- (/.'#ao-?L6Ye11,+- v1(G9lo5A6$=[LD4%Yq->M6J0' !5dB:#;CF]xA@=K3fO8Z5# CX J73276=!"%547#4.+#".54;547!"#32#!"#"5463!2>ThMP;)T E/a@b8# |8  Kd'6@  /Hn;W+=K2Eo-_++6B-):4W 0 'V~=H(-Co=;*DCXG7262#"547!"+>32#!"#"5463!2654&#"#"547#, G8  B-*4$?}V  /Hov3* #-%*A( +/YW 2 '?2"J10WS1(-Co=;Qh8F-X($+*r&_Y Td732654#"".5467&#">32#".5463263!+"3276#"5463#"74.#"326X7&)#V++3K%99>HFo>* [5 &cI-F&ͧUd@S V HR Iu.'4'E4%)D77G(q07VP$19,>N7:#;%`p->M5)(v1(lXn73!2654>7))>=))D )j>,/5   \%265#"#432#!"&54>73&7MRO|lcX=))2Svry/5  #\'%#!"&'#&54>73274>73!2654>7#)>4,;Xh)AB))D )j>,"%Gc KeI   mX/72>32#"547!+"#"54>54>3#"i 4(GBV /=6-7- A AYS, 1/J+  "$71s'`=42325432632+"#"5&546;2654#"#"54#"#".5a$&O-UeC  /Hy_\*2&(QLF!, k(0h42Ki8(-C"- =;sk>;43yvu[.*X<J%#".54>3232=4./632#"=4#">324&#"32>f$99:V%=ds=4D! tW $*G=w7W0 [5 &O+/E7&% ;V,Ws:VN'@G6ǭ$3& aq{,.377(/XIX%262#"5463#"3262#"54#">32#".54>32>3!+"%4#"326Z.,G _!.,Gq] [5*,#998N! 2L^W$v"22sVZ+ /)#B(LYv&(LZZru:!C.;V,BaGFvK6J&$, n5kr" '- G \K%265#".5!"&54>73!432+;2+"#".546232>>5SR-"=)) e+HTV@MOZ"5"/5`?0L+ !6"-L?7J$&2Hv /0/5  rNj6X/' +!2:2!'0# &26G#683z[AM4.#">32#".54>32!2654>7#!"54>4#"326*V91F:/G01U#99-F$/J\Z(;]6$ -(7 ))>@080Y'0 :7)"0KU: %:jD7,KV;V,/@P3BsM8#5HC#8dG- >, )3p;r)'$\F$X z%4#"326">54&+#"'676?!"54>54.#">32#".547632!767.54>32'3254.Y'0 :7)"L'8 O7 - AE6d 0 0D*6,A -, *V91F:/G01U"77.G%?m;]7# V0)'WS!.8)-G'<M>! b; r)'$\F#3)Bd -&)=M0'3"&j):`:KU: %:jD7,KV;V,/@O5eV#5HC#e&*81#uA,F'*3% &< =2#1::  (\J\2#"=4#"#"54.#">32#".54>3263232=4./64&#"32>I8I $-- ,'6V0! [5 &aQ:V%,BqFt65_[@tX%$+/&  /% \le{%M203G.G#-=O3:#;%`pWs;LcR8azǭBI R2> '- (/$V w%4#"3264>54.#">32#".54>323265432632#!"#"5463!2>54#"#"54#"#!"Z'0 :7)#` -, *V91F:/H0 &cJ7P#/UN;]7# U1`%$Q.UeB  /H @W.\*2&(QL-;Aq)'$\Gt):`:KU: %:jD7,#;%]sCaI6ugB#5HC#g'h42Li8)-Co== ?L3>;43yvu+(X+62#"547!+"3262#"5463#"32 ,!GBV# ,!H !j*.YS+`'(*.Y1r&%"#&546763?62#"54.?Y*7i.0.JIM".,G*;6T!74</8.D#:BF-&#LYGl=' t 7254&#"&54632#"&54&"!A-jAYxW6N4;6D*(*;*3V([!Z@1l*8;1( b354'#"&=4'!263!2# 6%  yG_L% +.1( 2c_ 8>'23267654'&#"32+"&=!26;!2#"&545467354'#4 ':nHS-2FTjaG'6$ #R~J.`{l"01"]LUSdtXc!/027Uwn=s{~In% Ev J%2654&#"4.#".54632#"&'&5463232>?2#"5)-!-,&3IYE%JR?)">$*[A 96 4eGb9,MjU< 2#DJF832#"&5467.5462654&#"4#,-!0V 96 |g4Ojc2tY!56F^* c54.#"%#".54>32632#"54>54&#"#".5467&#">324&#"326Y /% )!, iC-G%Vp\hHbBi?)VK.7._-:gT7P#9:HF;WE7[5 &V[%"GG828 '- (/.'#jf->N4Ye.-#5GA!S=+;qBgYq@^I28% !5dB:#;]CFrv'w&zv'".54632X!, > * %$&#/(%$ * YGV%262#"54#">32#".547632>3!+"3262#"563#"'4#"3265.,Es] [5*,#99-F$?mu#22sV ".,G_Z+ /)#B(KYZru:!C.;V,.?O4eWK&$+n5(KXw&kr" '- GK\ 2#"&5462654&#"I?H=;QK;2B;1?65S5CWY@>K7,2;E+((\$ )7"546324632#""3274&3254&#"H#'#c,"!HC.)B,.K%'!(`(", ,%2,,(!H?73254#"32#"5437&5432#".54632#"54732654#"w/+. "H(,%O96P%/-'$? TV9-)&%M *C>0 9=%-A55>'#B "?QG(&Z(.6A%#"&54632#"=32654'53"&54632'654#"'"32654gh1/#"?8<.M< !!"+$!/+hPg6E'$; 3 )5  :*,#%%/(*R 'V,=H%#"&54>54'#".54632>54#"+"'&"#"&54632632%3267&#" Q$5 C/V0 B8  r-!3)_,1$%E [6 "&  #!0;I25!  #%22pS'&-/'QYbk%#"&547##".'#53>74.54327676323223&54632#"'654#"24#"'4&#"#32>)"$-XB(5&SRP7"!  AN@#0El")")5[R95 I4$5  =,.!N$+1$ BM >+8P   8L1 P4#,%((& $ kN&u4D,!(1'LS%3254#"7".#";:;!32?3254&#"&54632#"'#"&54>7&54;2<*)*)W9&-B!;! +#, !X  4$&N:-?,M&B* m!"#4&3$+%B" $#"^.::9@D(5+ *"& BTzQ[d~%#"&47##"'#"&5467&5432632&5432#".#"!&5462#"54654"254&#"'3254&#"254&##"&47#32?1%-%$" ,:.B2-5N= T 9)+G%>& d31+)&X !$,$3 %"(5/H-4E;!I3Ge$&.) 1!#!3)"-' (.05!{B# $"4#*#)-$YB60m2#"&54732654'&54'2#"&54732654&'&542654.5432#"'#"&54>54+"&5463232>7 !)@5.9 '9-0c/D?7,: ,20.:)$'# C0%4 ,#0,5,5 '. #'*3*5 $3"L5BR9.221Ce_ODT9-4/4D4@ )5,? U\"=27:&*!-! $'%!)#-3(6)e532654&'263#"&54654"&#"#"54632>32T&43 o#/W I#  0+ N0# &,P@3I//"A#' #*dm L#1W#0)Wj"(3723254.'&5432#"'#"&546"546254&#"&%I23" 9F+,8 6!-(iC48"&,&^9N(C36032&23254.'&5432#"'#"&546"546254&#"o)) /-0&%I23" 9F+,8 6!-(iC48"C*8*#- w&,&^9N(C36054#"&54>70;0<*& +'< .J-  %%62;251' -&+(26$,1&.(( .%"0(-( 4  [D"&5473.54323232673254'432".3#"&54>541'E  !+2<2<*& +'< .J-  %%62;2( 3@*) , %!1'+(27#,1&.)( .%"0(- ]`&#"32"&'47##32673254'432".3#"&54>54#"&547#53654'"#"&#"4323!2H%;7=D1&,2<2<*& +'< .J-  %%62;251'+0#U? )6 0+$,%-!1'+(27#,1&.)( .%"0(-( 4/' *+%#Te3*%#".543232654.54632#".#"eJ>(;   D8,.AA.6-+H & YGTG\0;-# 4"  ("!0 +Y4:CM2#"'#"547#"&4632654#"&5463232654.546&#"3262654&"jD(/ 32+$)D"+,,{0%&cA3 -*O/10!4V[-/#!2'D :0)/*,#"z;22A,5 ?W1"2#"'&>54.#"#"&54>IX8 &* 6%-R9 6@1dM.c&E( %-I5=Fd/5>*Zv39DM2#".54732654&'&62#"'+"&54323254&'"546"3254&#&54%PH,+ &:+/<'(Pe8( )I ! ! [B*54 3hOME)  /2->:E  nOv5/"I V;K $*P V!Z3E"&5463237332>73254'432#"547#"&54>76541'.)!-4VI!4  .=  O T&11"' 2$&$ ^^"' # .--1#L  O4&!,S902#"'#"&547.5463232>33254.54Nac5 #2"$ X&&=%! 1H!//!9lU><%0 '!,-.1,V3F T91<2#"'#"&547.5463232>33254.54+"54Nab8 #2"$ X&&=# 1H!//!9jU>;%0 '!+"1+U2E G,&Y<P%2#"547#"&54>7654#"&54323254.'&5432#"&'32>73254'44$P*.6- *:(Y#)7C  /"7 L,5   H> x1%.J @7$  . 5I& !-,!#0)"( S/ 832#"'"547#"&54323254&'6323264&'&546 $=34 4 .54'#"&54632>54#"'4#"#"&5463263273533#&#"321  K)-BG.S K; =') =0\&S!^C/H0]B -*  #1'!$ <I7L  $(52rL)"H0(U>G%2654.5432#"'#"&5467.5432#"&5472>32'254#"e$) & $A7A080:>5 $$ V& O--./(4->gH:W>32#".2654&#"74&#"326] @+FTPE#8!2QD3:EDa'.:'VEJ]'/%[9B2@F4/D(\/1:%432#"&'#"&54632#".#"32>23254'#"7254#"7FB?,7 06/kXp  9,GV&!&$IV7<<%'%{=U5?4U2QfLZD!*&%L>4$\/6?J%432#"&'#".54632#".#"3276323254'#"&254#"&54747FC& 6 0%1kXq 9,GV!&A IV7%<%'%_}32#"&546322654#"&#"3"532>32#"&5464&=&546323254&#!.#[, &4)0U")CL mq %'54'*511"+!,O7#"&5473254&5.)' 2^GE]XJ$"/  %6"S@@%M',/DSYCGg *%" !+A) ;!^1'/;74632#"'#"&#.%4&#"32>32326"54672654&#"^aOGT?(3*),1G<*5$D!:)!, nVmjOF<87BS?M <*]$#E+*>#+':  ^1)74632#"'#"&#.%4.#"32>32326^aOGT?(3*),1 7%+5$D";(!lXmlOG<87BT-. =)^$$F+^1'/74632#"'#"&#.%4&#"32>32326"546^aOGT?(3*),1G<*5$D!:)!,nVmjOF<87BS?M <*]$#E+*>#+':`8&2#"/&"#"&543232654&'"54Be60.D<%+%MB8[k7H)@!+?"J !;$B_ X&*2#"'+"&54323254&'"543654&#"/(Qe9) *J!" ! ]C*5&pQx6 0"K!!X54#"&5463232>32E"&# $+/$7;"0+5+6!&.J*1*2""(2.A  i:";2>@:%)!.!#(F)#*#1-X7F2#"&'#"5467#"54>54&#"&5463232>323254'.76)@& ]  'N)2) &+ #'(1(9($8Eu#7*:7u00+ 6O , # ((-.1'Q]174>32#".2654&#"] @+FTPE#8!2QD3:ED.:'VEJ]'/%[9B2@F4/DS-*5%#"&54632#"&54732654&'"5432'4#"326"77H[<1F$ +0,9X%#  +3L%bI9Q@$I#2 :C(4 7&MH2#"&54>2654&#"2H!#@(Ee#@2@B0/CBH*=1 %2)`J $2)D.1A@20B8'2"&42"&4672654&"2654&#"iD11D1S<1D11"" /H//H(+$//H/ LGUh74632632632#".54>7&#"#4.#"#"&547&#".2654'2654+53264&'Lt`F+4Gv.3[`B?QB&8 &1!'N;6T .(B20(J0C"042 i<;RL`Ygz74632632632#"'732654.'#".54>7&#"#4.#"#"&547&#".2654'2654+53264&'Lt`F+4Gv.3[{?ZWkD4$&`|1%QB&8 &1!'N;6T .(B20(J0C"042 i<;RL`9E3"3!!"&5463!2654&#"#54&#"632#"&54632632#%2654&#"!:\2>>2uEPN>'0TH56Y$:0?D2>2uEPN>'0TH56Y$:0?D26@4CTmYD] $:0?D2=IjGi5!# !QjJKACd'II-A1 6hWOc( h<3SA  \z-*I:%,7dLViA28HnMZG^t.KL}1%"/-#'0OK/;FU2#".547&54632#"'32>5#"&5462654.#"%3254&#"2654.#"BPxx?zS2\b;xxQA4@?3?&{9SI&)>4>?A!!#=#y,GE#%HF+gM)^1. ?-`+MgE59I>\A !@/>J84F0$ !%."WT#1W".;90* *0R+5?2#".5467&"#4&#"#"&5463262654'!2654'fUD)< :0`AS1&10: <(BWf]>D'6Ug6H(7gU4qQm.C5:r$.%5H&p:6C.lRqGGuI8nHQl3GF4lQIm7JN>6>2'654&#"33#".5#5654&#"&54632354626=#k2ygT\nS?4(< H:+0@1<\KHb${"-¯mgx1#u5G&>> -O/9F9G.[M]YJ:*0' =7MN@OW%#"/32654&+532654&#"33#"&5#5654&#"&54632354>3226=#'5K< #2)&UE"DA(S?3@PH:+0@1<\KHb${"5GC"?`.", R>Jb?=-6V^g2'654&#"33#".5#5654&#"&546323546!2'654&#"632#"&54626=#%264&"j2zjRZpS?4(< H9+2>0<]JHb${ay1W^J)A% ,=2C?4AN"-q&'@()°lf{1#u7E&>> -O.:G8F.[M]YJ:*0ɄnHAxYp"/>*HQ@9GmTy' =7M-H1.H0NJ1=2#"/32654&+532654.#"632#"&54>2654&#"f]|EPP<# % '/(((!<9,?1BB6;IsT<_9$m.%#0-$-(N R^2#".'332654&#"#546!2#"/32654&+532654.#"632#"&54>2654&#"'O`^N*@ 2'3C:1'4 V~]|EPP<# % '/(((!<9,?1BB6;IsT<_9$m.%#0-$-(N:lx4632632#"&=332654&#"#54&#"#&5465%2#"/32654&+532654.#"632#"&54>2654&#"]FN/6LH681cCQo!+)7O`I:",T1 ) ]|EPP<# % '/(((!<9,?1BB6;IsT<_9$m.%#0-$-(K)08C2#"/32654&+#"'#"&546;4632#4&#"325#32=#"H?C1&!'2ETER'!A:IRU%N?%:E8,+44*f?"bT57I/3'4&fPPV:H1Vk#.=#:PM=I=R? %`UM$02!3!5654&#"632#"&5462654&#"7^VSIebI)A$ ,=2CB6>K !)' *&zdkXGJtPi"/>)HS<:HeS~l.%#0-$'.M+2'>54&#"#"&547326=46N_ =-$3 J6%<ZCUe|42I<%8au_9KC6I2#"/3254.+532654&#"#4&#"632#"&54>3262654&#"zGbBJ_G) 8U--'$.717/ASS,-?1AD9=CQ7Sr+7$)#* + 9(R>I-G"?/"80! $. H1>%4632#"&547&#"!532654&"#&546323&2654&'udbECR@8Jo$Mf_"-(D- +H;AQ2<'1%fe|QL`ZrXFZmWx;">-*3.%=IY=D,TB@F>TTc!1 KLYb2+"32$32#"&547'#"&546;2654&#"#54&#"632#"&5463262654&#"324#"3>+,W;,8!>2,86-#< ?`/8fS9L5'(0R@0=$(&'*5.lS\:!1** ?*.-&t3H,-!Z3&5AC5+57,Vg#0& 9E;$BR56f fLKW"'#"&=4.#"#".5467&#"&546326323265332654.'2654'X*9 k9.RB_:-(lUD)< 9/-M^^!kwb?4.MJX<)"?S2):N 3#D)5We(@D3cMLaLa :2ZzRl.B6;n% nW~?Mj`M]LD,#D4>iM-94K6oIPo #,MR=GQ2'654&#"#"&5467&#"#4&#"632#"&54>3263262654'264&#"Xo{1WkY mSB?P9/"6CSS,->2B>6@N1QR+RE9\7.8P+3Wf6 >&' *iHBv\{ [|RjdS54&+"&54>32&#"36HT%=> D=o6-.5a:J(O7D5i?L) ?5*= G9 ''F4/.G80)"M 2"&5462>54&#"'dyQ1<*bGHa"Ihd{afn!H0Id`G3>+M@#"'#"&=74&#".5463232653327654&'W)8 "/:)S92YHa5!(0 6.*; qK7\G-50S(.5*.G)@D08X1 MLePSG>%M2J74>32632632'654&#"#4&#"#4&#"632#"&2654&#"L$8\:i0/Xj/*SN:A 3)+hK;'3S@2&6SS,-> !*E4>Lw,(*&%HJ8#OMHJ=Df3U6 ARf-$3B),)5G =*:Hj0,#'0-$'.L -72'654&#"#"&5467&#"&5463262654' t5'1VqSnSB@P9/&0H#^!kX:84M*5We2Öf,<=Cpa~]zTheR;n%0G=~?Nl rH8oIPo4EM 2!33546"!54& \uqTps@P#RyciWg3YFιSaM*2#"/32654&+532654&#"&54623K"KOgL%-1;G4+*4==2M]( .% @K;P 7)"'2,)"$/yfO` rL{M.#"'#"'&54>732>5332654.'a&,nQV98PJ9; <*#*0B9(,S2*9M0" 6R0gMM@Dc4F?o54.#"#4.#"632#"&5463262654&#"eTdUIm#? 6%)8S40-;/>=2>Kj\C4$%&'s`HGmQ44-!,$. HR<;IkRuQOn.#%1.H1MC%2#"/32654.5463232654.#"&54>32#"&#"326+8PWDM /  "7 /^AIf }BLo9#3( +'M "2!546!54&#4&#"6!7>.Nk % 9 "BUFI &e $8dA,/6 jm36 4݅{O!/@%2654'7#"'#"&54632632'>54&#"%327.54&#"!WmL%Xn8*7VEK,@T*?@!-7-.>D "2R31D1#&1"x]nBN{n sSoVV*=4M4:)@UTČt]pWG[x]o@Jgp>H=UTc:8L2'654&#".546/]t"4-bXADY0#*.~f3V6)2vK\]M(82 5P/iM2!!3!546"!54&^uSsv@U(Pj/Gl0UC6%N[JM.=G"3!!"&46;2>54춮&#"632#"&54632#'2654&"!:w1<>/ . =$)7QBRl$:/@B78LtAQ7II$4+"$4 !)I6V@#5/$*4L98G98J\Cg} ?+=+B$3 1#$/-H2M&12#"'73254'"&5473&546>54&#"o$9 PK ?4c%F>]xK%#G9+O"==/%#*$, 7\+3F6<mMT6#+=@W?PMDL-)75+KL233!5654&#".546)\{SSvkZBFT+ )7zy\GNcL_bJ'51!AD/dM-72#"&547&#"#"&54>7326=463254&'iPA8Px(*2I[HRb >+'5!/' $:i[?MlÔtVnWG`"_HIOe~_7HC:@,2J!BJCZi:8{(lWK.4>%>73!5654&#"&5463235".54>3273"54SpH8.1A4D`MJc%/9( 6&B2e5' 7G-O.:B4B$5WK[ZJ9)?* #+RT# _%O g*<. w>L8#"&=4&#"#4&#"&5463263232654.'H/>^PGbD-)+S8"3',snOU91TDd<05A 4&FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7K22'654&#"!5>54&#"&546323&546a|"6,aZHF\L8@(!7,0=5D\KIa&M~h5V4)2qKa\LH^ E-6=.G!2[FVSE7.EjlM 2#".5332654&#"#546O`^N*@ 2'4B;0'4 R†cb'9/'=jNIa10  EbY2#4&#"#>q=QT1'&2"VYI=-,70'AN*Y!2#4&#"#"&5462654&#BTS4' #,$%1Q*"YI=-3B' $-2'4C#&9,  "7#"&547654'72654.#" #>20A]6rR) " '' 4"2EK4gvN$D Z. !",#",(#"&547654'7'&#"32'3265#"Z>Y2k6[5(- $d%%%E2`rE#@!Xj/U+- !+)"J }$.>54.'&5473#"&54632264&";']Q=8aG5V@5(5(?)'@(# ?3&/[!&4cYf_2AY5>8E223 -B.-"8L(2'654&#"632#"&546264&"9ay1W^J)A% ,=2C?4AN &'@()„nHAxYp"/>*HQ@9GmTym-H1.H0L#,62"&547&#"327&54632#"&5462654'>54&#"4Hb3R6* DQRC+:)&3aGj~ =**2D6'0.%/%mq-(1-&6Bec742*1-L8(HQ2'654&#"632#"&546264&"2'654&#"632#"&546264&"Uay1W^J)A% ,=2C?4AN &'@()vay1W^J)A% ,=2C?4AN &'@()„nHAxYp"/>*HQ@:FmTym-H1.H0nHAxYp"/>*HQ@9GmTym-H1.H0Ph>(BFkw2#!".54632>=4&#!"34632"=332654#"##53%2'654&#"632#"&5462654&#">U$5++5$V= +$W;b=U$5*2Az/$I'#%VV/A4%t.UZB%=" *8/ ;1=G{ #$'0>U=*? ?*O=U6!@SU>*? 4DCxHE(:P)'F,gU?^AZ&1!:(# /9RD\.(#$!P>)EIpx2#!".54632>54&#!"34632"=33254#"##532#".54>32#"&547&#"327&54674'324.#"6}+4$$5*f+5$V=v+5$U>=U$5*:9zSJ %WW&RC2H& 6: BSE3ii .L."(".> >**? ?*O=U ?*>UU>*? @L;{ O($+5":="4J&4+H $,-&l1 )/+' L64632632#"&=332654&#"#54&#"#&=6M_CQ-6LH681cCSm!+)7O`H;0T2 ) QjJKADc(JH,C/ iVMe!'h;4 @, X2654'3#"&5473k$0*Q=;NM.-$  =ID8 )L64632632#"&=332654&#"#54&#"#&=6M_CQ-6LH681cCSm!+)7O`H;0T2 ) QjJKADc(JH,C/ iVMe!'h;4 @, O-8DRs73265#"&54632#".547&54632#"%2654&#"%3254&#"2654&#"72'654&#"#54#"&546326xq|0<2>A1AO6\`65b]7P@1A=3>{%3!$B"" a~d&II,$0?) '%+"2 80('mZWoQR@;NtX0j0E##E0k5WuM D,<"!Mn<IS"&547632632#72654.'#"&5467&#"#4&#"%2>54'%2654'AXEDh[C@fGz@Vo[@U ,&PA/9JE$c*NS1&. 194  9?-1(7gU4 nPjPQPRVNuQ_w;aN0BYwH5=e l-!5H&o;(7-<-$ GI*(&F4lQIm6KIj7>3!#%"32654'3#"&IS>2(24&'2!> X@73546"!54&[v-8& Mtr@T(UuW (7)(F]8M;۲MdM23!5654.#".5464WuSk>*IVm>J}~_e\"Nc65!YJuD(t@kN%23#5654&#"#4&#"&546326@THJ:*'!@%/D[gU@NaiQ"WlLi2;4eKnUj|_HHO#2#"&5".5463532654&#|kRDYBx'T AYi9T0;iV1Âl[~J7gJ:0SzEfS;Qc#NANG2#654.#"3254퀆&#".54632#"&546ElA* C5hGvsIj8)Ib#)d1<);U 1W9N8Wsk5 1)?s;qpD;&1g(lPRO*I;b 4#\s5;+џPC52#"/32>54#"#4#"#4#"&543263261)9 =FiP4.I$?;#[?:C&TH"Y5&EC#0[kGqbr9E[.]'"W~KYD@7;MC$12#"/32654'&#"632#"&5462>54&#"~pP6 /QTnJJeYk4GB[);0Nj( ;"@:ëDtfFGjLCQ<*? vWog(&.(*!+<PC%233#"/326=!654&#"&5461]tTTp*Y ==lQjU?E[k]~FChM";1H7F``FpHEePh*32#"&=#"#4.#"&54632>3534&+322H% 5$-7"+G"! f_ h\IA':4k.<)B1QQ*#CC(aG4' zAPdF)SfhO3r 64>32#"& 1'<h 2#"&546"2654&Hd10FGe`L %.EfJEaGF24cHEd- 4"3JI51F2 #/7#"/4632'"32654&'"&54632'"32654&D* 7(,=i&- ).-?4),@5<$.!)45.H(;9 (")++d6.);:,(:*" +, #( {l9HX2>7#"/27#"'5#"&5463224/"#"&543327&#%4&5747326Nl G7(7'$@&8[ :Y(qP  "D[.' 0lU90=+ G'9 *"( փct&HOQu kUI&,<$"$cs2#".#"37>54&'.'5;23267>54&'&/"32?"&54632#"'&54676323#".546232654&#"@+%   &= K|AXc 4e!.eH/R2LB&h-$5NC9?KD'*QFiG=XE1e!+ &7/*A 0P &56.!9#  !9&'   )T)Hr  3% e5  J98CI@Gb1W{!,=hA" 1*$6 ,% F4B 6'-6.j E^ju4632#"&74&#"2672322#'"'.54>76?>74&'#"2>767'4632#"&74&#"26[+ #/. 0 *aAQ  d"%D0a:IM,B!$8XQr(FQ qbx VG3V#!NL'(2$'#/. 0 * ..# .03d 1\ vX:l!@C5=`;8#5-O (Tb6!+ ;g/&/>1.# .0 ZC%#"'.547>7632326374&/"#"&/4;2#' 32654'71HyJFN oH8Ly ( - -&*-l -8C/yPT aJ`P8/բB PD*  Ki#9 F%Q}*$ ),7;?#3,7? N̐xp< A3 !T@( x8I$"$6 &Q;# : o4&#"3274654&#";2>52>7>32#"'#"&546?232654&'#"&4632#"&4>75.'4&'.#"#"'6;2&$$$+ (*?2+@ 4$''5*  *A(|"?(bp;@#"#'Z?JO%" 2+>=+?igHPr?6?$s2uy&<3u(( ("(: .F:(/D6# !  4MA<"n&~`s$ :($2<6 %21N3U<;IIwI6.;<A&cK4^GX,PF#Yc32654&#";>2+"/3264'&#"2#"/#"'&#"#"'>7674&#"#"&5'4632>yz4=UDE23##,' \HNMo-!4%JY@AH5V. I"H*  6q] % "=#_K9=2.MuV;?kw, Ix<\4* uTS3$G9GuQr%I+yG"^/  32?>732#"''>54'&#">%4>75.'4&'.#"#"'6;2&g%4(+ )%N$A5'MU 1X7j#'+L 8H"Y@K+50 1~Vi5,?6?$s2uy&<3u(( f.*3N;*'=c9N?-pf/K$ ?s+@A'7T'UQC/$+I6.;<A&cK4^GX,PF?\[%+'.'&54632&#";2>5&'&'4>32#"/7;7267654&'&#"672ek -0," ~A@Rh8RE 45(I".AN9q]*8M!  #. ::V!4Jb,,Lf -6D p\7T* 'K  *5U2" v4?$  =l^x" XH !@: Nu"2654&4&#"2>7>'#"32?6732732#"'#"&5467#"&5464>75.'4&'.#"#"'6;2&_*PO ![ -45A73#"&'&54>7+"&5434&#""&54672"'6;2&'4&'.#"#Cd@]PcF&,T/. .JrB*" '(J(9119($s2uy&<:H6%)?6?:&-E"RQ! #`767654632632#"&546?632;4.'"+"&54632+"'#"n@0!4 2+ '   j#:acFi#G+@ F+=|$k0G<6[:@N<"6 4  bX2AT5/ Gg"& #* " "%(9"y::F7*(9 85."'>?>2.IHsE~=P #:(N6'B K" n2654&#2654&'&+46?6?632632#"&54732#"&546?632;&'"+"&54632+"'#"n5!@A<{=0 :D, ))E6B .( *%! A;T#30ݣN<"6 4 ObX2X. 5/ Gg#:ac!, @T,I>\~! !1*0 -""D;v~=P K :(H4B:(9"0a726532654.#"632#"&54632>32672&#"#"72?#".547>37632.'&#"#"&5&#"2#"&5#"'&#'>74&#""&547>772>?-S"A1HQf)!@w( H 1  _D*6 DzbSVO`_ *G A^0NG`&# MD/=9.7^. 2O  3)Fj+;4!YE $:< b+(  6k=m6! ,+<'(F"7>4&#"4632632&"72?#".547>32632.'&#"#"'&"#"'&547632326"&547>772>?IG,/  ; 57mQ;4^BS9/$(o-NG`&# M& A>W<)1 1z $ D/   -1&b+(  6k=o7" ,+<* sRKdZ\{p[e,.!))-? L~="7%* ,(+:!@"!2673#".=74>;&"'6;2'654'4'.#"#1H# /:2wHr *F)E /-$s2uy&<;q&% * :.a/.y]42w6i?B &0)LA&gHJ@/$+ 4YJ]*KV!"&'#"&/467"32>532>=&'#".547./3267&'(+='6WUqw?g1R,0:(6@_ 4H'*= " +R]F  2JH6<I 0DMa*iCX)T1"F/(-Lr!$X?##3(2: *YcQP$/6#2E[>:=d%;72732#"&5#"'&5467#5!4&#"#"&54632'"26%4>75.'4&'.#"#"'6;2&}.=) 86$D:aa:S9:",HF3+L B/Eg( XA:6F?6?$s2uy&<3u(( /qo!!B10CHI_E@-AI'%EQ%." 17>+I6.;<A&cK4^GX,PF*^i"#"&'4672"326?652>=&'#".547./#".'#"&546?#"543!4.73267&'MA#2my4&#"632#"&57#"./.'#"&'>?&54654632%672632#"&5732654&=4./"2654&#"%2327>54.'.54632#'.'4&#"3267&#":D '/ $-1F=,-D6?BZ%?;(3  [aD83C)]p<" 'e-'$D;(*=058%"' &%&$6&23"KOs4L"#!  O<'5&%,A17#8&#$"?7WPjY&> ;'!B1+;$?G?  ,7#47"0&(!1s % F8&5 " /?$'!2 0'+: #$ %!&$JD !R[m4&#"#"&54>32>322+"/3267654&#"2#"&/&''>?64.#"2326& $&+4(* #HA%,9RB .z*!e|& 1")B& & #.+>lCWi*;?0.6 *B+:K=+(*2* >3I .E!+1EU%'/;".547'&'#"&547>32&#"32654&''327.'%9 0 V`.,E9SZ@ag-Q}*$ ),7;?#3,7? N̐xo42"p`!7 x8I$"$6 &Q;#0M_;V&##"/72?#".5476;632.'&#"#"&56?2"&547>772>?Je  eLNG`&# M&:&)b+(  6k=n8G ,+<' <&l="7%* ,( :4[3".54632632#"326732732#"./%4>75.'4&'.#"#"'6;2&0K)e} -^cV@BW"">') (/e!/  5?6?$s2uy&<3u(( ):I4i`B^/0/1 ,Y$&  I6.;<A&cK4^GX,PFWQl2"&'>5'&#"#"/46;>72"'7;>74&#"#";267>54&'1D6' KGRq329." ++!-rF  *zZ0eaF"' N - 7/ I C6)#  (!CD(32B> .R4"&;ODV X99%2#/-:q%91 2X9J*Ka( 0 Ib%)-*'  5*<@Fl#>[4632&'";267#&'."#".'>332654&".547>73272747GU;4C;I=*] S V9;} 3S@_& A>I)7,C1, $U2'C$"G.   )D*]s %,hnD sBILG))0% 0 3$4 - :iJU!"&546?632;4.'"+"&54632+"'#"2654&'&+'46;24&#"?27N<"6 4  bX2AT5/ Gg#:acF@A<{gI '/c݃L&0Zd`, ~=P #:(N6'B:(9"@T,I 2i 4-#~v/D5%'EQ".547./#"&54>724/"#"&/4632&#""232654&''327.'%9 0 V`0eH% > PD*  Ki#9 F%Q}*$ ),7;?#3,7? N̔t#>@*A3 !T@( x8I$"$6 &Q;# : Mt7"32654&'>32+'37>732#"&'.54?32654&#"4632#"&'&%4>75.'4&'.#"#"'6;2&"*%+"2B;c?: d#<] Gb=M$,_ZNw 7'+?<*%.6?6?$s2uy&<3u(( '4)&).@d;&v]:B$# [Th$X* )#-!@#B&?9*);#EsI6.;<A&cK4^GX,PFs^I4632#"'72654&/"#".547#"547!4&#"&54632"32>54_ou&F"#D[`W!Dd%jN|7#"&'4632#"&54>?4&#"326?67#".'&'4>3232654'"'6;2'54'4&'.#"#&! *! "15%5 74={E0(BJ$K Zs# 3?*w;w %,! ;0]BUhG$s2uy&5&) $]B, :ZI+D! *w?i63I6Z5%3"?02NA>)-A&(]J* =;<: 4&#"32623>7>32#".54>74##"#"&54>3232654&'"&54632#"&54654&#"32654&546?2274>75.'4&'.#"#"'6;2&#")09-# ob55!81 ?>dn&W=0 I68U 4L3L)1OdEF[HD02.'"'@%1!!&=?6?$s2uy&<3u(( (0#& -8  <-!  ,<L|R)/ E1* $ &5/&*9O3=Ll#& q8A  !(PI6.;<A&cK4^GX,PF,=aJV46327&#";726?33>?4.+4&54632#"&''"'&4&#"3226,u]&-#-68vhJ! E  e@P@%J/~A=P&$]S8S"87Dm">  j"$kF6h2 ;#:5>O )0"7U72## D>19#7,X0)30ai'B2#'&/&'4>76?>?2324&'#"3267>5 &7a; a8FHiH.?-O (3d 1Vf,0l' +D0bTY2#"&'&547'"'672#'254.#"327>54&'7#'.'.5>7>{04Lx$0&%L[BHa%  U?  $ 5 #1R,&!Oo6ID0MtTRy} &   $[0? JC7f*H0,p= DPF'4$7 4:JuU4'@4<&*:1Q4672#"3 73#".=>76374&#""&"'6;2&546/4&'.#"#a9119(G2W_832.#".54>#5 *,%/  !2[;Wb ,$ /S5W'%b_J1*B@/5< >r^&+/7rG08 &($ -48(<56*   (,=1#8@1 )7. Vm   54&#"3263232%""&547>32#"2;>54'#"&546;7&+"'4632#".54634t<#1**!iG/d )F@H.װ !T+iO?O.obj`""#!&D#[9 ME !2 9(L,$$!1!!9PbD@ \)|5{^ZmW/BhQb32654&+"'46322#"&/#"&5467#&547!4#""&547>32#";265%654&#"3263232"F0QaN=T+iOAR @{bEOTAcz&1I =e]93Gh,V%Q8CI3G/32&+"#"&54632&+32654&&546?2"/632>74.#"6$"#2[o~C.Q  X/c(  . `M ;y%)Nl^y67C! *# +Z8*,&4&Hei @0P o$' !8c tDQ5&+ _ y$h3  <&?zV0fVh%#"'&546?632/"32>54'4#'".'54'32654.76"#"&'76324 !8Db%+kjuW`cr !0& -Ke 2\; r0LbP7z   0/  $ 95P({R94632>32+'#"'526754&##4&#"327"&(j=`D`w%g)6+Vn b74&'eO,:0">YJ?(,${6BN+NO ]YUu ,\=v +L.<\,!*".'54654&#"'&5463232632'3254#" #(5&[ !)/ B W7 (+%.687P]+"'4632#".'53267654'4&i# L6 +6-  ,L#4 1*#0 =33M@)>*6!)% 52<'?S~&543767!37#.54?67# 29T \(ci)W&/{ ~X;J* s]HE490#"&'.5467#57+*.'4?732?6| B?)9332}$!& 8g5&6#![2RQ)' 6):#76W8 &.#$XE#/.$.B % "+N' (2;7!"&463/";26bg"/?J7 (9M&7HQhA % -&1/=#"#"&54632&#"326327.(?]_2( "H@.9; c' 5G;$: #)3I B , oZ#474>32674&#"'>32'&#".763267& &7-/HI:#B W/9O%!),9*/!0:'75P':G_$$.7[W/SD%' N+#*#"Rs!!in5A#.54632#"&'&547632'&#"32654&'&#'"32654&"/ J,B3)qSRfW}# $#3;)$2<[(6@7=N*$M>fgP3A^`  RTjUkWG>?X?1 /5*/E'!19BMbb<   #%5>aE O*aZV;e<)F  U,305z7gUmTF@  **0  :LF;-7%#!5354>54&#""&546;2326534&"26&9'%"#&4&F1BHGZ$$R"0&<% %)0 "00"5GL/ 02 (x((((F:8B4>3263232653#!5354>54&#"#4&#""74&"26F& ($.@KZ&7!'!#&4B$$D4 *)F3 02 ("0.H#/#  !)0 "0R((((F7'134.54632#4&#"4>32#"'4&"26 {]d}ZKDHV 0"*#(P$$Hn7S0Wp}k2cW@3,33 !.C((((F 73=4632632#4&#"#4&#"54>32#"'#4.%4&"26FQ<:#C;AZ$%,<  0!)#(U"$$nYp66gU?1')Y.2+03 !.Fl7T((((FC:@JT4>326323#.'#"&546754>54&#"#4&#""74&"2632=F& ($.>-bZZ '>'P848/!'!#&4B$$ "# D4 *)F3 02 =:"4@+ rXL+,C .H#/#  !)0 "0R((((45YF74632#7#"74&"26&./:UB$$D260/tAR((((F7",2#54&'+"&5463254.#"'>4&"26 ^Z+*$&,%F:,+oBrU$$7hTe.  30"%0G0,@ ^>H((((Fl7+1;2#"=#5#"&4632>754&#"'>254'%4&"26$a/848P'>' U&&./:c,PFvEz&FF$$7gU C,+LXr +@4"0D2609<zEU_ :L4LY((((F\+5@%#!5354>54&#""&546;26=3%4&"2654'326&7!'!'%"#&4&F1;E&Z13d$$&GIR"0.H#/)0 "00"5G;*`C> ((((c!W0(F\7EO4>326326=3#!5354>54&#"#4&#""54'3264&"26F& ($-9'Z13d&7!'!#&4H&K$$D4 *)<(cC> "0.H#/#  !)0 "0a)0 (((((F7:@J23#4.'#"&546754&#"632#"&=467.'>2=4&"26aK.ZY 2"P848/PFf?*I&&./:,305zFFY$$7gU/;;, rXL+,C |EUB 0D260*0  :L945Yr((((F72JT^232653+4&#"632#"&=467.'>2654'3#"&54632#"'74&"26%4&"26aRZ&V;f?*I  &&./:,305zX(1JRT>I.+&&$$$$7gU("0mTFB  0D260*0  :LVH e{Q2'60D0"r((((((((F 27@JV2#&'#"&546326534&#"#"&5463254>7.'>4&"26&#"326QaZ&5 E'6FA<87-V;f?_(  ?2'#&'% z_$$43$-:$77gUD+&,2! 7-6TFB@ 3D5"0+  :L((((#(F 27GQ]2#'#4'#"&546326=374&#"#"&5463254>7.'>4&"26&#"326QaP7.( 8,951,/'-V;f?_(  ?2'#&'% z_$$**$/+7gU80#(2! 7#!,% eeTFB@ 3D5"0+  :L((((#(F3-R\fp22673#"&#"632#4'"&5463254#">4632#'#&'"&54632775#"4&"264&"26&#"32 k  ,bL>5_JZG &4&-$45<,aB%,*-?3)%+#%( .2*$$l$$ .1 -!BPL4"00"'/0 eMkD251BB6$$( ! JEz((((((((F}<@J%632#4&#"#4>54&#"#4&#""&4>32632'4&"26CMP@%8W)(#"Z##&4&& ($-2>$$|8"(e w~.H#/"!)0 "00D4 *)D5/\0((((F7FPV2#.546326323#4.'#"&546754&#"#&#">7.5464&"262= '!&/&\%%V/@"C:<K.ZY 2"P848/$;+11 '%#E$$+FF9I@^.L{g5hl66dT/;;, rXL+,C @0'BPA+NV1 /"4S((((45YF47;AK2673#"=#4&#"632#"&=467.'>254'4&"26a.KU/848P"2 YV;f?*I  &&./:,305zFF>$$7gU/C C,+LXr ,;;mTFB  0D260*0  :L4LY'((((F7(23.54632#4&#"67.546324&"26|[d}ZMB8[1 + %#) (&/&O$$?k32632#4&#"#&#"7.5464&"26 (&/&\%%.)@"C;AZ$;+11 8%#E$$1!PFc.L{g56W/66gU?1'BPA+NVc/"4S((((F7(22#4&#"632#"&=467.'>4&"26aZV;f?*I  &&./:,305z1$$7gUmTFB  0D260*0  :L((((F<<)%632#4&#"##"&4632'4&"26MP@%8W))"!U&&./:U$$|8"(et0D260((((F3",22673#"&#"632#!53>54&+326 k  ,bL:8To&&a8<P.1 -!BHS"0iMk$71(Fk7!+54632>73#"&=##"254.'4&"26F&./:],Z/848&/&;' T" $$D260:<C C,+L-+r +@4"4Y5((((F!7"463232653#!53#"74&"26F&./:Z&7B$$D260G("0R((((F!""463232653#!53#"74&"26F&./:Z&7B$$D260G(0"0R((((F72#"'3#'#464&"26.&&ZZ]:k$$73!"006T((((F#2#"'3#'#464&"26.&&ZZ]:k$$73!"006T((((FY746323# ##"74&"26F&./:~~Zest_B$$D260PR((((FY#46323# ##"74&"26F&./:~~Zest_B$$D260PR((((F27,62#4&#"#"&5463254>7.'>4&"26QaZV;f?_(  :/.&&'% z_$$7gUmTFB@ 063!"0+  :L((((F 8 *446323#.'#"&54675#"74&"2632=F&./:-aZY '>'P848/B$$E"# D260<:"4@+ rXL+,C R((((45YF9,62653"&=4675.=4632#"'74&"26!(! "!?Z>Zrr?%:0;0/&&Q$$$  8;0*;;*<4II43=?  :"(;>3D0@((((F3)322673#"&#"632#"&5463254#">4&"26 k  ,bK:8hB:/.&&=*a$$.1 -!B LN063!"0fMk((((F7(22#4&#"632#"&=467.'>4&"26aZV;f?*I  &&./:,305z1$$7gU_TFB  0D260*0  :L((((F7*42#5.'#"632#"&=463254.#"'>4&"26 ^Z D24!&&./:PHb1,+oBr8$$7hT1HC?A0D260IXS8,@ ^>H((((F 27,62#4&#"#"&5463254>7.'>4&"26QaZV;f?_(  :/.&&'% z_$$7gU`TFB@ 063!"0+  :L((((F7&4.#"'>32#"&=46324&"26-+oBr:\:/.&'$$m,A^>HbW063!!.C((((FV!3=34.54632673#4'#"'267&#"4>4&"26 {]Y?[)Z!*()1 ]HV 0W$$Hn7S0Wp6#2N84E25)!.!_W@3,3S((((Fw72<F4632326=#.54632#"'3273673#!53#"4&"26'4&"26F&./: ?H.+&&)Z6T&74$$$$D260G(Q2'40D0!C3KuC"0.((((((((F U08B$#"&=463267.#"'>32673#5.'#"6327=4'4&"26#&./:PH", E'oBr:Z>[&Z D24!!m$$mD260IX ! *^>H/2I6&O1HC?A "! ((((F=>%/9%>7&5462#4&#"##"&463274&"26%4&"26(3&.@. X!,F2[&&./:$$$$_. &%55%. ),)0D260((((((((F &0:46326=3# ##"&4632#"&57";54&4&"26'.*9&@7-est_&&./:~~+6?# $$"2.)+=0SP0D260 1%>#4#C%((((F7&02"&=4632#"'26=4.#"'>4&"26 ^rr:/.&&?Z>,+oBr7$$7hT4II4063!"0|*;;*,@ ^>H((((Fd,6@4632653"&=4632#"'26=4'#"7"327&4&"26FzLDB;22rr:/.&&?Z>WVL3"D7).$$Y&'+A-2I4II4063!"0g*;;*;&*g "#((((F<(2".=4632#"'3274>32#4&#"'4&"26#3 .+&&= #-W  -$$],# (60D0M ##5%:'#+ ((((F6+5?#"&54632#"'3267#"&54632#"'32674&"264&"26xX>I.+&&,0FJxX>I.+&&,0F$$$$6_Q2'60D0!]f_Q2'60D0!]f((((((((g|\#"&54632#"'32674&"26xX>I.+&&,0F$$\_Q2'60D0!]fR((((By7 !#4&#"'632yZ$,=<Xd/L33X GVy"&462#4&#"'6324&"2M-@--@YZ$,=<Xd/L$$D//D/33X GV &&I[4"#"54632&.#"326320_D2J%sXN>(4v%S!-?* O 7S%&[[o"#"5463253&.#"326320_D6,?sXN>(4v%SP/IO 7S%&I[n+"#"5463254632&64&"2.#"326320_D"!"$/sI N>(4v%S""'3b O~7S%&[[o "#"54675353&.#"326321\C>?w\N>(4v$S;B P/IO 7S%& 4632#5#"74&"26%,*-@B$$D251vR(((($463226=3+"&=#"74&"26%,*-@!N!B$$D251rѸ 22 +R((((VL "&5462;%&$ .!~!"uQ"*29@%+#5!5>54&'5!53'4'>"#"4'&'6&#Q1^? B>"">B+v$' e*#6)"77  1#o 0Xd F7 $#"&536324&"26&./:U$$lD260SR((((F7 #-$#"&53632#"&536324&"26'4&"26&./:U&./:U $$$$lD260S0D260SR((((((((P%*42632#"&54#"463232673#"&#"64&"26>hB&&./:=*s@%(   ,^Z:2$$LN0D260fJn  -!B ((((P(2<$#"&54&#"&546;2#"&546326324&"264&"26P&./:=%$2%&$!+JY>?[$$$$lD260-BA.#!20"#/Y5>YY> ((((((((P!+>32632#"&54&#"&54324&"26D,%9&&./:`$$j[R9$0D260=(!?[::((((7 #4&#"'632Z$,=<Xd/L33X GVV <2<4632>32#7>54&#"#.#"632#".4&"26V>/%' 22 3W3 ('0$&&( y$$9?OO?9 )0B#&0D0DC5((((]|5?4>3232657632327.54632#".#".%4&"26] C0=,.6PSE 2 %$% <0   :@$$**'41&'!-? ,!$/(%1CN$((((Z#"&'\a]]%232>73#"'567#"&44&"26*%&;7aABS]$6* C/%B:"#'6  #]0:4>3263232>73#"'5654&#"#4&#""&74&"26#%%   %';hc8 *T#0"!** C/Nu >!&''   : ##5#53533Y7-::-7;;*::z 4632326?"#"&74&"265>  !&-9&!"'o'< )& -'+  |"&4624&"2Y-@--@ $$D//D/d&&}#4>32&#"&"327#"&4632& %9& ($ 1"11"2{   ? &-!07N74G}6$4&"26"&4624&"2"&462AZAAZꦦꉔҔ%SvSSvZAAZAꦦ|ҔҔ8vSSvS<"&4624&"263SzSSzS"|||NkkNMll<,62#"&54632'654.#"3267#"&=464&"26$-V.Cc]\M<G#+ 7Y1%&  &*>$$9*6tLX|X95z/L* pIOj/(0!!2S((((*=G%"&54632>32#".=4'7326=4&#"#.#"63274&"26 '6F6/ .=eIY?;D.VVaI' + &" $$z^154&#"#.#"327.546274&"26*6-gD< 'O.[IE'$/*  -1*# &4&R:$$ -K.Y{UTi[?uFIR$4  p;1J% -"00"8?w((((=v3=74>=73263&5432#"'&#"#"&%4&"26=<`tt`<9ci{&$bOE B\&& HL'f#(Rd$$?[3(%-P7GQ74>7&5462>=7#3263&5432#"'&#"#"&4&"64&"26<%C/R(2F2DX;UFgMBbOE B\&& HL'f#(Sei 1B$$$<&' .#22#XA :W+ -'E(2H&Rh0D0#$ %$\w$((((-774632#"'3264&#"'654&'7632#".74&"26<2!&&2C6DD6!O,F/LX:=TvvT-H) }$$*32 "0Gjj#%.Dz M(||(1$((((<NX'>54&#"#.#"327.5462#".54632632>54'.'4&"26;`<. :}U'$/*  -1*# &4&R/*6-gD< 'O.[&$BC ec.$$*3D:C%OauFIR$4  p;1J% -"00"8? -K.Y{UTi[+l$U33um((((<g?I27#"&#"&5432;27#"&4632#".#".5>324&"26r 3"&''<@6C&&$5) ([H$2H"mO!X$$V";/\V5%>9'.'0D086#4 .-%/@7Uh,((((<==G2657#"&#"#.5.#"&5462#".546326324&"26 ! :"y4P&!-1G&4&9,*D' gD< 56$$c#6$CB(3]#)4G16:)p;M]%"00"./"132#'54&#"#".=4632#"'74&"26cV%#1V  7#3 .+&& $$7mΘ7%56%-,:'#+ ,# (60D0_(((($>(/7?GPW`gp67&546267&546267&546267&546327&54267&5476;#""&547'"547.'"&547&'"&547&'"&547.'"&547.'"&547&'#".54>32#"&54632#"'32>54.#"32>7&5463246'4#"64'32'4#"6654/'"6544'32'4#"6654'54#"64'24+"64'24'32Y& -% &   .      (   "&&#2& "&m5D7&,CD":;"/)-?0 "*)''26?=(1MH!:bD.,&$7  S  \ v    !   ,MF?,01$; $!L'.  +( 1? $  "("  0(  $ #" $""  ,;<"+  11 : ,4  -6)j34LB*?mEJu@!(T<9T(09*= 8!.&J23I%=lDNt:9`jZ6,fQA1 3 *"7Nyc=Sz(J/ThM1a?;G3d32632#"&'&/.#"54&#"26BIwGrP>!"G28;1AD`E_*[((P]=$`%MH1 #B/3#1g'*11255DB.. 33! i8D(!H3] <% N *%"&54>332654&#"#"&54632Xl 4$ 9*(<3#$4?"_QZko ]N"*"&&""'%$/)/BO[gUmM ?%"&54>3326=4&+5326=4&#"#"&54632Vk:) 9(';11$5"#2(]L`! \ aI20  '%"t *%#1 '!BPj$*e/<M ,92#"&=4>=4&#"3"5463254&#"32 6'7>*VkNs2GF2),+aHI`0;&A9'a)'(=(a>#%#%$%M "0%#654&'"#"&546326324&#"326FG12$:lUSmgZFLB8!3&>"&;=#':Xj,4!*3)Pnh\*Nf11"C-l1*!#.)M (732#".54>32+7>54&#" )9)R84M(8-%7ET)387"#9<+ *&"M-2#".54>3326=4&+5;2=4a#>mR6R):*8$"B00 &9%b 9&@Z)<320(31x!(N MR%.'&#"#572.54326326327>=4&#"#54&#"#54&#"M@1P'f%@U| =F3.9/<3<00;F2 ( ,H,)S''+>&JD+ #9'& +-H,//00=< x3#%``/%#``1/Z3% BD!MM #1%#"&463254.#"#"&546354&#"326%T9MrqP6* *%8'wGPp`02&87+&87F0qr "6) ((9^oPG6*'99L %3#"&'"632#".5432324&#"3265 ,+a 0/*:= %S=%<+ C2E5,)6<%(6/ "O<(>C%&M4R"&#%'!1)M -%#654&##54&#"6#.54632632N?17!$0I;%&;&4@pQX-4P5:(Tm&8-$$1*!M3 wG2Bn$$)H+M ;%#".54632326=4&+532=4.'&5467)P<:A-%;%*8110 =$'W*<+`*@8!@()() +$< (  7 $M *2673#"54633265+5326=*N0(=';=8$50'':S? J6+)!&O/x )4 G5- L =%#6=4&#"#54&"#"&'&546?67>32632BP25!$1I:L:('$1 Ix-. *J4X9 Q:V)+W4H"Zd0.-#%!',">#%Tw.b'!?100$/&&&?< $#".55763232654.543,8)1U";(!RbV-5"'J1 5!%/')!6fD 0BO%#"&54672>=4./326=4632#"&547.54632'54&#"3260$5V4pc,%]4@9+&0 -"+AO)&=,j#sX0>B2!^l%l1B8$0*/  6*P './1d#,k1/1#M 092#"&546732654&#"#54&#"#"&5432#"'26326CRSn9@ ;%':.Ha%g&PBVS(Nz)%#%$I``) I+ LG @;I#"&546326=4&+532=4&#"#"54>3263254&#"326@bb'T;Ul@:9N;010$  $O7B%<$$BLG"  tV_ ;?%[K%S"&&"0H%, &7F$$=!L 1%#"&546332654&#"2#"&54632557673'Q8Rm=:%'.33% 8"g@3.010*.9>?TR%&6 M C%.'ȳ.=4632>32#6=4&"#54&#"BJvFrP>, cAI/5OTFL1+:,U+  %6%27T.# 'A/1!:!h9E1Bc3I-""ll# T)0#dM+%#".4>3265#"&54>3326=3Ͻ7S):* 9N9/GO\ 3% 4'-8aͿ);3&20  "&&"7X1.208M -;%#"&5463254&#"#54#""&463263254&#"326)O7WjlU4-,H*+NN=",#"BR`>#&;8- =$>8 ZfWj"II085X4?FB/+ !'&M !-%#>=4&#"#46326324&#"2>eC 1:VaSV>S"S,A(( 3..726=4&+532654.5472t#*#T(/X?6( CjB$$$!; %1 :!$>&4PB#.9J21+p8WV9w2..'6 L %%#".5463254&'&3254&#"326qQ*8/!qO2/7*Hxa7,&77*'8Ns )H,Nr'8sO+66*(99M --6#>=4&#"#54&#"632+463263254'"2-  "I 078 :7!aIH;$$7*6%U-.L` 1yyI$G1qfBB$$*a`E M 7B4632'4#"#"&#.'326327672#"/#5#".5&#"32MS7, ' !*0-"1.TV .`&66%7.G<& &! ,*: lR :7 k )%#"&557632637354.#"326pPOq0\*7/00` *%:+&8NpqP ah'ܒ "9' #9M{/+%"'#74/#'763273&"7/0(xr6 0%~7 7.T`##s*#0r VG@*W'$$ +  N M37632#"&5463232>=4&+532654&+532654&#"5467 '0'. U/2)R8Om$% a HH%HH'5R& 6><65 CH.H x,$(%$7K DM#"&5463232=4.+532654&+532654&5467>54#"g % %)''N)%&T;WeG8*0F3gZ !!!: 3(' "$5:M03MOEQp;1<= $&($ OdGK0IR 3$4%#"'#"5432327&54632326'4&">3-HD26,/#;&}\CE[W/<+q,8,!SIG+  GVh*OG2*a20j'/M.2+>54&/4?"#".547232>iD1Noo$@\<%Q9 A9.#5,L+ %:C3];# (BR%#F '5" &M E2#"5463;2>=4+532>=4.54632".'"%2A '?(@9;&** +5+A("D %2;2.43 U&!I+j  #&+/*-! 8M !,5##"&5463<.&"546323#3'54&#"'"32IJU@YWYCEWIII"6CD4<=5OICY; DJCA`x ($$`&"Ǩ.`H! (#".5432326=4'&54>7.4.[i32654&#"2636"VP$-"+ ! +'K "6%>zέ<*! J60$-+HH/ <)3G6"<"!  )/A(`d: <#f!/0؄ <% !-#".=>7;>54&+#"&54632;R'8) :&&87$.*^JO42/1"%&!4#$/*AO!>#"&'54>7";>=4&+532>=4&'#"#"&54632gWVk 2#D$:112$ 1%'YO^cb+9RRmYP!)))(s"&#$0"&AOIGn :-! 0A%#"&=47>=4'#""'5463254&#"32>[fUlq9)D,$bG58$80'6(`:%&<@ :VKEaR2, m8"I  lF= 7$(*5!&% #% ! (77432>732#>=4&'#"#"%5.'#"26!#3 -/!/` GI ,%/ 0) .'&7=F?׸ 67#4Vh & %.%G`a#&.0! )2#7>=4&##".546)9/!;)?#$;$3 o)J/9*&)0*/-D6Zl!,#"&'&5467326=4&+532=4&'52lQ?i@8 9&(90;%4*c[a(9SZe.&"+2Iz!%#$1x!%HGQ2=Q.'.'5632.5432>326732#2>=4&'#"#54&#"#54&'#"Dzgy-;+.=> @/<FI &"CH,S )/.U<6D_*$ 7S6/5[ x,H``/ !``100b# 2G`! &6%#"&5463254&'#"#"&'54673254&'#"326oQMrqP6*7)0 (mQPl`5+&86*&8NqqOPq&8/ # @LkS-36*'89! (7227#"&'"6732+".546354&#"3260S:?"#i%:06(d_ ("(OI5,)64+)5 :/ )E,nV'?'RDK"&#%"%$! 87"&54747632>3#6=4&'#"#54&+6321<2a$A$QY`100$ 1I=#'7" fVI[$Q> Nq00*%$/$$! ;#"&'54732326=4&+532=4.54 I>$6. B,.4&O-T  )(!+$<$)!.73265#+5326=326=3#"&546;%$< 0, S< `.b/%M5]`: 0y '- G( M##='h@#R! =26=4&'#"#54&#"32+.=46?677>3267IU F.35" 1I=#&:<*9]bE}!XIDNI(])!hMa)\L?,$$/+#(3:-Rg(<C[N06+%&$! +%#".55763232654&'5463(J0+9)1U !;(!TI:2#'J2 5!%0&~0(9+>*!FT#"&54632>=4.'32=4;#"&547.=4732'54&"3267`;t{M: ?8$7%* M18NkaBqW(!#OJ1^j %5f7%$6  /$!55*P (%ZW K o00@2632#".54673254&#"#54&#"#"&54632#"'32>')2@H&K3>>(>:<([G X!   )-PB)9&#A)4FEy"$G%#,__*E  $$!M[%##"&'54>3326=4&'&5463>=4&'#"#"&54673263254&'#"326   alRLs/ 9&(92. DER@?W<#BGM16 % &D^Ve_G " !%#$ # H@NLDFG$(C04!!525572>73#"&'54>332654'"#"5467.E01 0TmgU 7' D &0T6 0HR<$e[Z@ "-$&x'%#3$# -f,E!S=J%74&#"&'&'563.=46;6732#"&754&"326+ 0C/! 6%LV :'"\F#,"/C>_37$>`+8,*)A" S* (/D)q/X9"f7F/DA/@ D""!*#"&'546;265#"&5463326=3_^Ot>6 9N9/GTWD4 <#,5aT\c]L S  '&"6S=8Y18 0C743254&'"#54&'"'.'546;672#"&'&%4.+"3265F4-$H=M8%)2^c4s #+&  4-@/II11%)4 Lm6:&#   '*! &0"#4632>7237>=4&74&#"26(-aPY>R164$WR$2( 61_tL]C6<;)`"L!<%"&'54632#"=4>7326=4&+5326754U)&' 3,0Yu7'/w>6##". %  '?IAou.8I0138uM=x6((! $%#"&'5463254&'5254&'#"326qQNqqO2/7*Osa6+&75*'8NsqPNr'8qQ(86*(8:),#'>=."#54&#"!#'467326;2#DG$("H )->+P&$6bL); .. xx! {,2&8&$G!KX$"/#"5767;>=4.'5#"&'5463254&#".5727632/&#";6  0%/`C sB*0"9ME8# I ')"bS0  TT < 0$g>H#h!;d"#-!` L*3E *  V< lS k! *%#"&5576;637354&'#"326pPOq0+* *7/00_7)&98)&8NpqP  ah&ݒ&87)(89F9%#"&/#526754ȷ'&#"&5467267#7327F;.L% N''Ne\WeD9(2F3eZ!"!*n'  A#-1 "$5 @6LLMOEKu<0<=I$'#$ &jL !4 *8%#"'+.546;327&=46732326'>=4&'";C=03A,E2 &TIFZ12%#(+RH$    ITH'QE4H^? 00x-(x+!22>32#>=./4?"#".5432$WA hD0Cet4'+N,# Q)8DG/#0/!=4.+5326=4.546;2 " 07WB'K2!;@&;>0+') **-,4,>'%*E(^;"c):* "G3&M3z$ #  +6%6 - ) ! )3##"&'54635#"'54623#3'54&'#"'"326ISI@WesYYIII6CD4<#?DJFGB`DJI;`x*$$`&"Ǩ.`H+E,73267654.76?2#"&54>4'&>?632#&52**+\?Z ' !(^4j~D'.> ? U&*sND , ED%#"&5""#"#"&574676.7>3232>54.76?6322>722)9 7  Y@[  L ")$&(< 6-$2V%  5,oT'+!4W|c+?sV1 XN7"547#"&546'&676;232?674&76?2?267>;2#"."#"&#!H"+8(y+ ++ @M@ ) C%  ;)8%   6P /!X  &N"N0 *&#  *"X57"547#"&54654?632327>/&76?632+!H"+&%!y $ 7  gg  06P .!U  a %:`(2,Y9I747+".546'&>;2327>'&'&7>3232#"&74+"'326#$ M K3?  O >W*56m. F 3K# X +J%*03N )+,  <a=3232>54654&54/&54632#".5465#"54>54&7>!4 g!;8! [&7>54&'&?26.#">j#$*N /;-?T" "! *)%/    bX$  %D'(( :'5&-#%U    :# ()PRy)!!   G" %011!\37467'.=4?2632+".'.'+"1J 5 '*., B  GO  K cm* M*3u\z2 Vq)8Q& 2\B7467.76?22672#"&'+"#".'.'+"2R'*+ 52/*h$ )'89+7 2K J`r!B  %F1[:2 1-S  + o%* 1\G7467.76?23>4676;2#"'"#""&+"/.'.'+"&1Q'*+ !' !# ;.1H#    2g Jck B <$2$3%Z'O(  *!2 2~t1`* &8#\4+"&'&54>767&74?2632+".'?9\ 7 2(;6  ?## A l7 * #B+- R4?+;7  )2\3A7467.76?232"#"+".'&'+"%4&+;2652Q'*+*.P&fVO/, "( 2p>9(/ %bn!B P0V.$ /c! ^Q-MU@L7467&/&5&>32"+.'.'.>32#"&732654&#"-R-*)  0%+   5$ <_E(3'%,$ /,d$#Hv!9  1 .)P0$`C$ -3 ,, 8%'  >4*, 1uUVb74>7&74?632?>7>7>32+"#'.547+".'.'+""32654&1@b097    @D 7 ! '3u %=%(@8#"(e>!!cIzN  00  7&[)$ @  + !] ! M ( !9v\V7"&54>7&74?263272>#"&5#"&'&6'&5467.'.'+T 4K>;6  F !5 4-- 0-8'%71%() ec9)4a@'R"L1tA  1 6)00 A D8EU  J_74>36=4.7>322+"&5>'.#+"54?"+"#"&5Rwd" O =" +3D9 E) BQ7) pBd1 ">8 4 I J/!1 ?j$ ;1oB%S9#  -Jw74>36=4.7>3227>7>#"&5+"54654.'&#+"54?"+"#"&5Rwd" O M[O B@2 )(;c 8%<+ E) BQ7) pBd1 "3 1 5+ $ Q&G*= ?j$ ;1oB%S9#  -Jq+"&'&=467>37>=4.7>323263>32#"'#"&+"54654&'+"&54?gG_-,  m% O C ? D. 3,GH @o_ E3,A=&(  *-.A,+\  Q 1 U " 1 3&T DO@h% $1oI\7+".5467>3>&'.7>37632+"&5>7'.#+"/&5467, <1){4   "Fe +:I5 @  7'6# ,62Y  (P1W C/"2 b  ])J`l74>36=4.7>3222++"54654.'&#+"54?"+"#"&5%232654&Rwd" O [kLRd^K3 %=* E) BQ7) ) pBd1 "'M2*# + (E*< @h% ;1oB%S9#  -ME"n4.'632>322+"&5>'.#+"54?"+"#"&=4>3>54&#'56 -'"* 1'=" +3D9 E) BQ7) Rwd" 1)6F     = >8 4 I J/!1 ?j$ ;1oB%S9#  -0Bd1  IZ74>3>4'.7>376322+"#"5475.'&'"+"&547+"&58O_G   "_oN &  (  B:S+, p5W2" -S%! @) 7 9 %@#'9)" (tIk7+".5467>3>&'.7>376322>#"&5"#'#"54654&#+"/&5467#"&54654&767272632, <1){4   "\qO )(9 $}] @  7'6#29,& U57   ,62Y  'Q5C   0 6+%QEU b  ]) 'K69\]F]ln%".#&#"#"&54>3276323632363632#"5+"&54?>.#"&#">326?64+">3>k #T(0&DsB#* $%.  ?>,i) =   6 <$ - % ^ P9 . (1a 3(LQ; *7Q/!  m) &f3."',@& 2M1 {:\OTk}%'.#&#"#"&5467632326323632326327>32#"'#'&+"54?4654&&#">326?63232654&+"k#T(0W*HR1B6$.  0 E.9I,! BJ;.@, )/# y?$ - % ^  )=1a2&5m248" / 40B %#) *"',@& 2v27.(d[v4."###"54>?3263232637632767>32+"'#"&+"547""+#"&5464&+"##32723267676;?, ';PxmH    '  C$!4 NH  @"[$) ($   *$&LfNJ/]I )\9X)   31% . 3JM(Z ) W) <>(#E.d8Wa%467"&'&54>'.###"54>?3263232+"4&+"##232632632676;?4#Ll %  ';PxmH $A!  *$  )  fNJ/]IJ&D  %5'*)\9X) *.42&! Y >H(#E+dEdo%>7"&'&54>'.###"54>?32632322+"#"&+"54&+"##2326326326763?"326=4'"&#?Ll %  ';PxmH $1> Nq&6,   1  *$  )  f NJ/]I %"5[-"  %5'*)\9X) ,.0##*  A! Y >H #E+ );dAS`3"5467>7&547>32$32#".=4&'#"#"+"4&#"#326=26=J 311546 ?toR$E<  %  'R&  1 %355"JR* 6 # ^81  V?6G ) !^/JN&O0'/1376#".=4.5+"&4&#"#326=%346.+7N."| 0( VCx 1/?6372632326327>32+"&5##"&'&654&5467&4&#"#3263272>76;2?[$)  '$ : (I?PzY$l   ^W  /*;[Tj9,( f f $&&  eNM[~HP+Y!8 9#2K&2'3/  * 4-&I 5 'W*CL$O>U[#"'#"&'.54654&54;263232?>7>'&>7>4&54;232654&76;2632(T7674&7>7>54&54;26323254&76;2326*(:9 6k)H4G 5M L 5   + 'hC5   7+ 6- #2  !0!  *  L( 7U #>H .* L9~%4>7"'&#+#"&54654&56;232>7>&?>54&'&6;263234674.76;2363>32#".#"+"'"&+"%`>{&$, ;&    ' IV A t "G+ /2$  . $M0pb -$U  _ !    (8]#  7"65!- 9a%467"'&#+#"&54654&56;23:>764?>4&5&6;26323>74&76;2+"&6a>{&$, ;&  & IVA t BT0 -$U  _ !    &9047!!CEDgu%467"'&##"#"&54654&>;2;2634676474>54&76;23>'&6;232+"#"&+"7.#&#326= ) +II#+ ,   # / % 3  @ ] XcDO%  1"#- V+?1#V ))) %>  &:43+4 4/54'4;23654&6;232654'&6;2#"&"#"/&+"vw>) , "!= < gL3=2b<$ X>, "4  #'[  n!3D >1' 27.+"&546'4&56;232632726?654&76;23274&76;2632#"'+"`:kH%"+=" 3  0 ot 3   -aAZ8ED8 7b1#b  !N' U.)2 f; 0;(`\cvG8%467"."#+#"&54654&56;232>7>54&5&6;23>74&76;237>32#"&5+"#"&'&>'&5467&5#A& {&$, ;& $ 'IU @ r  0V 0.8P 8h15' e S4  -$U  _ !  X;-6"$6*0 6)"Q & $0+2"'#"&547>7>372327>32I5#MdvDX. G $9DE9$0(915(  * , B7^T/>E2  -M71.0A%+5   RP&F7467"&54>=46;2;2>#"&5#"#"+"&9TGTG - /BB/7L (O2*2*:  ? 0 m!'(A&9 " *=$ 0   4 4- u !1&746;232654&54?2632#"&54>765 0 '9.9 r0;* 0L0y!4O$@9K k  #@-, IS% 2!+ $#,3'F6%) GM0'N%#"&5#"&54>76=46;2632327>;>32()::$$f<;\B_aJ -  7MPN7+#!) Oy i 5," & '5=6W>;P0 -J5/< %)$/'=" *1+?K%2##"'#.54>74>?263232>7&547>3>32654&#"3%6%B@N778!?\]F 8 ;9NL(/,!$<Hy+$4(0  2#3V@?V2  ,J8)2=M"= #/ i*,!-'G%"'#".5&54&5>7272632;2#"&5"32>7>732I0J1*,sd:/ X 1+A)5"H3 1@(  * , 2$& 2  +3F $ "#  -~IIW%"'#".5&54&5>727263232632#"&#"#".47#3263>7322654.#"I0J1*,nh1 *"E%73<9"- >MU)G@(  *! $ , 2$$ 4 5(&9 )'rQ'"#  ( #0{r".547>5"&#"+"&654&5&632726;23>32#"&+7>;>32#"&5#/.TVR46. (=  8HF* )$6,#3#8EG;+EB!) Oy '):#*  U / !!,G06R8  ! -$  )4 # /L4-*->& */ '=" .5, ) %-HE4674'4&546?26322##"&5>54&#"#"=4&-sO C  9G)45! 3& KZ0  1 ~" $J 71'M5!F<,C -He4674'4&546?26323;2>#"&5#"#"5465>54&#"#"=4&-sO C HF2 1*9] ;E-D]3& KZ0  1 t6  2 6,  ?; j8/_MB7+C ,H[4674'4&546?263227>26467>;23#"''&565>54&#"#"=.,vM C gO @"  : @K, F+B`2 ' J\0  1 FB% + 4^!80aM%%G8+C>v,HI4674'4&546?26322##.45>54&#"#".'.,f] C  (A//;)3 %7b0  1 ~"  n-6!I2)7(4-HN\4674'4&546?263222+"&5465>54&#"#&=4&4&+;26-sO C  &6,1F, "0' 4% ;"1 'K[0  1 }M  j80$A)82+ @! 0 -GDF4675./&'&37632632#"5465>54&#"+"=4&7-h= 6& VYE*Bb2 & GZ =a# v~580`N%%G8+A -HP4>74'4&546?26323#"54654&#"#"&=474&-CS, C IR  9 @/19'  8  "1N& 0  1 ?7c/+6!E.; $+ 9: ;3.t G\467&76372632236#"&5''#"'&6'&7>34654&#"#".'4&.B C    ((:;8T2%() )E+19'  7  $Cbd H{5/-&1 8) 11 A  D80"F\A  >pg2>7>;2#".#"632#"=4&5>54&#"#"&/&546?6=##"'5>54'46?6@ ?;N!C* $F%* 1$=2<99&.5$  Z 6E(,P1 !X3 # 0 ]5*" ( +6)#G/# +E;;2M Z! "  2>7>;2#".#"2632632#"&5"#"#"54&54654&#"#"&/&546?6=##"'5>54'46?6@ ?;N!C* $F%* 1 M;?o(+7 ) S9&.5$  Z 6E(,P1 !X3 # 0 ]=) -, 2 8(u 0#1*#G/# +E;;2M Z! " 0v2>7>;2#".#"632?>763+"'&54654&#"3#"&/&54676=##"'5>54'46?6@ ?;N!C* $F%* 10-= Q!  4 P W1!<#-5$  Z XK,P1 !X3 # 0 ] /@; * 0 3$ 0*"F.5  +E;;FM Z! " pc2>7>;2#".#"2632#"54&54654&#"#.'&54>75##"'5>54'46?6@ ?;N!C* $F%* 1 X9+:h 4 2F:,P1 !X3 # 0 ^p-* 0,&.\CK'P (D&d! " r26726;67323#".'.322+"'&546=4&#"#".'&54675##"'5>54&'6;234&+;2658C9^  /0# FR %6,u 8) "+# Z  mGBO1  &.! "/ '& 8  4  ]52~M 25$, $=&\1 M_ e""73 $y4'6;27263>76;23#".#63#"=4654&#"2'#"&=4&=4>75&/##"'5>[5 X8(!#!5$#'  4MY9&>Y  <  );57 1 "l ! !  -  02<# 0.+4(^K (( d%A' TA"pr2>7>;2#".#"2632'&54&54654&#"##".'&54>76=##"'5>54'46?6@ ?;N!C* $F%* 1 =]  h8& ",$   R  6-!,P1 !X3 # 0 ]3;\ . e#,":$'    %;' Z! " (4>75#"#"'"&654&=463272>72723>32##"&+2632;2632#"&5+"''##"'&>'&763;&546=4&#"#".J2G:,%-  '08   " HC1 *  ))"5#$V +(9. 9U9,+ ?<>=&G[ 7)E'c   ! 5 A $ Rp:  1 7+8C  6( .)h8G A4@{G=NZ"=4>7#"&=4>?4654.76372632###3263>7%4&#">-  '0R7L[P   _ &J@-YQ   *|K !"L9!!))GP +;  M2L-# $ (>Y%1+& "@GTeq"&5>7#"&=4>?4654.76372632#>7272>32#"'""33263>7%4&#">+'0R7L[P   _ &J@-YQ ) 6)! +3J .  ZK !"L9!!)$i +;  M2L-# $\&241 (>Y%1+& "@GJ[g"54>7#"&=4>?4654.76372632#2367>32#"'&3263>7%4&#">,  '0R7L[P   _ &J@-YQ # C- ;*5CK !"L9!!)5 K4 +;  M2L-# $ !,!* (>Y%1+& "GGYa4>3>54.6372632##"&54654&763232;267>7"5473272?65654.'w>]K   _/X$/35$3Rj8)3   A -U:)x% !0 m",+> - 3 38*8))> 0 %) 6CC* >&@{G8IUc"54>7#"&=4>?4654.76372632#2+3263>7%4&#">4&+;265,  '0R7L[P   _ &J@-YQ@>&&K !"L9!!)!, *4 J5 +;  M2L-# $;L% (>Y%1+& "J?{Pbn4&'5632632632####"=4>7#"&54654>?4654&##"'5>3263>7%4&#">B34 %- &J@-YQ   *  ,1N6LZQ  ") K   L9!!)X 5J-# $ )GP +:  T &>Y!2+& "A3ANZl%"&=47"&'.54>765654&54>32632#654&#"32?4&#""2>7>5N84 FTI>"F.**?+0"I^ 5:>K  .#7 &k( % -4 2< F / .&, ,(= ( $ 7 nS$.Y MY$-- @GUfr~"=47#"&=4>?4654.76372632#32326;2632+"#".547#3263>7%4&#">32654&#".!'0R7L[P   _ &J@-YQB )+Q )52; %F(W   QK !"L9!!).#$) +;  M2L-# $&6(%7! I(>Y%1+& "*")!@Gq"=4>7#"54654723274654.763726;22>54.76;232632#"&5"&+"?####32?%4&#">.  8+~   _ 0b 8 A R 4'8/$ OzGgr7"&547467>7>54.763722#;2+"&54654#"#"&#&#"&'&654&76723>7&547732767"267654.'LNtM (   _ w^$$WT 4 .   8 '&9  % #  ^ 4{JzI %:F 7/6?8 7& ,  T $4  6  H j 1zL2* lzGOgr$467#"&54>7>54.763722#32"'"&"#"&=4654.7>7'263767>57">5&'4&+;265 !WB2IH7   ^ w]2XO-1:(.|u  ^;,&%yG[  -'L.M="'$ +<j"!0D? 16@8#!>M 1  7=>,! ).S :@Gfw"=4>7#"&=4>?4654.763726323:674654&76;2>32#"&547####3263>7%4&#">-  '0R7L[P   _ ?Q /   D '+*4/Y%1+& "kv~4'6323263:32>'>3232#"'6;2"#"54?65"#"54654>?#">32637%&#">L'/ ! !l#%.  @" 5+JA' !0BX   T!66R?@! V1!kA&Mb L:, 3] ` #   <5 @.<%7 ! !- ,K,4'6323263:32>'>3232#"'632"27272>32#"'"#"#"5765"#"54654>?#">32637%&#">L'/ ! !l#%.  @" 5+JA"Nf '/7 % 6)! +3JE  W66R?@! V1!kA&Mb L:, 3] 3+     &24  4QQ<%7 ! !- ,K,s~4'6323263:32>'>3232#"'6;2";67>32#"'&#"5465"#"54654>?#">32637%&#">L'/ ! !l#%.  @" 5+JA' b  # C- ;*5Cl 66R?@! V1!kA&Mb L:, 3] ` ** )h !,!* 0<%7 ! !- ,K,hq4'6323263:32>'>3232#"'632##"&54654&763233265#"547232>=#">2>54&#2635)- ! !l#%.  @" 5+J`e6 :S5"-Xj8)3   !GCe21@" V1!D %.; "*', 3 b%3" !4,)> 0 @L 8x_! !-1  grz4'6323263:32>'>3232#"'632#"2+#"5465"#"54654>?#">32637%&#">4&+;265L'/ ! !l#%.  @" 5+JA"Fq9D4@>#$+! 66R?@! V1!kA&Mb L:!-% *, 3] .4"  "K& 4<%7 ! !- ,K,1 $t%"&=4>?#".>7"&+"&654&54632;2326;26?>763#".#""76632####"547"'32637>5.# T:6U8: n) ))9C!  - -%7"   )9"'(G!<;# YU   +" +'@ &$(;5 %6 ; " ;%  9  (   1I.!<"-AYp}4'56322>32"632+"&=47"&'.54>765654.5467&'#"'526%4&54;2632#"&546654&#"32?4&#""2>7>-'"*& *5H3& 0"I^ 5:>K  XN84 FTI &&-5 #V <  8'#t.#7 &k( % -4 2< l  " 9* '!( $ 7 F / 7 (#   !2 #S$.Y MY$-- 4'6323263:32>'>3232#"'632"32326;2632+"#".547##"54?65"#"54654>?#">32637%&#">32654&#"L'/ ! !l#%.  @" 5+JA( 9=$1v( G (!R 18O (_  R!66R?@! V1!kA&Mb L:-#$, 3] ( %  "$;! 9 5 @.<%7 ! !- ,K,*")!4'6323263:32>'>3232#"'6322>54.76;232632#"&5"&+"?#"#"54?65"#"&=4>?#">;7%4&+">M)- ! !l#%.  @" 5+JA!'>3232#"'632";2632+"&54?'"#"&""#"&5>76&54;263&5465#'.54676?#">;67>=4&#L'/ ! !l#%.  @" 5+JA( 3?."HT 5 0< 7 F' `  6P /.FB@! V1!iH,$,=<, 3H %    *D)    >: "   35j! !1|8- ."9+O4'6323263:32>'>3232#"'632"#"32+"&#"#"&=4654&54>7&5465#'.54676?#">;67>=4&#4&+;265L'/ ! !l#%.  @" 5+JA#>?&#CL  f]%7* -# ^;+%%/r, 6P /.FB@! V1!iH,$,=N1  35j! !1|8- ."9+1 4'6323263:32>'>3232#"'2>323:674654&76;2>32#"&547#"#"54?65"#"54654>?#">32637%&#">L'/ ! !l#%.  @" 5+JA *J>/   D '+*4/   T!66R?@! V1!kA&Mb L:, 3] 1& EV   2 BK  <5 @.<%7 ! !- ,K,4B74&54632""#"&=465>54654.#"#&546 vOd ,--;`  %ag|I<45" . $3&4dt ' =4V%"'"#"&=465>=4&#"'#"=4&54>3267>32wK  0 >0/1 0 ' 2EV=Nc* G) # <3*d4!  $ - "5 4?+W;@>5S- F:h"/ 4I"'"&546?54.#"#"54&'467632?>3I' 00 2 & 2HRQ)LA<G.!B&4")#E / -X=)[i ;EG>`#)?248 !- 4?4>32""#"5474654654.#"#&54654&2GV<Od ,&' AW  P $ Z4R. I<45H,  / oQf '  ?P4CS232#"#"&=46?4654&'#"54&54>4&+;26,:;%l]"4&"WJ6%1  0 ' 0DT=0"3! '4 7&-, #";%E.@(R7'{vA?6T/ $ 1  4J"&54&'#"&5465'&7>726?>32#"=4654'&#"9 `B$% K]H*K?   ( !E// @!*3% 3A 3 4L"@1*(D 04.;+X; 4/4>32"&=4654&#"#"&=4&1DT<+LA E.D.+5$51 Q7U/ @2(& #%0='R8 !"*t4\#"'&6'&76727&5465465.#"#"=4&54>3232>#"&5'&#"#$8-)% x3!5)@V  F) 1FU=*L>"E22 ((:<A 8 &I; #67++oR59)  A W4R- @146 '  1 6*7(k226372>7632#"'##"ᘖ&'64&54632""#"&=465>54654.#"#&546ED6  :+4H$$ S26. vOd ,--;`  %2    )"3  " /g|I<45" . $3&4dt ' =(226372>7632#"'##"ᘖ&'6"'"#"&=465>=4&#"'#"=4&54>3267>32ED6  :+4H$$ S26.WK  0 >0/1 0 ' 2EV=Nc* G) # <2    )"3  " /D3*d4!  $ - "5 4?+W;@>5S- F:h"/ (r226372>7632#"'##"ᘖ&'6"'"&546?54.#"#"54&'467632?>3ED6  :+4H$$ S26.fI' 00 2 & 2HRQ)LA<G.!B2    )"3  " /14")#E / -X=)[i ;EG>`#)?248 !- 7(h226372>7632#"'##"ᘖ&'64>32""#"5474654654.#"#&54654&ED6  :+4H$$ S26.2GV<Od ,&' AW  P $ 2    )"3  " /4R. I<45H,  / oQf '  ?P(jz226372>7632#"'##"ᘖ&'6232#"#"&=46?54&'#"54&54>4&+;26ED6  :+4H$$ S26. :;%l]"4&"WB=%1  0 ' 0DT=0"3! '2    )"3  " /u 7&-, $ "E+G(R7'{vA?6T/ $ 1  /(s226372>7632#"'##"ᘖ&'6"&54&'#"&5465'&7>726?>32#"=4654'&#"=D6  :+4H$$ S26.! `B$% K]H*K?   ( !E// @2    )"3  " /S!*3% 3A 3 4L"@1*(D 04.;+X; 7(X226372>7632#"'##"ᘖ&'64>32"&=4654&#"#"&=4&ED6  :+4H$$ S26.1DT<+LA E.D.+5$51 2    )"3  " /7U/ @2(& #%0='R8 !"*t(226372>7632#"'##"ᘖ&'6#"'&6'&76727&5465465.#"#"=4&54>3232?6#"&5'&#"#ED6  :+4H$$ S26.8-)% x3!5)@V  F) "9@E0Oc69,? *':!8C 8 2    )"3  " /:&I; #67++oR59)  A]+G-!I<46 1 6+%GW%467#"&=4654&54>7265>54.7>32>7>#"&5#"'##"#" i3%&).Z*   R f"G 1*9"; ' V. - 012  *7  d   1 7*%Gw%467#"&=4654&54>7265>54.7>32>7>#"&5#"'#>?67632#"'"##" i3%&).Z*   R f"G 1*9";  !Q!)5K  &,5 012  *7  d   1 7*-. 3  %Gj"54#"&=4654&54>7265>54.7>32>7>#"&5#"'#7263>32#".##- &i3%&).Z*   R f"G 1*9";    C-  +5& 1! 012  *7  d   1 7*<  $#Gg4>74654.7>322>#"&5"#"##"&54>'&5432332>7>5#"'&6'.25  T %M22  +(8&%  '5Up$ 2 ;5I&A% *&Vr ; V   7* (#):+,  ! 07&< $3 ?  %GVg%47#"&=4654&54>7265>54.7>32>7>#"&5#"'#2+#"7";26564'4# !i3%&).Z*   R f"G 1*9"; A> . ~ $'H4 $ 012  *7  d   1 7*L% *'%h>54.5+"#"&654&54632;2>7>#"&5#"'###"547#"&546'&54672>38  <  #551 # wG 1);+3    3$l +,$ /Z-5 v W " AV   3 8)H  .   #( C3Vc"&54>7#"&54654&54>7265654654.54>32#>67672#"&5+654&#"0 cG& &)\, (;37J .'& )- 4(8e  PV.#7 E:$CJ<95 #4 8,!2 ,   8)z/4# wS$.Y 'nG%4#"&74654&5467265>54.7>32>7>#"&5#"'#2636#".5&#""'#"&54>'&7673>3& &iA$)S   R mE2*9)  " 3%0 # 4W&  g <1  4A 2  *7  d  2 7*:  3 *' .# ;zo26;>7>323#".#"#>76#"&5"'3##"&547#"&54>'&7>;>?##"'52654'5>323&o& :C6;*8% H x\   "$+8d $%f$ & J L [ t !1"" !$,#3h  +9(    +  !2  "   A# ;z26;>7>323#".#"#>76#"&5"'67272>32#".#"2##"&54?>7#"&54>'&7>;>?##"'52654'5>323&o& :C6;*8% H x\   "$+8d& 5)! ;'% < $%f$ & J L [ t !1"" !$,#3h  +9( 1 3.  C''  !2  "   A# ;z273263>323#"'.>76#"&5"'?2>32#"&'#"#"&545#"&54>'&7>;>?#"'5>54'46@ 6 C6   :; %x\   "$+8d (;4$  8%0 $ f$ & J L Qv  :S3% 2 " 3h  +9(  /U  /  '  !2  "   A"1z763237>323#"#"&'>76#"&'#"'##"&54>'&5432332676?#"&'&654&54732632674654654&#+#"'5>54'4632aa YC6." $. 7  u_ /(74)Vz9(2 A 3[b2%&nR  Ou  :D $- s  !# 7*dV%0.: ! %?e  215  ;A":nu63276?6323#"'>7>72#"&5#"'32+#"&545#"&54654&546;>?"#""춮'46324&#"#326;265 W H:02Fa d ,+ '(;G.Ep&6,#"&f$ &D(L "! ;,!:B' .! '. '"3   )6) #) &  "4 1 "!6X74654&7673>?#".>7"&+"&654&54632;2>;7>323#".'32>3>#"&5#"'+"545#"&u  dL : o) (:3 K 5# :@"-R 8 l` )*:H @Ee3%'7 +  (7,   0' S    )  ?2 c 2  878>54'5>32:;5&54654&76;2#"'>72#"&5+"#"&5467#"#"&54654&476;27254654.54>7'&#"+"&#%112654&+"$ %#)   # Q  ?0$ +W-_B9 (,9A  O L -%&4T  0 nj*! /  C#' #  *  (+71J   8 >4$ 8(' '/  9  (,(  /8%R ;nz26;>7>323#".#"#>76#"&5"'326#"&'#"'""'#"&'&>'&54>7&547#"&54>'&7>;>?##"'52654'5>323&o& :C6;*8% H x\   "$+8d  &,7*  0V% ) -x( f$ & J L [ t !1"" !$,#3h  +9(  &700 #3  #  #  !2  "   A# ,CW43232632654&54;2;2+"&546754'#/&#"#"&="#"&546'4&5U!g 7 A:  E7   ++'"C  % S %*  *8=  Cn4;2326326=4&76;2;232672#"&5#"+"&54654'.#"#"&="#"&54>'&4J ! d 3  :,?0 (*9-    E:   $ ' , 'L#C 1 7+ 8> *!   "1  Cr4;2326326=4&76;22;2?267632+"'"#""&+"54?464'.#"#"&="#"&54>'&4J ! d 3   (": & \ 0" M -0   $ ' , 'L . 0 - 3?6   "1  %CU4&546?6654&54;232##"&54>'&6;232>54&'.+"5465#"&'&6LN}) 7 ?2@n;$1   J-WX6 3 R*% *   C  % S w-+?!7$1   A-f!  $5  =CVc43232632654&54;2;22++"&546754'#/&#"#"&="#"&546'4&326=4U!g 7 @'CB#@8   ++'" .(&8C  % S %L% ,   *8=  ( 7DV"5465"+"&546762725654&47632;2;2+"&546754'#/&#"I0Z 0 V  5  A:  E7  !=8  I`  %N %* 0Ndp47#"&54654&67>727>32633>72632#"&#"#"&5473273632+"&54654.+"%2654&#"(DG+5i1 h-#?<,/5 . #,),+N*    = = @!"=,$=8 1 &,-C $$ !E0=>A55   -&Ct432632654&54;2;23263232632#"&#"#"&547#"#"+"&546754'#/&#"#"&="#"&54>'&2654&#"5W.U  7 BA! ( 8*56- / 3'47 -  E7   l2%& 2  C  % S ) 6'(67&!  ,  00"!!'C43726326=4&76;22;23234654.76;2326#"&5#"&4>7#"&#"+"&54654'.#"#"&="#"&54>'&5W.< 3   (!4  ' .0  2'<    E:   l15& , 'L ,1 4 n " 7, 'C#0 *!   "P$TCy43726326=4&76;2;22;2+"&54654+"'#"&54654&54>7&54654'#.#"#"&="#"'&6'&5W.< 3  ;1; 7  4 '!& <-$ <  l15,' , 'L 8 %.  T   ,T2    "PDCp~432632654&54;2;22"#"#"&+"'"'&6'.67>7&54654'#.#"#"&="#"&54>'&4&+"32655W.U  7 ?oW"5$ $ o2J&"/x@ ;  l2%& ) $)&C  % S ' e-  87?     00"6 >Cu432632654&54;2;23>54&76;2>32#"&547+"&546754'#/&#"#"&="#"&54>'&5W.U  7 B9 7 E 130  G8   l2%& C  % S !+ VZ 1 A 2t,(*   00"0ZB6;2#"#"&5476&+'&'4654&#&636BAi _! 8B$m /      kAN%"&5#""&=4'.#"#"54654.54;6322632326*7, "  I  '  & C") *6,%?B!   ! k   k M  ! lAB"'##"&5476&'&"#"54654.54;63276327>3}J; F u'  & ""OI,":3  ! k   k "- ?)E#"&'32632632+"54654&"+#"54>726726323(7"*:3(  l' <84 ?*O2 5 \  6) a:@D  ) R'5," /]A<J%++"54765&#"#"54?4654.7636327226=4&#;(:-#91w0 #G-J^(!+ ! V! % " @ ! i ^;)W @ 2'G4&#"#"&=4654&54>?632;2#"'4?>'&+"54?66 -2#&3N=n  P9*m G  t  N     563   4 Z# ?  D!?fP\"&54732>7276;632+"'4654&"+"54>7263>32#"&#"72654&#"u",),+ )  ?. ( C@$3@/# 8)?> ' ; .>!"y'! !E0=>  ( Q+F( - ! -&%tk)e46727&4654.#"54>7>32632#"&'3263263237>#"&5##"&54654&;2R4! > E)X< -(5"*:3(  l)I!  ((<=Uj<0#  S5A0( 2 6) a:@?d  " 4, 1E0 Izn4'46323>7232>56;23#".'&#"#32637632+#"&5454&#&54?654&+#"'5>; b &[..& "  & z#2 $s !" /.  F      N A"Hz2>7232>5672#".'&#"#32632326#"&5#*##"&54>76'.'"54654&#"&##"'52654'46?6A 2&B &NE% #   0%  **7(2(  <D& E (z !S3 +/ _   5  ! 6,cW  +V% j @#" Hz2>7232>5672#".'&#"#32?263272>732#"'+"#"&54>?>'.'"54654&#"&##"'52654'46?6A 2&B &NE% # &$F G /* :+3N *+ 5 O E (z !S3 +/ _  D+  )"3  ! % j @#" 32>7>32#".'&32672636#".'"&#"32632632+"&54654.*##"54>7>26&67#+"'5>54'6E9cN !*  8"$  $/)   ( #H4E& n(  +0 @&# 4 O1 o2  . : +V?>=  Q6$ " !#+l2>?672326763232#"'326372632++".'4>?65.#"&54654'#">54'56"32632>5654&#&D ( % 8  Q 6+GI'*(:.#9 b G;-"0A-$a32 . 4k  O9 @! #  i "!,]  6v~&>7#"#"'"&>54/&54322326;>7>32##"&+"2;2#"#&546?4+"54?654&'"#"&74654&7>3,*  5)GV.  >'&  .)!4+Q16s)!J! ,3&' v     6( ",     `" # < 8  553 34'632723263>32#"&'237;2632#"&#"#"&547.#"32632732632+"#"&54654&###"546747#+"'5>2654&#"i 2B   , N"   3+ 4E -:4&!/# 6 *%<4D&L)  ! B @w: 4 Q0$$ 2$ 4 >) &)"$ X@;A    TF[E"#+6t7"54>76567#"+.>54&5432;2;26;67>32#+"&+"2632#".'"&#"+"#"'72>373263237>#"&5##"&74654&546727&4654."+?:DA2 ,' 5)F3 0  ?' !*  T ( # % '%I!  ((<=Uj<0&2R4!- P5J!  !5("- # &5+ (/$"$ " 4, 1E 1   /8M7467#".'&6;2322+".'.#"#"&+"#"&5/gvX L)7  $,;,  H 47L ;  $Gk: u ' 4.U% $O-&?  /8V7467#".'&6;232232672#"&5#+".'.#"#"&+"#"&5/gvX L)8+rT *?0 1*94-B  63N ;  $Gk: u )5J 2 5+#y "V1"=  /*8a7467#".'&6;2322272>7632#"'"&+".'.#"+"&5/gvX L)8+, 6 #)5K:  M , 2; $Gk: u )' Z/9  ) 1  $A$   &s7 /8I74675#"&'&6;2322+".'.'"&#"&#"5#+"#"5&5/VT L)8;'3B. $#A   +# %BK,)^ u(  |{ "R0 32 % /8Xd7467#".'&6;2322632++"#".'.#*#"&+"#"&5%4&+23265/gvX L)8++ aT&7/A  , : ;  E#$4 %$Gk: u )-L. "T.   _V Ei(Lj4'5>32#"'>4>75+"54?>32;26;2+".'.'"&#"#"&+"#") hN-3r:OG+1   2  ' /7-  4    [ 72# 50t\C   -      5.d, #S0  sO% / 8G7467#".'&6;2322+*.'.#"+"&5/fwX L)7  $'@-    2 :5HL !Hl: u '  #" +"&> v4'632326;>7>;2#"&'322+".'.#"#"&+"#"&5467#"'&'&"'#"Ȏ8#! 1'B(+B$    9&/07  $,;,  H 47L ;  gvK  (}# 1 L/ ' 4.U% $O-&?  Gk ` @#BmU74675&'&54?656&#&63637632632#"=46=4.#"#".'4&B:   $'OQ33 #& )# 4Q#)   LaS! *k/ 5$  B.+(v   nAmf74675&'&54?656&#&6363763263272#"&5##"&54654&#"#"5'.A;   $'OR%B7 '*99     7'7P .& J_S! *k/=0?!   6* R ) # !(-8wF,UBmf74675&'&54?656&#&63637632632>6467>32+"'#"54654654&###".'4&B:   $'MR>b C#!  1 M ~) ;%5O )   LaS! *k/;C#   ,3D 91y   nJmJ47"'&5>&'.'&63637632632#"=46=4&#"#"&JG3  $GX14#(7'8J H ]=  HK c( 6&57C  ,5qX!&  0AmM[74675&'&54?656&#&636376326322&546=4&#"2#&5'.26=4&#3A;   $'OQ%B8 eX%@7S $ ''1J_S! *k/&'&763637632632##"54654&>u=B   $'XE43 + )A229  %   \ F7 H=% )o( 5#08?>35 [6 *T2  BmO74675&'&54?656&#&63637632632#.54654.#""#"&5'&B;  $'OR22  * )&6R(  L`S! *k/ 4#b  r&0 s ""0Q>Cgs4&54;2+"546"&547#+"&'&54654.#"+"54&5'&54>32;26;232632#"&#"7"32654&L  0 1r)5]7 .#7M 9  "1V5Jq^/  ( 2 +54+ 5 .9"!#  7S Lw5'yY+E92;22B$ 6F9'SH6(&7!! >Cx4&54;2+"54647#+"&'&54654.#"+"54&5'&54>232>76;2;2632#"&5#+"&L  0 1*i7  )7M 9  "2VjQ(fP   [ 0.8.G  7S L &Uf+E92; $*A$ 6F:(&8.', 2 7* QoCl4&54;2+"546232?674654654&+"+"&54>3232+"&54674'"&#"&'&654.7632_  0 1i@XO ) 8 *L0Wx9  6  =$(    7S LC kOK8QC ;PA.s]  1  / :26 QCmv4&54;2+"546##"&#"&#"#"&5&6'&6323267654&546=4654&##"+"&54654>32324&+326_< 3xYi (/:#0$ $E`A2-0 8 )U8Wy!.:(f%5  V L.  *. < $ %&IY7    M[?t^ l>hCq4&54;2+"546"&5"#+"&'&54654&#"+"&5.5>76322;254654.'&;22632L< 3(8 7 5*'.! 7 =08F4[  N% T * V L9) 33PY1?J,+(L*W9  Cn &-) 6 <,3  63237>322#".'&#632#"=46=4.#"#".'4&54675&'&54?46'4#&##"+"'52654'5632} gD) 00& 4OQ33 #& )# 4Q#)   :  . $_&#/*=#. n/ 5$  =.+(v   nLaV  .%  63237>322#".'&#63272#"&5##"&54654&#"#"5'.54675&'&54?46'4#&##"+"'52654'5632} gD) 00& 4OR%B7 '*99     7'7P .& ;  . $_&#/*=#. n/=0?!   6* R ) # !(-8wF,UJ_V  .%  4'5632>?>32632#"'632>6467>32+"'#"54654654&###".'4&54675&'&54?46'4#&##"+"'526?#/*-? v%   7)I:MR>b C#!  1 M ~) ;%5O )   :  . $_&$%  - 4x/;C#   ,3D 91y   nLaV  . u63237>322#".'&#632#"=46=4&#"#"&547"'&546=4#&##"+"'52654'5632} gD) 00& 4GX14#(7'8J H G3. $_&#/*=#. 'J( 6&57C  ,5qX!&  0E]= r  .%  Zz63237>322#".'&#6322&546=4&#"2#&5'.54675&'&54?46'4#&##"+"'52654'563226=4&#3} gD) 00& 4OQ%B8 eX%@7S $ ;  . $_&#/*''1=#. n/322#".'&#632##"54654&>#"&5&547"'&547"'&?6&'&##"+"'52654'5632} gD) 00& 4XE43 + )@229  %  =B . $_&#/*=#. L ( 5#08?>35 [6 *T2    \ F7J) .%  |63237>322#".'&#632#.54654.#""#"&5'&54675&'&54?46'4#&##"+"'52654'5632} gD) 00& 4OR22  * )&6R(  ; . $_&#/*=#. n/ 4#b  r&0 s ""0QL`V  .%  663237>322#".'&#63222636322632#"&#"#"&547#"#"=7654&#"##".'4&54675&'&54?46'4#&##"+"'52654'56322>4.#"} gD) 00& 4OQ32V+  /0 )55+2 0 )4: / ):%5Q )   :  . $_&#/*#=#. n/ 6% 6$)77' @pp:2v   nLaV  .% D " e2>72326;>32#".'#"63232>76;2;2326#"&5#+"&546547###"&=4654654&#"#"&'&54>7"#"5>54&#"&#+"'5>54'6323 ?. [ C1 ##'&\G21] P8 -)9.L^  >"4S .  "6  O-  7 >%.  V. 6%((* T   7+  $! 7/x,FV6V" v ! ! 2672326;>;2#".'&#63232+"&54674.5##"&'&>'&632323?674754654'.#"#"+"&7>75#"546'&"##"&#+"'52654'56323:A [ D*5"&% 4+8Zw9   6 Ig8+&   :X1(4 ,2#)$  #O-'#3! > #. _#s]#  0  / 1;   @8@('{;2 -)v s! #/2672326;>;2#".'&#63232##"&#"&#"#"&'&?654&476;32676=4&546=4654&+"&5675#"546'&"##"&#+"'52654'563234&+326:A [ D*5"&% 4.3W}!.:(Yi /+8%(  "  ]I+$14H)$  #O-'#3! 0%5 > #. _#q[  .   &/   $ @^wi- s! #Ul  63237>322#".'&#6323265654'&;22632#"&5###"54654&#"#"5'.54675&'&54?46'4#&##"+"'52654'5632} gD) 00& 4OR8]) M P 2*8   ( %<#5Q G' ;  . $_&#/*=#. n/30- <  2 6+35I.25/v F,UJ_V  .% @Y4BQ2>3232632;#"+"#"&+"##"#"&5467>&#"326%4&#"327>@ 1  XZ""-a+  *   NT!s4;  3, !/:& = "7>;23#".'"#&5"+"#"&#"#"54676327>76&#&#"%4&#"327>.7! hf//.  A& 9 :%( A =   -K&$@$R<2 %::& = " ;UAv /  h($@; /6.{A2 c73J\2672632#"&54632654&#"3263>32#"'+".5>7#"&54>32>7"&#"('4-@T %?', ?(# @HC.3,FU 04)134 "M&,&73BT"547#"&54>37263>67>32#"54632654&#""32>7"&#"!!?J4L=1  2=VX3A  =& -  ) )" $7" =2/DM9#$,0 <@*9X g"M&,&Kv4ER^"54?67#"&54673263>2>7625463>74&#"2#"32>7"2654'4&+:=Hwk  "P=5 G )<!    "=<$=9!D+  :S#"*# !%{: ;2BY!1))-$#SABx< %  g" "I&Y L @YHUh26;327>32#"."#"+"#"&#"##"#"&5467>&#"326%4&#"327>A %pYG C- -3! !%<(! <!PR#s2<  3, !08& ->"HE  # 6K',90p%1:#?5a4)1<H7"=4>?67"&54>7326;2#&+32674&+2326D/A+'n_ /S6 'Wi_9% G_1 5 9G3$*3 3# %!#) :$"/'P?>T -::$ ;6 !=58&A2N2".547676632+"73>76=4654.'!*;| .0P8J" s *2A)(SAM8{A[  EP2h' e /.(:8%2EN0H"&54>766322672#".5+"73>76=4654.'/ +?9#-&-)  2&0 R4MR*2A)(TwxAb;&  6$70 *( p (= /.(:8%2F<WJ[4.547#"&+"&54632326327>3#"'"&+".'4654?6%326>54&#"  %4@z(?  E]H,"2%T:  B  <" <+4Nb( :,L^v'M#   "- 2   @!, S./K<0W+<%"74?6.547#"&+"&54632;2#326>54&#"' R  %4@z(F g " <+4Nb-:,L^v'M  !, S./K;NASb4&5465+"#"&5467632;23+"#"&+"&546?>'2654&#"3724&'"&"3256#!95&?OY#C * #A?  8 6 ?4L#*"+   K1H <(1=#F-P  @$  }$!::?$6 .& #1Q% A0-B7467&/.5&6;2&"2"#"&73267654654.'A@Z @   (Z :,n #8g: E1+ot, !=5%$:$$+ #OX{^4 -; >R@C+N(57"&54>767&=47>32+"+2654#"t!C.Mr>YO H1A{ F4u 8E@N)($,Q63?+S  +EJ~x ]"F7>4.76?2632#"&=67###"5454'.>32  &$ .  80   % &/ B*H K()#$"" !#BJ$ "\7>54/&763632>72#"&5#"&547###"5454'.>32  !#g. *(;=  $#   % &/ B*H K$ !"0 5+M.(*!#BJ$ "Y7>4.76?632?267>32#"'.#"&=4?##&5454'.>32  %% . $  C% *1;e    %/ B*H K("#!  "" "&F!#)J$ "F7>4.76?2632#"&=67"#"#"5654.636372 &$ .  80$  K(. 9 d K()#$"" D  ?  $"J^7>54/&7>322#"#"&547###"5454'.>3226=4654&+"3  = "4&!E$   % &/ B*"+"!+  H K$ & %BK   !#BJ$ (% `2>74654/&763632#"&=467##"54?654&+"#"&54654&546326B& *  O###!&  #BCA "% %6  1"D7>54.7>32"#"547###"5454'.>32   D).) (   % &/ B*H<1> 9&g!#BJ$ "ts7>54/&763263232>?6#"&5"#"'#"'#"&74654&7>2727&54?"#"#"5654.636372  B+/ ;; " )*9 0  : W -* e&  $  K(. 9 d L$B"$ 17) !) 1 ?D  ?  $&5j?>?2632#"&'6"#&=467#"#"54?654&#"#"&=46'4&54>76;2 =' s1 .&8&! , #%#$   #   ! '  <+&":S*3##M%.+2 5' 4(A  #D FA $# ?2632#"&'>2#"&5"#"&=467#"#"54?654&#"#"&=46'4&54>76;2 =' s1 .&8  7f* *(;/ $#    #   ! '  <+&":S*3##M%.+2 5'%&H$0 5+SR!" #D FA $# ?2632#"&'7>467>32#".#"=4>7#"#"54?654&#"#"&=46'4&54>76;2 =' s1 %&84!   9+ ,6%  _(  #   ! '  <+&":S*3##M%.+4 5'"3F   " B ~P #D FA $# ?2632#"&'6"#&=467#&'4&5>54&#"+"&=4654&7>76.\C =' s1 .&8&! , #%#$   I   & +}*@ M%.+2 5' 4(A   * /;]&! &9  4 &5k}?>?2632#"&'2+"##"5467#"#"54?654&#"#"&=46'4&54>76;226=4654&+"3 =' s1 .&84%5- #)  #   ! '  <+&":S*3##+"!+  #M%.+2 5'"0;n?M A  #D FA $# 7635#"#"'"&>54&=43232;2326;23>7>32##"&+#67267>?2>72#".'#"54&5467"#"#"5454#")#4S ,'+  4'>, - # A'3 %(!6 #]KD, @2 (#,1 0 %# '!)f   ^%.-$ =   A   !+# "-"  8  ,! "'3 &  -&%   @ $  !@!6=< &9 &4q2672>?>7>32#"&'&5467#"#"54?654&#"#"&=46'4&54>76;2 *r0 3&9" ( !'#   ! '  <+&":S*3## )'1 5'  2 !k#D FA $# ?2632#"&'2>#"&5"#'"#"'#"&'&>'&7>;263&=467#&'4&5>54&#"+"&=4654&7>76.\C =' s1 .&8.# " $F44 +(: '  . I& &  A6 !  I   & +}*@ M%.+2 5'$   : 6*#3 #      * /;]&! &9  4 0(-;##"&+"&=4.54>;2'">74} %  '! #:eB;2#7272632">74)9   - 15qQ65'4F-! ## e *'3"7Q%i5,`9d"6)!;<$$(@$     1  E/'5).0(M[%"&45#+"&=4.54>;2#254&76;2326#"&5">74U C )7sQ @3} &B 7) 1*:'3"7Q%z B&T1#!::"'Mf# ; " 7+ E/'5).%OD*<723267.54632#"&"#"ᘖ'56">54&!E 4"o]@  BTC6*K!4)8- g ^W-`v\Mg  5-" ,7&!:%&0L(IZg%"&#"+"&547&'+"&=4.54!32#3;26322632">54&"32654. = ( #<"   4 <1y$ S 0. !'% )!.G'"X ' L ' T /&'Ne&   '&">( #+  4iDBN72727.54632#3254.76;2+"'#'."&546'&>2"654&m5.,nz "+@ + 7>)F#-5(*"(; | %4Xu]Mf&:& O 8 !&  #> ; +@2$%0(GU"&5"#"&##+"&=4.54>;2>2%">74X*9< $-Y5% +8oM<-++Q0' 2'3"7Q%8)"] 'S'8*::$&5.    E/'5).%26DP72;27.5&>7632#32>#"&5'#"&546'4&5&6">54&VA(B - AGEu ; C'.':4:)1" ,D3?+% _F$ "-Lg\  2 6, 0< ;  Uh"B++GDkz2;27&54>32#326?632326#"&5#"&#"#"54654&##".#"&=4654.76%2>54&#"W"B6*DE$%+)( ,3  )):6  H l   ;#3 .6'(./ ; 86+>Z* #*! 6, )D%  #    +2 2 .7")<,7+/Ds2;27&54>32#263726326372>32#".'&##"&54?6&+#".#"&=4654.76%2>54&#"W"B6*DE$%+)(   ($ O  =3& 4&' 2* , L   ;#3 .6'(./ ; 86+>Z*    -  &v  +2 2 .7")<,7+`DRa2727&54>32#32637632#"#"&54?4#"#".#"&54654&76%2>54&#"V,; 0*DE$%+)( #("  4 3  0n   <(1.6'(./ : 86+>Z*    .  (8 8 /7")<,7%6FR\72;27.5&>7632#3632#"&#"#"&547'#"&546'4&5&6">54&"264&VA(B - AGEu ; "77C;(! 2 ) (5:)1" ,D3?+%, _F$ "-Lg\>%!))" 0< ;  Uh"B+c"*%6Xd72;27.=4>3232672#"&5#"'"#32>#"&5'#"&546'4&5&6">54&VA(0+0eIHF,1B. *+7A  $)T4 ; C' 2':4:)1" ,D3?+% DN#?A'"-412 7*\  4 6, 0< ;  Uh"B+QE>N7467&54>32632#"&5"/.#+"&">54&QmbA .T5A`:WD?:,J" 0,:: =K  *c/?)<(/IAL$3*)04L% * 5. }DXD #!( '+tD2;27&54>3267>363232326#"&5#"&#"##"&'&654&5467263&54?654"#"'&#"&=4654.76%2>54&#"W"B6*DE$$5C4   "H 3 )):B6 3 15( 1T6 ;o$  9&1 .6'(./ ; 86+>[$7    1 6+#Q 7    +  (5 2 .7")<,7%l.^h46;2"+"&5232>7'&54632#7>32#"./&/&/"&##"&546'4&5&"654&1 .  0#>!aQ97!i4s7 )( .%7 " 031" -D/ 8 9 dF1Tp +FS' 2    F ; $h#0=s4632;2&#"&52327.54632#3263263232672#"&5#"2#"7>'&+#"&'4654.76">54&  1  1-;-)+v_k &:51B. *(9 . Q 8 %81# ,&.. %.)&% 7  s'BQZFS' 2 8*0' )  2 =<-0/)f=|4632;2"+*&454654&4763223>7.54632#3263?262676323+"'"#"#"?654&"#"#"&"7>54&  0  1  =#%&-xb1M5"## % %. 1 T  1 NN9  =  w!<(1D &'(%  9   #3 w'CR\*= ? >0 -3  )9 3"6 %&=\k4632;2&#"&52327.54632#326376322#"7>'&+#"&'4654.76">54&  1  1-;-)+v_k '"#; Q 8 %81# ,&.. %.)&% 7  s'BQZFS>"' )  2 =<-0/)%S.Zdn46;2"+"&5232>7'&54632#2637632#"&#"#"&547'#"&546'4&5&"654&"264&1 .  0#>!aQ97!i'  E<(! . & ',031" -D/* 8 9 dF1Tp +FSv *>&!))6( F ; $h#00,%.q{46;2"+"&5232>7.54>3232632#"&5##7>32#"./&/&/"&##"&546'4&5&"654&1 .  0#>!&J3 0U()8De4s7 )( .%7 " 031" -D/ 8 9 XK#??(] "5,>R' 2    F ; $h#04=O^4632;2&#"&5467.54632#632#"&5"/&#"#"&+"&">54&N  1  1hh!!zbk2d2O ,'78 1Y   &b.. %.)&% 7 Jz!`#EO[ES*  3 9* tR  <-0/)Xvx46;2&#"&527275.54632#32632326#"&5#"#"'&6'&7>3&4?654#"&54654'&6?>54&#"326 0  0,5*&-ycl%A66 0 +'9y$C2%'' .+.+& 9+18Y%'5 _8  v'DQ\DS?   2 6+  00D  $k$   < 3x B4(559%F2>7>;2636?2>76322+"'"+"'&67"">54'>232>7'&54632#7>32#"./&/&/"&##"&546'4&5&"654&B 1 )     $. L 7 9 5'Z! 37#>!aQ97!i4s7 )( .%7 " 031" -D/_3   03 =6)""  dF1Tp +FS' 2    F ; $h#002?327>;2#"'+".>7##"'5>54'62327.54632#3263263232672#"&5#"2#"7>'&+#"&'4654.76">54&BI'wD* ;+4IS 8 4P2  -;-)+v_k &:51B. *(9 . Q 8 %81# ,&.. %.)&n3 # ,!3L#! # s'BQZFS' 2 8*0' )  2 =<-0/)f<26>;2".'&+"&547&#"'5>54'6323264654&4763223>7.54632#3263?262676323+"'"#"#"?654&"#"#"&"7>54&DDI D*$ 8:&  ( 7 '  S!  3"# 2& =#%&-xb1M5"## % %. 1 T  1 NN9  =  w!<(1D &'(K #/ D7 # 3 w'CR\*= ? >0 -3  )9 3"6 %&0w2?327>;2#"'+".>7##"'5>54'62327.54632#326376322#"7>'&+#"&'4654.76">54&BI'wD* ;+4IS 8 4P2  -;-)+v_k '"#; Q 8 %81# ,&.. %.)&n3 # ,!3L#! # s'BQZFS>"' )  2 =<-0/)%SF2>7>;2636?2>76322+"'"+"'&67"">54'>232>7'&54632#2637632#"&#"#"&547'#"&546'4&5&"654&"264&B 1 )     $. L 7 9 5'Z! 37#>!aQ97!i'  E<(! . & ',031" -D/*_3   03 =6)""  dF1Tp +FSv *>&!))6( F ; $h#00,%F2>7>;2636?2>76322+"'"+"'&67"">54'>232>7.54>3232632#"&5##7>32#"./&/&/"&##"&546'4&5&"654&B 1 )     $. L 7 9 5'Z! 37#>!&J3 0U()8De4s7 )( .%7 " 031" -D/_3   03 =6)""  XK#??(] "5,>R' 2    F ; $h#040jy2?327>;2#"'+".>7##"'5>54'6467.54632#632#"&5"/&#"#"&+"&">54&BI'wD* ;+4IS 8 4P2  Vhh!!zbk2d2O ,'78 1Y   &b.. %.)&n3 # ,!3L#! #NJz!`#EO[ES*  3 9* tR  <-0/) X<4'6323?26;>7>32".#"+".6=#"'5>27275.54632#32632326#"&5#"#"'&6'&7>3&4?654#"&54654'&6?>54&#"326E)-"  -B" B&   (6%  ?8 6 V0 "+5*&-ycl%A66 0 +'9y$C2%'' .+.+& 9+1 8Y%'5 M 0  : 2"" v'DQ\DS?   2 6+  00D  $k$   < 3x B4(559#52%45.'""&=4654&54673>3"#"G4$9+')?'61LH  (3d$: -J0  K0#5G"54765.'"#"&54654&547263>72#".'"(& 44$B#'{T&0MF]$ 3 #3   6B $: 5D4 K0 1 *   #5?%45.'""&=4654&5467376322>7>323#".#"H4$:+%+=-,.TH*E4:+4& )3l $: .J0  G8 % '%B2C4.#"#"&'&676&54>7632##"&54654&7>;2>54&5" H&  *j%$+$M )8^iO;+,g1Ke6 0  >: 3 :0Y:Q;$*P 4 "CO6!!#E57E2#"##"54?654&##"&=4654&546732634&+;262rX#6%! *& )7% ;,%+<W#0M/!/ ' .:.b @:G4  J2?'$5/:&54?65.##"&#"#"&5463226322654&"# 14'!6-3'bM!#j,OGJ&"2 >#<'*4 *;HE7 )3P<4#"#"&=46=4&767276=4&7>322"&54?>i  +' X+ EJJ >U) . %+3 +& H&F" T )#@5O\%45.'"#"&54654.7673>3;267232632#"&#"#"&547#""#""32654&G4$B#'U)71LU & 9 *47- - 0 )3e * ( +!3d$: 5D2   I6l  6R38% 6###<5d$4?4&'"#"&=46=4&547263;24654&76;222632#"&5"&+"5467###&$%5$2%&{T&5H A  ) ,6P -*9;# B/  M#'9 332Q+.&2 2p1 7, 5+5Z4'"&##"&54654&5473263232+"#"&=46'&+"#"&'4654&54>?>II G(^y0G?654&#""#"&54654&54673>;22#"74.'"32561GD2&$""b,  d7$!"& %(?=U 5KLG_&7/<  (FY  88 >   = 4 %5  2 H& *! M=% #5Z$4?4&'"#"&=46=4&547263326746=4&76;2632#"&5+"+##&$%5$2%&{T&5H 8  C U 3,7 !W/  M#'9 332Q+.& H ,=1 9/+T1d654'56323?267>;23#".'"#"&#45.'""&=4654&54673>3"#" 7),/,  D' ;$' >+FG4$9+')?'61LH  (# 0!   - d$: -J0  K01y654'56323?267>;23#".'"#"&#"54765.'"#"&54654&547263>72#".'" 7),/,  D' ;$' >+l& 44$B#'{T&0MF]$ 3 #3   # 0!   - 6B $: 5D4 K0 1 *   1q654'56323?267>;23#".'"#"&#45.'""&=4654&5467376322>7>323#".#" 7),/,  D' ;$' <,EH4$:+%+=-,.TH*E4:+4& )# 0!   - l $: .J0  G8 % '%2u22672>7>32#".'##"#"ᘖ'56"##"&'&>'&54632632##"&54654&7>7654&=4&!)   D% *1'  ZQ$+6) $ '  I*^!2R2a{`;+, i|8  "    1!!2  ?H CX; *P 4 .00Z <41dr654'56323?267>;23#".'"#"&#45.'"#"&54654&54726322+"#"74&+;265 7),/,  D' ;$' >+EH4$ +&z\-Q2m^%8,#)# +# 0!   - c $:  %* 1 H6 -!`9T/^j226726&67632#".##"">54'56#&56?.#"##"&#"#"&546322>322654&#"d@ ! :*6 $  ZQ8,*J$04'!6+5 'cK&:;5L2    )"  "7L#<")6 )":G Q**)Fa267>77>;2+".#2"&54?>54#"#"&'&6=4&54632676=+"'5>54'6U@ ( - 8A1 *4#  &JJ >U) i B$'R &6 Q0 !p3%#[&F" T ).5D4  >""?g463>2632###.=4&'&#"#"&5465?#"=46567>d & 259g " .F)   C 2# =) =/& +      *r]3  "   G#&'$!    >V-O^?463>2632767323#".'&#"#2#&=4&54.'&#"#"&5465?#"=46567>d & 44(8/$A ^)6%   #&$ ,:   C 2# =) %E,7  D" . 4PX' &    G#&'$!    >V-O^?u463>2632?>76;2#".#""#&=4.'&#"##"&5465?#"=46567>d & ):6a   <&& 52% -7   F 2# =) 6..    1 ;3Z`(  G#&'$!    >V-O^>S4>7467232##"'454&'#"##"54?67"#"#"54&>8ab96WpL (*9_R' ! ) :E3 5'49R*92  ,]-6  5 -e#"F.  5?dv263232+##".54'.#"#"&5465?#"=46567>3463>4&+;265-67c#3E/&8)) $B)!  F 2# =)W "0' (7/)x # $(   G#&'$!    >V-O^   1C465""'+"=>32+"=.'32+"&54?#"&62?+ 0BcO:3 +0)) 9 ( Ua/ E0  (Ij(M2 "4 ;R K :ww?P"=4674326;232623##"54654'"##"5467"e&;  BQH $,  % ( %5,# <  2'a 9lc  1 9 '>sK/?W463>>323267263#"&5"#'"#"'#"&'&654&7>;263&=6.'&#"6##"#"&76567##&546d ' 6a [1 3(:*  . ;34& " <-)/    ( Zb-l   :/+', 7)Q 4 #/O=1 n  P] C n?)kv263232+#"#&=4.'&#"32+#"54654672+#"#&5467>34632>4&+32546%4&+325464&#"#326 ;M+K1 SO!0& 8%4H; XM!0& Z) V^P!0& 8%"z %2 #?4%#?P'#$,*$+m/! 9-JZ3 4 BC . 0 ("lU-! =H[$1Tl+ -?+ l?a~26326;2672#"&5#32+#"#&=4.'&#"32+#"54654672+#"#&5467>34632>4&+32546%4&+325464&#"#326 =J9kKD' -)9jSO!0& 8%4H; XM!0& Z) V^P!0& 8%"z %2 #?4%#?P'#$,6* 2 6,2r/! 9-JZ3 4 BC . 0 ("lU-! =H[$1Tl+ -?+ l?ko{2632;2632#"&5"&#"#"&=4.'&#"32+#"54654672+#"#&5467>34632>4&+325464&#"#326 =JM[ *(: - !* 3I": XM!0& Z) V^P!0& 8%"z %#?P'#$,\Y8o,  1 8*,_e 3#. 0 ("lU-! =H[$1T-?+ l*]lx>34637632632322+#.5?=4#;#+"&5467#2##"&546574#"326546!4&+232654&+326514QX& 0$ $UL87J  - !.VF**$ _o=QVF_> &_'(B"& "&N//  } /% ;b'L "*  4 *#") + /- ll?26322;>3>32+"#"&5#32+#"#&=4.'&#"32+#"54654672+#"#&5467>34632>"32654&4&+32546%4&+325464&#"#326 =K|I ;# B'53<O "9JSO!0& 8%4H; XM!0& Z) V^P!0& 8%"z [! "!%2 #?4%#?P'#$,m 7)#8.5Q>(#".)"w& )S0 =Wj8&-0 7I /");b45 F. 7 ' I[E/% ; '!&Fu 0  + ?Qi|4>3766323262#"&5#"'"#"'#"&'&654&7673>7&=4'.#"32#+#"5465"2###"&=464&#"&#"&6;265%4.#"#326 , 9NM ( )(<*  , <9+ )"  b %R.BUJMO#& O^J <) #?3)#!B)l  ,^Y?h+ 0 5+*D 5&%(- 8.1 $ o/}p  lF6^S`74675.54>76=46;22#"&#"#".5.'4&+"+"2654&#"FY698*11 8 8ZM`NO  >F  ..\B%/ 67@A('4 + 991*>$ *)   D v6 2=$(%'# $3G^_l74675.54>76=46;2232672#"&5+"&6'.'4.+"+"2654&#"GW798*11 8 8ZM`$&m .-9C  413F 4 ,\B%/ 65BA('4 + 991*>$   1 7(J!%F u:2=$(%'# $3F%^er74675.54>76=46;223272>7632#"'"#""&+".5.'4&+"+"2654&#"FY698*11 8 8ZM`nP  )5K%   ?L ,/\B%/ 67@A('4 + 991*>$%G" - 1  R mA2=$(%'# $386^_l74>75.5472>54=46;22+"&6'.'4&+".45+".72654&#"8#3( (7 0 z304  3&I ,*   ;M;!(*54 <)]. % W /  6?   %G  - 6*#- + #5F^Q^l74675.54>76=46;2232+"#"&+./.'4&+"+"&2654&#"4&#"#3265FY698*11 8 8ZM`RQoW^(  $$MF  <\B%/ 6s' $5BA('4 + 991*>$- * "N w5 =$(%'# $3,+F^kx74675.54>76=46;2;2632#"&5#"2#"&#"#".5.'4&+"+"2654&#"FY698*11 8 +0; \ 1*9: NO   >F  ..\B%/ 67@A('4 + 9 +1 5+/4 *)   D v6 2=$(%'# $3F^CP74675.54>76=46;22+"&'4&54&+"+"&2654&#"FY698*11 8 8ZM`ZY -/OE  <\B%/ 65BA('4 + 991*>$% /  x5 =$(%'# $38v^74>75.5472>54=46;2237>32#"&'"/##"&'&6'&>7267&=4&'4&+".45+".72654&#"8#3( (7 0 z304zV"N)&6,< I$ & $DZ%N ,*   ;M;!(*54 <)]. % W / 'D0 0 8&  "2 =  P  - 6*#- + #5F6 HU74675.54>322#"&#"#".5.'4&+"+"2654&#"FY698'??" >?&,/INO  >F  ..\B%/ 67@B($5 1!2 *)   D v6 2=$(%'# $3G Ta74675.54>32232672#"&5+"&6'.'4.+"+"2654&#"GW798'??" >?&,/I$&m .-9C  413F 4 ,\B%/ 65BB($5 1!2   1 7(J!%F u:2=$(%'# $3F% Zg74675.54>3223272>7632#"'"#""&+".5.'4&+"+"2654&#"FY698'??" >?&,/InP  )5K%   ?L ,/\B%/ 67@B($5 1!2%G" - 1  R mA2=$(%'# $386 HV74>75.546322+"&6'.'4&+".45+".72654&#"8#3( *4[jXl214  3&I ,*   ;M;! "54 >(1NA8 0  6?   %G  - 6*#-%#5F FSa74675.54>32232+"#"&+./.'4&+"+"&2654&#"4&#"#3265FY698'??" >?&,/IRQoW^(  $$MF  <\B%/ 6s' $5BB($5 1!2- * "N w5 =$(%'# $3,+F [h74675.54>32;2632#"&5#"2#"&#"#".5.'4&+"+"2654&#"FY67:'??"Xk; \ 1*9: NO   >F  ..\B%/ 67@B($5 ?41 5+/4 *)   D v6 2=$(%'# $3F 8E74675.54>322+"&'4&54&+"+"&2654&#"FY698'??" >?&,/IZY -/OE  <\B%/ 65BB($5 1!2% /  x5 =$(%'# $38v lz74>75.54632237>32#"&'"/##"&'&6'&>7267&=4&'4&+".45+".72654&#"8#3( *4[jXl214zV"N)&6,< I$ & $DZ%N ,*   ;M;! "54 >(1NA8 0 'D0 0 8&  "2 =  P  - 6*#-%#5Z/B74&547>632+"#".7>?26=4.'32676=]":/L'+(% o] # #   ^%9:@J7|(7=E "!!+!b/)=& %#[0DT%#"&5+"#"'.54>326322672%>?26=4.'37>765)(9A+:$K .?85EDu  ] #  ! K=+(D % 6+U +UeCj@)I="`"Z "*7 ) 3G -@f""A&8LU7"&54>7>7"&54>726327>3#"'#"&#4.#">72632765 7j!G/*AT FXH-!"2,J(    I0"  )!z8-(2'[0 >:-  !+ 3   ;,%M&"&%8B7"54?>7"&54>72632+4.">72632765& >h H2()@ ,4 NX( w +2#!./7-'3'"2) 3X?  !$;' O! "&)=FS74>7".546726322+"+"&544.#">72632765"232654& %LM0YM(?W\Lr%6+  E   I0" *"s B) +2W Y- $#*    ;,%M&#<  A0/@J2&"2#"'.54767&'46;2654&'.'>2=!  (Z .-@$/ >)% @ $   VP:0!=5%&A#2 (@49% {  A *E2T'/ @7C+N(/77"&54>767&=47>32+"+.#">=t!C.Mr>YO H1A{ tN#7 8E@N)($,Q63?+S  (sM6-ZI@BP%#".+#"&4>54.'&6?632>26;2>763%32654&#""*6 '*775IA\\A 9 '!;;J!6T" ($ ]! 7D2;+' 6*a?j]GEW0A)G:.8-"! 7Q)#203!GIGUg7"'54?>7#"&54>54./&476376326;27>32#"'2+;2>7654'  !=/9(88( #*KB !.P-" *2J S:  Q5F  ,  $  C +$";+)5  949 <0  ", s  + %  I>R266;265<62;2+"&#"&54>54.'&476?6.#"#""3265'7pS=',)$9( @ E(#9_,:NA\\A 9 T 2    7(7$I?5XZC "0*#97  ?W $B54^GFX0  ,,'"*(%!/IH_s%"&'4&5>7"#"&54>54&/.763726>;2332672#"&5"&#"#"+"7>54+1 EB9*==* H %5_ +!& R  2*9 )    ~-$<)(2  2*>=    D1 6, `  E, " #9IIWd"&547"&#"&#"&4>54.'&6?6326326326323263#"&#"%32654&#"2654.#"A-+ #''.6';MA\\A 9 '>^A:1E.  !$-A,2;;29#;"%5* $)QA Aj]HEW0>)B@L4#7!*!2J8 +$#63(  #1'i%"54?>7"#"&=4>7632;2#"&547#"2>54.54;2;2>#"&5#"+ >R8/RN:F7 4)AH*: ++E*6 HG3();`  ?%,O)-7Q0  -(85*K! #? 1 7+ E( *J[ev%#".+"&#"&5'&54>7263232632#"&#"#".5476326;2>;232654&""32654&#"  +1$ +%- K).I(9Q3267'>7"#"&54>54&/.763726>2;2>72632#"&5"#"32636#".5"+"&#"#"&5"7>54+"'&(GEB9*==* H %5_ $0  8X  1*9 (c 3%0 = 9@$2  j0   ^-$<)(2  2*>=   ? " 6+[  1 *' 3C, " #&d@%45#"&54654&54>?>323>;2#"&5#"*R1%,(D-FB2 W (): Y !E 25 3   & 5, ] &dW%4?#"&54654&54>?>323>;2#"&5767323#".#"&+R1%,(D-FB2 W (): ; ]:*0#*  *J L" 25 3   & 5, i6  '%j & #&dY%4>7#"&54654&54>?>323>;2#"&532636723#"'#"&#"#&+R1%,(D-FB2 W ():$5 m  :$JG  8IOٖ 25 3   & 5, B:= 1 3  YQ47""#"&'4676&54726323>32#"&5##"&54654&76;6367>5p;& % m]w& ro 2+8 d:$% Wp=X> #4  (2 7( y)\8J[2, #?K?&dDS%45#"&54654&54>?>323>;2#"&52#"574&+;265+R1%,(D-FB2 W (): k]<&""!,"+ (I 25 3   & 5, -:.B) CeP7#"&54654&47>7>37>323>32632#"&532#".547#"Iz2$&( & U  -*:*V(* 2 9%  01 2  2 5, &50 <(dW"&54>7674'#"&'&674&546;2?>?>323>;2#"&5##E;]dc 2%&GF& X ():O7Z_f$ 716V5292  11 -   & 5,3,32;&545#"&54654&54>?>323>;2#"&532632#"&5#@#- 7R1%,(D-FB2 W ():%` )(<B9 4  25 3   & 5, ]  56,1qe2>7>;2>7264676322+"'3267654&7>32#"&54>7>5"#">54'56A 1 )' ! 1 N63td/! L  54&5&632726363>32#+"&+6363>3232#"&+"&'&5467""&'.54654'4.#"#"#&##"#".%4#"#"#326363>2637.*>!/8  :'HE(% *)"4 &  .  :4s$4^N%7 e$D"@I7Q3ZI[A     5  &7 # >9,-  /  ^) +"`5 X 3; 5# 1qo2>7>;2636?264676322#"'632326;265<62;2+""#"&54>5#">54'56"326=.#"#"< 0 )   ! :;&F2/6e'E 6* 9( ? F(>[.:N,BLB,7 T2 ,?!7(7$ 2  I3   '"3 ,T4W '5( 97 =X #B6*O;C;O)"$|<((%!/,'0-43?632""#"=4>3>72#"=0**   > ;  i >   ?  E C,BS4376;2"#"=".54=46?632#"4>72##"=74>72#"= S ? A =3  L 65 i  > ?W> >  3  A 3A:X\D,A3254>764672"#"=4376;2#&=G )_*! ĥ X  ; P  A D      2  A ??:2]#9O254?62.4=43764>732#"5"54676;2D)#" . Lm2  M :" < (_+ >  ?   7     ;i-$=>32"+"=42546>32+"=4d -   - 3d $   / @   /@ 0(?437632"#"=4&#54?>724672"#"=4&0L , ?L*)_!X  :  > @ x |  2 A0(n+C2#"=4632632##&=46"=4676;2##"  M  L L >  >n  5   C A   A ? ?  0(n'=Ui}2#"=4672.=4376!2.4=437632#+"=454676764672"#"=4&4>72"#"54376;2"#"= L  { . L . L ))   H!X :  68  : L    W n 5 Ab> ?  >  ?  qA @  2 A   2 " =   ?2t|#HY{"&'#"&'&6'&632632++"&5467>54&/&6;22>54&+"3"&5"&54676&76326329(8 % && -@  3VhU /81-S(  ;3",4%"+ 4 l *8 +8$ R  *3. #3  D' >O6Da '"  )$$4-2)>&6+ #(% '$ #t2%Q[#"&5#"&546'&6323>2#"';2654&+"&76;2+"&'.54>32"254&#"&5#"&5465'&7>;263221,8BO13&" 2J j#!, H,M#)!1 /FecQ'&76323>32"&5+"&5>732632632"&5#"&54654.76;2632M1(<9.+ b _~)$ a*9p B D x[ & ):9-, Yi ** 5+ 'K "   07+ %   -g6+ 'K 0'0 LtM&:Jn#"&5#"&54>'&76323>324>3#".7"32654&'&"&5#"&54654.76;2632M1(<9.+ b _~)$ 2J>7E.u]4Q- o !5,A  ):9-, Yi ** 5+ 'K "   03M&'O5'&76323>32#"'#"&54>54632;232632#"&5#"#"?63>323"&5#"&54>'&76;263231)<9-& b _~)$  B&0A'77'  5/T 1*95 X'f I- +*89-%  Yi *) 4, (J!  A ,%>- ;./=" '71 7+E7%##'$- 6+ (K" '$ `2$bu#"&5#"&'&654.76;26324&'63227262#+".'&67>7654'#+#">4&#";2564#"&5#"&54654.763263220,9\ZH, Wj  #3   LD_YiB 3 % M/#F, Q',9\Z% %O|   6(  ;8 / '$ . *"-  6U !") % 6(  "3 3 '2O`&x2632#"&'#"&'&676&7>34&#"#"&'&676.7>326263>32726&676;2#".'"#"+"#"=4?6#"&5#"&54654&5432632i )-7\Z$ & D ? 2%( Jh ,(2!#  ;)8&  \/ } 0-8Z]++&^}  d'( 6(  "2       32 )  6     *"9$ 6(  *81'1QZ#s>32#"&5#"&'&654&76;2"&54>'&54>7#"&'&>'&54326;2632#".'2632#"&5##"&5#"&54654.763232632V}t  )(<{A$-  L' (k3PA&& vM1K * #R0 !.*8TW_3,,8| B+% > ( h  u 46+D: 5 x " * 0C + +66* 01T 9(-Q3   'OtO(Sa#"&5#"&'&654.7672632326322>?>54.7>32#"&54654&54?632>7"&'#"&54676&7>32632O2)99-& I A   N0-=\3@X$) 5) )8 +%  '&.C ,) 5+ (J 5 ( 247"I9CQG0X  &#%=N)#Z2. #( '2 2`2$Fj#"&5#"&54654.76;2632>54.763732+"&'4&#"&5#"&54654.763263220,9\ZH% Wj  9 ; &5 1`',9\Z% %O|   6(  ;8 . '$r  6     6(  "3 3 '2%d"|2632#"&5#"&'&654&54324>54'#"&54654&54;2$76;2#"&52+"&'4+"+"&5"&5#"&54654&54;2>32e  ));G' Xv,,`2%&j (*#  1+9a 5C+7 d T  Aw+9j09-%M \{B  1r"+5, :7 45+,;!  112  6+  */*&Ald' #6+ (I2  fd$b"&5#"&'&654&54323263246;2#"+"&'&54654&#"&546323265"&'#"&54654.76;2632^)9 *' X^ *]H XR * 6"65Ccg8  !%*8f37,2 Hx  0 6+  "' 4"% FT6Iu $t96H)#2J$ZGTm #F/(aP@3. 'J2 !1 Hf&y"&5#"&'&654&54.76;2632"5&54?67&'#"&546'&;232635465.54;2>54&74;2+#"&5#"&546'&76;2632A.72$* N#f  )P  .?;dJ*$ 5  :  5 HDJC>)(;f3& %$  O#c 6) .. 2  !5 W #3  ,K B #V  # : U!   5* "1 A !&6f'g#"&5#"&54654&54;26323>2467##"&54654&36;232?6>54.76;+"&#"&5#"&54654&54;263232632&-7|++%Io % 3'" 8 !#$  C ID0-8|H&KQ 7(  )72&; 2FQ  a  )   6)  :72! 1Cd*j#"&5#"&'&654.76323>32"5467#"&54>'&676326;2632#"&5"#"#"#"&546'.5467>3>;22>326#"&5+"#"&5#"&54654&54;2632v )(<$ ' HTp&$]% * =N1g .,6;    %#5\ N  7  3(:2J% k91);f32$+ Jk   56+  "1 4   Q  !2  " 1 :'8 =  Z9s $ 6+&Il 5,// 3 !(1d)n{>32#"&5#"&'&654&54;2"'#".54>3763232632#"&#"#".547"32>7>32"32654."&5#"&54>'&76;2632So%$ /';$ & M  K2F2:0(7K79 C !19 :#- TST2" /  :* "):f3$ %  Ik  2r + 6+ !2  4 , 6)Lp9$ ($9 '%nQ  '%"$6+ "2 #  !% %fb&#"&5#"&'&654&763232632"54?>7#"&54654&5&323?326;>72#".'"+"&5467##"&5#"&54654&763232632 ),9 *( Zs U0 ^2$'f)N8&~ KKA- - $     E4/   `)-82$( Zp x3 7(  "(3!/Gu4 123 % )Ej' 6 6)  ./ 0! 22d#(So#"&5#"&'&654&7632326324&547>32+"54654&#"#"&746"&'4?>32;2#"&5#"&54654&54.76;2632#-(<*`% &  C!^ I;92 " 3#*   =,(c  3Q  1*:f3 ++ He   & 6+"3 1 " +  %3  B   *R 0  (}  5, "' 2  !d#&JX"&5#"&'&6'&7632326322#+"&54654.546">54&#"&5#"&546'4&54;2632+81Z *'%  E ] -.TM2  1W| 'MR1)'&7632326"&54654.'+"&54654.54632!>7&5474632!+"654&!"654&"'#"&54>'&6323>32.c /)9A *,  R   /^wYD!6`t"  ,(D)D[Y H9-% +Dq.#  -}+ 5, "' "   9 &<.AG5%}?0 # >BZ| 6 6>$Z&57 ['a (I!  !#5654&'##5>762/./ [A#A@EI!A2(x$ "0%+5654&'532'4&#"264.#2>m@'&!:<$d3Go>;C$*34)x;='.& 1#K 97#,'  # %+5654&'5324#"326˓o$$wX&!dUls$.$psZ+%!5>54&'5!#.+"32673#.+6:>7$$n'2ZY()Y *  rr$.#b-'(   #"546323254&'53(E=M '&>H2-;% 5!#5354.'#5>54&'532>54.537 "HI&(&'L/1 '$z  UF%)'$%C,9  x  %!5>54&'536:>7$$$ *! rr$.## !Y%!#5>5##5>54&'533Y(,'$$(1~s#/%X#$ #.##5>5#"#7! &2,'*$8' N4#&*S7t  #"&=4&'5332=4&'53+NQTv&%:Az*#.Sb[Q%$@8.%"&'&'&'53>54'53 ZB#.a8+/!2(u$t>#"&'#"'.'537.'53>54.'53  \ p   .*:[ & $!(# { *(',V  u5+ []T[RY %!5#"#7!3267 /[E-&2vk(E &'3#5>54&'5324.#"32/NI)&'$"<:"P/* qG,:|%('$ 4%( .=#"&5462326='5##"&5463254&5677'54&#"326/!0""z*WY]vY91&V=(?(,;B1=!., !+=@]\+%(,(54&567>54#53"67-!0" C[   ,h32/]C&(+ !., ![v  ,` 3D"3 *#"&5462326=#5>54.567>7-!0" +"#b= !., !)!  B#"&5462326=#5>=4#"#5>54#"567>327-!0" (M(;" &# K?;&3 !., !&+a9!(9O">9&eU  K#"&5462326=#52>54&'3#5>?'.#53">54'5367-!0"  T V(r^  +< 9(4S5/; !., !    \ U *xWJL #f$%#fIDQ!#e%9#eDEuQ#ej%k#eD`EQ#q%#qEuE)y#v~)"v!#e'"e>Gu#ej'k#e\`G#q'#q\uG)#z'"zfG%#X*'#X\ G U#CZ,#C^ U#vdZ,#v %U#X*(#X: H nU#hZ(d#h:PH )U[#d)"d: "!#ep)9#e"I  #q*& "qRJ!#e+ 9#ePKu#ej+ u#ePjK!#j+ 9#jQK)#z+ )"z\K;#d@+ ;#dR@KnK#hZ,n+#hZL<#vo  A#v"i#v.#v3N"u#ej.u#eXjN"#q.#qZN uV#ej/u#ejO uV#qu& #q V#q/&#qO %V#X*/%&#X*O _i#v0#vP _!#e0M#eP u_#ej0u#ejP !#e1M"eSQ j#e_1u#eSjQ #qt1#qTQ #X1%#XT*Q"%#vQ#v,"#jo #jR"#CZ,#Cw"#vZ,#v,i#vJ3'"v S!#ep3'M"eFS!#e5OM"eUu#ej5uO#ejUu#q uO "q #q5O#qU*9#ec63\M"e V*g#ec\63k\#e `V*#ec3n9#e(*#ec"'^9#e#*g9#ec 3k\M"e  Q!#e7 "e`WuQ#ej7 kC#e`WQ#q7.C#quW%Q#X*7.C#X Wg#j\8 k#jM`X`#hL8 d#hNPX#X8 #XN X%#v* Q#v'+#jJ, "jMv-(#h9T"hRYj#e_9g#eP\Yi#CR:#CZi#v:#vZ!#j.:M#jZ!#e-:M#eZj#e-_:g#e\Z !#e;M"eP[ !#j;M"jQ[!#e<&M"eM\ Ue#X="X8] uU#ej=u#e7j] U#q=#q8] #qRK'"j`W#fZ&"fN\%"V6D9#e"Au#ej$%k#eH`D#t$%#tDI#v%#v"I#C%#Cm#t%#tR#h%@#hJu}#X D%k"XI E?#v%k#v"?#C%k#Cm#tJ%F#t#h%*#hJus#d D%k"dI E uU#ej(k#e9`H U#t(#tH U(#h(T"h:H UI#vd#v UI#C#C^ `#t#tX U#h@#h: uUe#X \k"X: ];#t,"tu;#ej,u#ejL"g#e\2k#eR`R"#t2#tR"I#v#v,"I#C#Cw"#t#ty"#h@#hT"g}#X pk"XS q"#[b#[c"#\b"\_c"#tb#tc"Y#hbj"h]c"S#eHbW(#ePLcg#e\8 k#eL`X#t 8 #tX:#[q "[dr:#\q "\ir:#t q #tr:P#hq "hJrS:P#eHq W|#eLri#C<&"Cr\u#ej<#eM\#t<&#t\(#h<&T"hN\)." N)." )." [)." h)." \)." i).L" ]).L" j"T" Z0"n [0"n h 0"n \0"n i&"d ]b&"d jb)" N)" )" [)" h)" \)" i!;#Tʹ+E# #@ [#J h#@ \#J i " N "  " [ " h " \ " i L" ] L" jh#T^# =# [x# hk# \o# ie# ]gJ# j`J! " N|! " | " [| " h| " \|" i|L" ]|L" j| #T # n3#T [#Z h=#^ \Ȧ#^ i#T ]J#T jJ" N" " [" h" \" iZ#TZ# V# [_# h# \`#" i" N" " [" h" \" iL" ]L" j Y# e#, h#6B i@5@#, j^)" Ng)" g)" [g)" hg)" \g)" ig)L" ]g)L" jg#T# i# [# hy# \# is# ]mb# jnb)." z)." )" z)"  " z " ; " z|; " |" z" " z" )" zg)" g)." C N)." C )." C [)." C h)." C \)." C i).L" C ]).L" C j"  Mi"  Mi"  M"  M"  M"  M"  M"  M" R N" R " R [" R h" R \" R iL" R ]L" R ji# MA _# M7 # M # M # M # M # M # M )" | Ng)" | g)" | [g)" | hg)" | \g)" | ig)L" | ]g)L" | jg# M` # M` # M # M # M # M # M # M ). /@#"&533267#".'##"&546323733265'4.#"32>CG9.0-9 d:Zks\AJ  T#+<-$2 9,.<XE.3.3u#!8H\^cG{r<B~,UF0LD"+OAOZ).&7!5!#".'##"&546323733265'4.#"32>79 d:Zks\AJ  T#+<-$2 9,.<K6u#!8H\^cG{r<B~,UF0LD"+OAOZ)." C z)."1B%#".'##"&546323733265#"=332654.#"32>.9 d:Zks\AJ  T#+]JL<-$2 9,.<ku#!8H\^cG{r<BXOc.N,UF0LD"+OAOZ)." C )." O)." C Os"d "q# z_# `# MslUCTXa(-N#"'732654#"#"54632N;*& $%'/ 4<*> $-*;]U#"&#"#>3232676'V%6*T)8+++6+l-"#"&#"#>323267"&462"&4626'V%6*V(((()8+++6+((((" R z#2#4#"#4.#"#4323>32#"=33265T>U*[$ F='4 ]JL&c@gd",,D`27%6XOc.N" R  " O" R O# z n# n^# zC^# D# Mv- #.54632#7254&+"&5432" evO *(--505 7c7 #8u- #7>2#7254&+"&5432S(wP*(- Rc7 #8]-L*#"&#"#>323267#"'732654#"#"546325(T% 6*V>0 %(/L*7+++6+ 0 !.  #"&533267#"&5332>=3CG9.0-'/97/TXE.3.3;>;9Y #!5!#"&5332>=37/97/TK6;>;9Y #/"&462#.5462"&462#"&5332>=3((R".((/97/Tq((`505  V((;>;9Y # -"&462'#7>2"&462#"&5332>=3 (()S(~((/97/Tq((H q((;>;9Y #" O|$" P|;["d B"q# zV# Me- $#.5462#"&54632#"&#"327"g &99.+"! -505   9&.6')d- $#7>32#"&54632#"&#"327"' &99/,#!  505 9&.6')]-L*#"&#"#>323267#"&54632#"&#"3276'T%6*TD!/.) L)8+++6+ /!(." 1#"&533267#"&54654#"#463232654&54632CG9.0-jHP#0(610$2=F=?XE.3.3qXI$$9\:FO4|6@g@($(!5!#"&54654#"#463232654&546327>HP#0(610$2=F=?K6XI$$9\:FO4|6@g@($A"&462#.5462"&462#"&54654#"#463232654&54632((R".((HP#0(610$2=F=?q((`505  V((XI$$9\:FO4|6@g@($?"&462'#7>2"&462#"&54654#"#463232654&54632(()K'~((HP#0(610$2=F=?q((H q((XI$$9\:FO4|6@g@($,#" N,#" " O" P)s"d) "q0E# zm/E# n# b|-"&462#.5462"&462((R".((q((`505  V((w-"&462'#7>2"&462(()K'~((q((H q((-4 #.546324" -505 )" | zg)@O%#"&'##"&546732>54&543232>=4.'5#"=33265`R9>>9R`j]*  #",/.+1!+ &]j]JLWI;;IW_#9(  8&(023S( -N#"&54632#"&#"327N%*<=4/'%": >*4;*-$'73#'1'  5!! 15!!1 )!5!5!5!  2(2s7632#"&5467  !".>2 R 3&-T82O#"&54632'654   !".>2 R< 3&-T82Osf#"&54632'654   !".>2 R 3&-T82s"&#".54>32&, R $&9; Z/)+'7632#"&546737632#"&5467`  !".>2 R  !".>2 R 3&-T82 3&-T82'#"&54632'6543#"&54632'654t !".>2 R !".>2 R< 3&-T82 3&-T82-sf'#"&54632'6543#"&54632'654  !".>2 R  !".>2 R 3&-T82 3&-T82+-"&#".54>323"&#".54>32x&, R $&&, R $&9; Z/); Z/);k."&'#54&'6=#"5463254&5462>32\&*(*)S , ]$$$%-O+h{{E3+ +" 2f i="&:gP>32#"&'>32#"&'#"&5465#"&463254'6=#"546324&54632)$&\ \%(%\  [&$$&[ [%())S , [&$vg?"& w0LI"?f g?"& %6r +">f (6 2#"&546:NP78ONO:6OO98N(67(/oxd #72#"&546!2#"&546!2#"&546!" !c!" !c!" !d" "" "" "*6BN[232673##"'#"&54632654.2#"&546"32654&%2#"&546"32654&"0 ,5C,R/5(#)`F2DtK '95O '@.2d@3FuT0Q 3S#D.2d?4FuS&? 3S"B, OO:U~A'V=8[P:PH(O&2=8[P;P]d(O'1L 1?N\ky #'#"'#".54632326732654.'2#".546"32>54&%2#".546"32>54&%2#".546"32>54&7R/ 4%+_G $rN#2",7?C 5M  2 .3e>%)wQ3*B#C.3e>%)wQ3*B#C.3e>%)wQ3*B#,Q:&E#>-C  =H7632q O4A W (L I-;Q ' 9^0!747'&5432#"1K6  7( AfD *]A 6";XDb3 )3''7'77"&5462"&5462$"&5462"&5462=%%%&$ .!%&$ .!&$ .!&$ .!%%%H!"!"!"!":#MD,8#'.54327>54&#"#"54632"&54632-/)#46 86!<&2g<-3'" ""?7:V2x$TR  X3L% ,?EK#= #UB5yy732>7#"&5EJxI &P9O<>Z-=}`p "6 #8# )Z))5yy7>32.#"5Eـ`}=-Z>7'.54>3254&5432>32#".'#"&54654#"&54>7'.54>3254&5432>32#".'#"&54654%#"&54>7'.54>3254&5432>32#".'#"&54654&0*C =) 4(%8& $F!Y,$2&0*C =) 4(%8& $F!Y,$2&0*C =) 4(%8& $F!Y,$2.  7 -L' X9%'6 :N U .  7 -L' X9%'6 :N U .  7 -L' X9%'6 :N U +!*#5!*XK #K>1NXK74675.=463"&5X$77$OV3(#22#(3VOy:9  9:S8 9622 2269 8TK(%#5>=4&'>=4&'52(OV3(#22#(3VO$77$yT8 9622 2269 8S:9  9DZ#""D#"#"M #"'7!)+ ;r3FfCx@14>32#".7"32654&21GTYB21P+%"$!:U+s^\u,YZZbR]Y9 2#"&4657#5>=4Ev" &&& !2 ##5#53#527F/F9ZZ1  ##"546232654&'&#"54657327+ nZS4 429> KdfEU2',*6B%J0"&54>7632'"32654&GW &=kF'@JPQ,,&!+aP9@0%|G<@N&*?@3,5;( ##"'7(G  x[_*!-#"&5467.54632'3254'>54&#"G-RL;M35N=:L*S'&( E> ,#'('6&09:-&%))+83&*^&-%,<&$"( 0 .2}E ##5#5353K2KK22KK2KK2#5222,#57#522d22@"*5>7>32#5>=4&#"#5>=4&# H"&$0 +02(ze! x-1 *98{*8(t*0#u*82 *0  *00 *8( *-* *60 *2e 2 2L 7H";54&'5!#.+"32673#./32673!5>=#"&546323273#.$23^F#i'8\ i++i#A>#^^$RM+W;ff~% a- ') %4s &tul8Euy.4=327#"'#7&'#7&54>3273733273#&'&'$.zh?o?&#.$1 9$?:`yA)$*%/$2& fc'IJ-6Ye!3&\QT.vy !dB C@W|OyJ"6=4.#"5673>32#"&#"327#"'#5.54>323273#.y<@0J? NF"7' 2zh?o?81-Td:`yA5x& p|+BoGi  Y3(#:-e!3&%yQT.!!Sf "-.+3267#.+!5>54&'5!#.+"3267 +0zz0,),:z$78#4 9T z;+Z h/7!$>8B'  +  Q72654&#"%#"'#"&54632654'#53.'#5354632#"&54#"3#3#32>2N!&/cG7W&(3* uohdoT=4.#"3##54&#"#52>=4.#"567>329C010v) )' &Do %,G"" HD&$6B-&u"rNS452 ! K 159=A#535#535.#53354&'533#3####5>57'#7'#5#35mVVVV$ '9 RRQQ&8;&8[Y7%B.F.$YQ+2+Y.F.uL2.NFFtootFF.SS\%+#"'!5>5#5354&'5!23'&#"#32$$:;MM7FoM>  6"%<I.:5 !M9.. `.v#V5GLPSWZ.'5337'.'5!"37654.'533#3##&'##&'#53.'#5&'#%#3#%7##!&##$ 5!#* M '%$ 9} 1+Tpd&; -^;J9V_! -R<& ec*. &.6s. 0 .t!%FFF.N|FF.K".%#"&'#73&547#73>32&#"!!!!327(MK1F9~K'l(?3. qqxf{gq;D{. .uD;i,V9.  .c|e1 'Ui#"&5##6?>324.#"32>%#"&#"&#"'>32>7>7#"&54>324&#"326 q15@e1*h-A L)1K&*0K&?- F,"5 %3!@` 3d;|jzl) QYmW("r_o}"4-%-@_W! .?\U*'&6KP/,J*6*9pB+B@b3p#/J4J o+*"%/323273#.+232>7#5$4670" M!    7%,$)/[F"*; &=?!!6/$ &>=JIAK.O`Be8# 2 &5464.#"3265L]HbTՒӗJwF.l\|y %%".54>323273#.#"327y?o~sb::`yA5x& pX947BzhyPq!3&'OZQT.!!Sfe$P#&,rN#),r1(6#"54632326767#"&54>3274&#"32> & \N +]*9D#52WA=  2e:2g<);`@  u6=!==$F7@m=.I&r0-u!qz326?6323>3232676;2#"&54?#"#"&54632#"'32767+"?6?#"&54654#"+"54632%"67654#!'\&jaG14tIc9#U( <^$:9L@<.yAP9K0#!$ ?4d+HJ VJ3.)%4$ i'!&j3bP0@73%Տ@6FI?fE3K8 FD60TkY[)& @">YiyW963 kUpD+-bpD%&#"'>32654.#"''7654.54>7327#".'67p+BD< FA+! !<4Dv+U4'GF5hJ$ lK,+,)2O6>9BL0J=l8c{P3nQ/S;+EO; V:!';45E%*J-@:/g4HN::1"+9)5>=!!5>54&'5!!54&'5!%4&'>"<9<<z9/999   &<3#!89!57!5D3#e%#!'D&"'23267#"&54?654&#"#654&#"+567632Q  ( -?&7 Z'!K LQx^%v  2 A1K R;.XsV  @%;%#"5454&#"#'?654+5677>3232>7;-R ^ Ksa y&PM. ='@H Q i$&(.2 d)/]m#!+?@  :!C7K/  : J>74632"'326?&547>7632>54'46;2#"&K(DO4Fws"b\( B@4632#"/&#"'763232>54/&54?&#".9l-H_ UC  +W " "(WGSD[+&6!,<#Vs.(l&8D( V5K )))*)U?G;9(  %A  CLT"327>3232676;2#"'+"546;26?#"&54>32"327&"67654TO`O7\gZ#,-ΰd=dnG1x" M|3TxfRIQEWP:V cY:!P11^:H@&U/H16Lrm:)$]U=B/KD22&1:Rz@=5sK $ -m%xC.3%0327#"&54>7'7>324&#">-S7**F?[8/5\ o%(?%$/=#+#+H%X$LI*\&v=W54&'5!34&'53&'>' H&8>##>'92+$zL2#67 NQ+9D< 32>I!5!4&'5354&>7632#"&#"##"&546323265%2#"&5463254&#"t$%; 3#,6 4L'(8 _@QXA?RU ,%G-$ '22L/J20'# $+@|b#6PK;?UO<@Ok=QW9H(&83254&##"&6324&#"326'+#5>=4&'532l+E(=ŏǑwyxu|D0? $$ %0CV)) {{z-0c   .--f=LX4>7.547>7>7>32#"&5463232>54#"#"&2654/) W0+, ,,0 RG!1y(8V/Nu>6A &&4f=C2$ 8Fp' $./O8"=?ee+  "\* O aH%2KX-voLA2&@oDgs.I%; G'&+6AI!N;*="0#"'!5>54&'5!24#"324&'>=>$$:<<lqm  N9;6" 9:Z\ &" (D( %"N',#"/.546324&#"326!h/'JI-…?s]83PX+9Uo~W1,,1[zLz7 .L{L,TSNO. : C韗_Qw >54'324632#"'326?46367&#"3267>=472#"&54>763263232676;2#"&54?65##"&#6Hjnp/#!# >3;=[<{r;7BF%?&mA7-&:*vW~qJ- $ "0>+ "K_/ "!NQ4""J>U;Pe$cz='U<" wU f,~SO4 615 K:,&")/%^z-A/ %E/(+0i(HC2#qHnX':[46327632327.'.+'7'&#"'&"'7>32>54&#"'>54.u`0)" ),!n((  Q?&h&&FN+AW%7 _0 $ %55%\p._ 5gJ XSW-K )qv^`2)X =7>m)" 0 1' 4  ">!-;!#!5>54&'5!24#"2>4&'>8 :<<x)KV4$=$3ݬ'$,K,#  44# 9: !K6&< -ֈ:&# (D(! &)5!#'#7'!5>54&'5!2734#"2>5-)8 ::6)KV4$=T,&[$3ݬ'$,K,#DR{4#%<6 !K6&< gLrp-ֈ::'+09#'##7#5>54&'5!27'5'654'&#"27t$=$3I0K-:64- 8He@*B'6)r&< - ]]%<6 B?,Q=f6=c%U#5>5#3#5>=4&'533%#"&+"#5332654/.546323273#&#"c$(#|  R0F    ,,/445A=7 L!#&b&%$N *!6 ]6> /#&8-+C {n%):/;#5>5#"#5!#.#>=##5>=&'533# &% 1 Y %  0yg  %$$6%XX% %6$$05$:%%#.'5!'5654.'53#-L-`'% .)J4$" WB% [?,Q,to9 "9 %!5#"#7!!2>7#3T3B! P/?$ DA`=a.!"/#$!!C@^BB%#".#"#>323254."'67&'732654&#"&54632Bw6K$9%'54&1B4 6/ "3<:KOCs N:jKaFXgPs$44$%.'87'!2H/"% 2* 9[>RlVAK\(Y;B^u"."r}"&54>327632#"&54>32#"32>54'#"'#"&54632"'3267>7&#"32>=472%>54'632"327&5,bI4  5@K8[: / +J.'A% =,oL%D5F?U;N/"!$( B6;=IRL?yo96 +:uA W{(SM'+  $/ 5#Vb*!  ,9(i3">9~Q$ $/( !) /Xz.,%bY'%<" yVgm8'xQL5(ny J~Bao2(O 2V8%#".54>327327#"''654&547."3267V\[D%G/!1 KI*(=K&<"hY ^(&:) 1`CIyX`iY+ejF,"^/#Y ")+RM)(.0?.$-J)?qlA3:#%#"&4632!3267%!.#"~ObbT%54&#"#"5>32#".54>7&54>7632#"&546324#"3xF-#S6F+X<%8!?%3R.@K1Y6 -4'N _1MBR6KC7P)(9G6!B-K>MBr&$X+ 6(n O ]+,>TP JND';.@:#^6 =n6$,V&,..T9."17+"5467>763267>32#"'"547#"&4>3232#"&#"32654&5463#"&>5&#")0#!$ +bV:@z R):`D?&% $'#C!t 7(/gF`~TB? C@GW5A\{ p#4-;@"@;_K&%!=Dif)A5"[ 537!.n(>aM'M4MU!5{>"Gz#E ! ").j7;>7676332>7>?6332676;2#"&547>7#"=>7#"&5463632#"'B: *Y:s IV<kMH* v-/G-o  Gl'+-?IwE-47B@Ca"Z7'&54>7>7"#"54>7&#"&/#57654& Z  !O +7$D2 3 V 5 :" l!, 2'410R!- "!Uu/"=  4,3c%S/5% l[$%!7!26=&#!"&546573!2[** G5& ,)R%  /<)% 0  (+ #&%#&#"#73254&/.#"&54657;2# $ #5& +!3N LL!,% .  L"##!"&546573!2   & 5& ,)b '&t|nI")% 0  {!5>=4&'52"&544(42V==X;(((=X;;-+#u #u"t  #  "t#   "u#   " #   #  " #   #  "u#   " #   $#  " ' X"{  ;,d!)5>54&'5!!2654&#"d?"!@R?#$>>#"?>$% 87 7D7!!99!"8D7# !/%2654&#"!!5>54&'!>54&;>#"?>$%{?#$>?"!@R?#$>?"!!99!"8D7# 7D7! 87 7D7! 87,"!5>54&'5!#654&'53#.;=%$>?"!@1.) )%'#7D7! 87[o0 ;%B'9,"#.'5!#654&'5!!5>54&% %% .) )?#$>?"">%C%[o0 7D7! 89!  932654&"%!!5>54&#"#.'5!#654&'$=<%"|$m?#$>?"">% %% .) ))D7#"89!#6 7D7! 89!>%C%[o04,:H)5>54&#"#.'5!#654&'5!!2654&#"#2654&#"4?""?$ '& .) )H?#$>>#"?>$%>#"?>$% 89!!<%B%[o0 7D7!!99!"8D7#!99!"8D7#C"326?'.%!"7654&'53!563654/!5>54&'=?%#:#)BmJ<["U*q()15/ '(23_w4 ,?"!@"7D6$!Qi3 v;2 !:+LA 87 ; C%2654&#"!563654/#5>?'.'5!"7654&'5!7#)8.7/ +D23_w4 ,'*@mF=2."U*q()?#$>#76$#;,LA Og4 v;2  7D7!   Q%2654&#"#2654&#"!563654/#5>?'.'5!"7654&'5!=$%<;''6$&;.60 +m23_w4 ,'*@mF=2."U*q()??#$>"88"#7D7##77#"<,LA Og4 v;2  7D7! V/y&' _0L#LL)#L,#LL#YLY#LY#L #LY#L #L #LY#[L[#L[#L #L[OFGP>4%!'7!$ww!!.]'#'7!8 w$w>4 ;.] <>4 '7!'7!'7vwwov !!"-S %'7'7'7!! yxxyy>]#!"-"->]#'''5!-""->] A>] B>4%!#7!'7!73!o-2-ww(*2*妦!!>4'7!#7!5!73!'7w-2-{*2*w!8!;4#7'3232>325&#"#".+7';w*cj2-Q=:D$5')XU-Q<:E$*cj2w!99/BB/&,Ub/BB/88!4#'7#"#".#"563232>;'7w*cj2-Q=:D$5')XU-Q<:E$*cj2w!99/BB/&,Ub/BB/88!>4%!'#'737!wvwwxw!!!!.]'75'7''ߐ!!!!wvwwxw>4 I.] J>4%'!'7!7vwwwU!!!!8H4 ME>4 %#5!'7!538ww84!!-1 O@>4 O-1 PV!5!''7'7'7 .!! 2yDxxy>4!##5!'7!54>324"32 5,8ww,1G9~??] .qq" +1F1??@>4!'7!#5".54632!'754"3w8,5 G1,w3~?!qq. 1F1+ !@??@ 4_.'7#"#".'#".+'7322>3232>;'7_wcx::9:@Cbwwb"F6:A3'+ 6D"cw!iT` `T45!!/.dc>K>./!>4'7!#7!'7!73!'7v-2-ww(*2*v !!"> !##'738ww!!> '7##3'7w8w!!> ##7'7'38ww!!> %'##3w8w!! X5!3'31TpoT!7[nZu3!'7!#7[nuTpoT #!#.#"7'7>32#Aٙv(! (蓴وlos #%'7.#"#4327#!(wA)olٙsl? &54732654&''?j"[4(">fiiӖq"a}8f>"ql? &547'7&' 654'7?jf? \\#iiӖq">@&`}a"o>%!7!x!>4%!'!%!5!'7x8!>4'7!5x<!8^%378;Hx'7!5!'7!'7!w$w$ww!8!Ð!!-^'#'%7'7!8!=!!w$w$ww>x!'7!'7!5!'7$www$w!!!8!>x%!'7'7!!!$wģw$uu;!̫!8-^'#'#'77!88!̫w$uu$wģ>x%'7!5!'7!5!'7w$ww$wģX!88!̫-^%''73737̫!88"ģw$ww$w>4 !7!'7!5xx<K!!8>4 !5!'7!'!x%!#7#'7373!!!%!3T2LL2g'X='7##7#'73733'7'#!%!3L2LL2L='=<]ii]]]]]JJI>'7##7!5!7!5!733'7'#!L2y'`2L=' ]ii88]]]J> %!'7!!!yLLJ=<]]8JI] '#'#'7]8JI8]Ly= '7!5!7'!5!'7Ly<=JL]8IJ8]] %'73737]8JI8]NLJ=<yL> '7!'7!'7'!!L0LLL==<0^]^]JJJS %'7'7'7'____KLLDNNN"Nz6>??> %(0^ 'Q )\x3' _0(x]( > /'/'/) Q' ^0(x\LxQ(_ 0' (> %?7?77 xQ(^ 1' {) (/ `'Rw> %Qx) '0 ^R )^w'0` >A%! !!!!!M5MCh'hq;]A@]8r8r>B '7!5!7!5!'!5!'7Mrh&hCM]8r8r8] 4$27'3232>732>3235".#".#"#".+7' w\A?:<=92), (#7A>9;<9D=5Acw!54Nc bP>I>"854Oc bPcc./! 4$2'7#"#".'#".#"#52>32>3232>;'7$w\A?:<=92), (#7A>9;<9D=5Acw!54Nc bP>I>"854Oc bPcc./!>4%#53#53#'73ࣣww8888!!>4 2 #33#2*hhwK\lu`]%#"&54632#.#"3267` nhhn H ZOJghIN[ opghqPbhJ IhbO*74>32654&#"'632#"&%&#"32>(R6&A0TH5?)M6oDa8PmT72>V0)%;DP7&C(u 3Ǐ4=q7|Y>G1HSC,)5!2=!5!54&#!5! p!<%2%%,z )#7#53#53!5!73354&+5#32#4$OG+%0%b E{N!%#%%'.#"'#7.54>3273'&#"74'32 0R5+! 1:3 0R5'% 193&/!!'K(UaJ160S(TaJ260$A@T,OR`3 %!AP3$ !UI4%#"&46;#"!!;ggJlk pEʔ2eI2Jd4h!&%#"'#7.546;733#3#;#"3#&0677#53.#"5632{5!''9.%lR"4,lp( %E-7Ep+ #3!5265!3!52654#5!"/21//22/_^u1  1K1  1rc#%3!5254!"!4!"^_/232/f/122/ccr1  1K1  1.#!!2673!!^!;1HVC6W K%'# %=ӥ>>%!5!>8>>!5!##5#53533>8848>>"&5462##5#53533s,,88,?8C6 C63#C.1N>?;74>7.546324&54632>2#"&'"&465"&>1U U; k  p0UU1 k  o`ce^  _ce\>G #"&546324&#"32mMOllOMm0R8:QQ:9NllNMmmrQQ9:P>G #"&54632mMOllOMmNllNMmm'7p_{8A/3O #u`" # `" >a*:&#"327#".'#"&54632>32.#"32a!ZE!(++0/ -6@>RF@J$05- .,50M0x =#/)$*).fCKGF#1 ! I17n4>!#/#"'#"&546326324&#"326%.#"326!dOoa'w6GOfO;q#taGM9B7&f ++936i-47A7&gP6XaHQT9`v;jO(94%D>8rE5;jO>)3!(Y>$)3!O26$>$ )33#&'O2)0uDO$Y2T.>-'4'6~ }3K2r0J1(XY)P333P(P(NNT73##5#7373 Dd(P(!De(P(!hz\S"iS>P,!# #3P998,>P, #3P9,,8>P=!#4&#"#462P3}YW3؜9RyX5no>P="&5332653P؞3WY}3on5XyR978*%"&54623254632"&5467&#",C"'acQ,C"'ac.'\.'s\78w+V"&546232>54632"&5467&#"!"&546232>54632"&5467&#",C"'%]N,C"'%],B"'$]N,C"'%].'!?B-[.'!?B-s\.'&!?A.[.'!?B-s\78*V"&5467&#"#"&546232>54632"&546232>54632"&5467&#"%#"&546232>54632"&5467&#""'#ZM,C"'$YM,CU"'#ZM#L"'#Z\J,C"(#YM,C"(#: A?/s\.'& @@/[./& @?0\9 A?/s\a.'& @@/[.' A?/V8z3:A%.546754632"&5467&#"#"&54623257>54&'#>nzbdQ,B"'aLm/adP,C"(`TbmyVTbmnaU\h8\.'8 Zo:g8\.'&QT]ST78wgkry2"&5467&#"!54632"&5467&#"#"&546232>=!#"&546232>=.5467546!!>54&',C"'% ]N,C"'%RmmR]N,B"'$]N,C"'%RmnQ]  _GG_XH^^H.'!?B-55[.'!?B-BB\.'&!?A.55\.'!?B-BZ\B[QPR>7 #"&5462"&5462#"&5462p,,,,,S,,>7"&5462#"&5462"&54627,,,,,,,S,H #"&5462#"&5462,,,S,>7%"&5462#"&5462"&5462#"&54627,,,,,,,,S,,>> "&5462!5!s,,,8> %!5!7"&5462"&5462>$&%!. $&%!. 8"!"!>> !+"&5462"&54625!5!%"&5462"&5462>$&%!. $&%!. o$&%!. $&%!. "!"!8"!"!8 E %"&5462"&5462%632327#".#"u$&%!. $&%!. &w&TP T)TL O'"!"!b77m 76Y8E@7632327#".#"8&w&TP T)TL O'77m 76Y8E@%&#"#"'732>32E'O LT)T PT&w Y67 m7763&54>54'765j !'!U)\V"Y"$I3AU*(80E#"'#7&#"'63273327E.6A6N6&N(&w+5A6N=$TG$)X$+l>>5!5#".#"'632327>%uB0<O~ B.;M&9"*"m ")"Y>> |68E6 &#"!!#7#537#"'732>?332E'O JG6G6:0T:B;63w3 Y88) m 1 >;>#".#"'632327!5!!5!>~(RKM&%u%SNP66X76l88> >%-#7#537!5!733#!#".#"'632327>0D0{a@0D0|a~(RKM&%u%SNP<324d4324d66X76l>>6,%!#7#537#537.#"'63273327#"'3#!>,6,.$ <1M&%u,456?P~.;oo8r8[/X& l E8r8KE%#".#"'6323275#".#"'632327E!C/<O&&v&TP S)TL O&&w&TP S")"Y77m76Y77m8E6.#"'327#"'#7&#"'6327.#"'63273327E&)NS9JJ6V$O&&w&)#0O&&v3KJ6U$Sh0m <YgY:m>;>$(#".#"'632327#".#"'632327!5!>~(QKL'%uB/=Q~(RKM&%u%SNP66X")"l66X76l8>>$6#".#"'63232?#".#"'632327#".#"'632327>~(RKM&%u%SNP~(QKL'%uB/=Q~(RKM&%u%SNPG66X76l66X")"l66X76l3<I)#".'7327& '4>32I!(2C%&B3'! [Z[Z 01N+%C3'!# # gg ff ') $ >;>#4&"#53>23#"&'#532653>):(>#4&"#53>23!5!>):(>9 "&462!5!!5!s,,,,88>>9 "&462!5!!5!"&462s,,,,,,88,,>>9 !5!$#"&462#"&4627!5!>j,,J8,,,,L8>>9 #"&462!5!!5!#"&462>,j,,,88,,Q!5!!5!%"&5462"&5462%&$ .!%&$ .!J88!"!"> "&5462"&5462'!5!!5!$&%!. $&%!. "!"!88>>%53&547#5!#3'4&#"326> ! '"!&8,-98,+H(+,%>> #"&4632!5!!5!4&#"32;)*99*)dR::R;88n,"$#>> 3''!5!!5!2 {{ 88>> '77!5!!5!2 {{ 88>> #3!5!!5!'y >>}88<>>6%!#7#537!5!733#!>G6G:G6G:888>;> !5!!5!!5!>888>>6%!#7#537#537!5!733#3#!>,6,..4,6,..;oo8r8r8oo8r8r>> !5!5!5!!5!!5!>:8r8t88>>> -5% !5!>`H8ú5>>> 5-5!5!>`989y5>>~ -5% !5!!5!>`8ä55>>~ 5-5!5!!5!>`y8955>R>~-5% %#7#537!5!733#!>`0D0{a@0D0|a8324d4324d>R>~5-5%#7#537!5!733#!>`0D0{a@0D0|ay89324d4324d4b -5% %5% b\\8884b %5-5 5-5b\\8888>V\!)&''67.547&'7>74'6\7A#2 4,,4 2#A7u1 "''" 1uIFFFF kE-  ))  -Eky)&&)yqqpp3I63%&+#7'>?.'7;7367IZ U6StG (*?$$?1%  Z U6TtG!*7)I0-F eP "&M" fQ  M'#>>h-#'5%737>_6gU6IHpYַK8WyM5>>h%#75?%573'>U6IH_6g`p4ַK8Wy8Y 5>^>%#7#537'5%737'!>*6*h|W?M6ARONĆ:ih4c<8In9y[?>^>%#7#5375?%573!'>*6*h|C>+a6iON`Z):ih4Z8g9NxH*h>>>%-5% #".#"'7>3232>5>`D0%@'94? :$!@*;0 H8Z8/")"K ''"*"!+>>>%5-5#".#"'7>3232>5>`D0%@'94? :$!@*;0 9898/")"K ''"*"!+>^>/2%#".'#7'7>?'5%737'32>5>D0(@;<6?"4?*A?M6AR<@< 0 Ć&8/&5 -$ 0)c<8In9y 5(!+ w[?>^>/2%#".'#7'7>?5?%57332>5'>D0(@;<6?"4?*->+a6i<@< 0 `Z)&8/&5 -$ 0)qZ8g9Nx 5(!+ *h>>S -5% 5-5>qqͺ232>>S 5-5%5% >qq322>^>!%#75?'57'5%737''>960nCS960nC˗3i{y(31I2OGZzy(20I3OFY]I76>^>!%#7'5?5%7%5737'>N6U& ">N6U&!,q3E4Qs5J^X3aTl2r5K^W2`Tm+>> '.'5>5> IkttkIMZIN9 ?DCCCB$M;D33.>> %57>7./5>tkIMZZM IktCCB$M>N%'.'5>5!5!> IkttkI)NZZN)5?DCCBB$L)=CD>)5>>N54>75.=!5!>tkI)NZIN9 Ikt5CBB$L)>C310L?DCx5>>N8%'.'5>5#".#"'7>3232>5> IkttkI)NZZN)D0%@'94? :$!@*;0 5?DCCBB$L)=CD>)[8/")"K ''"*"!+>>N954>75.=#".#"'7>3232>5>tkI)NZIN9 IktD0%@'94? :$!@*;0 5CBB$L)>C310L?DC8/")"K ''"*"!+>>h!&5'.'#&'5673>?%> 5oGo6v^nqn6b1O% .X4 Ny+*: 5G).<*M)6OP >>h#%#757>?./53&'6>rm6aY^iC P="&5332653#'73P؞3WY}3YYon5XyR9ll>P= 2#"&546"&5332653H+;<)*;:2؞3WY}3;+);;+);on5XyR9>P= ##5#53533"&533265333p؞3WY}33vv3^on5XyR94H%!!!!H2t4H%!5!!5!H424H< %!!!!5!HL2v54H< %5!!5!!5!HL435>P#!#!#!P3T3#>P#)3!3P33#k. "&462.''3'>5#k],]\~]\.]k. "&462."%326k Ɣdc~bb.bk. "&462&#"4'/'32k(I[]G<<<hG][~i<<}GGG <k."&462&#"%4'326k(I[j<YX|W,>+,==X~jҗԖ=XW|WX=+V=7.546324&54632>23#"&'"&465"&kijji0V V; k  p0UV2 k  o~iԖԖ_ce^  _ce\k. %!5!6"&4624&#"32!5!jxijjiLj.iԖԖ%.k."&4624&#"327!5!kijji[x~iԖԖ.=? )!5##5#5##5#?888孭孭=? )!5!5!?8nn孭孭=? )!!#''?`ɡPj8B(=?)!!$#"&5462?8n""!06n0!!">%!#3!`88> T>&!#!5!8L8>&)5!3! 8 8>%!#3!88> %!#3!!!888> %!#3!#388h88> %!#3!#3#388h88z88> %!#3!!!#388h888%##5#733733#J8*Ak82Cb88s8 %!#5#733733#3'#8*Ak8~]C^^nT88s}}8q%!#5#5#7373733 8B8 Kk8B8M ٟD[!!oD%!#5#5#73733733#!'#8B8 Kk8B8XyMyyo"D[!!oD}}8r!$>>-5%>2YX>>%%>` >>> -5%!5!'>2H5W>>> !5!%>`9y5H>Y#"&'!#"&4632!>324&"2bF?]  ^>FbbF>]  ]>FEbEEbFaP<Y#"&'!#"&4632!>324&"2bF?]  ^>FbbF>]  ]>F0EbEEbFaP<Y #"&'!5!>324&"2bF?]  ]>F0EbEEbFaP<8P #3!5!P99+9C4>P !5!# #3P994C9+>P !5!#3P94+9>P, >P, >P= >P= *"'7'֙ߢE6 #"&54632@m 373'7@))j(ii(6||L}MM}9>$ %"&5462"&5462'773#''7#5L" (!" (t%%%% %%8%%8?/}7#"&54632 632#"'%7a   4 &   ;4! ' 7""B""B"BB"4! '""""B"">>732>32&#"#"!5!>O<0Bu%&M;.B ~ m"*"Y")"92K#.'3>7K5]>' 9sELDggD~>W#1dd12K%#.'#>73KMDggDLEs9 '>]1dd1#ȾW>~4H!%!"&5463!!"3!!"&463!!"3!H5IJ4+-ggQouK"J32K2,>,ʔ2vQRu4H!#!5!2654&#!5!2#!5!264&#!5!2Hg"KuoQg J4+-5Ifʔ2uRQv22K2,>*4J>P=!!#4&#"#462#4&"#4632P3WY}3؞u2:P:2W<=X9XyR5on,)7:&*>WW>>P=!#"&532653"&5332653W<=X2:P:2u؞3WY}3>WW>*)7;%,on5XyR9>P!#4&'##46753P3kO8Ok3b8d9Kz  uP5g g>>%3##5##5#535#533333#5#(P((P((P888""8>> #"&5462%5% ,e`,8>>%5-5$#"&5462>`,88 ,4 -5% %5% %5% \\\888884 %5-5 5-5 5-5\\\888888>*> %5% !5!5-5>qqR24ɺ32>*> 5-5!5!%5% >qq 3242>>H 5%%5% >`8r8>>H %55-5>`989>>X '5>54.'5>?>HiwqlKIkttkI )NZZN)  ??C2EII)R$BBCCD?L)>DC=)>>X '.=54>75.=>wiH KlqtkI)NZZN) IktC?>!MFJFCBB$L)=CD>)L?DC>>h/5'.'#7&'57&'56?3>5'.'>:wJ\6cRgqYaJ6:-3V>O2G$;+SLU&i8+L2CED4 x  >>h/5%#754>?54>?.=7367'5&'6>R6BGQ[@&Ln6f=Cp: :zNV6\Oc~e&w ?ͥ._M%K b#WL/;9<2!L$;I%^/\4^H%#7#537#!733#!!!!3H*6*q!l*6*r#!Xډ:ih4Qih2v4Qu4^H%!!!#7#537#53!5!733#H!W*6*r!l*6*r2TLQ4ih4Q42ihDv4H<%!!!733!#7#5H.D..D.L2v2252254H<%5!!5!733!#7#5H.D..D.L43225225>>>)-5% #"'#7&#"'7>327332>5>`D056#DB,&4? :$16$DA-(0 H8Z8/+'F#K ''+'F$!+>>>)5-5#"'#7&#"'7>327332>5>`D056#DB,&4? :$16$DA-(0 9898/+'F#K ''+'F$!+>>N<%'.'5>5#"'#7&#"'7>327332>5> IkttkI)NZZN)D056#DB,&4? :$16$DA-(0 5?DCCBB$L)=CD>)[8/+'F#K ''+'F$!+>>N=54>75.=#"'#7&#"'7>327332>5>tkI)NZIN9 IktD056#DB,&4? :$16$DA-(0 5CBB$L)>C310L?DC8/+'F#K ''+'F$!+>>h -#'5%7377>_6gU6I2HpYַKYX@M5>>h %#773'7'7>U6I_6g`p4ЈַKY 5b@>^>%#7#537'5%737'!'7>*6*h|W?M6AON2hRĆ:ih4c< yŜW1ϰ[?>^>%#7#53773!'/7>*6*h|C+a6iON`Z):ih4ZNxH*h}lOE #2#"&5462#"&5462#"&546wtr6 ##"&54632#"&54632#"&54632rtr ##"&54632#"&54632#"&54632rtr #4632#"&4632#"&4632#"&tMM5I *5"&632762#"'#"&54?&542>54'.I) ,5CcX@ 8aW@  7.J) ,5!/:*D7,E7  CUb7  DTa!/:*D7,#$%32#"&/4737!"&547632!2 1  Ip   +n   N >O!#!<^q^>O#!5!<^O"<>^)3!<"^>^)5!3"<<"lCn4@H44'&#"3276632#"'&54##"&547546232TVwxUUxvWT_aa`al   l JxTVUWvxUTbaˆ_a`a    L"#4>32#"&547&TJkS3GW?"7(!d0eX'.&#  iF>T<%&#"'7>2TZZ 01NVM11 ff **>T<#".'7327T!'3C%&B3'! ZZ3 $ # ff:223AA:.'7.33(7b#%#&'!!673!2#!!"&5463!2 (bHb(!EE q Sj66jV=(=   7b#&'3!!#67!"43!"&5463!2eE!(bHb(!EA q =Vj6h"h6jV=(T   7b$567&'!!!&5!"&5463!2p=Uo75qW;  L q E!+lk,!E";   7b$%&'547!!!6!"&5463!2*q57oU= H ; q G,kl+!Ev"E   7b463!2#!"&5#&/#!7 q  }H~  "L #2SR  - 73!2=3!5F  4cZ1V#/;!5326=4&+567'2 &5464.#"326$# Fl-5L]HbTL$!!(  ?vՒӗJwF.l\|#)5E326=3!&54>4&#"#"&54632'2#"&5464.#"326*/GJA !!.AA."# P=LZҕ5L]HbT+>!"* )I87FL/  +8FՒӗJxE/l]{#>JY%32654&#"532654&#""&546323#"&546322#"&5464.#" 6F):5- ,:'&TCELS #.nUCYJҕ5L]HbT E0+3$5-")  '171K 2!AT;-ՒӗJwF.l\|##3%;#5326=#533#32#"&5464.#"326 /BooVҕ5L]HbT!!'A-ՒӗJwF.l\|#0<L%32654&#"'67327#"#"'632#"&546322#"&5464.#"3269 (8-#*')s*I5-!%&- .DEZrUAVWҕ5L]HbT  D1-;2l( y$O=BY8*ՒӗJwF.l\|#%1<K4654&#"632#".547632#"&"32654&2 &5464.#" 6 3S;NfN8Q)D.W@S4)72('1-&5L]HbT ]5)KL:G]/KJ%wN64(o?/0>=/3=WՒӗJwF.l\|#)8%"&54>?##5!2#"&5464.#" 6 "4# 8H d] "ҕ5L]HbT0  $I-Ie ""4JՒӗJwF.l]{#"-9H#"&5467.54632'654&#"'326542#"&5464.#" 6:2eNJY,8&R@8H t*2) (S:D7)(6Oҕ5L]HbTA-BUE9*: ,!6E6*, /&#$!(E*71%3ՒӗJwF.l\|##/;K%327>54'#"&54632#"&54632"32654&'2#"&5464.#"326P 1U;NgNXln[@T9&2-&)73!ҕ5L]HbT^4KL:G]io4(J=/3=@.0>ՒӗJwF.l\|#&2B;#53265.+567"54632"3254'2#"&5464.#"326>  3b"ݐJFMF434ҕ5L]HbTM{##  9"u}~kАՒӗJwF.l\|yD!!yD0y\!!y\`8!3#00!8!3#``!8yD!!#g0D0$8y\!!#g0\`<8yD!!#`D0$8y\!!#`\`<8D#!50PD08\#!50P\`8D#!5`hD08\#!5`h\`y!3!0 #0y!%3!0%;`y!3!` #0y!%3!`%;`!!5!3 00!%!5!3 0`!!5!3`0!%!5!3``8y!3!!0g#0$8y!!!#3g00\`<8y! #3!!#`g0 #0$8y! 3!!#0`D#0$ 8y!!!#3``D0$8y! %#3!!#`g0%;`<8y! 3!!#0`\;`<$8y!3!!`;`<8!#!5!0P!08!#!5!0P!`8! !3##!`0PD$8! 3#!5!3`h0D08!#!5!`h!08! %!5!3##P`0`<8! 33#!50`h\;`8!#!5!`h!(`a8yD!!#!yg0PD0$8y\ #!5!!0P$`08y\ 5!!#!5g0PD`<08y\%!5!!#Pyg0``<8yD#!5!`hy$008y\ #!5!!`h$`08y\ !5!5!!#h`0`<8y\!!#!y`h\`<y!!5!3!y00#y! !!!5!3g 0D0`y! !!5!5!7P!;`0y!!!5!30\``y!3!!5`D#00y! !!!5!3`D0`y! !5!3!!h`0;`y!%!5!3!y``;8y! !5!3!!#P0g00#0$8y! #!5!3!0P0$`#08y! !!#!5!3g0P0\`<08y! !!#!5!3g0P0\`<`8y! 3!!#!5`g0PD#0$08y! #!5!3!`h0$0#08y! !5!3!!#h``0#0$8y! ##!5!3!0P`<`#08y! %#5!5!3!!#h`g00;`<8y! 3!!#!5!3`h0\0$`8y! 533!!#!50`hD;`<08y! %!5!3!!#P`g0`;`<8y! 3!!#!50`h\;`<`8y! #!5!3!`h`$`#08y! !5!3!!#h``0;`<8y! %!5!3!!#h```;`<y5!!5!!yy00h8(!3#3#h0000!8y !!!!#gg00`0lh8yD !!###h0`0D0$$h8y %263!+!!+o0`00lT08 #!5!5!50PP0`08(D ###!5(0`0D$08( %#!=!#0(0=0`0$y! %3!!!0gUk0`0hy! 333!h0`0Q ##0hy! %!373!y0`0Q0Uak0! %!5!5!5!3 P00`0(! !5!333(h0`00#(! 3!5'!5!30`hh0!0a08y! 3!!!!0ggk0`0lh8y! 3!!+30Q0`00!#0$h8y! 33!!!#h0`0Q0k0`0l8! #!5!5!5!0PP!0`08(! 3+!5!300`0h0!08(! 35!3#!5!0h00$0;08y !!!#!5yyg0P0`0l08yD !!###!y0`0D0$$8y !!!##!5!yy0`00`0l<0y! %!5!%5!3!yy00`0k0y! !5!333!yh0`0Q0##y! %!5!3!)5!3yy0Qh00%k00;8y!!5!3!!!!#!5!P0gg0P\0k0`0l08y!##!5!333!!#`0h0`0Q0$0##0$8y! #!5!3!!!#%5!30`0Q0h00%k0`0l`0;y!#54670ѫ0%!!8!5!}82!5!8!!w8,!!8!!q8&!!8!!k8 !!8 !!f8; !!;;8 !!$8} !!}}8 !!8 #38` #3```|8 !!} !5!}8 #3``#)!M#)!!M ms#Z)Z^ ^:6d#Z Zed?^  ># hghg 33' ѿ?yk:<5# "32654&'2#"&546ԕ Ք՗r"/:CMW&'#5#&'7'&#"'632'654'>7#'>7&47#"'7327%&'#'n? + ! + Ki  ?! ' A*=MM;##"& !-6 !++ ; HH!" #  +2    ++ #@#  In =#)!!Mms#7!!!Cs M sm#!!!M # !''!U YZ쪪# ''%77'7'bF<gH0> z|Ҕ7n*732654.#"4>327632"'&`*5% Hg$A)If)%4@/N; 2A?*B$hG &3+gH3Q- 2  =MY~??7q2=2>54&#"".546327&54632#"'4&#"32#/I(sPQrsP8Y1 aPBV;a8X2 EEbR?W;ECuOPstOQD!/:*QrsPQr((9F2b2CYa(9F2`GE3CYaEEstOQr"609EOZ%+!"'"'>7654'#"'67>32#"'.''627&#""32654&%#"&'32%#"&'32Ax !$ (AZY@(<<E):8)(99 =$2%,/ ,1!7=^U  C!!D  h))N8()99(':   # ##4632327>763#"&'.!!!3  7z&#IJ5 ?M /]" Oc $Wms#+ v*= y: #z8*;263326767>54.'.#"%#"'32654&#"l 46h:4M'5( ,2ZݙR($ $*1# !' 6 U.+=[.B_KS]OPq#z8*;"&##"&'&'.54>7>32%327#"&546327l 46h:4M'5( ,2ZݙR($ $*1# !' 6 U.+=[.B_KS]OPq#/*.Xbu%2>737'#"&#"&#"3327#'23#"'5>7>737'#"'7'#"&54?6432#"&2632#"'.47"&54632'#"&5464F6#S i |(+$i" X6,x 6!, .O 6C %2'+ ;$Gt?GeE! ]$&"l `  <8 #J 1 Z "L .!$ 2C0R #*51  G=2Ra !*  *" 1  $  *.V_r#!7#54654'654&#"&#"&#"&#"%5!7#4./&54737'&5477'&546322'546#"&5476324632#"&7#"&54632;0Z "K / # 2C0R  .# +40  H<2Ra " * )# 1  # `4F6#S h|)*&j" X6-6!, ,R ! 6B $2(, <"HTH$e"![2 $%"l b  <8"J #/*.[i}%".'#'732632632##"'33275.'.'#'7327'732654/&#"%327654'.#"#"'&#"327>4"327>54&"32654&4F6#S i|)*%i" X6, 6! .O 6C %2'+ ;$G#(4G''= !. ]N  (7  ' #J 1 Z "L .!$ 2C"  #*51  G!DR  ~% !* A&   Q $  ,0]j}4>7#5'7!##"&5#"'#"'#"&547&!#3>7>757732?654'&'.327>54&'&54?4&#"324'&/.#"3264'./&'&#"326;0Z "L / # 2C" # +40  H"DR  ~$" * A&  R  # T4F5#T h |)*&i" X6-i7!-Q 6B $2(, <"H"%4H$#'< !/ ![1N   '7   "J "_go#"/.5462#"/7326767632#"'#"'&'#"'"54>767&'#"547&54323254#"3254#"3273254.3  ?ZY !  !  !$ C"W0 !'O?R, ?2<6.  "?I2+*%&%&&%$' {290?HI>&E0(--#5  ' ) 75"13 $%  6 +.&)+.&N  VI"46462#"&#&'27#"'n1Y%2$$$D\1a6nEXVKG7Z$%##*$U;,(q&Lm{4>3"&#"&'4>7&%4&'2654.#"'654&+5>2654'7372657#"'#"'4632&#""&6=63&'2.54,5**< <* #/K?R$:, IL?*D( NO$4)K-# )< ?Q#  #D?-D"A/SB9Rn8,H.:4 /(0(ZD1 Y2A*D( %1'&2$) HV@("&:T*$CCN,6*%"i=5*!#*> D )#/'HW;!   !'1R ! $!GDZ/ ) m =\`$V<#7'75#535#53533#3#7#H"j\\Q\\I"kQe!H1PPPPPPPP!H2#3##5#535#53533 Q\\Q\PPPPH"?#"&54632373'7zThbs6V=Žh^aaONNmxwTh#!‹C\\8]99]nlu4'6.54675#7.5467&'7#>54&'&'"&547&'"5475"&547>77>54' V+! dH15$,H$J-AG5 ZZ 5GA-Jfr>(Ge |3Z&l&Z4|!+V 5?Z'< E3IGS#Lx$!,-J*# ,&X4=Y .. Z=6V,`[;x#zK-gRQ`J   08v$**$v80   L <'Z?5+H )#"'&54763!'6'7654.'aa`aa_~`TW-]Q3HG3Q\-ˆ_a`aaaܨBD)FoAnQPoBoE)C ,832654'&#"632#"&546324&#"3262#"&546YCBY\[Jt@* AZoRD\]C|\Z5J^@XD_‹‹2& 3!5!5!5!5!5!2   ddddd2& 35+3!5!5!5!^d  ddpddd2& 3!5!%35+3'!5!2 ,d ddddd2& 35+335+3!5!^ddd ddddd2& 7#553!5!5,  dddddddddd2& 35+335+3'!5!^ddd ddpddd2& %3+5373+53'!!^ddd dddddd2& 35+335+335+3^ddddddddddd CYp %&'#"54323&'#"543247#"543267&542&5432#"'632#"'2632#"547"54&'&'&'26326326323#"'#"'#"'676767&547&547&5475&547&547&5472654&"7263263263&'67#"'#"'#"67&'&'&'676767&'bF"!  A !! F !"GaBaG!"! F !! A !"!FbB-         + )/  0( $&{       9 /)  (0 @@  !"Ga!"ZN!"! @ !! @ !"!NZ"!aG"!  @ !!: )/ > /) +       {6 0(K )/ -       H)2;4'&#"3276632#"'&54&#"'>32'"&4622"&4632TVwxUUxvWT_aa`a*:9,A('A""JxTVUWvxUTbaˆ_a`a''%--%" ""H(1:#"'&54763654'&#"32'#"&'726"&4632#"&462aa`aa_TTVwxUUxv E()E1zQ""ˆ_a`aaaTyxTVUWvx%++%%"" "H"*632#"'&54327'#"'264&":64&"_aa`a/SQ11675"""3aˆ_a`aBB$""" V"32654&'763232+"/"&=&'"&4?&'#"&46;67'&5462675462PloMNno9G7U T.x x.T U5I  H7U U/w w/U U8G  mONnoMNnw/U U7H  I5U T.x x.T U7G  G8U  U/w 8I#%#"567>4&'&'432>54.'Ԟ&GPPG&BUC/0EW?jCDk=*97I#.464632#"&BUC/0EW?jCDk=*9햹 44 7)H32654&#".5467.54632326546232+"&=#"&46;`*5% HghGIf^fG68E  fIHg  E86GrQ    B*B$hGHgg J@li@ IffI @il?Uy   7)032654&#".546232+"&=#"&46;`*5% HghGIf^frQ    B*B$hGHgg JY~XUy   75732654&#"#"'&54675#"&46;546232+`*5% HghGIf%3@.XA?sQ    Kx*B$hGHggH3P- ??YUz     v7n4732654.#"4>327#"&46;2"&="'&`*5% Hg$A)If)%4@/N;ɒ   2A?*B$hG &3+gH3Q- 2   =MY~??33>32356732+"=#"&54>54&#"#"3W29=!) ( 33($ &(=FG:,t[,   e=*3- 0><"&5#"&5467356323+>32;2+"5454&M/B  I I H K!V#Un]Bj^U.B4   H F 4&Y1F  K%(Js7|4>732654&#"#"'&54675#"&54?632"/2#"&54`*5% HghGIf%3@.XA?sQY  { { XKx  c*B$hGHggH3P- ??YUzX  {{ XvF  K m%"264&".54675.="&54?632#"/5#"&54?632"'>=#"&54?62#"' &3+gghG3Q- rRSq 7 7  YB 7 7 BY  87 qRLw??$A)Ifhhy%4@/UyzT 88 Cc 88 cC 88 TzuZXA?7,%2#!"&546;2#4.#2> O 4@gAM,-LAdB29AbT<32#"5654&#"  `N8PgHEffEHgO8S[U ^M5-FdUDDUcF.5Mt{9%2>54&#"2#".5467.54322654&54x2O, }VW}~>VEAR+322654&"23267#"&5462#"'&546T;;T;C/54&#""6264&"#O8#R.ÂS_$33$8N7  NpO6A6tu6A6NpN77N7\pOm9t=zM0bSQ]+'77' 8NN8:}\w4`||`4w\}:8N(7N77N#>NZ4>7&54&""&54&""&54&#"&4632>32>32>32#"'#"&7654&#"u)]+KjL  KjL  L5 0PP0/PO02S[:Jn  !% ҄U;?_ ,(35KK5 5KK5 5K  0((00((05,+9bIl   D f-7LN7$$\ 17!2#!"&462!2#!&=654&#"!"&463!5468  l  }YZ{  (   љt  db  tK#"&54&""&54&""&54&#"&4632>32>32327#"&46;2"&5Xah>OKjL  KjL  L5 0PP0/PO0Fb<0OR: o  L?:5KK5 5KK5 5K  0((00((0bF%->  o *k*7#"&546;2"&=#"/#"&4?'&562y       y     ! +<"&463!2632#"'.547"&4767>7326754&#"5  "Z^z#',\%&Zga v+o'7C2Kmt79   &N0pay ^742i 2Od);\4" _H [v;"]B%".+".#"#"54632;>?232654'54732".+".#"#"&54632;>?232654'54732(C,'0(!#1 8*+9 3KcC(B+(/(!#1 %D.F'2LbC(C,'02$<# &D.F'3K cC(B+(0(!#1 &D.F'3Kb#12# +*!#12#I5 ,E`#12#+*!5?5I4+E`#21#.605@5I5 E`#21#++ 5@5I4,E`!4##"&547>4&'&546323>7632#"'.ya \mm\ ayya [mm[ ayGj+  )Ȩ)  +kk+  (ed)  +a0;GWdo2#"'.54>32474675'53733>>54#"7"3>54&.'6326"3265."32>54C $-!#-% 11)%  %)% 9)+1h*3!YI /+B EegC$51(}g`+8E 4"*"*O6CCFZ 2$#4 ' %$&&$+, +;;+VeQ4+(2&.22(H Qe   5$*2%32232=4&#"32>&#"62&544  "32544&5462654&5463265'&54632+&#&52&74654/&5&'&5462654.54626%"3254'"324!"324"3254&.'&'63267&547.y, I{45z;AOSWK << F;!. 6 !A!"."KI1".!.!@".!6D     63 RQ44-  h@{":!!9#1`r:!!! *%:C*"!)( \ :":8 *)!!$,A,($+ !!9s[S @222@ @7?73/b F0&0//HW2 .?-K#';35'575'57335733573%!5%!'#'5#!75'##'5fXZnZXf@BpBA8 D D 8A|EgM[[MgEO''c@@o8778J)7Cd"'632&547"2654"#43254&#"'32767.5#53533#23274&&'&#""326326732632.'.'632327&54654.5467&4632F'OO/1G/7Au*- ,ohpq>""$"" -5;2/A[" ;)B.1@oG6*41! &_} zL  !17)7Gs"'' u   j  h G^.<  8.^,'++',  ! <" ?5  0? "? 8"?i: !h?8ZOMv72#"547"54632'267&!654'&+.';2673232767>3272!>7#"&'#"'>54'32636 ]&0 05J'< '9 i,Q' 8H;)]!&#'7  0x61 z $ ,[N.{$@ )  #D#(B G =[a/%.H&9!1( <&%3"/ $eL.L!4.54>54/&546=4&#"&5467.547&5462j**e % /@E D3F3E!EA (N6-G' .  $ "" "We#2C"+,!D 1$dW! `!1Bm|"#"54.#"327327>54&>32#"4#"326323254675'53733632#"'.'&546322#"'.546?-5&%6,)0=%'WX'&;0$ 'A>b(6no&)% " $(#/24I'%'I341 %-=?''J/1L%,'[  W',$:"P   \(&$%%$#0&D3)6 8^DD3O5)2E<!C, P1!)1%"326373233254'"3247"324!"324"3254&#"&54654&'4/&'&54632654.54632654&5462654&54632654'4632"3254&4#"32?3222A<l   k' in\}G .!"@!!7!.6!!  @!!. 0  -AN 2?22 2?2 A(@W 217* !#-A)-%*  !&8s^2$; !8$2^r9" ! &,)A-!!(?k 7 z !G#3'575'57335733573%35'35eNG&o&HNeGdMYYMdG""""I R^g%"3254#'2654+"4.54>7&4632372.'.'>3327&5467535#5##3"3254\3-7d31?%3n'(L&4/ '(1d<G4-;#"B+: !8 l4:E= # 0   *!#9j.&++&.aM3=T2654#">54'43263632!>7#"5#'.7"265454'#""322%}x )= 9H<)Z"'$&8  /SH;  .5.d' $%&("/(=[a.%,G(:2) =  %hZ 1E|N,dL!&5467.547&5462E E@UAE E4F2B3#dW# #Vf"2 C!,,!"O,%!5>7#"&54>7#"I!  !4R5K,FJHGKF-K5R5&!  !&5PJ5-J=BkCBjB>J.5J#7.'.5463267632">54&#"#".'&\Qm<+U>U22F=W6E1='57I. DJF.84?/ 9KOY/?VK,6"8T;8pW/F4%KFI_N&/hX[c/398 /!*J"0 &'67>7.(8F!JE;;8-0>P<6jj1?0#5!5>7#"&54632&5462>32#" ".F--F/! O&@\S;""']]'+;S\@n%%9%./$:#,"(_CA\ 82?ZZ?28 \AC_#>32.'.54632\Y6=W5QTMQm<+U>w0JFT;6phiBKOY/?V"0 &'6(8F!J0>P<7 %#"&46323B,-BB-3"S%..J.-7"&46323#54'&BZBB-6 T&\%..J.-7mC88m7#"&4632#"&4632"F0/FF/:#F/0EE0:"ks&--L-'&--L-b75%#"&46325%#"&4632wF/0EE0:"F0/FF/:#=='&--L-ځ&--L-Bp#"577>324&#"326p;W_&( -FNW%'30;b,C|R0  VO=#"#&'57654.'5673;54&'567332>7332673#.+#.#"#&'#'L*J  ! XI" &'N U 0 Q$N#  %- T$  *Q&M/! WQ*  )%S   0 ] $(48<'#&'675#&'6735'6737'5#5#'5#5##3355#5#`l=3573"o` ""Xu?53<.=k] 7 &@@@&70:J%632'#'"#"&546323267&'.54632'"32654&"32654&&K* $ _k^`\eb14(-D2#TE8091#.F_":"48%3!%0 0(=7nr &2@*"2#_ ;&"0B*)!1 0!/$*#Qc3<H32%632 #"'%"&5463267&#"&4632&"3264"32654&&_&8<)&z'8-9;Y '. %?.&")%'v(r #(65)/;%A9X76$:*&:-#'!$#Eg5AM3727#"'%#"&54>7>7.#"#"&54632"32654&"32654&1ee\`m]"'I)F."1'55(YER#2D-(44":! 5> 2%#0%  ro6=&/ )*B0"!2 F##2"*@00!/!f/!*# #  *5Ax72"&546"32654&2"&46"3264&2#"&547"32654&'26327632 #"/#"&#"#"&547>4.'&546324&546327&#"+"3267327-4654&#";27&#"#"$44J55+&%#"$44J44*%%""&/  8!cJ*@%B5[CI03R?BQ@#{NS#9QB=W*F /3C.b9DKB63A8E",1D43AL?C:^  'G5$%44&%3&&&&5$%45J3%4%%4%   W _9 '=1~ ,+:LQCS) : *OBQN7%/, * >C>7CCh&&/1@E6:E 8 #@IR%"&#"32654& #"&54632#"&54?4&5467>32#"'67"'6ZE] "LՒכQm bD9>%- 3"7 )6ygOՕD3LM RyQ <1L D!# ".=%'>5%7&&#"76322"&5462#"&546"32654'.i!''C 1)("(;;T;<.ӕ֗eVËo,tV?&u>[nT'L ù<)*;<*);Փԗo^~Ċd(.#R4&'"'7'7'7>3765464./3232+32+32+32++76x2sJ3!##!3J$=!% W% '=!1<J Fx]jJ<1!='  %W cv vc   7  F  cc  F  7 X#,!75'#"'!62v;9Fv,]) Ģ77g g773m{746;&54632&'&5.46327>32#"."'5332654'.#"32654/&'376;.'#.#"632>54&#"32654'&'7&'-0&%(& ++( g8W0 8, 3 % 6)Pe2R  >L ![%( 8  M</ X G -&"#/ f_.&5@oqAA#Yp ,=z(8E2pT26'n"mS ' b % Loi ! 4 B<| pu* !;4x(cs?67>776327#''#"'#"5?267327654/327#";2654&5'#43632'7&"3677654&#"327326547326%#7654R# EL1=U J]&  \hc*O4Y8 C&B%K Bx;/:|   X%>K ' w   <'O $xX iZ4KA8#`  T; Gg8 8! o& 8%(D FF5  $B Y :!  # V$^]>2UKO ;CN#3l  *17=2#"&5467#!"''??2654/654'%>7%>7 . 0_ $N)Q|E!yI#QBFn?q+Do ( *>>W  t|Y-%Rp/ ishGb$#&(-492"5'57!2"%5'%7654/'!!&!654'!!!6jNNee RRR(WaB|wD NOOvw   b__nmWP4()L#1l| ",39?2#"&546/763!27/4&+76%654''%.''%.'- /}Q)$U"Iy!E%FBQ p+ l ' b< =  v{r*/oQ";G ##&E7"&546;32>32#".#"7232675##"&5463235."#"'#";>8EJ:/',5hN5*$4G-&z'_0'(-_#w8(- =):8# 2U>CWK)0)xWH&-&Bb&-&:HI0"#2FK?)0)JE2-G##gL6E22#".5.#""#"'.5463:32>76#&#"32?64a!8/4S3:W1,7$"2   1%.J?R2'4    !o *$$* HnL*?B:  ;#"&'."M T:Z-pQ%,)G4wf  7$+574&54>7>3232767632#"&'&'8    nm  B)4J7G k!/'   ?'qW  R#J/;@/3 #  ' 7  ;; ;y;!; ; # ''7'77׮<P#"&'#"&54654&54>767.'&'&5463262676327632>;2<eBX  [rT#  (  ,%   n#[" 3 + -#)kP +U ) $N7#"&##".'#'?4"".54654&'67.'6732632>32Q Zy# .:O =   t2$M <&D"  r  #;T hU,2?,"[6K# #3##5#53573##5#535##33535#\ġp\\F## 3##5#535# !33)!%!!Ennnp""""nnn# !5353!3#%3#A# 33###53[[[][#33##'#'537#3335#5uLANkV8Z]GME|GLu|]c]# #33###53'33###537#3335#5[[2UbUʘbb#`S1;54&'5!#"732673#54.#!526=+"#;iV[HnF[ Oj,W<[HF] NkJZSnmS\G32SkiN ^Eo#  #3#'#7'337/373#/?#ZiffijffRRRRT?}A=<<==32#"&'#"&546=#"&54632.54625&'#"&546#/% 029P:2/ *&(1'99(1''3/  9P:2/3''2'990 )'(1'99(1''302:P92/$1!'99'0))2/2:(':#C%4>=#"&546323.54622>32#".##"& #*#!0,5OM5 0-!!MjM 6$3235#"&547&54632#"'3&4632632#"'#"&547#632"&547.546325##"&'#"&4632$($H&(%$%1!" 8%$$ (6' &$%% '&!%'&8 "' %&4$G $#D%$$ '& $$%% &2##!2#"'.'.'&54>7>76s x C.(& ;o12K ki 6v,(P833y* #&3#.'5>767>7.'.ǀz {-/agqT2*",)HN 俿 >,-??X?# #''%7632%7&/&547cE@f?  3hh#JE&2 ,5B H-,# 3'7'3!''!7#7'7#Ez7-tCkZMiXڨ=F'\cc\M܂܅# (23'7'372#"/#"'5'&543%7627'7'-x]"jn%Xt;=fH52uGMMGZ i qttq # !%'!%''5?%_f` RNNAS簰bSbb0䙂0b#x 3#'''!7#7'7#{R?ZVaQQKk#7'#5'7'75NNNNvmnuunmv# #553'77''7mm666V6Mz_zz_zz_zz_z#7%!'#'7!5'7 = 1%9 +;+ A"643274322#"/#"'#"54?%&543%'&5432f # #&),/7'#''7'57'777!'/'7?7'.|u 7 .xx:+15+jl/gֵ/4+ngk{6 1wv5 3yk5lܷ.6'flo16'#$#/"/"54?'&543762726666YPPPQ#5732/#"/#"?#"54?'&54;'&327632 +++ , 0', ¿#7''77''٧٨⩩ک#7'''77'7''7G1}}12----2,26..62,#/3777!!'''#'7'7'7!5!'7'7'7l!`#j j#`!a$jj$ak#c!a$nn$a!c#k# ".8BK#"&54>7>32.54632#".2#"&547&54632"&54o<$*5L&1_#*5L&+H4($Z+H5'$^F22$#1U:  994 '&#iGW&#"&R"&W1F22$"DzLI|IJ#oy%4654.'&##"&54>54&54654.546323267>54&5463232>32#".#"#"&"2654&%$   *&9"BNBBNB"9()  #$#%   *(8#BNBBNB#8(* ! %#$=++<+*9w  )0'!$,   ,$!(1( +)>o   (1(!%+   +$!(1( k!)++>++ +#N%".'&5465#"'&54>7.5476324&5467>3282%@%CMMC$@$3#(>mmA8)z 6"%F6 (0&")%j$*"&0(% 22 %}3!( g  h &"|&#53"$|"& g  g (!3 $- DH5&+||+&5#V`%4654"#"&467254#"#"&5463232654.546232>32#"/"3#"."3264& 8%:]T(  Y3 6%8II8A #Y>9H C*7W$5,ICbEE`E# ?Rf{%#"&54>7#"&54632&5462>32#"'#".7632654&#"?3232654&#"32654.'#"/&#"327/&54323267'#"54? %6L ++ )FUL5$A2%LlK%1B$5LUF) $L6/  !'6)*6^ V&8L7'KF1&6+",C>0-"+# =-&6HZ6&1!UEN6&-= #+~!3&6XJ E\ #4=Wk#"'#"'#"&547.4>7&4632632632%"264&#"&54?'32654/#"&54?'32?'#"&46327'&#"32?'&546327'&#"7'&546327654&#"76327654&#"7632#"/3264&#"#"/32654/*?+/SO/*@**>,.QP.*@)&66J55  )1"#1)f< _h02#5.>n "" nj "00" j _!; .5"2/hQ )1"#1)f< _h02"6.>n "" nj "00!j _ < . (#1/hx>-+JaaG +->-+:JaaH+5J55J5m "" mj "00" j_ < .3#1/gR, (1D1(f< _g02"5.>n "" nj "00" j_!< .4"20gR, (1D2(f< _g1#4. #  %*/4>2 &5466327#"'7.'%'%&47'>7'"264&ԓD!#$!EE%&<6 U6  >D 6JD 6QIdedeԓҔ C 6C 6RE J EE J 6 U6 `dHGeeg!:AGLSY^&547>32#"&'.547#"'&5467.547632%&#"654%>54&'3267%RRb0(IU[$5u 2&fPR/31'IT\$5s 2&ea* F\V * F!YW C9( KsW1%17/3#+[iD(& MsW1%17.3"+[d0#(ap'MG#(ap&KI$A7'/'#7'757'7'77''7'7'5'7'37?7'znadc!g Z&Z g!ceannaec!g Z&Z g!cdanXQ708 :k{QD;rr;DQ{k: 807QQ708 ;l{QD;rr;DQ{l; 807#LPTX\`d'4;7377632##"/'/"57'#"/&54?'7'"4?6327577'5'75'7'Ä  }}  ~~rrrqssrrrqsscKKTDMLDTKKTDLMDTvCAABdBBACAABcAAB#A7'/'#7'7''7'7'77''7'7'77'7'37?7'ric\X42imM"Mmi24X\ciic\X42imM"Mmi24X\cU>"018f;yx+FhhF+xy;f810">="018f;yx+FhhF+xy;f810" " &2?LZi'>7#'&543'32.'7#"52#"&546#"'&54634632#.2#"&5476"&=>321    w  F####L& & e& ' tnN-IN-     j  ####mN-|pmN-|% & e% !   # *=M]7'7''762"&42'.546"&546763?2#"&'&5/>324632#"&U8D00D0JF/  K4)F4*4E1-9O#D30.7R"By\1"!00DF1-,M!B10.0Y &@$!BpF/ M3*D0 M4#P7&54632#"'62#"&547'#"&5475#"&54627'#"&546325&5462u5#%44$%H43%#4F4"#5G5#%45H #$43%#4F3F5GxM "22#$5 NN 5%#12"L=#54#>L "31#%5 NN!6%#13"M<$54#> # #-:GQ[g#'&546323#"&547'7632#"&547%57632#"'%#"&546327#"''&546322#"&546 1  X# X#l  ]  v # #&88'(88ޜ ] v # # 1  X#K X#8('88'(8$a'&546276327632#"/#"/#"&54?&'#"&54?&'#"&463267'&546326q "." m! * $$ * "m "# m  * $$* m $$* !m "." m"* $$* "m "." n  #F "&546324.#"326㱭j$hC3 k\z# 3!5#!!nil* haR!# )35!#!olHh!MfG # !'!!Vw3xs@!# )7!!Vw;@sW# ''7'7%7ŕęƕ#h#hEM##M#|!|M#e4>;#"32632#"&#'=fA W9( %4&#"#"&4632e|6R( %=T\DIZ u)# TzTc#y"#"632>;632#"'#"&546>K{&#T2eL)!>ZX@b.O1D[L8PeuN5Z~Xg.9eLp$z&'3267#"'+'267#"&54632>32_K|&$T2dJ )!>YX@c,O1D[ %:lL9OeuO6Z>?Xf-9eL8N>/#q%4<%".54676;573#"'#"&5463232>7#ERx=^K1E. ! %I Mxg:8.'&547>22#"&466L(%JJ%6G* 9SS;32.'&5462"&46( *6B, 0082:'B9SSvST"  L?%5%/()6*A?LNTtTTvR#(k&2>2.'.546/K2bs!##ZM NZ%#!s96$ObuZ+#(@>=A( #+Yt#y!.54632327&#"#"&5467NJiI5F(2#23 Z>[8IgJNdb:Hg-HMO!AH*J4?fI;b#9Df#"&54632563232654&54632#"'&54>7.#"654&#"632327632#"&54632Uq;5A""$1 52+" "?2 0 uh&8n$ 66N.B$5>5$#C `@{M;b3! 7.46;32&5463232654'632>54'j>Mm% 7!L> ( $/^=/.$& #' 58<)%G #  Q-2,H/VCM7%+S+ 1)3Z 6" $$.'%4&#!  '/ E*# 2 &546#32+!5#"&5$7vM "$( ԓӗ]H  ## (# 52#"&5464&54632!5#+>54&#"326ҕ[ &%C?su%!IQN2eTDX Ւԗ 3)8Q.Vc /'&9$)D0@L>/!# L2#"&546#"'632#"&54654&#"32654.'&54>54&#"32654/>32ҕ>1&18>+  bK]y!1( ")"RMF] "*Ւӗ0:(8/5L !3C]G%8  1$7<4(  .# "#2 &546"&=35##3+!5rxxK4 Ւӗ17M"* ### :2#"&5464654&#"32654&#"732>7#"'632#"&ҕ*" _F_cMN1 1*.(5,!Ւӗ "-?bICX( ,#~6B27M# >2#"&5462#"&54632654&#"&5463232654&#"(15*+6;*ҕG-Z>VrVB[9@5 \F3Q0 oB84AC43ESՒӗ)RS4iOAURYx !+9'73326ҕե &yv! ~X%$Ւӗ4"AB&% qI )$# !9'&54632#"&542#"&546>54&#"32654&/6, !,AE;+,54&#"327#"&54654&#"+78V355ҕՇ?]/xbUpXFZ6@5![KC43DA74BwՒӗ7[[/sgNBRC\w%-;#)62"2#"&546"&5#32+35265#"||Aӕh&D:9  ܓOXNR-7LLԔӔ"   &&.rNk:# %3##532672#"&5464.#"326%54&#"#54632'2#"&5464.#"326&<=: sG/3)(0=T@BWҕ5L]HbT-G.'.4 QK.=.-97- ?STՒӗJwF.l\|#(4D"#>32#"&54?32654&+532654&'2#"&5464.#"32616J<=PDQTCGJ8GW=MD4  d1'+.++-&-ՒӗJwF.l\|# )##5#53'32#"&5464.#"326K888ҕ5L]HbT2vv24ՒӗJwF.l\|#(8%254&#"#3#632#"&'72#"&5464.#"326`4*#/-@ASZE8F-0%ҕ5L]HbT.8+' 2,YGLdA8 %."ՒӗJwF.l\|#+7G4>324.#"632#".7"32654&2#"&5464.#"32664e3 19 L;LS>'+)67*&//ҕ5L]HbT\Jh1k^Q DSAE\ 2WZ=.3C<15?EՒӗJwF.l\|# &!#>7#72#"&5464.#"3268SYDmMҕ5L]HbTH*yib\ՒӗJwF.l\|#)5E"&547&54632'"32654&"2654&2#"&5464.#"326KUUSZHN<;I&..%&1.+)46P41&ҕ5L]HbTKX%".547632"3254%3##5>72#"&5464.#"326$(*'A..T.*R)54&#"&5462!5ӕQ 7@=)`IG]X(F++8L%<Ւӗ*)2H+DXVA  .55+(>"6/.A" ;2#"&5464.'654&#"4632#"'632#"547326ӕ6:WB-/R& #-'"' ),)"IRWDH[Ւӗ=!1 E;N ;* ,.)&#(=*&%.U :KT##2#"&546##3353{ҕ.KHRKՒԗk1Buu# &2 &5462#"&532654&#"535!36՚P+(#&GL?LcZJ(*Gԓӗm:>/+=FfPK\_AQ# 32#"&542#"&54627&#"32654&#">cD'& $/[ҕՑLr7;#55 D[R@4. 'x:1-5=.*ՒӗѠ q2kLJf1bIDY)XA# 2#"&546!3>75ҕJe_LOՓӗkA_eo2#  62#"&462"&5462#"&546>54&#"32654& $&#$&+,F-+*ҕ$R?@W@R\EF]!'("#+)F),N11'&-nՒӗ/$9KL7H !V@UXA'3# 02"&54672#"&546#"&'32>54.#"32$/.D'&0ҕ MLn79"55E[Q?;'=.*8:1-5Ւӗ"'w3lMJg1_IEY#(2#"&54'2#"&546#+33"32654GD"'ҕ5B.0SVQLNR%ƺi[Ւӗi(#6}y#:\z3 #7!5!Bz#^U7%7%{ENSUu3p#z'' 7#PwPCβB#^U7'%'%'{XpSzN^}q2t#t &'567#k>+ް+>pPXTDZQ#|!"'.546763!'&54632#"&47FY462/7%$%&70 +, 2.&%6 !7L0#{2!55!#}j#}1!55!#ן# !55!'3#'3#'3#6fLLS--Zgg#aFR 353#5#3#3#3#3#VQaGGZ22[!!^jN#!Kh#hL!55!#aa#Ryb'#V&b #Ryb7  %#&V$~[R #r #OV"S`37!5 5!"'.6'5K6R+#_:#0 `S=SS*06*#T`%5!"#5467>3!5!H-*(4(%;_T Y HES# 5#35ZBY#FPm !53#5!# v]",]#+"3 #5!!7!! vvӜ##+"3 #5!!7!! tquԜ##e@M5!57!7!!%>D;;Mu\5HM#e@O%'!'5!57%!!C}]s:aeT\vL#, '5#'3-#3zTR?QUZO#,%5#7357%#3-RT&,iPQ?dP#KHe 5!'7'!7!!7; 2DD=7D e`A!92#KHe%5!7'7!57'!!;DDDD7KZA`ֽ3##".'! !67>32خ2_Y<b8)%H <)x=7&#"467'%67"%.}*3FM#1}0yS  i!6O`  7i dCw#>&547#53&54!67!%!!&G27a(PW9iS>? +; K"" "!"!1D-H3"$'7.5327.'%&%467%}1#(BH4*WPt i7  bM7!wI"U%&5467&#">7'&#"%632&54'&(7e*#DI^Ni5S3fM>MMTa,@=0F.U )d+ 72WBBK 67A#{8"!>7&'!;.'>7XfkO<{R .F=+ (x "ITgIl0>O" p?A2MY("U$%&547#"'%32?.'327.547)+*aTMM7#"&54632H%E&) HD32&547&5467L?a<5@&26 2'(=1;nL?MJLL"S!0/!?4&.- //#'5R27 62O*#{9$4654+"+"&54?654/&54;2;254&54632#"w!Q(0 >;,6 $R$%yk",  ;  d [ B ' ne#Kg;7"&54?654/&546;23254&54632#"&54654#"#0/  ,1;1+' & $'%"! '/9K-Z8 $^!'#1N  G#' $'#U F0"ctP 3#>7.'3!5!.5!#>75>KW>=VZMl8k4#Hm{4f"8LPvlXYD8qO5t&-%`-%n9&efXX/".fk.?^/7tDrPe62"&46"2654T<V==V&/"!//!"892X2?22b#$%67#547>737#".' YVO~T[1H"  73noJ:[*Z~sj <**  sH"G+:d}k""3>54.".=4>326yjEeV]Y@xNFL62*ݢlq}dk !!#!=!}KK KK' dDdd>'7'K ddddnR v%27&'7>7267654&76632632"'>54&#"#"'#"&547567#".7632746=4&7632>-VQs00"0 2|5 &5 35S. EmDCD9\M^ Q3+D ' 2"5/AV+V DLN0q u=  2 +5'1=  %A$8K%FFE]*XM6o ! =$ &Yi 727&'7>7267654&7663632#"7>54&#""&/#"&5476747#".'&7632746=4.7632>5og:981"D> A2 = Bh9% %D5^gv_ aD8SM 5##& B%G9}blXI&V^#` 9O  $@ &6C0 4!! )p:J]\-Wr8'J?G(8! "-C#"&'63765654&'&'%4.5432676?#".- ee//0/#0&    ;7 $$H%@,+G 51 2 l/;(  ) O !,-]9-qFy J#"&'&73654654&'./3$4.543267>2#"&'&y!w%: >> A,J? %84 Y-.#(WQ  A. DvtJ ) 3J,*s<\+-8N6a"/"#"&/4632632'5>54&'"&543KD $  6x,L9';+7cPJI4)* F0,U>?#+[A1!zU  D#0"#".'&54632632#5654&'"&543NBpI# E ;4G"@y^'#a ]@#:&32d{.}OE0r' ^-W#"&'.7632"54>7>7#".'&76;2326?263263232632#".#"#g 7 0H 7"r!F-,4H  % f..); ,!'>)q }Jd,&%'d , D6 (&+  #  "0 / &&% %' wXyzU#"&'.'&632"&54>7>7#".763263263232632#".#""#A-/$D) )U(eNf&4 h ( (f (D-\>+  NPYz7'1$ .= 5A %  "2"]',,U [~$+$ .- 55jX&.56.#""543763654672>7&5.473727632>32#".'"54332654#"".'#"&563272>7654'#"&76;2O7EPB")&&% $   >GO#z5H[RP,4 $.IPW` )"  0  ;&,,  '   P!`* 3 (D,*-`EF3 *6y6n# +::)@= Xhv%.'"56'&#"'43>567274&5.67632632>32+".'"5632654.#"".'#".'&563252>7465&'#"&76c u:  S)=! )Zn;&)6G *_ $^/.C^pe`5E >,Ua !E1jz 4*  %L-)- 7 a; u 7 &!;" )V753wVW> 3E11FP($J IG= Jq{'2654'.'&7616#""3632"54>7#".'&5623263232>7654.7632632#".'&76332654&#")@e/C %+ 74'5   !    J"P&,-=, 3(UY4!(D#=!7D%Q2    9   %'H!Y v A.:X$$0(V=3 ScNq{ A#".'&7#".'&62654'.'&7616#""3632"54>7#".'&5623263232>7654.7632632#".'&76332654&#" $""CP #N%)@e/C %+ 74'5   !    J"P&,-=, 3(UY4!(D##2 5[%0+=!7D%Q2    9   %'H!Y v A.:X$$0(V=3 ScN6-23%'#".'&76;237.'.'&563232632>32>32"##".#"32632#".54676323'.'#".'&56326 ;( (     ! T"8S0 (]+&2, %/:T/XyuK* YQ!Io6jZ $kg(- 7# !+*(    4$$  K` !((g"'\ .C97`? aE $6 #".'&74#".'&7623%'#".'&76;237.'.'&563232632>32>32"##".#"32632#".54676323'.'#".'&56326  $DDQ "O$ ;( (     ! T"8S0 (]+&2, %/:T/XyuK* YQ!Io6jZ $kg(- 7# !7 $14Z&0)*(    4$$  K` !((g"'\ .C97`? aE $/R0%#"/.'&547>?>=4&4732 k >|D/c0 !%)VL  @l4oo { Jt6,:0 TE !E)5#@=   ,V:vCzv E#".'&7#".'&6#"/.'.54?>=4&672172v $!"DP #N%z`$%DL#2 5[%0+n BE 5 &7@  A'!@c!  #0Ua0Bh2#5>54'#".7632>74.'&6326%>76#"&54654&7632t *8[JVj + M#[;  /#fL # !&0 39]E?(37i' <:  D<5 "R p.9orB9e8e *Kz`#".'&632#".'&76#"47>54&5#".7632>7.'&632632%>#"54654/4'&632  $O  C "O$Mx.FRDJ` ' K_=  U ` "(<".&$1  ]&0)q*ElCC B^ψ  76  )%C) F w'0fo/?D0[50| . ?0A%2#".'&5463326+"##"5&6727.'.54332632 ^KxE1)-%6FD -ngKl!OPCCBI$/# S'"' !( 93  r>a#".'&632#".'&6322#".'&5463326+"##"5&6727.'.54332632  $O  C " J $l^KxE1)-%6FD -ngKl!OPCCBI$1  ]&0 )$/# S'"' !( 93  Xc'#".'&7632632327.'.'&4326327632+".#"72#"'.54>32326R=5%"#    4 * V O"   TN\( +* DDV-2I"X#".'&632#".'&6'#".'&7632632327.'.'&4326327632+".#"72#"'.54>32326 $N  P "T %R=5%"#    4 * V O"   TN\( +* DDV-2I"ii,454&'&543232>76#"&+  +$Mo.U,O?Y0hNn m  #CFO@ NK&P(:u4H#".'&632#".'&6%4&543232676#"&54654&546 $N  P "T % ' #FZD Y0RU2\E%0 C'/ 'K 3xIb4R%3fb# L# _3267.#"'2675.7632632#"&+#"7>7#".54>3254'#".'&546W,=  #8F"9. 1 P8XA590V )X'7#.*3' 'C!$&  M7OO" " ,  3@,""q&3: #Y# 6&'?%  4'+ L#*~#".'&72#".'&63267.#"'2675.7632632#"&+#"7>7#".54>3254'#".'&546  $ N  Q  "U $PW,=  #8F"9. 1 P8XA590V )X'7#.*3' 'C!$&  C &/  C '/ $lM7OO" " ,  3@,""q&3: #Y# 6&'?%  4'+ f_tv%".=47#".'&54627>54.7667>54.763232#"&'#".'&76327467"32632Vq[*p! 65 D 3  3 iX }+  2 Bp '#*&. S_0ZF0/`. "-&F#  H? 1 ^F %X#* 2, |D "  f_t #".'&74#".'&76".=47#".'&54627>54.7667>54.763232#"&'#".'&76327467"32632  $DDQ "O$Vq[*p! 65 D 3  3 iX }+  2 Bp '#*&. S $14Z&0)0ZF0/`. "-&F#  H? 1 ^F %X#* 2, |D "  wCGO"&54>76?67"##"&7632623263%$32#".5467 AB  nB*@   &6: ;50DD0IQ=W  *c~ ==$(W'm')( 3Z>1C! #:_2Pw5 3wC i#".'&7#".'&6"&54>76?67"##"&7632623263%$32#".5467 $!"DP #N%< AB  nB*@   &6: ;50DD0IQ=W#2 5[%0+  *c~ ==$(W'm')( 3Z>1C! #:_2Pw5 3mK2Ll7"546767#".76327654.76327632%"&546746232632"=43>32##"54>7.+"&m- =;& \69  7t[Psn9M 3 t9 =5/4%LIK$Mrn%&<?#! W> '@3 1 4,  5   mK Nh#".'&7#".'&6"546767#".76327654.76327632%"&546746232632"=43>32##"54>7.+"&e  $""DQ  "U $um- =;& \69  7t[Psn9M 3 t9 =5/4%LI &/ 6Z '/ $l$Mrn%&<?#! W> '@3 1 4,  5   U_R"&54>7"#".546327654&632>32>32"43>54&#"G $K' 0 GT- 5 =B4  Rn=d5*F5Z_M8,e)^ 701!h !#= ( Jt*$*!`M3b& R;S24~i|#".'&72#".'&6"&54>7#".'&546327654&7632>32>32"5&3>54.#"  $ N  Q  "U $  %P   O $P2 7 D,>}6  Wt>'OS4cI5aIq=' 'E+;5 &/  C '/ $U $qT2 \ !" # Af$% A,[P /3<* #*5Y("&54?>32#"&#"543>765.#"#+f}9dxe>\H=BuPe6 &!kPKJ(:+7$((qj."&54?2?632#"&#"543>74&#":7 'p{gOu:#9CG6RIhT>`yFMQ/? )+1NN'6Z<,  &8d?Wf!'!qN#".'&632#".'&632"&54?2?632#"&#"543>74&#"  $O  C " J $U:7 'p{gOu:#9CG6RIhT>`yFMQ?$1  ]&0 )? )+1NN'6Z<,  &8d?Wf!'!D]aI@4>7##".'&543767>32#".'&*>THL )z)bn[   dm., &"C60rw=kIC'+   +    Tk/$(V2/D]I \#".'&7#".'&64>7##".'&543767>32#".'&  $""DQ  "U $;*>THL )z)bn[   dm., &"C60r5 &/ 6Z '/ $=kIC'+   +    Tk/$(V2/"2467.'.4&3432>32#32632+"._G P6 ;"c<Z=j""#L7>u.-  !T %7#AJ'@0*K L#".'&7#".'&6467.'.4&3432>32#32632+". $3& "T %_G P6 ;"c<Z=j""#L8%0'/ '>u.-  !T %7#AJ'@0*KO2>}"54>7#".'&546327654.763276323267.#"724&54>727.7632'&#"#".'#".4>"P*2% W S Ls$R}McvE/1S a(=#9:@-  @H6!26* PQ = Z63L"&NR*4L 7&*:Q'"4//,PTAW+  +0 760?&D082*! $whoZ3^%#"&54>743232632.#"&7>32+"&676%762#"5654&54654&'&432o~  62s :1S WCc)#W)=(34 *! 96TC& "&'   $ %&( T YvERrq Sg"<6C K  X ~327&#"67327&'47.'&7667654&7632632#"/#"&54>7632654.#"#"/#"&V%KCD95W%5"Es &"&G$_VP % 1D2x 3Rd6d%8*HN' ,P232654.#"#".'&'G1(G^'<1$i 4 8  !.B" 59^Hd,?63F** 5)!!.@28( 5 e:$ ,3'`! 6 ?%N/*FJ)TH! 0QG'* !<>:Q()V.)(O(74&#"#".54>32"6762>54&'P&y1#?+WrW" ;'K|nJW3Pz -ػW][i\=%>4&*, 6)^ Zd\+uS Z%327>7&#"%4.'#".'&76327&=4.7632>32#"/#".5462667>76#"&5454&'&5432K3>- \?&F ,4?E #D 4 )= Uj_Dd /7).F"TOM2  ) & +" 3> 3Y3j $(G!  ' #   ;E *5  >)+$ (5 lE( 7&#"%4.'#".'&76327&=4.7632>7.76'#"/#".5462667>76#"&5454&'&5432 $""CK3>- \?&F ,4?E #D 4 M$,>%N>_Dd /7).F"TOM2  ) & +" 3#2 5> 3Y3j $(G!  ' # $$ ;E *5  >)+$ (5 lE( 7&#"%4.'#".'&76327&=4.763267#"&54622632#"/#".5462667>76#"&5454&'&5432]&&&K3>- \?&F ,4?E #D 4 t)(:)Uj_Dd /7).F"TOM2  ) & +" 3N&&> 3Y3j $(G!  ' #)))%  ;E *5  >)+$ (5 lE( 7&#"#".'&54632632327674&546;2F0<,E]mANP   m 8PO87+.9H&   7|AF -%8m>ca*()!BQ\pfXv|<8.Oy1To#".'&632#".'&76#".'#"&54>7&#".'&54632632327674&546;2  $O  C "O$ ** 5$A[g=IL!e ;'F,D"   4$1  ]&0)v !Ztle7l@ba0)(!%$#!P7I)8- r=?Vy+R b2"&546"264#".'#"&54>7&#".'&54632632327674&546;2h)*8))/&&2 ** 5$A[g=IL!e ;'F,D"   4)8*))&&v !Ztle7l@ba0)(!%$#!P7I)8- r=?Vy+yq_d7>7.546=4.7632#".+"4326727.'#".'&7632654'#".'&56 "$5;Q.1f(!A *L7w (B$D<' 4E<".'  ) L',4%5   $(" M7*w  7R-,)= 2 :($* $\( Cyq_ #".'&7#".'&6>7.546=4.7632#".+"4326727.'#".'&7632654'#".'&56Q  $""DQ  "U $ "$5;Q.1f(!A *L7w (B$D<' 4E<".'  )q &/ 6Z '/ ${ L',4%5   $(" M7*w  7R-,)= 2 :($* $\( Cyq_ w2#"&46"264>7.546=4.7632#".+"4326727.'#".'&7632654'#".'&56))))0&& "$5;Q.1f(!A *L7w (B$D<' 4E<".'  )))):(&&= L',4%5   $(" M7*w  7R-,)= 2 :($* $\( C?,"".'&56326232>32#"'.QEH& >=S%($%!"8Q PSR;H;#080 #&>H JeFo' J#".'&632#".'&632"".'&56326232>32#"'.I $O  P # J %LBD$  :8O$3?$0RWd#2 A%0 +6@6 *2*6'1rG L`o <2#"&546"264"".'&56326232>32#"'.:)))X&&LBD$  :8O$3?$0RWd)))&&G6@6 *2*6'1rG L`nC o%326?&#"&'#"&#"&'"5>3263>32632#"&'#"&54632654'+"&'.>2327&%762#"5454&'&5432qT()I QE1D %  `)  & ^  IQBD 08'YS}=1F,$  Zc| 89(+'6-  3'&%2lV % %  RB(%* "& ,G(>-?Z  WD nnPv0-^*L"C %#".'&7#".'&6326?&#"&'#"&#"&'"5>3263>32632#"&'#"&54632654'+"&'.>2327&%762#"5454&'&5432 $""CP #N%T()I QE1D %  `)  & ^  IQBD 08'YS}=1F,$  Zc| 89(+'6-  3#2 5[%0+t'&%2lV % %  RB(%* "& ,G(>-?Z  WD nnPv0-^*L"C2#"&47"264&326?&#"&'#"&#"&'"5>3263>32632#"&'#"&54632654'+"&'.>2327&%762#"5454&'&5432?:())F&T()I QE1D %  `)  & ^  IQBD 08'YS}=1F,$  Zc| 89(+'6-  3):((:&&'&%2lV % %  RB(%* "& ,G(>-?Z  WD nnPv0-^*L"oX j%32>7&#"7254'".'.7>;&'#"&546;5.'&632>3267.76#".'#"&546E-/> 4KO="34I_ )Y1 9 j+ A#=h,,F}pHm2Sn@Us,"5' 6` .Q* Q32 e %9  0U/ ""5$c 5QNY>3764>;67&#".'&76332632654&76#"/"'4>767&'#"&&9#   &L9\#(T4v0) H!.$)F>!L }H.now "767&#4632475#"&'"5432?4.7632>3232>54.54632+"#"&#"43676=32'4&#"#"=#"&%.++oL8  h!u!?" 4ofN$ z'|p---#$Y9   @c(ABPu[ 'M(!)4  V2CA >'D!$+0 # # G4 x"$*-Xx56HNX;(5h%6 TPkf]673>7&467'&'.'&7667654&7632"1"'47654&'".'+"&4+_7jTH2!:9)Q] Y  w}(1F`N7O?.VCz( H5'I?=uo_@x.(U?N2H9+ /J$Jf"#((:e>o[%bgk b4i6W f67'4>7.'&76654.7632#"'#"'32>7654&/6#".547&'& X=%cZ?RQ:@K :}C#  I! 0 1>+9GZ/S6! ,- &7a;%HG+Ob-^^ 0P59 1 '.M&-1* > wY  ;5EQ+BM$ *ZAf'@TE0.\?*C >T9U%"'./#".'&57627&546;274&7432#"&#"7632#".'"54332654&#"M, 3+;5   --+/0, 5 G 37#toKZDH5)5 &.A2<1^NV ndQ)c *  >)(5< "F*(A,/8  +%0S |5BJ[%#"'.'&'#".'&54627'.546;274&7632+"&#"7632#"&5632654&#"b  A6 4J+!  77 @ A=:CX @,/! Y;S'ZCJ*L@M>x_n' j#d3W&!4  :5$ FJ  #$B52-*:E*6$.7&'#"&5&54654&54>7&54>32632AK#:/ 9F7) `"H%!#` "X%! % * # +E% 0F#$Fp!5zLbgM';*-Q/"UPhj Q <(3[_@ / o )]   &+I,L[?V'>@!&HH+zo~ c67.'"%32654.'654'#"4767&'#"&54654&'&54>7&54>;2632#"\U* %E ;GW%0!u, :N&38m J    4 , 7$V*59+ .N2)M)3ayc2M) Q(z %(" -7 4[ \pNl #6[9"EM;'n H%3265&#"46;24&54654.'.'&32>32#'#".'#"&\H3>F5T^    MLn p-E#v0  /R65GD@< )5 >&^%>6 - *! /=B# * 5kAz J7326765&#"4;23&54654.'.'&632>32#"'#".'#"&x6B$QWB %    ^Lh0!-> ] Fh8XoEWU'D%(v_9n-"'&EH !' >#7^ P& *4 KWASOP#43676&4.632#"&"&5467>7633>32#"543>54&#"s6"01 =; !  WZ@3O, T9aQM-Sa '`+ K . `h(!%T4L 34+$3?/~N+ &3N/Be*M<"547&=4654.5432>32#7>54&#"U 66s%)(-@,h >Z-% 9/# #rn+5 "$LOho32>54.#"c<>4 ("8 >!. O6* 5ő`jUg,*/Y7D-$H/.~PT, 22)Y )@   -.8# 7=kXg?3) H4.I()0!+'-Mks6565'2674654.76326327>3232?#"&54654&#"#".'&76654'#"5475#".'&54l G%G)  2&2J7*,@?JG4>5*"@68*' ,'L ;,#" 7 #=%H&( ?8!6QTA$)J,.]L>$)4,772t}K:$U&OyFR_ ,  {<_=632#"'43>54.#""&54>7>7#"#".'&63326k+|+dUP8p$K1^5 4 ;;\'x-VYIWN! !P $-Q- 7'#2 1e0 f%=47#"&/6;6765.763262632"'>5.#""#".'#"547k+6& 0% B &tq1I#L:c5<>(DPfc $8[4 5F $ ^2!   F e-A6RE"1N.>_f[<6 H&- "bp m%=47#".'&7632>7654&763263223632'47$54.#"#".'#"&54746J)* $ !=  6 //L ,>\+_(8'L5{  (  63=&  $0~7 ( O }9SDcZ%7o"?>%jSFB !H'8! jd?d j%3267.#"'7>767"&54676=".#"#".'&6322632632#"&546;2654.#"!$U%(2%7&#".6332>>32#"'#6322>32#".#"#".#"#"'"5&54>7&5463232>54.#"#"& * &˘,55SD> .O73C(Pf8RAHP #)63m, !4 %J *%1fL  [5=&*+ 0H#';.*;M"    !$" '{O$[A-@ <  -("# $;: <`&1$ *$ +D  VMzu&#"'&5>?#".54632?67.'"5432632>32>32>7.76#".'32632#".546:-K)'   (@q7 Ke-X/L# \ #,6T \$OL&8%H/& %>E `^eb#88gc;| ' B  !#5I%(+7 !) $! j;f:x'& < 6%,yg{B%".#"#"&54>7654.7632>3232>763,9)!_S  5 5 ">)2>,&D='0@Kz)u|134&6#"47>7"#".'&4332$72632#"7>75&$&6 \ AM '& *C< #`_-S#; #"*eJٽ U@"^ zz;4.76#"767"#".'&43232$726;2#"67>7&ND)D S`ɯY6I ) xw=f 48)+62A  _ ' %kP.t&U64&46&'#>767>?5654'5632#"&546c LNC3-B+>05C    n""/#_9&L  1$@?  6G: |K>4654&'"47>767>?5654.7632#.54654&{#|`q=Q1T :77    . #G')sG+c  =?3 >T^*(r| ]4&5.5423234&54#'.'&6322>32#7>7>54&43'.##"#"&46 ' >N & H]3+=0PJU1%6 $  ! !!10#5A^*!w $= <zLZ4&'5.54623234.54&7632>32#"767>=4&##"+"546   . Ma.0_y  ;6L;eR('l#%   t)  $E','*!=<+D*%  % N5EH{`'&'4'#".'&63276;2632+"&#3;2#"&##"'##"&/47632672634>546 6F  J !k[46464&'&5"#".'.63232>;2632##"&#2#".##"'##".'&546374CV R %!0W )*' -v_% ?} ;Sf  K )6 _% &  &;C+    '   eJQ%4>=4'>7#".'&763274&54654&632>32#"&'&#>-='PqHY^ O(B 8 1.[)  b02 FF32;U4.+K}*,F01A 2 P  za}V#47>7#".'&763754654.7632>32#"&'63&54>=1*O;N2aX#'  b$ 1H=9s2 'JK1IlB;5Y̙  49/!;>S A,# @9i  WD?]x]"#"&#"'47>7#"&54323763>54&5432>32#".'.'3>5 &3QZsU9bC:#  J]@ H$\\* L e&(/-  /;:3, {WF3%OHK@@2 @ *L S"*! bV( &E G 59"}j] y#".'&74#".'&76"#"&#"'47>7#"&54323763>54&5432>32#".'.'3>  $DDQ "O$ &3QZsU9bC:#  J]@ H$\\* L e&(/-  /;:3, $14Z&0)a {WF3%OHK@@2 @ *L S"*! bV( &E G 59"}joO}_"&54632>7'#".'&7632>7./.'&632>32%632"&'.'@ / !.lC,5F  E! =-    H &f1B @9~6O G 7|E    * ' 0,    D99  T    *=>*& oO~#".'&632#".'&6"&54632>7'#".'&7632>7./.'&632>32%632"&'.' $O  P #N%s@ / !.lC,5F  E! =-    H &f1B @9~6O G 7(#2 A%0+oE    * ' 0,    D99  T    *=>*& |!tI67&54?54/632>2#47>767"&#"M! #Jc   0.D_>=fPB1)aJ$20C_ E #      sW'#>>&F%F>=998<="5@*&|t e#".'&7#".'&667&54?54/632>2#47>767"&#"  $""DQ  "U $WM! #Jc   0.D_>=fPB1)aJ$20C &/ 6Z '/ $_ E #      sW'#>>&F%F>=998<="5@*&x}wS6>7654654/37>32#""#"'+4>7&6>?654.732>1j?q 9X:% %"00W;(# 5V'O& 1f 6!"2@(W[8[ 6#  &17 #X8%- Ax}|,9r6>7654654'%#".'&632#".'&6%37>32#""#"'+4>7&6>?654.732>1j?q 9X:% $O  P #N% %"00W;(# 5V'O& 1f 6!"2@(W[8[ #2 A%0+56#  &17 #X8%- A7A%.#"#"&763672636'"#".'&54276 676326;2#"' H8 H  ' </+6 Y M/-   T ~`#".'&632#".'&72.#"#"&763672636'"#".'&54276 676326;2#"' $N  P " L % H8 H  ' </+6 %0 C'/ 'Y M/-   T }tu["&=4&=4'#"&54667&54.76>7>&/632632+"&#">7a 79: G> #c_y*6  , !8 4!< ,A"o   P Q$A&#53 KE [TI/ *_Ma;Z">0}zz#".'&72#".'&6"&=4&=4'#"&54667&54.76>7>&/632632+"&#">7  $ N  Q  "U $ 79: G> #c_y*6  , !8 4!< ,A"o  &/  C '/ $  P Q$A&#53 KE [TI/ *_Ma;Z">0vHX7#"&563#"&'&76"./6767w  N n"S   ! ]~^ma3B d$ .2  ,/[ zd)5v[X ,9S#".'&7#".'&6#"&563#"&'&76"./6767[  $""DQ  "U $w  N n"S   ! ]~^ma3B &/ 6Z '/ $ d$ .2  ,/[ zd)5xDC%#".'&'"#'43>767'#"#".'&727>32326324O *T ljU*W7 S ]U !)+XN]24[v2g6ZFnyP2  "   333M2xc#".'&632#".'&632#".'&'"#'43>767'#"#".'&727>3232632  $O  C " J $14O *T ljU*W7 S ]U !)+XN]2]$1  ]&0 )4[v2g6ZFnyP2  "   333M2pdmi%4654&5#"./632?4&54654.7632>7>2>7&'&/3#&#"32632#". 1M %" M  #>"o) *ZF  =>%@9 X~-bT /  ,* p$'>!!@G!P#  E" Ia%@*!   1pdm #".'&7#".'&64654&5#"./632?4&54654.7632>7>2>7&'&/3#&#"32632#". $!"DP #N% 1M %" M  #>"o) *ZF  =>%@9 X~-#2 5[%0+ bT /  ,* p$'>!!@G!P#  E" Ia%@*!   19I4&5".'&%4&7432#"547>76A &(  M$"lm>dJ'%$D 7!5_,3   ?;fB)Ed|!/S#".'&632#".'&72&5".'&%4&7432#"547>76 $N  P " L %1A &(  M$"lm>dJ'%W%0 C'/ 'D 7!5_,3   ?;fB)Ed|!n -H4.'63>32>7.'&'>5>='#&#&*  @uv`TV. (_EJ4 YBg& -" Z#2"7   !pU01c\;%&450+8&>%  $n Ni#".'&632#".'&6324.'63>32>7.'&'>5>='#&#& $O  P # J %$*  @uv`TV. (_EJ4 YBg& -" Z#2"U#2 A%0 +   !pU01c\;%&450+8&>%  $u|uW"&##"&7>7#".'&546;23267&=4&54654'"5436$7262&632PN-?(3@  x 5Ob Fm# }!@XOoJK+?og20&  & [)G uw#".'&632#".'&632"&##"&7>7#".'&546;23267&=4&54654'"5436$7262&632  $O  C " J $2N-?(3@  x 5Ob Fm# }!@XN$1  ]&0 )OoJK+?og20&  & [)G z%C#".'.'&372#".'.'&5%4.732"547>76  M   .  &Qd^Ea}4) 3 3'# A$y- (  #6"  $(Y>)Dgr4x]q$E#".'.'&32#".'&546"547>7654.743  a   #53 >`L6   /f7654.743 $N  P " L %I  a   #53 >`L6   /f76?45"#".'&763237376;2#"&"&#"#".'&5432>32  S   (:)A )MZ'  44_tRZT0+   G iak 06HC%) !>.__>'    ,  tp;Zz#".'&72#".'&6.76#4>76?45"#".'&763237376;2#"&"&#"#".'&5432>32  $ N  Q  "U $m S   (:)A )MZ'  44_tRZT0+   G iak &/  C '/ $ 06HC%) !>.__>'    ,  *Rs1".'"&54654&54654&'&542,4}Q 6<2LW+s/Q(8UF <;1+1; _H 0*R s M#".'&74#".'&76".'"&54654&54654&'&542  $DDQ "O$ ,4}Q 6<2LW+ $14Z&0)/Q(8UF <;1+1; _H 0~ytI"&+"476765"#".'&57632>74&54654&/6326322`H8S9%Y) I &oQ  ;a^R) \xPM1<^( ^*5 79C  t8"#".'&57632632#"&"#".'&543;232632#"&Au$m zz bd    T^?3!2  ["   NE".'#"=47$7.76>5#"&/4326;23>7632 ! 6>d-%M4*'&W  &  co 5K(q+:JQo?.*  K8)    +q!x\rb#"&'.76"&76354767&767>7"#".'&763>7632#"&54654&54.5'&U2X* 'PV+# H3=>y0g% /Kt\ *!   R ) .Pl $FL^)%    $D76/ISb.DiE0$5 -3/S=@-XIR?T<^!v/#".'&'&?2"57>7674654.732 *T<O(4-B3B 7L98v.>@$CdM J7674654.732 $O  P # J %" *T<O(4-B3B 7L#2 A%0 +h8v.>@$CdM J7674654.732v&&K:)))k *T<O(4-B3B 7L&&2)8*)18v.>@$CdM J54&732632#"&546=474&'&42!)=G< F\=CLf\V8'Y% !+  S!60;O [Ch4K]` ]#".'&72#".'&632>54&732632#"&546=474&'&42  $ N  Q  " L $!)=G< F\=CLf\V8 &/  C '/ $'Y% !+  S!60;O [Ch4K]WM"264&2"&4>54&732632#"&546=474&'&42N&&K:)):(!)=G< F\=CLf\V8?&&3))(:'Y% !+  S!60;O [Ch4K]&4"#".'&546326?632#47>7654&5&h# _ GOO ZpL1j@mKG%.   +*   # u3.MB^8e#/ U#".'&632#".'&632"#".'&546326?632#47>7654&5& $O  P # J %h# _ GOO ZpL1j@mKG%.   K#2 A%0 +Q+*   # u3.MB^8e#/F"264.2#"&4"#".'&546326?632#47>7654&5&f&0:())Xh# _ GOO ZpL1j@mKG%.   &&):((:+*   # u3.MB^8e#/s;)"&/32>;232>32#".#" "  FZ'I+G"To! } <<"=5AbwbS s;$H#".'&632#".'&72"&/32>;232>32#".#"] $N  P " L % "  FZ'I+G"To! }%0 C'/ ' <<"=5AbwbS s;@;"264'2#"&46"&/32>;232>32#".#"&&-)))) "  FZ'I+G"To! }(&&2(:)):( <<"=5AbwbS [ps%%#".'.'&767>54&7654&546=4'#".'&57632674&54654/.76263632#"&#"#"#"&'&736p&#3<B70W\ect BhU / " 8  y&< &M*2Vg)>d3:y#O8{#@ #(  )0 88" 15 $.S% V  [/C#".'&632#".'&6#".'.'&767>54&7654&546=4'#".'&57632674&54654/.76263632#"&#"#"#"&'&736 $N  P "T %1&#3<B70W\ect BhU / " 8  y&<  %0 C'/ '&M*2Vg)>d3:y#O8{#@ #(  )0 88" 15 $.S% V  [p#7"264'2#"&46#".'.'&767>54&7654&546=4'#".'&57632674&54654/.76263632#"&#"#"#"&'&736&&-))))&#3<B70W\ect BhU / " 8  y&< x&&2(:)):(T&M*2Vg)>d3:y#O8{#@ #(  )0 88" 15 $.S% V  w<%#".'.6>767&##".'&533>7632+-M&'E4-   0Z"  eݹ4 'LF)+L >&5 . +&'##    -    "+f Tp(9%#"&'&'"56#"&'.=4#"&'.563` 0:\I-%W9\1"  ,w9Z3LD?W")lK=+%O2  &A #$v>&A%#".'#".'&5432%.764&54654&?3#&57>4 4&$ n /: $ #=--[)-- 2 (V2T&\ ,#A"\[zt4".'"'47>7.563>54&7632,)3@M^8]P*54&'#".'&732$32#"&#"6;2#"&#"32632#".6{/ 21*b 8! 66?#^=H g,,)^$:/b Si4L:$  K ADA$ K].(;!&2BPX4N%#"./"&/532632327.'.'&632>7>3'&>767* -C!   r    ?+/ $OU ) #;w 2:A^ 17  HL  !W3 + 8  ]Lw+$}QqO%#"./#"&5423263232>7.'.'&632>763&>767"6  , ?  %" 5.##"&/63262326326;2#"&#"#"&5+ rx   jr  'J6)nk.,,@0X    _G   5 yCF"#".'&5763>75>765.##"&'&763263232>32632#"&z W&@ )  !cu2 0@@7 N *  $4  'uU  [43326?2+"'#"'&#"#"#".'&74327>747#"#".'&763>3656'34'&+"#".'&  , FG  ]),L!%dS ?   H  $ - %$-eZ2$3232+#"'&#"+".'&732767465"&#"#".'&763%676'56'&+"#".'&542Dg   &! ! W&$ , !Sh32 Ci    -  1/ B7 Z-D".'&542332632#&7>76=&'2"'&/432326z q>)UdYJnP4+ -5=n4*$5 _# "mG<%#AF8T;5  "#?zt'C4654.7432#"47>54&4654&'&5432"&54& 5 2\2E!  5%6 #K)S$`9vQh)+dS!O  +*` Qxk'+J632267>7#".54>54&'43#47>54&546 . &sOHy;  % '6:K &  ui>\# \#XaQd  cʇ p l" (3L8, 'agA( #T*'63232$7#"&54>ED)nC$EIuM p/ f0 s" pQ)?,9-M45P22+&'&#"+"&5&5&47./&'&4332>32632636?.#"#"'4B D   MLSp%! F#'  )\Et}     oA~78 ,F0]' ?2>76&#"&#""&54654&543263> @+f8R9%  !TL  7x>Lc vT$!?B (IL=X<8    8  < >*GD"#"&#""&=465./43216$7632>76'4#&pB  =Y 2$2F2^<_B4    IK N   '/?!;7"; *SFW>d?< Rctx232>7.'&767263547#"&763263232674654&?26;2#"622#"&+"&5&'"#"&563269('5 :?qv D   <$2V480B>>&  e9*D  $ CH #A ?]% 5 (H   3  pb;k^4&'#'./63232$72632>7>7&#2#".##"'##".'&54637474646 ' 4?$fAiAW=5F  v_% ?} ;Sf  K =a1 /  @ )W  ;C+    '   )6 @3M2>72674/#&#"+"#".'&43232>32#&7>7#".'&76|/e : K 55(T X|N3k>)\"  \6 )  !&5/D0 sl/#"&'&74366&232676763#"&5326" '  &K*Be:M-R~ &CV9uK-32#"767>=4&##"+"546  $ N  Q  "U $,   . Ma.0_y  ;6L;eR('l#%   / &/  C '/ $)  $E','*!=<+D*%  % N5Ec*U#"&#"#47>7#"./632>73654.7632>32#".'.'>7> &FJ^>x/n  1G>  ? lS  ' .0 LawD:$N =/ C> I$Np. 8 2 '0J+}CE6>?654/32>72+"#"'>?&657>54'7432/0S5U ]\& " Q9:L):;:(6 )1As  1#   %%"GR 4"usRu"ubk"uv&#uF6yus"&#"#".'&5433>32p Om$:9#Pw!2  +  "8&567#"&5463232654M-PLVS)527jp<>M{<a#"&54632'654   !".>2 R 3&-T822 5@"&=46 4&#";26'#3#'#3#5254Ȕ4&+"676ʏ(}~~# x _/1 C"59<Hʏˎ~~~+   e"+3#+323273#.#"326?#"&5466  264&"F?2:M@J$2   Vjo⢳(@cH?^   lVWo%W7!54/3#525'%33#"3#525#3#5254&+=M%23%M`r~p)2333 aC8Ca 3 oP3#88'5!<V882 .5"&=46 4&#";262#'.+#254+ʏ}~~<=# :}1GGzʏ~~~G.;#>L0 4|F=1 (04>32#.#"32673#"&6  264&" &@( ," 3?(8CD7/?//+HK]⢳B48* 1!!.YICTD$80-k-%##5!###33#1}+}2i1GllG1%Q++5|C5( #7>74T"JT=.pbW KoI'(\3#(44( .'&3\ .=TJ"T4bp 'IoK U!#U77I737OT3!!7I7 #4>760\Bf0"K5CU5/ M674&'5>=3#ZabY6&..) )..&6V$V8Y4**4Y8 .53B\06"0fF /5UC5X6M36P L3LSX'6 %'7# .=TJ"T4p 'IoKZ3#446 6364T"JT=.pZKoI'h!#!R71h317Oh3!5!177 #4'&'B\06"0f /5UC5S6M#54>7.=3ZabY6&..) )..&6V$V8Y4**4Y8 35676560\Bf0"X5CU5/ M6#1=#".#"3##5>5##5>5#53>32632%"347.<{z)+)+DDljW+J"B)? #nYt ) .D) .D m|''>Q+P1* 8".#"327#5>54&+#5>5#53>32 #"5 2?*.HV**DE ,P5:E> ) A+ 5-03()0C!"5E- &   %17>5#53>76323267#5>5##".#"35 ,EG-L H 9)'+E A 79 BH ?'%N"H4#GT"327#5>54&#"##5>5##5>5#53>32632#".!"367.1)?<5+/"L5 )*)+DEljf6_0N$)?#>Q+ B .!0&)!-D) .D m|33 ( >Q+K3#3BN!#5>5##5>5##5>5#53>3263232675#".#"'"347.% '/)+DElj[*?H 6 ' C)?$%N$!59) .D m|**'>Q+J5*!3]4>7#".#"3273#&#"#"&#"#5332654.5463&54632326?63#327#"5#& , MM,.7!  U.+l**W:M 6<#./CB/T:5I4 H7@ ee3! @#\5 /#66<-"B {$.@5)9H CI&#-#'@)9A5=4I)2)t T# ,-#">#">>#"#",8>#">#",8>H#X@% H#mH%H#"H%V#">&'(V""V>'T#">(V#">)0V""L>*0 V"">+V#":-=w""^@.4#";/V#">0K#">1W#">3/V""V>5V#">63#",88V#",89 V"">;4#"<<V#">=V#",8> V#"=?0#">*#&#0#9rv #%'7%4.'7!"&547'?'7455 B,79G 4*4555557743C' @(U+7O}e*&7749774rv #%'7%4.'7!"&547'?'7455 B,79G 4*4555557743C' @(U+7O}e*&7749774|- 7'7'?'7#'!54'9::t999v9::--4 8::::;;:I:::ATJnS f8|- 7'7'?'7#'!54'9::t999v9::--4 8::::;;:I:::ATJnS f8{- 5%'7'7'7237# 327#&'&5&546767.#">>??>??>??rZ6'O7r%0-A?a6o63""5p??==??===>!?MO#A@&-/2 @=CyIv "}/9=A%'7;#.5%237# 327#&'&5&546767.#">'7'7433 +2((iY5)H0nC--@>`3r43 0;433h433 443>R,Q#?0%y!>LO18)"$0?= CxHt 0&4433443b %'7'7'7>32!"5%'&#"244422#333 "o>c!T;3333333443U'M9#LKZb %'7'7'7>32!"5%'&#"244422#333 "o>c!T;3333333443U'M9#LKZgk '7''7'77>7654'k455466455 16h",0A&!K221G220221EOOH +7`?65-Wgk '7''7'77>7654'k455466455 16h",0A&!K221G220221EOOH +7`?65-Wy[04;!654/&/&546?+%"'&5476Ij }= [~mk"*N2KI yA j2,5"&+%7!654/&/&546?'6ǀk"*4}= "_z2R6n'&"09*$#^N m=  :O/>j2,-2&#"32632#".547$7&+"546!!"]P ?YuRv<S 4h^..c_  V%vO5#;>"ksbS]8A 126=4#"+&5465476;"&#";2#.'547ri n*T-m2 . oLoMrfU[7* C0+ :2M#1@T AH cmV7G'/K7'7'7#"5!54';==;==--41@879999999>NEhN `5K7'7'7#"5!54';==;==--41@879999999>NEhN `52:^e254/7#&'#"'.54>35732654'73263%327523654'636#"'#"5473632654'67&'7- 7.m c<+"6B*7 ")7-Q#%[   "Wn-ASbBIKr(&-"M[F+)k!Pk"  )  I%f, (,0N#".'&'7;4&'#"/7327654'7'7'7#"54732654/5473X%*w1($IDBA@4977"`\; ,s7j*( $27Ta)C9e?#&2q 9723764AX10;21PN77>729;29J wJ ,7>7'7>7/:;/:J >J 6 7>729J 3kn'#67'&546324&#"6 2"]G5"4" ' @$'I #1*   ,7>7/:J X4#"'#"&547332>72654'7 !   $ %-   2 eQ23267#"&#&>54'73 $).694/#"07 *$7D){54'7  *b71UY.;"&'654'7 MWF/K,.6.QbcV=af~ %'7%4.'7!"&547444NA287F 4*665AN@)S*7N} h%$!~ %'7%4.'7!"&547444NA287F 4*665AN@)S*7N} h%$!? 7'7#!7!54'CDDZ-4 7EEDASIoS f7? 7'7#!7!54'CDDZ-4 7EEDASIoS f7{'7'74&'7!"&547ACCACC ?K47D 2)>BBCCBBCOD='P)5Kyd%# {'7'74&'7!"&547ACCACC ?K47D 2)>BBCCBBCOD='P)5Kyd%# *'7'7+'!54'9;;9;;,37::;<;;:BRJoSb7*'7'7+'!54'9;;9;;,37::;<;;:BRJoSb7 !'7'?'74&'7!"&547@CC@CCABBW!A777F 3*BBCCBBC7CCB8QF?)R*7N{f&$! !'7'?'74&'7!"&547@CC@CCABBW!A777F 3*BBCCBBC7CCB8QF?)R*7N{f&$!5W '7'7''7+'!54'===<>>===_-47==>@==>;>>=ASIoS f75W '7'7''7+'!54'===<>>===_-47==>@==>;>>=ASIoS f7|)-237#"327#&'&5&546767.#">'7JoXJ6'L5m0.-?>^8i54 .<544!?fkLR#A?&//1@= DvKv 0'}553} <%'7%#.';%237#"327#&'&5&546767.#">544N-A%8Dv[L7 )E,p%0.@@`]?(5 !"7T5548Yf #! !?flNP48*/01@>!DyJy  !]632!"5%'.#"'7g,W"[a~B544L5`LJX 554]632!"5%'.#"'7g,W"[a~B544L5`LJX 554z4)237#"327#&'&5&546767.#">J pYK6'M5r%/-@>^1s52 4; >djKP"@?'-.0?; CwHv  4"} :;#.5%237#"327#&'&5&546767.#">~8-( v[L7(N6o%0.@@`]?(5 !"7#! P!4+i!?flNP"BA'/:'@>!DyJy  !^>32!"5%'&#"0p;b~#Qa&""M8#LJX^>32!"5%'&#"0p;b~#Qa&""M8#LJXpZ(,237# 327#&'&5&546767.#">7'74jT3#G1i+*=:X0m1. -8o,++;FK <<%;<- ;9BpBn  -$,,+} :'7#.';%237#"327#&'&5&546767.#">655r-=, 19<t\O7*I0v$2/BAc[D*5 ##7665Lm B*"AimOS2;+132B?"F|Jz  #X'7>32!"5%.#"@200{#9c:B"#Pj110&"KI*-X'7>32!"5%.#"@200{#9c:B"#Pj110&"KI*-r4.'7+"=7~  4"87 $ O (8hCN`&r4.'7+"=7~  4"87 $ O (8hCN`&r '7.'7+"=7/977  4!76 997 #,&N (7gBM_&r '7.'7+"=7/977  4!76 997 #,&N (7gBM_&gY76?>54'E 07hSEE%EOH H 1 ddQ&-WgY76?>54'E 07hSEE%EOH H 1 ddQ&-WgY'7767>54'F8;;7 +54'F?CC> +"R C:F&?*! k( $Z$e47!"-E'  A/@h6H5 )00H8@E7&|9254'7+&'#"+.547326764'732=7r5(-)) !$:1+?Y!"5>"R C:F&?*! k( $Z$e47!"-E'  A/@h6H5 )00H8@E7&`,2654'7#"'+"'+"'27654'73254'7 "49+-!S !L  Q6Q,S$&&&&K5,5+/@7`,2654'7#"'+"'+"'27654'73254'7 "49+-!S !L  Q6Q,S$&&&&K5,5+/@7|=AEI254'7#.'#"+.5473267654'732=7'7''7'7l1',%$";0-#& )!j( $!/11"/11$/11W$c42% !7I,9&?e6F3 ),KE-H8>D7%---:..,---|=AEI254'7#.'#"+.5473267654'732=7'7''7'7l1',%$";0-#& )!j( $!/11"/11$/11W$c42% !7I,9&?e6F3 ),KE-H8>D7%---:..,---2+/372654'7#"'+"'+"'27654'73254'7'7''7'7: 9?01!$[! !%S  7788'788)699 X54'77674#"23276@$&%GR8QkA\-?",x:1JTRe@ 8'!""C[/oVOILS!45GIHix7R(32##"567>54'77674#"23276@$&%GR8QkA\-?",x:1JTRe@ 8'!""C[/oVOILS!45GIHix7RM"#!"'+&53>?;>4'!6o +`03// -eS}R-K7$h00F'}[D  6!M"#!"'+&53>?;>4'!6o +`03// -eS}R-K7$h00F'}[D  6!(372##"567>54'77674#"23276'7@$&%GR8QkA\-?",x:1JTRe@100 8'!""C[/oVOILS!45GIHix7RH000(372##"567>54'77674#"23276'7@$&%GR8QkA\-?",x:1JTRe@100 8'!""C[/oVOILS!45GIHix7RH0009$'7#!"'+&53>?327>74'!6`100"+`03//#*\ WyT3R|]$000HCh00P .AvXC 9$'7#!"'+&53>?327>74'!6`100"+`03//#*\ WyT3R|]$000HCh00P .AvXC 8 6547632#!'%4&#"!6V? tf2I= :$)bSE3BVQO-';8$'76547632#!'%4&#"!6.//V? tf2I= :$)bd../SE3BVQO-';%$467&'5476;&#";673&'&>>W#A8F5D Mb.xr#MiohqKC44K* =91*8$R: CK}FL.A !|l\/;#&'327#"&54>7.#"#6g "&&df4JN5NA3J+hPh7F> = ' !LLY6rG*@*38yb@wO9  w+327+"5&5>3&#"V:e2@ _:8W"`63Y$\M1L_:5I'"%8%2;#"'+&'723254.#"#5>Z8LH$2JLH=Q_  B( %O>M]]MY>C,%)467&'=476;&#";673&'&'7A:W"A7E4E M_.wp#IdngrJ011><0J*=90)9$Q:BJyHL-A !b000|l\3'7;#&'327#"&54>7.#"#6122 "&&df4JN5NA3J+hPh7F> =221 ' !LLY6rG*@*38yb@wO9  wX"327+"5&5>3&#"'7J9].; V43M O8-S...]J0I^63F$"#2001[#'2;#"'+&'73254&#"#5>7'7c;LJ&2abJ?Rb   Dj111 ($LB\$%#6LN$"0 $#@>9W =1'J223+%/3#%.'67326;2=.5476;23275.''7V""S))S:L'!..4$T'*122 `>B\$%#6LN$"0 $#@>9W =1'J223>#)#!5732=.5476;2''7".(SP5K' -.S1000" !"BX?\J/ #"B98/2222 !<1>#)#!5732=.5476;2''7".(SP5K' -.S1000" !"BX?\J/ #"B98/2222 !<1i.<'7'7+&54&54733267654&#""546";27254/777f877n$HG[3 8rXmK  _A#) &27777777UF?,8-v`zgA'5/ $K3/p8/ i.<'7'7+&54&54733267654&#""546";27254/777f877n$HG[3 8rXmK  _A#) &27777777UF?,8-v`zgA'5/ $K3/p8/ 9%)#!5732=.546;2''7.#"'7$RO4I(8*.0//()%!'"/00=X>ZH. ##7w.220 3V12209%)#!5732=.546;2''7.#"'7$RO4I(8*.0//()%!'"/00=X>ZH. ##7w.220 3V1220y0+%"'&547;!654/&'&54>7m*U/(*N2Ob }= "4!8TtMW3)hD@u7m*U/(*N2Ob }= "4!8TtMW3)hD@u767K1kUQ*4}= "40\w]Rnfc_N j= 0 -(,0$"+%7!654/&'&54>767K1kUQ*4}= "40\w]Rnfc_N j= 0 -(,0$j%#"54732765?>rY=.LYHQ#Y%&4/4 UlR$aKJ4.o&)@0j%#"54732765?>rY=.LYHQ#Y%&4/4 UlR$aKJ4.o&)@0 '?6'((-+lN\  yJPMm '?6'((-+lN\  yJPMm7n%"&54732#'&#".'54>32&Pkd8$GF1=  ?(l_/&A"G'>$?0%7n%"&54732#'&#".'54>32&Pkd8$GF1=  ?(l_/&A"G'>$?0%2"/+5>3254/3%UMC/- 8ee"/()*4z8= (L -,"4!2"/+5>3254/3%UMC/- 8ee"/()*4z8= (L -,"4!y '7265&'7#"'"&547;::(:*HP8 i777Ql `GNF^/jg\aI9y '7265&'7#"'"&547;::(:*HP8 i777Ql `GNF^/jg\aI9K'7#!'!54'=>>E-4 68v:::>E-4 68v:::B;e ' (s HD"WJ g(%"&'#&547&547;%3267.'ggY KJ,>^GD5  UMGU^ &&VH" -$C *&'#727&'47'62654''654'a#fXXfST38 F3_&0Q`뮿2B2 ROL0U0%.LV^S/m?7 c9"(/*23#+"&/#737>324.#"3>654&#z0% .F' +  ))*;   77:@W:'" M='MQ6eM}A;^"  ;W13)3?I#%#&=476;+5>76547.#"3232Jc**3 Dj;l5w=-" - % H>9 UrK E6J7*g51fI#%#&=476;+5>76547.#"3232Jc**3 Dj;l5w=-" - % H>9 UrK E6J7*g51fzf(/>7'4&547767'&'"#"&5432>54'*D<  /6;hz/44qAJ6-\07 (4K}i6+[1PM 74.2>{%#"5'#"'6764';%&+'0i -\F6yx*%hwdhŤb>5:U ]wp5ؐ# 354>54&#"34632#3 #*#8#*#H=5#.$,888hg0 2#,8"7A/2'A{hgc"%->&54>&'&5!2632#!#".54657674&'"32>_`  #a ?\r]Bl>*C7';C$L*+c$/UIWP#, #A n18D"1:,.?3H0)+ '$"1 ;Q~;"&5473327UB7!8y'* %haΓV0#"&5463232=332654.=3('wZJ^#&8  .5(>T+*S-R@?L)GX<1)(  '>2*C7DyRlI9C#"&547.5463232=332654.=3264&#"('B@C13BJX#&8  .5(>T+*S 4"#"-R@?L)J-I1CC1#:0)(  '>2*C7DyRl#2#";J_#"&547.5463232=332654.=32654&+2>54'#"&'('QST=>R)$1#&8  .5(>T+*S,,%  C*2(1*(-R@?L)T- \AYTB?& +)(  '>2*C7DyRl  u# " %6$ #. !533S;#Fe/923##".546;.#"#4&#".54632632=#"@s H:)7P;@')3Q+"*? t7LlRd%(R"A(?eP*d|87;K95+$.?*?2lQ A]GG1(E\!2#"54654#"#"'46323276" .8>c3  /-R9\" P.  oKbZ8CJR]%2#"&547##"'#"&546;4632>54&#"'>322654&+'4&#"325#32=#">MQ@5H TER'!A7LRU%N?+@ + D41'2O!4?$,5 /$.*22 &8,+44*f?"bE9:PX=4fPPS=H1Vk,G4OQ!$*#,"80#L6>1% 2X;:PM=I=R@ %`UMq\LXa"&547&#"#4&#"#4&#"632#"&54>32632632654&#"'>322654'264&"*3XnKs>70SA3'3SS,->2B?5@N $7\;TE5\Z59\1.0'6 9.*De$,8#D# &'@() w=jaQ>m- 5@( ,)5GP=;HiT$FJ8$ONKL%+' ' 39$gL?f=l=(3 -H1.H0M[6A#"'&547&#"#4&#"&54632632654&#"'6322654')4U?5&"sF*4S,#A+(vpRh%1UC+1#3!*aik'/8#D)!wH#"&547&#"#"&54>7326=4>32654&#"'6322654'!,%4 C708"98O70$3!(bib+5l?hQk_YE`3M>1IaRB8;R'"#,&Qk$h?Hr5We:8N\'22#"&547&#"&54632654&#"'62654&'w*D+]PB9Jp0Nf_ua?+1'4j&- f,\39(5Tv_sWG[vTs;Hk$,'RJ<'aTc1@K29DO2#"/3254&+53254+#"'#"&547634632#4&#"325#32=#"#07;@)!6,CTER'!A:IC!hN?.B E8,+4)f?"b#+1*% !3!!'fPPR>T Vk0F7:PM=P (1"%( $`UG_@GOY%#!"3!!"&5463!2654&+532654+#"'#"&546;4>3232%4&#"325#32=#" 3)/T,66,"-#A/TEQ("@8KTP( ;(EVZ307-+44*f "?"b,%, %G3*+; !$ $RcCCC69,43 \I),w1C?5A4@. #%QBK 3:CM2#"&54632&#"32654&+#"'#".546;4632#4&#"26=#26=#"mCYXkv_]M+4H'Yb~<1WFS"'B&+N1KO@BWH6,*4\.63$(\+wW~)"$/%"nASb{QQ>)?6VkkVTA#=J0'UJ)9EF<C\dnx2#"'#"&547&#"#54&#"#"&5467#"&546346324&#"2654&##"'632632#'%3265#2654'32=#"2654'&jW@/ $IC5/@M#$.G"!M 0 6BE% 3CUoK=*=B7(0*3%0FQCN%F/5R 2'(9(%PB-6(CQ"5*,JPYc>32'654.#"32#".547##"'#"&546;46322654&+'4&"3265#26=#"x *+5!^GE}1[(2$ 2U iT@4#4 /TER'#?:IUZN?$8'!*#>29V44*'?^'"b(3L&DD_hNt.H(K?7Q:G+>42fPPV:H1Vk +<&8*4@<9QN*#Q4?>2:H0SFS&!A9JTX%)#>*8,+44*f?"bTm-G5(+B;"!<6F 3+"C45(8  E92654&+'4&"325#32=#"vYuOLET4q.88.J>)#&J/UnB9CA3.I&SFQ("@8KTT$M@%:0F&+"49V44*f "?"bKx K0K!(G5V55$!+30 -'Q,:.5@CN.WjCCC6:,E]%5F`' ") h2A?4=6C4 #%QGK/NZait2#".54>32&"32654&#"2#".54>5##"'#"&546;46323>2654&+'4&#"325#32=#"?f >N7bUSK?'jI\"fT38,+44*f?"bĮ"" tP97Q:G+?4  %JI.PPR>H1Vk#.=#Psl8*4B::PK?H@P= $`U@$P^dnx2#".54732>54&#"32#".547##"'#"&546346323>2654&+'4&"325#32=#"hMx|_u\:'bT!te@\L1RZUE+"4 -SCR$A9GSsL>#77 )*4!U$!)!=9R3! d "= am=ooQ2/BITO(~sdj/GcW/UpI>6OC;)<4 (e|NNQ54&#"32#".547##"'#"&546346323>2654&+2654.#"4&"325#32=#"hd+.*" #3 _u\:'bT!te@\L1RZUE+"4 -SCR$A9GSsL>#77 )*4!U$!)!=6"(9R3! d "= amg A&"2 *"  4/BITO(~sdj/GcW/UpI>6OC;)<4 (e|NNQ54&#"32#".547##"'#"&546346323>2654&+'4&"2654&#"2654'#"&'325#32=#"h{9>#4*"6 r_u\:'bT!te@\L1RZUE+"4 -SCR$A9GSsL>#77 )*4!U$!)!=9R3B""d.21$#- ! d "= amk T/*> "+ &/BITO(~sdj/GcW/UpI>6OC;)<4 (e|NNQ@'0H?C1&!'2ETER'!A:IRU%N?%:E8,+44*f?"bu&;0%&/5./&5(-T57I/3'4&fPPV:H1Vk#.=#:PM=I=R? %`UK)08Cp{2#"/32654&+#"'#"&546;4632#4&#"325#32=#"2#"&547&'73254+"&54632&#"3264&#"H?C1&!'2ETER'!A:IRU%N?%:E8,+44*f?"b703<! .B*6&KS>@'0:DT0$C#6-?#!#$T57I/3'4&fPPV:H1Vk#.=#:PM=I=R? %`U09D*?16! &5(-$&;0%&-&--%K)08Co|2#"/32654&+#"'#"&546;4632#4&#"325#32=#"2#"&547&'73254+"&54632&#"32654'#"'2>54'#"&547H?C1&!'2ETER'!A:IRU%N?%:E8,+44*f?"b708?-# 4H6.&KS>@'0:DT0$C#6-$ ", 3&#/T57I/3'4&fPPV:H1Vk#.=#:PM=I=R? %`U/;$G$5 G4A$&5(-$&;0%&   P#!  '"4 & 0K)08Cn2#"/32654&+#"'#"&546;4632#4&#"325#32=#"2#".54732654+"54632&#"3H?C1&!'2ETER'!A:IRU%N?%:E8,+44*f?"b0-.#N.:0%#!K)08Cw2#"/32654&+#"'#"&546;4632#4&#"325#32=#"2#"&547.54732654+"54632&#"32>54&#"H?C1&!'2ETER'!A:IRU%N?%:E8,+44*f?"b0<34! /A$P_8,65M+4?zK-.#N.:0%#! "-%K)08Cv2#"/32654&+#"'#"&546;4632#4&#"325#32=#"2#"&547.54732654+"54632&#"32654'#"'2654'"&547H?C1&!'2ETER'!A:IRU%N?%:E8,+44*f?"b0<:9 4"4H0LV8,65M+4?zK-.#N.:0%#!   P." 44 &".K)`goz2#"/32654&+#"'#"&546;46322'654&#"#54&#"#54&#"632#"&54>3263264&#"325#32=#"2654#"H?C1&!'2ETER'!A:IRU%N?%:A7Pb$H-&>)!>&(d&!/0#+3 67C!9DP8,+44*f?"b" +T57I/3'4&fPPV:H1Vk#.=#VCm*-V5>Ѷ)*t&4+'1F63J'0.+- :PM=I=R? %`U42F)ekt~2#"/32654&+#"'#"&546;46322"&547&#"#54&#"#54&#"632#"&54>3263264&"325#2654'32=#"3254&#"H?B2&!'4CTER'!A;HRU%N?%:2EZ6X7D!,>, >," 0 (#.,#,6'0# >.%=:%.?9V44*fm!1@! (?"b/+T56J/3'4&fPPU;H1Vk#.=#fK8DC7P5 ҵ&!!, &:)&.D7+D%11.,9QM=I=R 4"'L.4E!)+:`UB"1O\i+y2#"/32654&+#"'#"&546;46324632632632#"'732>54'#"&5467&#"#54&#"#54&#"632#"&4&"325#2654'32=#"3254#"&8 B2% (2ETER'!A:IST%M@%:_B=0"=9$(=S$9;dD)(+1!7 5,'3=)1%#?+ >&) / %"/1,49V44*fQ 0!(?"b;)(,,6J/2(4&fPPV:H1Wj#.=#:Pf11..L X5Md# ?*C;H8,6C&#Ҷ'!*,&9*-'D9QM=I=R"&+%-$$*;`UA!23GAMS\e2'654&#"#".547&#"#5&+#"'#"&5463>322>3262654'%4&"325#32=#"byk/L]L^K<%5 Y%>W)J>G#84AOdD8(:   eO6/2G$,JW"0J+-$W)5T†fMC}Zp \yPn-C5M qB g~LLR?I1Vi.K.NzwH6lHNm #*8MF?J;R ,5.^RK]Q[air"3!!"&5463!2654&#"#"&547&#"#5&##"'#"&546;>322>32632#'2654'%."327#32=#"+"1+3)IWXI!^K<5HY': ) 8'F$85?NMC9s ]J1-.>arfM$,JV8/J,-#V!5T!M<&(;hRQlLgC]\@iB %7, =>%??F4=*IWDg}fay<.\;B[6.0>=1?2D 4#/NEK]hry2#!"3!!"&5463!2654&+532654&#"#".547&#"#5&##"'#"&546;463232>3262654'%.#"327#32=#"=Y(DE`M0%,45+RG %%'HP+^K<%5 Y(0!*J>H" 64ANOE8!3"&0 /10E$-KV81$%,-#W"5T-$ 4&'B8K!M6,*9<&24"#9LgC]&9-jA @, Wi??E5=*GY%4,A#;/[3232>3262654'%4&#"325#32=#"dyXm\F50:mVs`O^K< #-Y%7^)K=G#83BOdC9!4 eO6/2G$,JW"1$&*-$W)5TŸ,%G# q [zRm$P7~N iK g~LLS>I1Vj"+@  OzvI6lHNm #+:LI=J;R<5.^RM_%#".54632.#"32>54.#"#".547&#"#5&+#"'#"&5463>322>326322'654&#"#54#"&546326'2654'%4&#"325#32=#"AL4]yC' P;?XZC=a:%'M5^K< #-Y#7^)J>G#83BOdC9!4  eO6/2:!;A.&% #"%$,JW"1$&*-$W)5T^ 2!6GB '/#&--G^X.;kg= [zRm$P7~N iK g~LLS>I1Vj"+@  Oz/L' + ;% &I6lHNm #+:LI=J5.^RI*[elu%>32632# 4>7!2>54&#"#".5467&#"#5&+#"'#"&5463463222654'%.#"3265#32=#"gO7.2:\AB #9_{l/- [sHt?ZK<%5 4*#,@ *J>G# 62DNfE8(: !#.F[.0$1-$#56TM|PPj(JTHD/#4i4jv`Z/FbW0_ W~Po.C6:m% -A4 eLLR?J0Tl.K.J5nFQj3E;K=IJ32632".547# 4>7!2>54&#"#".5467&#"#5&+#"'#"&5463463222654'2>54&#".#"3265#32=#"gO7.2:\ABb,4*"#*/- [sHt?ZK<%5 4*#,@ *J>G# 62DNfE8(: !#.F[. *+0$1-$#56TM|PPjhC("3 3" ?#4i4jv`Z/FbW0_ W~Po.C6:m% -A4 eLLR?J0Tl.K.J5nFQj3E  ;K=IJ7!2>54&#"#".5467&#"#5&+#"'#"&546346322>32632%2654'264&'"2654&'#"&=.#"3265#32=#" ( U>+> /- [sHt?ZK<%5 4*#,@ *J>G# 62DNfE8(: !gO7.2:\AB#.F[..!V7'#8+-/)0$1-$#56Tj4 >U$5*$"/#4i4jv`Z/FbW0_ W~Po.C6:m% -A4 eLLR?J0Tl.K. M|PPj8J5nFQj3E,z:( 5 588 (;K=IJ ?(. 9'(1KUK:7&$T57I/3'4&fPPV:H1Vk#.=#:PM=I=R? %`UWB>K*Z+Fѵ&!A0\#.hCX10K)08Cgq2#"/32654&+#"'#"&546;4632#4&#"325#32=#"2#"&547&#"#54#"&5463262654'H?C1&!'2ETER'!A:IRU%N?%:E8,+44*f?"bCZ5,*7D *97'4MYK74'-m6B#T57I/3'4&fPPV:H1Vk#.=#:PM=I=R? %`UiJ7ED6R6 ѵHC3Z!-hAZ0/)"O.4E#,KX)08C2#"/32654&+#"'#"&546;4632#4&#"325#32=#"4>32632#"'732>54'#"&5467&#"#54#"&264'H?C1&!'2ETER'!A:IRU%N?%:E8,+44*f?"b5 0& 4',;R0<9bH&& !3; 6+&2>+>",98  NZx"=%T57I/3'4&fPPV:H1Vk#.=#:PM=I=R? %`Ut.B 0.KT2Kf '0# P&$5 .>"9:PM=I=R).gM<$6TN] %`UP." ,+ '".JD18AK2#"$54732>54&+#"'#"&54;4632#4&#"325#32=#"=IڬVFv;ni?0&(UEQ'#?:IDM@$9F9+2,5)f "?!cQB١k"nyZP5gG+9fPPR>yUl ,;'9QV4I54&+#"'#"&54;4632324&#"325#2>54&"32=#"E#2 1"1CF\VFv;ni?0&(UEQ'#?:IDM@$9B=I9+2,5)fG.#2#3 "?!cU>* "*C1 ١k"nyZP5gG+9fPPR>yUl ,;'QBr9QV4I54&+#"'#"&54;4632#4&#"325#2654.#"2654'#"'32=#"=Ir%2 >*?R3BVFv;ni?0&(UEQ'#?:IDM@$9F9+2,5)f,%D+75%C#& "?!cQBT$.-8&Y=% ١k"nyZP5gG+9fPPR>yUl ,;'9QV4I,#N@,5_F:D=?V90I8NaH:+Z5:a"':PM=I=R? %`U #&C6%NOK)X_gr~2#"/32654&+#"'#"&546;4632"&547&=4&#"#"&5463232654'4&#"325#32=#"264&+"'2654'H?C1&!'2B TER'!A:IRU%N?%:_*5:B\B-6,#N@,5_F:D=?V90I8NaH:+Z5:a"':PM=I=R? %`Ub-&--%#&C6%NOK )\ckv2#"/32654&+#"'#"&546;4632#"&547&=4&#"#"&5463232654'4&#"325#32=#"2654'#"'2654'#"&547'2654'H?C1&!'2B TER'!A:IRU%N?%:_*6C$ 4H93,#N@,5_F:D=?V90I8NaH:+Z5:a"':PM=I=R? %`U  P." ,4 '!/#&C6%NOM8=IOXc%>73!5654&+#"'#".546;46323235"&54632"54&4&"3265#26=#"I} R) TER'#E-<BN:N?$8*=K$GUF9.CH\( 9V44*'?]'6- 9G!P&4fPP@>.EVk +<&P75!T>7CQ] Xb( -r"9QN73##".547!5654&+#"'#".546;46323235"&54632"54&264&"4&"3265#26=#"I} E/ "*PR) TER'#E-<BN:N?$8*=K$GUF9.CH\( 2##2#9V44*'?]'6- 9G,3A 2!*!P&4fPP@>.EVk +<&P75!T>7CQ] Xb( -r""4""4V9QN73#"&547!5654&+#"'#".546;46323235"&54632"54&2654'#2>54'#"&'4&"3265#26=#"I} )+TzS.tR) TER'#E-<BN:N?$8*=K$GUF9.CH\( &$!$(+3&1E9V44*'?]'6- 9G!>BYW?A#!P&4fPP@>.EVk +<&P75!T>7CQ] Xb( -r"! !X 0%" &4"! 0-9QN73#"&54632&#"327675&=!5>54&##"'#"&546346323235".5463273"544&"265#32=#"#ec >4J/Vk#.=#?J5?*3EXTP/Ig2- w>9QM=H@PTa= $`UM8qv%>73!5654&+#"'#".546;46323235"&546322'654&#"#54&#"#54&#"632#"&54>3263267"54&4&"3265#2654#"26=#"I} R) TER'#E-<BN:N?$8*=K$GUF9.Cs6O`F0' :) ":'*l +/"*2 67D !8FhH\( 9V44*'?J-'6- 9G!P&4fPP@>.EVk +<&P75!T>7CQ] VCm**[3DѶ ++.)&0F53K&21./6Xb( -r"9QN73!5654&+#"'#".546;46323235"&546322#"&547&#"#54&#"#54&#"3632#"&54>3263267"54&2654'4&"3265#3254&#"%26=#"I} R) TER'#E-<BN:N?$8*=K$GUF9.CZCZ8(,6G#.:"("9.#,*",*#,4(:.=0$>;$.H\( #5B#9V44*'?.'6- 9G!P&4fPP@>.EVk +<&P75!T>7CQ] eM9BE5Q6 Ӷ-"' .8*&-D75N#330.9Xb( -r"b#)P/5I"+9QN73!5654&+#"'#".546;46323235"&546324>32632632#"'732>54'#"&54>7&#"#54&#"#54&#"632#"&"54&2654'4&"3265#26=#"3254&#"I} R) TER'#E-<BN:N?$8*=K$GUF9.C&/# ?.">:$(=T";9cD)% (=> 4+&2.4,:)!!:.$#2 )"-$)3,H\(  #9V44*'?]'6- -,9G!P&4fPP@>.EVk +<&P75!T>7CQ] B+D&3300L U7Oa %5.J#;G7, !,!+Ҷ")"1 .:(4KXb( -r"a'-) %%9QN73!5654&+#"'#".546;46323235"&54632"54&4&"3265#26=#"4632!7354&'4#"6I} R) TER'#E-<BN:N?$8*=K$GUF9.CH\( 9V44*'?]'6- 9T&-/*2,Am9G!P&4fPP@>.EVk +<&P75!T>7CQ] Xb( -r"9QN73!5654&+#"'#".546;46323235"&54632"54&4&"3265#26=#"4632##"&547#7354&'4#"62654'#I} R) TER'#E-<BN:N?$8*=K$GUF9.CH\( 9V44*'?]'6- 9T&A/1?&o&-/*2,Am.&11%9G!P&4fPP@>.EVk +<&P75!T>7CQ] Xb( -r"9QN73!5654&+#"'#".546;46323235"&54632"54&4&"3265#26=#"4632#".547#7354&'4#"6264&#"2>4'#"&5477#I} R) TER'#E-<BN:N?$8*=K$GUF9.CH\( 9V44*'?]'6- 9T*3$%3c&-/*2,Am%') )/' 9G!P&4fPP@>.EVk +<&P75!T>7CQ] Xb( -r"9QN..>").gM<$6TN$P '< ,+ '". M,8=IOXc%>73!5654&+#"'#".546;46323235"&54632"54&4&"3265#26=#"4>32#".54632&#"326=#7354&#'"654&I} R) TER'#E-<BN:N?$8*=K$GUF9.CH\( 9V44*'?]'6- ,-CV38J5B;7N;)#$(30,_(t 9G!P&4fPP@>.EVk +<&P75!T>7CQ] Xb( -r"9QN%$bPB!5?tS[!K)[bju2#"/32654&+#"'#"&546;46322654'7#"&=4&#"#54#"&546326324&#"325#32=#"H?C1&!'2B TER'!A:IRU%N?%:T"*Q^?5/A,,9: LWI57&!7/A&z8,+44*f?"bT57I/3'4&fPPV:H1Vk#.=#=/b$*x?M@2190ѵI .b$-u?O0/A08)2:PM=I=R? %`UK)biq|2#"/32654&+#"'#"&546;46322654'7"&547&=4&#"#54#"&546326324&#"325#32=#"264&#"H?C1&!'2B TER'!A:IRU%N?%:T"*Q^58B\B18,,9: LWI57&!7/A&z8,+44*f?"b#!#$T57I/3'4&fPPV:H1Vk#.=#=/b$*xS'A1??1;! D190ѵI .b$-u?O0/A08)2:PM=I=R? %`Ub-&--%K )fmu2#"/32654&+#"'#"&546;46322654'7#"&547&=4&#"#54#"&546326324&#"325#32=#"2654'#"'2654'#"&547H?C1&!'2B TER'!A:IRU%N?%:T"*Q^6A$ 4H=5,,9: LWI57&!7/A&z8,+44*f?"b  &4)'"0T57I/3'4&fPPV:H1Vk#.=#=/b$*xT&#I.G4F$ B190ѵI .b$-u?O0/A08)2:PM=I=R? %`U  P." ,4 '!/K+)w~2#"/32654&+#"'#"&546;46322>54'7#"&54632&+"32>5#"&'.#"#54#"&54>326324&#"325#32=#"H?C1&!'2B TER'!A:IRU%N?%:G DZ%>;!=S`811*VR+>!:.6."97BNZ /% 5'!60BT8,+44*f?"bT57I/3'4&fPPV:H1Vk#.=# 2"V&LC_-251F:W6ҶH:=Z!+m-B 0/O> Y:PM=I=R? %`UK)AW^fq2#"/32654&+#"'#"&546;46322'654&#"&54&2'654&#"&544&#"325#32=#"H?C1&!'2ETER'!A:IRU%N?%:|L+A7+-8H [|LA$A7+-8H [a8,+44*f?"bT57I/3'4&fPPV:H1Vk#.=#RD$0) !L0;<1V*iEVRD@K !L0;<1V*iEk:PM=I=R? %`UK )Jbiq|2#"/32654&+#"'#"&546;4632#"&547'654&#"&54632%2'654&#"&5464&#"325#32=#"2654&#"H?C1&!'2B TER'!A:IRU%N?%:v*.B./A@A6,-8H [V?>L*>L*(@6,-8I [V+8,+44*f?"b %!"$T57I/3'4&fPPV:H1Vk#.=# >%1?@0G!L0;<1V*iDWRDGRD.G"K1:>/V*iEV:PM=I=R? %`Ub$.-&K )Mcjr}2#"/32654&+#"'#"&546;4632#"&5467'654&#"&5462$2'654&#"&544&#"325#32=#"2654''2654'#"&547H?C1&!'2B TER'!A:IRU%N?%:k.3$ 4H4A7+-8H [W|L|LA$A6,-8H [8,+44*f?"b#&4)'"0T57I/3'4&fPPV:H1Vk#.=# F(.G4/9 !L0;<1V*iEVRDHRD@K !L0;<1V*iEk:PM=I=R? %`U # P." ,4 '!/M6/;G2!3##"&547#5654&#"632#"&5462>54&"%2654&#"7^VS&%A31C&ebI)A$ ,=2CB6>K#2#:!)' *&zdkXG"41CC13#JtPi"/>)HS<:HeS~ ""+.%#0-$'.M/<NZ2!3##"&547#5654&#"632#"&5462654&#"2654'#"&'%2654&#"7^VS/.U<=S1ebI)A$ ,=2CB6>K%$,64%".ES!)' *&zdkXG%BDWTBD(JtPi"/>)HS<:HeS~X9)$ (2( 0-.%#0-$'.M <H233#"&54632&#"3265!5654&#">32#"&5462654&#".cSS/YDht^IHG"$}W"aBa_I(A% +!4B6>AM%"'"((†V;8J;,# &#[cHjQp".=)+\31PeTsn8%2.#9I_>2#!"3!!"&5463!2654&#"#"&546732654&5466O(59V9 0;1:G]A4"3VJRhQ<2F& $<Y'?B#`JP(H:+#:tYE\GN$HVmXMf YC$: 9?5?OIbK2#!"3!!"&5463!254&+532654&#"#"&54>7326='546*D' AAcO90;294}($46/)[FOj 2)3E /%,4`& 9#F;I$H:+#:T"0$+ !7<'TGYlZ-L,Z?-B =4W:FH72#"54632&#"32654&#"#"&54>732=4>\snWmK(.$4 J=[M§T"" ")hMh`2JC5>1K`#/QAM@b%#".54632.#"32>5#"#"&54732=4>322'654&#"#54#"&546326ɤAL4]xD' O;?XZCAe='}%/ZCUe|fI54&#"#"&547326=462'654&#"#"&54732=46N_ =-$3 J6%<ZCUe|42I<%8a}5?bP-";;/8DUD-%9Cu_9KC6w-%Y1>e*.=RCi1)P3@Q64AMX+e2'>54&#"#"&547326=462+"3!!"&46;2654&#"#"&546732654&546N_ =-$3 J6%<ZCUe|42I<%8at$5 8&$$H (( -<)"6>,4G.1#.2"&<u_9KC654&#"#"&547326=462+"3!!"&546;254&+532654#"#"&5467326='46N_ =-$3 J6%<ZCUe|42I<%8as@:((@6$$Q '' Q D8;05F1."/ %?u_9KC654&#"#"&547326=462#"5432&#"32654&#"#"&546732=46N_ =-$3 J6%<ZCUe|42I<%8ae;N{fE6%5LQOa1';<+7E*5!' /(:Cu_9KC654'#2>54&'#".=wXS+7V= +$7vJM&7/Ue|42I<'6RCSBT#c*%&0 ("83%!,  *[nG+H>U8#G,UB,D!{fFSLSdU.SSdFVF6* [+( 76!-"  #MAMU%4632!!3#".54>32&#"326=!5#54#"#"&547326=463237"!5&wXS \b7P?`F6B'iO:z[JM&7/Ue|42I<'6RCSBT#[nGvv &" VXUB,D!{fFSLSdU.SSdFVF6IC2#"/32654&+532654&#"#".54>732?> 2L%LRbJ%$ 1#;3)#".(>",A(<377! =+'5G5a#9:,& CO732?>264&" 2L%LR8:A3"2  1#;3)#".(>",A(<377! =+'5G5a#9:N4""4",& CO@&"C1C+! ' <%+&8,2)KYK,C!/\?7G@9?+Ma;9Q)"4""4IKYk2#"&547/32654&+532654&#"#".54>732?>2654'+2654'#"&' 2L%LRCBU<=S0 1#;3)#".(>",A(<377! =+'5G5a#9:: +72'$.E,& COG&$PDWUAB)<%+&8,2)KYK,C!/\?7G@9?+Ma;9Q)X:($ $6) 2+HDL#".5432&#"32654&+532654&#"#"&54>7326=4>329/y<@]5D.W-"=Q9GVC6&&-9/60LZBSg >.$4 J=4'$1K`KI77P)MHk#"'#"&54>54&#"##532654&#"#"&54>7326=4>323265332>54&'u;A+4'I2T>8H)2)"& %& &:L=GW+&(D(! 0 5617!2" 1(C;3%J1LaHDs#"&547&'#"&54>54&#"##532654&#"#"&54>7326=4>323265332>54&'2654&+"u;AGH 1"1C4&T>8H)2)"& %& &:L=GW+&(D(! 0 56* !IoDO "*C1$871)#*% BMOL_z`3W9# eQ/F!@JI3L'>17!2" 1(C;3%J1La* Hp}"&547&'#"&54>54&#"##532654&#"#"&54>7326=4>323265332>54&'2654'+2654'#"&'u;AYWTzS7%T>8H)2)"& %& &:L=GW+&(D(! 0 5617!2" 1(C;3%J1La( X9)" '3( #. Ns#".54632&#"3265#"'#"54>54#"+532654#"#".546732676323265332>54'D35eN8C/mP'U(3mI$eP1B[4j(1(H4/I'& ?:1G F:k 2"') @O7- "P3BL'!%6 k@tlek1" '" vk1HTY0*)3QttQ5N?H'Wz.9&Xe90H,%#1'D1<)=2tSL(|h%3254'7#"$54732>7#&'#"&54>54+5;254&#"#".546732>763232653!'k~b `Q_/ \5i6P)0)HG$6*O<1G F:k*" %%)N;P7/['P5@M*C9OvleRw6$FT)00*EpdMi6O>H'Wz.D Ja{"B;.H/"A"/(DL}u~#"&547#"$54732>7#&'#"&54>54+5;254&#"#".546732>7632326533254'7264&#"&9*" 0Fb `Q_/ \5i6P)0)HG$6*O<1G F:k*" %%)N;P7/['P5@M!'k~2""$&>."3 B4HeRw6$FT)00*EpdMi6O>H'Wz.D Ja{"B;.H/"A"/(D*C9O#2"!4L|r%3254'7"&547#"$54732>7#&'#"&54>54+5;254&#"#".546732>7632326532654.'#2654&'#".=!'k~:@U|Tsyb `Q_/ \5i6P)0)HG$6*O<1G F:k*" %%)N;P7/['P5@M/.&A+7'#8'# $':*C9Os V1=VU>+eRw6$FT)00*EpdMi6O>H'Wz.D Ja{"B;.H/"A"/(Dr y:( 5 6& & +7H=2'>54.#"#4&#"#"&5467326=4626 Pw :*"/ 0(!2S9+-CVEOjR/#1 /(#4h8;ńe3D?7<*2L%5=D .@KaO`}c\u6<,2L%?KMRg67G<9E2#"&547&#"#4&#"#"&54>7326=463262654&'=rI:4`k27CHbTa4632632#"'7327654&'#"&54>7.#"#4.#"#"&54>732652654'PbO\8G^I[WMLg;8('X=?7+M@7Q E0 H5/IS& )C\EPd ;*#1-# %;O2%3!0)ET77sLpML*JIa?R -:[mUF4?-)08:":CkK_|d3HB6<,5N#ISBDF& 7&1?F+72!5>54&#"#"&54>732654&5&546354.'.my^^)!+?bGPa ;*m@2.9}KF.%)hNO'-@2\Rh|f4F@7J]O? NaDs;*>)F;6BJ2##"&547#5>54&#"#"&54>732654&5&546354.'264&".m!!A31C!^^)!+?bGPa ;*m@2.9}KF.%)4""4"h /0DC1/ NO'-@2\Rh|f4F@7J]O? NaDs;*>)"4""4F6BOa2##"&547#5>54&#"#"&54>732654&5&546354.'2654&#"2654'#"&'.m.,U<=S/^^)!+?bGPa ;*m@2.9}KF.%)%$,64%".Eh&?DWTBD&NO'-@2\Rh|f4F@7J]O? NaDs;*>)3X9)$ (2( 2+GGJ52#".54732654&#"#"&5467326=463J&\tr[G#@D7*=`DPb<8"07B6+8c-JK'jrqjhXqżM_9,BYucH#r@F\<0oL_GK?J#"&=#".54732654&#"#"&5467326=4632264&#"%9A31CJTr[G#@D7*=`DPb<8"07B6+8cI3J&s##("1>.0DC1 qjhXqżM_9,BYucH#r@F\<0oL_-JK'"4"#"GLBNa"&547#".54732654&#"#"&5467326=46322654&#"2654'#"&'%.TzS 4;r[G#@D7*=`DPb<8"07B6+8cI3J&DY&%'%*85$1 *(U 8%AZUAqjhXqżM_9,BYucH#r@F\<0oL_-JK'UX9)" '3 # #. M+S\2'>54&#"#"&547326=46#"&=4&#"#"&5463232654'2654'N_ =-$3 J6%<ZCUe|42I<%8a*C4/>,#N@,5`E:D=?V90I8NaH:+Z5:a"#&C6'LOM+[gp2'>54&#"#"&547326=46#"&547&=4&#"#"&5463232654'2654&+"'2654'N_ =-$3 J6%<ZCUe|42I<%8a*5:B./A-6,#N@,5`E:D=?V90I8NaH:+Z5:a"f&.-#&C6'LOM+^l2'>54&#"#"&547326=46#"&547&=4&#"#"&5463232654'2654'#"'2654'#"&547'2654'N_ =-$3 J6%<ZCUe|42I<%8a*6C$ 4H93,#N@,5`E:D=?V90I8NaH:+Z5:a"   P." ,4 '!#&C6'LOL;O19A%4632!!3##"&547!5#5654&#"&5463237"!5&264&"wXS A31C TI7(+4,;UEF]$vBT#s4""4"[nG#.1CD0.#,H.9B76#2XHYYJ4'VF6"4""4LI08EW%4632!!3##"&547!5#5654&#"&5463237"!5&2654&#"2654'#"&'wXS,.T=>R1I7(+4,;UEF]$vBT#\%%+72'1 E[nG&ZUAD(,H.9B76#2XHYYJ4'VF6X9)$ %5"! 2+HxHO23467632!!3#"&54>32&#"325!5#5654.#"&546"!4 $1(#-0J8O1 SF'@@ WQ#L02DU*I&2D8Dc7OC("<&3(Mh"&.LQ9L.&+IB3= 2XHX*]@6LGBbj%4632!!3##"&54632.#"3276=!5#5654&#"&5463232'654&#"#54#"&546326"!5&wXSŐ_z}_xD' Q;QFWFjKLI7(+4,;UEF]$vD% #HBT#[nG{L+6GB (:$/HIf,H.9B76#2XHYYJ4'$% ;;% % VF6LG&.T%4632!!3!5#5654&#"&5463237"!5&2'654&#"#54&#"&546326wXSI7(+4,;UEF]$vBT#s6H)?(. 9'(1KUJ;7&%[nG,H.9B76#2XHYYJ4'VF6UWB$-) *Z+Fѵ&!A0\#/gAZ10LG&.R\%4632!!3!5#5654&#"&5463237"!5&2#"&547&#"#54#"&5463262654'wXSI7(+4,;UEF]$vBT#YCZ6+*7D+97'4MYJ86%/k 6B$[nG,H.9B76#2XHYYJ4'VF6UgL7ED6R6 ѵHC3Z!-hAZ0/)"O.4E$+LXG&.jv%4632!!3!5#5654&#"&5463237"!5&4>32632#"'732>54'#"&5467&#"#54#"&2654'wXSI7(+4,;UEF]$vBT# 0%5&,;R0<9_K&& (: ; 6+&2>+>",98  NZx"$%[nG,H.9B76#2XHYYJ4'VF6.B 0.KT2Ih ':0P&"!4Og&aDZ-SKxӊ$)# I@.1<5C 45*<)[D2+(R_F>'FP9&?_=7V9s +J-9;1F 0Y-C!)236IrKT`23432!!3#"&547#"$&54673 =!5#5654&#"&54>"!42654&#"Og&aDZ-SL3 2"4Bǭ$)# I@.1<5C 45*<)f2""[D2+(R_F>bB8- #*F0 )?_=7V9s +J-9;1F 0Y-C!)236!!!6IIRau23432!!3#"&547#"$&54673 =!5#5654&#"&54>"!42654.'#2654&'#"&=Og&aDZ-Sw67U>=Uy$)# I@.1<5C 45*<)3.A+7'#8+-/)9[D2+(R_F>|GQ.>UU>-$?_=7V9s +J-9;1F 0Y-C!)236  y:( 5 588 )9L;+HP[2#".547&/3254&+532654&#"#4&#"632#"&54>326264&"%2654&#"zGbBJ86A3"2   8U29'$.717/ASS,-?1AD93262654'+2654'#"&'%2654&#"zGbBJ=FTzS/ 8U29'$.717/ASS,-?1AD932632#4&#"3265#';54#"26=#"v=J(# #'%(/ %/! !?/ '. B.0H)I@\D7.$:5*.76+$?'H&"cI<%9 /F!28X0 1#" :'I)-" "PMkS9L>GI>SdS  )'c%,4UT)H5<DNY%#"/324+5324+#"'#"&547&54>3263232%4&#"3265#';54#"32=#"$>1:H:H'20P)#?:IBD .(G%OEV78,+44*'?æ9)$?4?"b##* ! ^"FD`.PPR>P@ 2 PPnSD^:PM=H@PTal*'c! $`UHdAHOZe"3!!"&5463!254+53254+#"'#"&547&54>3263232#4&#"325#'";5432=#"8S1;<0}6*/EZ;P)#?8KBD96G%O%:@|/5P;|7-+44*f_.$"$?"b 'B1()9:0(-dWCCC6D5%0 CC%4>,*,9%1C?5<4E!S%QGM:@JU^2#"&54632&#"32654&+#"'#"&547&54>32632#4&"';54#"32>5#32=#"nE]Dw\[B(0>"^T+r5,UEP)#?:IBD .(G%O.A E9V49)$?.5)&1(?"br[},#.m@Ue|PPR>P@ 2 PP/I29QN32#"&546326326322654&+53254'$264&#"+,SE(, AH(/0**%.41ES@KF:K ;(6]2*"L:\4% .!/=$ 9Fa948dB'yF^ + &D@.32>&& % ?$9E:!L 4211/$-E'>5$F #-^`?s" !/<.)M;!3bPNMF4?) '.7;!h;=L-H1.HL;oer%#"&547&/3254&+532654&#"#4&#"#"&5467&#">32#"&546326326322654&'%2654&+53254'$264&#"+,42A31C AH(/0**%.41ES@KF:K ;(6]2*"L:\4% .!/=$ 9Fa948dB'yF^4"& = + &D@.32>&& % ?$A"!?0DC1- :!L 4211/$-E'>5$F #-^`?s" !/<.)M;!3bPNMF4?v" ) '.7;!h;=L-H1.HL{dn%"&547&/3254&+532654&#"#4&#"#"&5467&#">32#"&546326326322654'#2>54'#"&'%2654&+53254'$264&#"+,;GS|R8 AH(/0**%.41ES@KF:K ;(6]2*"L:\4% .!/=$ 9Fa948dB'yF^.)(C&0 5$"./B + &D@.32>&& % ?$D##TCXV@I):!L 4211/$-E'>5$F #-^`?s" !/<.)M;!3bPNMF4?% $v+'  '3) C) '.7;!h;=L-H1.HJ7)1233##"&547!532654&#"#&54>264&"=CQ7S"$B21C$4+7$)#* + 974""4"(R>I-G"3/ED03""?/"80! $. S#2##2J)5H233##"&547!532654&#"#&54>2654&#"2>54'#"&'=CQ7S,0S>=S2]+7$)#* + 9.%C&0 3&1 /(R>I-G&BCXUAD)"?/"80! $. mw+(  %5"! CJ9%-233!5>7!532654&#"#&54>5#=CQ7R<9[8 C+7$)#* + 9oJ&#(R>I- .9."?/"80! $. 7):Jz3;F233##"&547!5>7!532654&#"#&54>5#264&#"=CQ7R!! .B!9[8 C+7$)#* + 9oJ&##!#$(R>I-!.*?1.! .9."?/"80! $. 7):-&--%Ja4<G\233##".547!5>7!532654&#"#&54>5#2654'#2654'#"&547=CQ7R"+-# $5 +9[8 C+7$)#* + 9oJ&#"&4)+1(R>I-%8$5 -# 7& .9."?/"80! $. 7):z P." *)  '$,JR\233!532654&#"#&54>2#"&547&#"!532654#"#&546323&54>2654'=CQ7Sr+7$)#* + 9.+B5,%2H4@>0 0(*7r&Di%B(R>I-G"?/"80! $. (:2=J:.V< J5M' '; (1;)*5E#>3(.I5@ )Jjnz233!532654&#"#&54>#!"3!!"&5463!2654'#"&5467&#"!532654&#"#&546323&54632'3254'=CQ7Sr+7$)#* + 9@4B$$5&&0>> 1)$/<'+0B>c#,%'7o%OI-G"?/"80! $. 3D&  A-B 2<3$,3>1A!.  &-!%.6:F? )%I$Jju233!532654&#"#&54>46322#!"3!!"&5463!254#5254&##"&547&#"!532654&#"#&546323&2654'=CQ7Sr+7$)#* + 99MI-G"?/"80! $. L;G-)/)'!!6&!'3?0)S7)C -  ',F .%'2F#J4u233!532654&#"#&54>4632#"&54632&#"32>54&'#".5467&#"!532654&"#&546323&2654'=CQ7Sr+7$)#* + 9IQAN(0BkV1``(51%#7A+@ #4+#:*/!2 #n *3 )6 r(V(R>I-G"?/"80! $. /CYK T@Y}  '@A"H '&.& #G<  -'4*)&8-5%& I3J}ir233!532654&#"#&54>4>32#"&54732654'#"&547&#"!53264&#"#&546323&73254=CQ7Sr+7$)#* + 9 .@,,u@9zg. *$K ( .K "*Z0$'(R>I-G"?/"80! $. N %.>E)UohO7 ;?\riM22B3%O.+E!,& +.!$/^*=I%Jt}233!532654&#"#&54>#"&547#"&54732654'#"&547&"!53264&#"#&546323&54>32'32542654&+=CQ7Sr+7$)#* + 9-:(G0'@9zh. *#K<( .K "*Z' @+-w+$' (  (R>I-G"?/"80! $. .)+702 gO7 ;?\riM10D3%O,,D",& +.!",9%6 >E)M.=I"" "J{233!532654&#"#&54>4>32#".547#"&54732>54'#"&547&"!53264&#"#&546323&732542654''32654'"&57?&=CQ7Sr+7$)#* + 9' @+-J B2!2 "@9z5I;*. *#K<( .K "*Z+$' $297 &:&)?(R>I-G"?/"80! $. N%6 >E)S6 %+?& hO7 ;?\r&D+10D3%O,,D",& +.!",a.=I"."7  :H[i"3!!"&54>3!2654.'#"&54>7&#"!532654&#"#&546323&547632632#'2>54'!$-,<$ O_$/ &O;?N2##/J72_#,("#, +H;=U2<@?Z\Cgf{% &&+0GJ:)* iN)B% AIVweL+I. =;Lx;">-(5/$3!2>54&+532>54&+#"&54>7&#"!532654&"#&546323&54>3262654'^{HJP:#*.+$),- ) TC"S<9K"7+%<5L#_"-(D- +H;AQ2< .O1g=p"*@G1{PC@(C4GI 0% & (%7#! ,4ATOp^A.N0$1G8x;">-*3.%=IY=D,Ti4A5$JUEK4^71@L1_m%4632#".54>32&#"32>54.'#".54>7&#"!532654&#"#&546323&2654'߂cz@Ji `e4K@SM99+#[f'7V4" +QD&7 E3$J5M#8+8*"#* + P3>W2>%#0),ir{d %)>TO(,8. 9Zy':-+>090F75m"U #11% E:O?A8VDM:;/.(JKvPZ%4>32#"$&547327654'#"&5467&#"!532654&#"#&546323&2654'j&T9u4MR䊜s 71$䬅UL92BQ9*5C-(U#7-& * 6?9K*2(TCS9p JgYo~g8cCY`Y%,)Y{YGL_2?8H: &J(,%0#2NR=@6RAL8B)J2oKy]gs#"&547#"$&547327654'#"&5467&#"!532654&#"#&546323&54>32%2654'2654&#"#++*" 4B}s 71$䬅UL92BQ9*5C-(U#7-& * 6?9K*2&T9u4MR(T "("M @%"3 F0 6o~g8cCY`Y%,)Y{YGL_2?8H: &J(,%0#2NR=@6RdCS9p Js-L8B)J2o$"""Kgz[ep#"&547#"$&547327654'#"&5467&#"!532654&#"#&546323&54>32%2654'2654.'2654&'#"&=2PW<=Ukys 71$䬅UL92BQ9*5C-(U#7-& * 6?9K*2&T9u4MR(T.:V7'#8+-/)tO=@SU>'&o~g8cCY`Y%,)Y{YGL_2?8H: &J(,%0#2NR=@6RdCS9p JKL8B)J2o.y:( 5 588 (H0(nw%2#!"3!!"&5463!2654'#"&547'#".54;2654&#"#54&#"632#"&54>32>32+"32>2654#"324#"G^SB*9g/<:1;L^8*)7 vp.14@M<03'S?3>! (&"-7,?7p0Y -C jzD:W).3Y**B61B ;.#$,.%?$(1-" B0 -!?4->D? O/7% 9 #8,(>7&7-:_4,>>//.f%M~%2#".54732>54#5254&##"&547'#"&54>;2654&#"#54&#"632#"&54>32>32+"32>2654#"324#"E[**=VkNCjD\"S?bz>UmJEN9#9)2. $'D@",PGW2AVC)5$S?4=!(%.#*9,A5p0X AXv6G2$#@8@e.3m**?2% (/K) Fjn}| qkb\< <)6(3!#.>>""1H7.:I63,DFO.8% 8(77-)> 7N=M[(!0 .. !//*4fM ?qz%2#".54632&#"32654&'#"&547'".546;2654&#"#54&#"632#"&54>32>32+"32762654#"324#"yWo;F0kWpC8.K4D[#p/-6,)7 B3 ap>O2:4&S?3>!(&.#.6,?7p0Y CUnY'9 +#4+.3O**aLc{"#,'nX-L$(1,#H7'! .KH4%=:< @.8% 9(77-(>7T=FX"AA //.fM@x%2#".54632.#"32654.'#"&547'#".54>;2654&#"#54&#"632#"&54>32>32+"32762'654&#"#54#"&54632672654#"324#"y8Q+nfAL4]yC' P;+7$[Br! 6,*6 g: #+(BC$;R<07"S?3>!(&.#-7,?7o1Y @XpWH=-!6&% #"Q.3O**57~VO 2!6GB '$&-m$6 $(1.!I6 /"3 E7,6;W@.8% 9(79+(>7Q@GW5!AA& + ;% % //.fMl%2"&547'#"&546;2>54#"#54&#"632#"'#"&54;2>54&#"#54&#"632#"&54>32>32+";2>7>32>32#"'#"32?62654#"324#"324#"*:8T6 ,%7.Q+6H}i@>f2'SG,=! (%.#0sOUK(=7/ZS?3>!(&.#.6,?7o1Y .C {fzu9QmE-@2p0X *A ~#?`R@:fA !.3F** ]**5'(1.! 2(5?7#bBA O7/% 8(7U\D<(^"1*'0 S.8% 9(77-(>7$4*GV843O\*,> 7 /(XC,)#://.%ffJN(%2#!"3!!"5463!254'#"&547#"&546;2>54#"5#4'&#"632#"'#"&54;2>54#"#54&#"632#"&54>32>32+"3267654632>32+"32>2654#"3254#"3254#">SZDX//D`7)n=0(&0 a^/8EsX54WMLH4 $#4)izqq44WLM+75 # *(1(:/a+ P&: A,o_y?[Fa+O2HPJ0&+##$$;1;F!5J$,Z1#(2,$ C-4+:F2$_|4]=$94,[[?3Cb4&_ 4BE$#! )78-*? 5 /(@+c_>T5 ' [?,==,X*01101LD232#!"3!!"&5463!254#5264&+#"&547#".54;2>54#"#4'&#"632#"'#"&54;2>54#"#6=4&#"632#"&54>32>32+'";7>54>32>2654#"3254#""3267#"&%3254#"H*/ (-%4% %01$&) 31'&0 UM / %-VNLG5 # *(>`Kzx45WMM+85 # *)1(90a+L&: yzEmIa<'81a+O'*""#+8A-%/8## 8%q D*)9- ((!"!'3-# A." +_|\=$#! (8OP73E`4&_ CD$$! )79,*> 5 /(6@7P[%(>5X&,, 01(.m "01"L0%2!".54632&#"32>54'#"&547#"&54;2>54#"#4'&#"632#"'#"'&54;2>54#"#54&#"632#"&54>32>32+"32>7>32>32+"32$2654#"324#"324#"15 5A-jTRC7(4mF)HE)D1'%1 6h=3,Sȟ#5 WMMH5 &!4)ft%44VML*84 # *(1'80a+N2ƱzST_a&."`,L'; Ų/=,"'+#### >,") -W=F##(2,$>#4($ _| \=$94,S_B9+]4&_44DC$#! )79,)=5 ' 3$Wx6#75!0'$v --+#b"bL2'654&#"#"'&5467&#"#4&#"632#".547!#"&546;2654&#"#54&#"632#"&54>32>32+";2>?>32>3262654'2654&#"%324#"j6'1YfU#nWA@)$9/*.CyZy ]zRl>6E9p% 3*,2+i_H<<))$;;5,+:T0$6::O7/% 8 #9+(<5!K=If%0K0*0P3 qK6nJPo3G')&1-$=%fJ%#".5467'654&#"#".5467&#"#4&#"632#"&547+"&46;2>54&#"#54&#"632#"&54>32>32+";2>?>32>326322654'2654&#"%2654&#"324#">-1" "*0 WeQ"lV?(< :,(-;Q:&N_ +6o-E2DRq]$,-#|?nDA pVK1F88B7g(3Ub54"+$"<$!&"(#F**D'- 2"+6 BvYu ZxPj-A47p" 1*%1*h[F"3)C;W^ :U*4V866#57:M&=$ &(&)8*': 3 I;Ja*&=#+1YO,# ezH6kIPk2E$!""7$1,#; "!dJ%#".5467654&#"#".5467&#"#4&#"632#"&547+"&46;2>54&#"#54&#"632#"&54>32>32+";2>?>32>326322654'2654&#"2>54'#"&'%2654&#"324#">%&S<*> O3JeQ"lV?(< :,(-;Q:&N_ +6o-E2DRq]$,-#|?nDA pVK1F88B7g(3Ub5*B)1%# #-8g$!&"(#F**?(54.#"#54&#"632#"&54632632+"32?6322654#"324#"i!]Q.$:)*6 !i+ #+hU,2"*)4'SA3:#(%/"*9hR`;1UFUkS0.'2KQDLb.4P** f묊~"mviZx($%1H,( D+ 05A 7$* KC@,;& 8(77-AN57K>CS ' !>"N@//.f%Fx%2#"&547#"$547327654&##"&547'#".546;2>54.#"#54&#"632#"&54632632+"32?62654#"264&+324#")LbOG 2"4BTbi!]Q.$:)*6 !i+ #+hU,2"*)4'SA3:#(%/"*9hR`;1UFUkS0.'2KQ .4!! #**N?Q@N #*F0묊~"mviZx($%1H,( D+ 05A 7$* KC@,;& 8(77-AN57K>CS ' !>"//.#2"#Df%F?w%2"&547#"$547327654&##"&547'#".546;2>54.#"#54&#"632#"&54632632+"32?62654#"324#"2654&'"2654&'#"&=)LbA33:U|TLGi!]Q.$:)*6 !i+ #+hU,2"*)4'SA3:#(%/"*9hR`;1UFUkS0.'2KQ .4P**.*A(:'#83%/):N?4X R/=VU>1& 묊~"mviZx($%1H,( D+ 05A 7$* KC@,;& 8(77-AN57K>CS ' !>"//.f% #y8* 5 5!-8 ,6LEWco#".547&'#"&=4.#"#".5467&#"&546326323265332654.'264&+%2654'X*9 GEE/ "*E0.RB_:-(lUD)< 9/-M^^!kwb?4.MJX<)"?S2):N 3#4""U)5We(@D3sD K3A 2!  ALaLa :2ZzRl.B6;n% nW~?Mj`M]LD,#D4>iM-94"4"K6oIPo #,LUbt#"&547&'#"&=4.#"#".5467&#"&546326323265332654.'2654'2654'#"&'%2654'X*9 VXU<=S,4'.RB_:-(lUD)< 9/-M^^!kwb?4.MJX<)"?S2):N 3#) %)92'#/EN)5We(@D3B`DWW?A'3LaLa :2ZzRl.B6;n% nW~?Mj`M]LD,#D4>iM-94% X8*$ %5) 2+K6oIPo #,Mht#".54>32&#"327#"'#".5&4.'&#"#".5467&#"&54632632265332>54'2654'y$AKe58CDZa'6SO,? Y()5We(&zCnz<!(%KK&90T"3(ZzRl-B67q& ,@7HU_RH"R+#Dq+A3YfK6oIPo #,Lo%#".54632.#"32>54'#"'#"&='.#"#".5467&#"&546326323265332654'72'654&#"#54#"&546326%2654',Fa_4AL4]zB' P;@WZCAg9% 5LU9.RD]<5&lXA)< 9/+N]^!kwb?4.M.C"fFS2)>Ju';&% #)5We(na\; 2!7FB '/#%./AR;8MLbG4>7'&'#".'4&#"#".5467&#"&546326323265332>54&'2654'r%.17'502HQQ$N$-I%8 *@# ]N:%5 /*&ATU _jU7.1;?NU#-LD'8 4+#.KV"AD'pzHh=7`B.EH&9/nZxSl.C67n' u?HY`WC"R*"Do.D74aJ5lHNm #+Pkw#"&=#"$&546732>7'&'#".'4&#"#".5467&#"&546326323265332>54&'72654&#"%2654'~,3F/0F17'502HQQ$N$-I%8 *@# ]N:%5 /*&ATU _jU7.1;?NU#-LD'8 4+ %.s ""#.KV" B(4BA5SiǀHh=7`B.EH&9/nZxSl.C67n' u?HY`WC"R*"Do.D74a AD'$"*"J5lHNm #+Pn|#"&547#"$&546732>7'&'#".'4&#"#".5467&#"&546326323265332>54&'72654&'"2654&'#"&=2654'V(; U>=U 17'502HQQ$N$-I%8 *@# ]N:%5 /*&ATU _jU7.1;?NU#-LD'8 4+ %. #(:,8+-/)8#.KV"B%2(>UU>32#"&54632>326322654'264&"%2654&#"))D01C2GpU$mX@)< 9/*0CS-$ -F%/!4B6>AMrk-J)>58Cky&3Wa5$2##2#%%"'"(( =%3AD0.6 PWZ{ [|Rl.C5:q# 5(,(#.?&)\31PeTxM#*l]=J7oILs3G"4""48%2.#9MSPZez2"&54>7654&#"#".5467&#"#4.#">32#"&54632>3262654'2654&#"2>54'#"&'%2654&#"XkZ\S|R!1%FpU$mX@)< 9/*0CS-$ -F%/!4B6>AMrk-J)>58K&3Wa5,%%C*3&1/6%"'"((†laZaCXV@); PWZ{ [|Rl.C5:q# 5(,(#.?&)\31PeTxM#*tJ7oILs3Gu" " &5$ F8%2.#9EDO[233!53654&#""&547&#"#4&#">32#"&54763263262654'2654&#"Vj_SןjJ8NNh@M&/SI63L&.!/F5>@OJH`_F$V.#)? )F",*O'&!)(}_}EG":KgInCRNCsA 2(,(6.I8)SA0LlOqRNON8/a-U*.:P/%$/.#9E;OWbn233##"&547!53654&#""&547&#"#4&#">32#"&5476326326264&"%2654'2654&#"Vj_S$(A31C)jJ8NNh@M&/SI63L&.!/F5>@OJH`_F$V.#)74""4" )F",*O'&!)(}_}EG51CC15":KgInCRNCsA 2(,(6.I8)SA0LlOqRNON"4""48/a-U*.:P/%$/.#9EN[ny233#"&547!53654&#""&547&#"#4&#">32#"&54763263262654&#"2654'#"&'2654'2654&#"Vj_S'1TzS3jJ8NNh@M&/SI63L&.!/F5>@OJH`_F$V.#),%$+72'1 *( )F",*O'&!)(}_}EG&CAZTBF(":KgInCRNCsA 2(,(6.I8)SA0LlOqRNONX:($ $6"! #. B8/a-U*.:P/%$/.#9Miu2!3#".54>32&#"326=!53>54&#"#"&547&#"#4&#">32#"&54632>3262654'2654&#"RgZS.IU=N4bVlB=j"\H6u+0D7" N 8%2?Z(0SJ2-F%+!4B6>AMrh0 ;+8()G#*@9 #L%"'"((vXr^ /5& $ !&_N"%e2LeNf-6%M;bT1),(5#.?&+\31PeT{M59.T4 U+*+P8%2.#9P=fs~2#"'&547&#"!53>54&#"#"&547&#"#4&#"632#".54632>326323&5462>54&'%2654'2654&#"w/J) H;5"`.C 2%#,;/ C 3#,9N(#M>-DV'6- 8/$5 |e[*-2"#/F^L6pX'$73,"""*;H6Zy7.:Z/E74l &c6HeMe,6%M7&#"!53>54&#"#"&547&#"#4&#"632#".54632>326323&547632632#!"3!!"&54>3!2654.'#"&%2654'2654&#"%2>54'[45#/J72_޴'(;/ C 3#,9N(#M>-DV'6- 8/$5 |e[*-2"#/F^L<@?Z\Cgf5!$K,<$ O_$/ &N<=P$73,"""6% &&+15X( =;Lx;"$r(HeMe,6%M54&+532>54&+#"&54>7&#"!53>54&#"#"&547&#"#4&#"632#".54632>3263232&54763262654'%2654'2654&#"Y]|HJQ9K).:*),,!) SD"S<9K"-!%<5L#_#,;/ C 3#,9N(#M>-DV'6- 8/$5 |e[*-2"#/F^L3^7<@?Zf> r"*@G1$73,"""PC@(C4GI 0&,< ($7#! +5ATPo^A%C+$$0G9x;&c6HeMe,6%M32&#"32>54&'#".5467&#"!53654&#"#"&547&#"#4&#"3>32".54632>326323&7327654'2654'2>54&#"qZl9A\r;J4POKF70(OQ(0K. ,'I<"2 EE$8.D +-O;/ C*# .7N(#M>,ES ), 9^<{e[*6$2"#0I[M5&$s$7!& } !"er_ % !)>TM'6_5X|(:.=k 5/E7)q &LmIeMf,@ N32#"&547'#".54>;2654#"#54&#"#"&547&#"#4&#">32#"&54632>3263262654#"%2654'2654&#"L-7%)B'-aHc.*;9*(8 ;E0 "*(BB"2^e3&S?35$(1#0CSJ2-F%.!4B6>AMrk-J);$'3r.-4z**%"'"(( 8' $!)!2%"-&D&#4 B0b9<-@.8 E #9+/&5(,(5#.?&)\31PeTxM#*55\//."??8%2.#9M:)%#!"3!!"&57>3!2654&'#"&547#"&546;2>54#"#54&#"#"&547&#"#4&#">32#"&54632>32632632+"32>322654&#"%2654'2654&#")T4S..5*8)!-H3'8-)7 _g05BwY $-e7"S?35$(1#0CSJ2-F%.!4B6>AMrk-J);$'3r.l-7%XJ-I(.fMh/BZ ! ~**%"'"(( 921%', 7")2'<.6,=J 0!b>T@.8 E #9+/&5(,(5#.?&)\31PfSxM#*55 8'HW%*!%-%I;"??8%2.#9M<%2#!"3!!"&5463!254#5254##"&547#"54>;2>54#"#54&#"#"&547&#"#4&#">32#"&54632>32632632+"32>762654#"%2654'2654&#"fV '2))[)33)%.'P8-)7 -E!A2FV1*> e7"S?35$(1#0CSJ2-F%.!4B6>AMrk-J);$'3r.l-7%]3HP&OGQ.1**%"'"((8&  0%:5$ '$*<$)2'/s.:* b>T@.8 E #9+/&5(,(5#.?&)\31PfSxM#*55 8'GX1'4)4!/*."??8%2.#9MUgs2'654&#"#".5467&#"#4&#"#".547&#"#4&#"632#"&54632632632>3262654'!2>54'2654&#"bl{1WlQ nUD)< 80'3JSF9(k ?+': a(0CSI3-F%-< "*F-@NsSE1VC,2Je:I9=,7N(5We"(X-02) &&!).•eHDt]z ]zOo.B67r% 5? 2#"&54632>32632>3262654'2654&#'%2>54'2654&#"bkN2DbC.)? )E+!nTE(< 80'3JSF9+k$4+': a*2ASI3Qa .B2 0!AMrl,K)D+:Bi6>1B'4K(5We"4"" ,$. X+21*$#&!).cVW 6.1CD0&@ MP1=2" ]zRl-B77r% 5? 7654.#"#".5467&#"#4&#"#".547&#"#4&#">2#"&54632>32632>3262654'2654&#"2654'#"'%2>54'2654&#"bkW`"+ =T0"F )E+!nTE(< 80'3JSF9+k$4+': a*2ASI3Qa .B2 0!AMrl,K)D+:Bi6>1B'4K(5We",%"D,65%C7$. X+21*$#&!).c]Ze%: W?(: PU1=2" ]zRl-B77r% 5? 54&+"&54>32&#"32654&"6HT>;A3"2 t==o6-.5a:J(O7D5i?L) k4""4"?5J)!E1C+! $!?9 ''F4/.G80)""##K.;N2"&547&'732>54&+"&54>32&#"32654&'#2654'#"&'6HTJKTzS+`1=o6-.5a:J(O7D5i?L) ^$$,63&"/*(?5S'"WAZUA@'49 ''F4/.G80)" !X:($ &4' #. K3"#"&54632&#"32>54/.54632&L@JbM`-IK(IjYDX<-><;/10cl%0r]H=8'MWE5L'.& 0*' 6%] <(FUE5A?+Q%2#"&54632&#"32654'#"&4632&#"32'654#"#465654#"&546326NYmIabK^5Z2EJ5`zi=R`qJ=T$  aOt9/-;62&!,r\HnU:4^J    '   G>4%#"&'532654&+53254&+"&54632&#";27Sa?wi5B9!x/#w:Ip^zG7g@O%e31 8'(B7+)1D*G4BOG70'# /!TG>K%#".547&'532654&+53254&+"&54632&#";22654&'#711A3"1 ~4i5B9!x/#w:Ip^zG7g@O%e31n ( (# 8'/#<1C)" &'7+)1D*G4BOG70'# /!T+ ,#G@;FY%"&547&'532654&+53254&+"&54632&#";22654&"2654'#"&'7HBTzS1c,i5B9!x/#w:Ip^zG7g@O%e31%&$,65$"/*( 8'>$PAZUAD( 7+)1D*G4BOG70'# /!T%X:(" '3' #. Jn,%2#"'&54732654&#"+"54632&#"327GZq\gdTBvAR.5o\|G7g9Zw K7=HRTogOBU^.&"uHUG7/lJEo7E%2#".547&'&54732654&#"+"54632&#"3272654&#GZ67E/ "*abTBvAR.5o\|G7g9Zw ,2#" K7;$!B3A 2!"RSmgOBU^.&"uHUG7/l"! Js5BT%2#"&547.54732654&#"+"54632&#"3272654&'2654'#"&'GZGLU<=S(I`TBvAR.5o\|G7g9Zw $,62'#/EK7E$"WDWUA='A}NgOBU^.&"uHUG7/l !X9)$ $6) 2+MT(4%#".547#"&546322>54&#"264&+0E/ ") _yad1<*bGHa"I2## 4 6-3A 1"{afhcH!H0Id`G3>+"4"M&6H2"&547.5462>54&#"2654&+2654'#"&''d`aTzS"*<.!yQ1<*bGHa"I&! +72'1EhwCeBYW?6' -O2fn!H0Id`G3>+X8*" %5"! 2+MEJR#".547&'#"&=74&#".5463232653327654&'264&"W)8 KE/ "*E12YHa5!(0 6.*; qK7\G-50S(.5*.G)2##2#@D0tE33A 2!" BLePSG>%M354'#"&'W)8 ^\S>=S.5%2YHa5!(0 6.*; qK7\G-50S(.5*.G) &0 3&1 E@D0CbCXU)5LePSG>%M35#"'#".54754#".546323265332654&'N:K`|[oF5c"_Z%@i=)3?e(3T86!S:Op*: gS8CX'6SOBRB1&~E*!*#"$5?2'KK*R9fJyLCC1e3TU`G+#DqcJ7qM@v#"'#"&=74&#".5463232653327654&'2>54'7#"'#"&=74#"&54632326=3W)8 "/:)S92YHa5!(0 6.*; qK7\G-50S(.5*.G)  KV .%7%!:3>7 JZI4,6.#:@D08X1 MLePSG>%M354'7"&547&'#"&=74#"&54632326=3264&+W)8 "/:)S92YHa5!(0 6.*; qK7\G-50S(.5*.G)  KV<=B\B+!:3>7 JZI4,6.#:C#!!$@D08X1 MLePSG>%M354'7#"&547&'#"&=74#"&54632326=32654'"'2654'#"&547W)8 "/:)S92YHa5!(0 6.*; qK7\G-50S(.5*.G)  KV=F$ 4H7!:3>7 JZI4,6.#:2 L4)'"@D08X1 MLePSG>%M3%M3,6'/( . M@~#"'#"&=74&#".5463232653327654&'2"&547&'#"&=4#"&54632326=33267#"&5462654&#"264&#"W)8 "/:)S92YHa5!(0 6.*; qK7\G-50S(.5*.G)F'1C?B\B&# %M3,6'/( . -&--%M@#"'#"&=74&#".5463232653327654&'2#"&547&'#"&=4#"&54632326=33267#"&5462654&#"2654'#"'2654'#"&547W)8 "/:)S92YHa5!(0 6.*; qK7\G-50S(.5*.G)F'1DH$ 4H1" %M3,6'/( .  P." ,4 '!M@HT[#"'#"&=74&#".5463232653327654&'4632!7354&'4#"6W)8 "/:)S92YHa5!(0 6.*; qK7\G-50S(.5*.G)9T&-/*2,Am@D08X1 MLePSG>%M2%M254'#"&5477#W)8 "/:)S92YHa5!(0 6.*; qK7\G-50S(.5*.G)9T*3 4"4H3c&-/*2,Am", )'"0& @D08X1 MLePSG>%M2 $,G4>").gM<$6TN P#!  ,4 '!/M,@bmv#"'#"&=74&#".5463232653327654&'4>32#".54632&#"326=#7354&#'"654&W)8 "/:)S92YHa5!(0 6.*; qK7\G-50S(.5*.G),-CV38J5B;7N;)#$(30,_(t @D08X1 MLePSG>%M2%$bPB!5?tS[!KIfK".547327#"'#"&=4&#".546323265332654'7[ysKi!dEip\22VFe3" (0"G(*: qM7YH.6-S4+8Kj|۷1Mjh7|tck0X[B*vJK`L\J?$I0PgDI4b{TaWNC9C3?cO:`K iXa#".=#".547327#"'#"&=4&#".546323265332654'7264&#"+.C1"2 ysKi!dEip\22VFe3" (0"G(*: qM7YH.6-S4+8Kj|4""' B%1C+! =1Mjh7|tck0X[B*vJK`L\J?$I0PgDI4b{TaWNC9C3?cO:`#2##2KgYfz#"&547#".547327#"'#"&=4&#".546323265332654'72654&#"2654'#"&'"-U<=SsysKi!dEip\22VFe3" (0"G(*: qM7YH.6-S4+8Kj|. C,64%"0 )6 8%DWUA(1Mjh7|tck0X[B*vJK`L\J?$I0PgDI4b{TaWNC9C3?cO:`" v9)" &4)  MFKVb2#".547&'#"&=4&#".54632326533265##"&5462654&#"2>4.#";HQ((E/ "*\D3XIa4"8Mo*; jS//E+6.S!0';`*)1@E=")' &$  $$mWM ?#3A 2! ONiVEKAkO8BG2`'M5HSH;A$5 cr&"R;7K.")1/J1.!6!MKVdv2#"&547&'#"&=4&#".54632326533265##"&5462654&#"2654&+2654'#"&';H"aS>=S&G73XIa4"8Mo*; jS//E+6.S!0';`*)1@E=")' &$ %%+72'17mW0R7 fCXUA<& @NiVEKAkO8BG2`'M5HSH;A$5 cr&"R;7K.")1/J1X9)$ %5"! %9MXd2#"&54632.#"3265#"'#".554#".546323265332>5##".5462654&#"yS8B}[lM=M%!`V+w;Zp,1\/F#S:Op@FgS7EU)5SL9,A! *#3 @G!**!'&q|+!(% i6LL&?B#>fKxL&|Db7YWZH-%@7D'CD&#4(4K.#;( ,7HA f%2654&#"".5473 7#"'#"&574&#".54632326533265##".54632 +*#%'zPb"]BfE!$`?5XL]2"*/ 1#(.hRBQ /!GSN8FU#E "+C154'#"&54>7&#"#4&#"#4&#"632#".547626326322654'%4&#"326g@4$$3@4$dNA8K >($S?5T?3'5SI5,F$-<2D7+5DJGF6\X6=](B)#6(#,%1 -R%")$%'lu, "2W5u"-6XlSB%6-$E:5@(,(6$/A$IV>4,@M+wPMONJK*! !.RkH:D, 9&-@NKGa_F3Ze0@Ql+# E !K' &%!).0 %/4," 3/) ")5'5@'!,(5$/@$H ?*1LfSuPNOMZZK<$*!&y/H0.#$2H;iq|%2#"&547&/3254/&5463232654&#"#4&#"#4&#"632#"&547632632632#"&#"326264&"%264&#"&3-61A31C?& 1_`=q=8#G D9C[SA3'3SJ5,E$-< "*5>@NKGa_F3Ze0@Ql+# E !K'2##2# &%!).0 0!>0DD0)4," 3/) ")5'5@'!,(5$/@$H ?*1LfSuPNOMZZK<$*!&"4""4/H0.#$2Hht%2"&547&/3254/&5463232654&#"#4&#"#4&#"632#"&547632632632#"&#"3262654'#2654'#"&'%264&#"&3-@=TzS+( 1_`=q=8#G D9C[SA3'3SJ5,E$-< "*5>@NKGa_F3Ze0@Ql+# E !K'.$ %)92'17 &%!).0 6%LBYUA?( 4," 3/) ")5'5@'!,(5$/@$H ?*1LfSuPNOMZZK<$*!&! X9)$ %5"! %9/H0.#$2O+iv%2# $5467!2>54/&546322654&#"#4&#"#4&#"632#"&54632632632#"&#"2654&#"rTXob47*92M[\=q=2)CE1EaSA0)4SH4Pa +>+9 /!6Xrk./Y54/&546322654&#"#4&#"#4&#"632#"&54632632632#"&#"2654&+2654&#"rTXLG 2"4B47*92M[\=q=2)CE1EaSA0)4SH4Pa +>+9 /!6Xrk./Y54/&546322654&#"#4&#"#4&#"632#"&54632632632#"&#"2654&'"#2654&'#".=2654&#"rTXs4;U|T47*92M[\=q=2)CE1EaSA0)4SH4Pa +>+9 /!6Xrk./Y/#!De=9^A-W=. 6(5 $!-3)5@( ,*3i_I<<))UczMM; ["2(<!j #y:( 5 5' & +79$3-$$$LK>J[g74>32632632'654&#"#4&#"#4&#"632#"&2#"&5462>54.#"2654&#"L$8\:i0/Xj/*SN:A 3)+hK;'3S@2&6SS,-> !*E4>LOfcNL`]? '.  & 5ML,(*&%HJ8#OMHJ=Df3U6 ARf-$3B),)5G =*:HjlcOIfcGOh 7$2H89Nr,#'0-$'.LVb%#"'#".=4&#"#4&#"#4&#"632#"&5476326326323265332654'74&#"326bIL2+M-7&.%*M7,!,N<.&="'6,<9.:E>BbC:*WS*'M%,(2"/:*FS>:HlRdRWJKHJ^JrD;*"C3%,(2"/:*FS>:HlRdRWJKHJ^JrD;*"C3<#2# +#$.+#%-L_k%2654'7#"&547&'#".=4&#"#4&#"#4&#"632#"&547632632632326532654&+"2>54'#"&'%2654&#"2AgyUYU<>R9(+M-7&.%*M7,!,N<.&="'6,<9.:E>BbC:*WS*'M%,(2"/:*FS>:HlRdRWJKHJ^JrD;*"C3<v+'  '3#  "+#$.+#%-Qx#".54632&#"32>7#"'#".'&54#"#4&#"#4&#"632#"&546326326323265332654'2654&#"%(4%@aE =<%mQNF0*8O]+?, '4W%-I"7KRL5- !#M>-'= '5/;:.;D{f]**M]*!K0<M#-MC6Jg,!$'#JJ+_h< !*% 9.,!HH", aZ2A ",'4#->%G_1;HgSvKKHH5WV]F*"CnhGlS%($1.!"1Ijny#"$&5467!2$7#"'#".'&54#"#4&#"#4&#"632#"&546326326323265332>54.'2654&"6B+6%0)$+J+*K"8KQM6-6M>-D^'6&31'9E|e^))M_* K~+;$-MC&7 !# + 4%'%Az{G`HAV9ziW QI"- [Z1B!$,&5qSG==7.fT{JJGGNFK+!Cn+?3>-- %($1-"$/Imz#".'!"$&5467!2$7#"'#".'&54#"#4&#"#4&#"632#"&546326326323265332>54.'7264&#"2654&" %; 1!+9+6%0)$+J+*K"8KQM6-6M>-D^'6&31'9E|e^))M_* K~+;$-MC&7 !# 6Bs !("+ 4%'-=0 "+10{G`HAV9ziW QI"- [Z1B!$,&5qSG==7.fT{JJGGNFK+!Cn+?3>-- %A$0##"%($1-"$/I{n2#".547!"$&5467!2$7#"'#".'&54#"#4&#"#4&#"632#"&546326326323265332>54.'72654.'2>54&'#".=2654&")5$$5* +$ +6%0)$+J+*K"8KQM6-6M>-D^'6&31'9E|e^))M_* K~+;$-MC&7 !# 6B.:A&0 ("8 +"!, 8+ 4%'_ @V? 8#f{G`HAV9ziW QI"- [Z1B!$,&5qSG==7.fT{JJGGNFK+!Cn+?3>-- %A/y+'85 ""  (:s%($1-"$/K_ky2#"'#".'&54#"#4&#"#4&#"632#".54632632632326533265#".5462654&#"2>54&#"G1K)R8`)&V*?JRM5-!-M>-DV'6- 9/$4 {f^))M^* K1<L2M@35Q!8(49?$#!{!#']m+RQ1II"4(aY1A',&4g]F"3+:G$<;uJJGG5WV[F7;1F]mC>;8F-!:(*6!%/+#$/MIs%#"&547"#"'#".'&54#"#4&#"#4&#"632#".546326326323265332>7#".54>32'2654&#"2654&#"%2654&#"~'= 00B `)&V#7KRM6,7M>-DV'6&307$5 |e^))M^* K2<L4M@3&8 !:- 1'#3 k##"!3&%]+ #''B$z+#:(+4,%($1-D1I{%#"'53264'#"&547&'#".'&54#"#4&#"#4&#"632#".546326326323265332>5#".54>32'2>54&#"2654&#"%2654&#"t2JdK9,$A)8 -#(7Y%$X#7KQM6, !#M>-EU'6- 8/$5 |e^))N^* K~L$.L?4&8 !9, 1'3Ik $" !"#' H:DSA09X )-/$(CJ!-\Z2A ",'4jZG#3+:H%;<zJJGGzF6<0H'AA"C"3+5,^l" <(*6 7$1/ $/K|2#"&54>32&#"32>5#"&'#".'&54#"#4&#"#4&#"632#".5463263263232653325#".5462654&#"2654&#"G$4 ,HqLXlDR.WG1Pqq>b;'6_*L&V"8KRM6,7M>-EU'6&307$5 {f]**L^*L2<L 1M@3{5- 9@##" z+"#'-LO+UoG(.&% ("%.%!4FA"N("J"- \Z3@!$,'4h\G==2Q%;<vKKHH5WW[F7<2E,#4*:F- ;(+4%(%0/ $/LK>s74>32632632'654&#"#4&#"#4&#"632#"&2'654&#"#54&#"#54&#"632#"&546326326%2654&#"2654#"L$8\:i0/Xj/*SN:A 3)+hK;'3S@2&6SS,-> !*E4>Ll6O`F0' :) ":'*k +./"*2fDE 9E C,(*&F-%HJ8#OMHJ=Df3U6 ARf-$3B),)5G =*:HjsVCm**[6AѶ ++.6)&0G4`U21./C,#'0-$'.76LK>|74>32632632'654&#"#4&#"#4&#"632#"&2#"&547&#"#54&#"#54&#"3632#"&54>3263262654'2654&#"3254&#"L$8\:i0/Xj/*SN:A 3)+hK;'3S@2&6SS,-> !*E4>LICZ5+,6G#.:"("9.#,*!-$),4(:.=0$>;$0j"5B$,(*& .%HJ8#OMHJ=Df3U6 ARf-$3B),)5G =*:HjteM7DE5Q6 Ӷ-"' .:( 3E65N#330.#)Q.5I"+G,#'0-$'.4LYY>74>32632632'654&#"#4&#"#4&#"632#"&4>32632632#"'732>54'#"&54>7&#"#54&#"#54&#"632#"&2654'2654&#"3254&#"L$8\:i0/Xj/*SN:A 3)+hK;'3S@2&6SS,-> !*E4>L&/# ?.">:$(=T";9cD)% (=> 4+&2.4,:)! :.$#2 )!.$)3,W #;,(*&,%HJ8#OMHJ=Df3U6 ARf-$3B),)5G =*:Hj+D&3300L U7Oa %5.J#;G7, !,!+Ҷ")"1 .:(4K '-) %$H,#'0-$'.(5 M1=HQ>32!4&#"#4&#"632#"&546326322654&#""654&354#"TF"H5#8SH4Ob +>!2 5?AMr 5( 4]?P$#'"(# . )sQNF[423A &,(5i_I"3+2OeS{ MB9%2.#=[#9;%3hEsF1MA;DOXd>32#"&547!4&#"#4&#"632#"&54632632354#'"654&2654&"%2654&#""TFCbC H5#8SH4Ob +>!2 5?AMr 5( 4]?PQNF . )z4"!6!$#'"(#[42-1CD0.3A &,(5i_I"3+2OeS{ MB^EsF1#9;%3"##29%2.#=M<EP]p|>32##"&547!4&#"#4&#"632#"&54632632354#'"654&2654&#"2654'#"&'%2654&#""TF.8U<=S:H5#8SH4Ob +>!2 5?AMr 5( 4]?PQNF . )m%)92'"/ 0$#'"(#[42 GDWUAJ"3A &,(5i_I"3+2OeS{ MB^EsF1#9;%3 "X8*$ $6( &)9%2.#=I\ I%2654'%#!"3!!"&5463!2654&+"#"&5467&#".54632632v*4We5bHl?#93>?2j8KgU nSB@P<,0IY*5!>.v_;37F6V3" s;1]=D\.8f_'J5,+5kMYlMgGWTF1` `H&^"g+Xx 1A;D\ S%2654'%#!"3!!"&54>3!2654&+532654&#"#"&5467&#"&54632632r*4Vf6I>J>>40B 0!eH>(-7@C5lU@?Q/:(HZ_!kxX<75d Kx<0Z>EY.8#xBfEAL,@co2#".54632.#"32654&#"#".547&#".54763262'654.#"#54#"&546326'2654'{˦AL4]xD' O;@WZCx`7nWB)< h)L`_!38DE_6.1 &%  #V)5We(Ι 2!7FB '/#%.Ɯ \zRl,B6}Q rU}>%vB^GG' , ;% 'I9oIQo #,GNXa2'654&#"#"&5467&#"#4&#"#"&5467&#"&5463263263262654' 2654' l,"1Zt]nSB@P:/!3KSL9lSB@P9/+'?% ^!k}]B04;k@1g5-9P*4Xe6T4WeÑh,L3 Bu]{ \{UgfQ9q$B5 @0-_vn_nRCAO:/!3KSJ;lRCAO9/+'?% ^!kyaA14;k@1g5-9@r9oBV3XeJ+3We4P*I4+-6h]r \{QkhO;o$B5 9O ZzQkhO9q$ /:-=Kc\[q=[I7mKPo3FI7oIPo4EGnw2#!"3!!"&5463!2654.+532654&#"#"&5467&#"#4&#"#"&5467&#"&54632632>3262654'2654',eRP-D5_"#Z1?@0_JZ$! &%^C7nRCAO90!5ISK:lRCAO71+'?% ^!kyaA14;k@N:5-;}V3XeJ+3We4N?G))K0E I6),7E:$/ ,B,:\{QkhO9o&D3 :N ZzQkhO9m( /:-=Kc\<tI7oIPo3FI7oIPo4EHdp|2#"&54632&#"32>54&#"#".5467&#"#4&#"#".5467&#"&5463263263262654'!2654'"p/GbX0Y|GZO0"U"\}%CK6#pV$nUD)< 9/SE9&lUD)< 9/,0I#_!j{]>57Di6$~%48Q*4We()5We(wbT5,$'+.IUg ]yRl-B69q$ t ;J[yRl,B6:o% ,?7HWa~[ZsJ8nJQo #,I9nJQo #,H<$2'654.#"#54#"&546326".54632.#"32>54.#"#".5467&#"#4&#"#".5467&#"&546326326326322654'!2654'&%  #"?N5]yC' O;?X<-3Pt; .T6+nUD)< 9/SF8"lWB)< 80*0I#_!j{]>57Di6$~'28Lt*4We()5We(' ,  ;% & 3#7FB '/#*?gj8JhT< \zRl-B6:o% t 8MZzRl,B69n' ,?7HUa~[Z֞kK7nJQo #,I9nJQo #,K=\fr2# $54732>54&#"#".547&#"#4&#"#".547&#"&54632632>3262654'!2654'1`vT؉[%R7FlFeP_K<%5 ZlL<1]N:%5 Z!@TU!_mR8./<]/ B29#2F".KV.P#-KV#i6gmR4޹ytgk/JyNWu ]yPo.C6|Q r :IZxSl.C6{Q t?FWa~V9wH6kINm2EI5lHNm "+Kgq~2#".547# $54732>54&#"#".547&#"#4&#"#".547&#"&54632632>3262654'2654&#"%2654'1`v]+0F/#2 [%R7FlFeP_K<%5 ZlL<1]N:%5 Z!@TU!_mR8./<]/ B29#2F".KV.2"! #-KV#ie B&4B*" A޹ytgk/JyNWu ]yPo-B7|Q r :IZxSl.C6{Q t?FWa~V9wH6kINm2E## I5lHNm "+Keo}2#"&547# $54732>54&#"#".547&#"#4&#"#".547&#"&54632632>3262654'2654&'"2654&'#"&=2654'1`vC?3NU>=U[%R7FlFeP_K<%5 ZlL<1]N:%5 Z!@TU!_mR8./<]/ B29#2F".KV.  #(:,8+-/)8#-KV#iM4N|UU>!/޹ytgk/JyNWu ]yPo-B7|Q r :IZxSl.C6{Q t?FWa~V9wH6kINm2E   [7+#5588 (:[I5lHNm "+I2<E2!5654&#"#"&5467&#".5463263235462654'"!54&[s|RfK$nSB?Q:.,L`_!47wb=63Hd~Cr*4We6=L#Uvb@lYy ]ySjeR9r# qV}>$wAhIVirH9nJQo6CYWEϟ[qIE?HT^2##".547!5654&#"#"&5467&#".546326323546"!54&2654&'#%2654'[s E/ "*!=RfK$nSB?Q:.,L`_!47wb=63Hd~Crj=L#U4"R*4We6vb-3A 2!-@lYy ]ySjeR9r# qV}>$wAhIVi5WEϟ[q"!!H9nJQo6CI=FSeot2##"&547!5654&#"#"&5467&#".546326323546"!54&2654&#"2654'#"&'%2654'#632[s$.U<=S1bRfK$nSB?Q:.,L`_!47wb=63Hd~Crj=L#U &&)92'#.7Y*4We6vb!@DWW?D"@lYy ]ySjeR9r# qV}>$wAhIVi5WEϟ[q"X8*" %5( &8H9nJQo6C5M[bn2#".54632&#"3265!5>54.#"#".5467&#"&54632632354>54#"%2654' .J, 4lMAL3x`RG!)M&ZJ6\e)*%K1$nUD)< 9/+0I#_!j{]?43Hb&>C )5We(,;7#??&!+#Rhh:>G1 ]yRl,B63263262654'H9B-0++iJ>&3S#5+nSB@P9/!Nc_!k*14%:69@gI9\T4We1bA1S6" ?Rb,%&7 ]zRjeR;m&F|?M0O2$!!LNoG9nJPo5HV[e%#"/3254.'&5463232654&#"#4&#"#"&5467&#"&54632632632#"&#"326322654'VU`O0 *]dHe .9# L =?B[SU@,#nTA@O9/#Mc^ k[<6=CvO?Qi+$ D M%*7%+4Xd4V';5+-/) 04(?L\{VggP=m$F~?Kg!#^ZI=#,'-EH9nJQo4EHcDlv%#!"3!!"&5463!2654&#""#"546323254&#"#54&#"#"&5467&#".54632632632#"&#"32636322654'DDN @#|4>@26?'  Y3) L (H;AUSW5*$nSA>R:.!Db(7 &FvYB1?>kSE}Ri%*8 ?M 1.-+4Xd5^)>)B1()9# Q")&!(-!>6MhGXTF0_ ^J)Z_IYmNLG3) ' K C/ 41**3   r/% B (C4F\SW5*$nSA>R:. 0=))6 &wYB16MhGXTF0_ !I2)Z-D(ZlNL6-& &!n`r|%2#".54>32&#"32654&#"&54>7654&#"#4&#"#".5467&#"&54632632632#"&#"2654'.C" "8`@2 \O3(M $'ZZ_LM4-*A-9C1E`SY76nVA)< 9/,0I#^ k{^>5;R7i?8D/\;.")6Xd500-2#!!#H74632632632!54.#"#"&5467&#"&%354#'"654&2654'Mwa;87=nJL-*3& % nTB@O80!$Ja^!jRMF@/+*4We6h ZZ)A%]yTigP32&#"3265!54.#"#".5467&#"&546326326354#'"654&2654'Eb4r_6OC\I6G&dP54&#""&5467&#"&54632632)6W`0&N.MާLxI0wC#!nTO9/#!2J!c&jX9:@;k:X5H:oIMs7Cwi\k"7IH&r\zUhhO;o$0F:>Kk {+X\E-KFPZ#".547#"$54732>54&#""&5467&#"&54632632%2654'264&#"O)-C1"2 P[N.MާLxI0wC#!nTO9/#!2J!c&jX9:@;kr)6W`0)4""*E ?&1C*! wi\k"7IH&r\zUhhO;o$0F:>Kk {H:oIMs7C"4"KFP]r#"&547#"$54732>54&#""&5467&#"&54632632%2654'2654&#"2>54'#"&'3,T=>R ??N.MާLxI0wC#!nTO9/#!2J!c&jX9:@;kr)6W`0.%C*2'1  /` 6%AZUA# wi\k"7IH&r\zUhhO;o$0F:>Kk {6H:oIMs7Cw# $ %5"! &)L -7_h2'654&#"#"&5467&#"&5463262654'#"&=4&#"#"&5463232654'2654' t5'1VqSnSB@P9/&0H#^!kX:84M*5We2J*C4/>,#N6%+6^G:D=?V/:I8NaH:+Z69a"#&C6%NOL  -\ft}2'654&#"#"&5467&#"&546326"&547&=4&#"#"&5463232654'%2654'2654&'+'2654' t5'1VqSnSB@P9/&0H#^!kX:84*.=A^A&9,#N6%+6^G:D=?V/:I8NaH:+Z69a"YH8oIPo4E$"+&#&C6%NOL -`jx2'654&#"#"&5467&#"&546326#"&547&=4&#"#"&5463232654'%2654'2654'#"'2654'#"&547'2654' t5'1VqSnSB@P9/&0H#^!kX:84*8G$ 4H<8,#N6%+6^G:D=?V/:I8NaH:+Z69a"YH8oIPo4E:   P." ,4 '!#&C6%NOGJT%2654'7#"&=4&#"#4&#"#"&5467&#"&54632632>32%2654'@4Hp ~bRES?) #*SJ4%lSBAO80%0I$_!k}]:81Jb=#6I[7_*4W`22iM;Hc~`QMRF 2! :K[ySjhO>l$1G=}?Mg [ hUEKCH9nJLt6CGEVcm%2654'7#".47.=4&#"#4&#"#"&5467&#"&54632632>32264&+%2654'@4Hp ~BB 2! "*?8?) #*SJ4%lSBAO80%0I$_!k}]:81Jb=#6I[7@4"" A*4W`22iM;Hu@ I "* 1Da>MRF 2! :K[ySjhO>l$1G=}?Mg [ hUEKC#2# H9nJLt6CGQ^pz%2654'7"&547&=4&#"#4&#"#"&5467&#"&54632632>322654&'"#2654'#"&'%2654'@4Hp ~VTTzS5_?) #*SJ4%lSBAO80%0I$_!k}]:81Jb=#6I[7. 'C,65$"..V*4W`22iM;H>]AZUAH''MRF 2! :K[ySjhO>l$1G=}?Mg [ hUEKC "v9)" (2) @H9nJLt6CHw%4&'7#".54632&#"32>5#".=4&54.#"#4&#"#".5467&#"&54632632>3232>2654'E5 #8MgB>P6x`rC8b&WZ$In?' .Z&9 ).LSE9&lUD)< 9/-0I#_!j{]>57Di6=1&=$ $)?)5W`3:l!i>_\C9# *#/A;!:&9/W %,6> ;J[yQr/D7=m$ ,?7HWa~[#, )83B6-*=4I9nJLt4FH"2'654.#"#54#"&546326".54632.#"32654'#"&'254&#"#4&#"#".5467&#"&54632632>3232654'72654'&%  #DN5]xD' P;?XXAy.RDY<(.LSE9$lXA)< 80,0I#_!j{]>57Di6X%*7+ ,8Bp (;,DaX)5W`3% , ;% & 2!7FB '/#%.n(g?QZL6> ;J[yTo/D7>l$ ,?7HWa~[2) ?,\). gL<Ojp=^R3lI9nJLt4FG U^h2!535462654'7#"&=4&#"#4&#"#"&5467&#"&54632632>32"!54&2654'\uّp4Hp ~bRES?) #*SJ4%lSBAO80%0I$_!k}]:81Jb=#6I[7 @P#Q*4W`2zb"WgpiM;Hc~`QMRF 2! :K[ySjhO>l$1G=}?Mg [ hUEKC]YFιRbH9nJLt6CGEbkv2##".547!535462654'7#"&=4&#"#4&#"#"&5467&#"&54632632>32"!54&2654'#%2654'\uD0 "*p4Hp ~bRES?) #*SJ4%lSBAO80%0I$_!k}]:81Jb=#6I[7 @P#Q"/-#%*4W`2zb,3A 2!,"WgpiM;Hc~`QMRF 2! :K[ySjhO>l$1G=}?Mg [ hUEKC]YFιRb"0 1!H9nJLt6CG_hs2#"&547!535462654'7#"&=4&#"#4&#"#"&5467&#"&54632632>32"!54&2654&"2>54'#"&'%2654'\u-TzS0p4Hp ~bRES?) #*SJ4%lSBAO80%0I$_!k}]:81Jb=#6I[7 @P#Q&%&%*2'1 /K*4W`2zb"AAZUAB&"WgpiM;Hc~`QMRF 2! :K[ySjhO>l$1G=}?Mg [ hUEKC]YFιRb X# " %5"! &)H9nJLt6CG%py2##"&54>32&#"3265!535462654'7#"&=4&#"#4&#"#"&5467&#"&54632632>32"!54&2654'#AD)_6OC\I6G&dPl$1G=}?Mg [ hUEKC]YFιaSH9nJLt6CGJpz%2654'7#"&=4&#"#4&#"#"&5467&#"&54632632>322'654&#"#54&#"&546326%2654'@4Hp ~bRES?) #*SJ4%lSBAO80%0I$_!k}]:81Jb=#6I[7K6H)?(. 9'(1KUJ;7&%G*4W`22iM;Hc~`QMRF 2! :K[ySjhO>l$1G=}?Mg [ hUEKCHWB$-) *Z+Fѵ&!A0\#/gAZ10KH9nJLt6CGJnx%2654'7#"&=4&#"#4&#"#"&5467&#"&54632632>322#"&547&#"#54#"&5463262654'2654'@4Hp ~bRES?) #*SJ4%lSBAO80%0I$_!k}]:81Jb=#6I[7+CZ6+*7D+97'4MYJ86%/k 6B$*4W`22iM;Hc~`QMRF 2! :K[ySjhO>l$1G=}?Mg [ hUEKCHiJ7EC7S5 ѵHB4Z!-hAZ0/)"O.4E$+OH9nJLt6CGXJ%2654'7#"&=4&#"#4&#"#"&5467&#"&54632632>324>32632#"'732>54'#"&5467&#"#54#"&2654'2654'@4Hp ~bRES?) #*SJ4%lSBAO80%0I$_!k}]:81Jb=#6I[7 0%5&,;R0<9bH&& (: ; 6+&2>+=",98  NZx"$%q*4W`22iM;Hc~`QMRF 2! :K[ySjhO>l$1G=}?Mg [ hUEKC.B 0.KT2Kf ':0P&32354&'4#"62654'9T4Hp ~bRES?) #*SJ4%lSBAO80%0I$_!k}]:81Jb=#6I[7a&-/*2,Am0*4W`2c]xliM;Hc~`QMRF 2! :K[ySjhO>l$1G=}?Mg [ hUEKC).gM<$6TOH9nJLt6CG JTfqx%2654'7#"&=4&#"#4&#"#"&5467&#"&54632632>32%2654'4632##"&547#7354&'4#"62654'#@4Hp ~bRES?) #*SJ4%lSBAO80%0I$_!k}]:81Jb=#6I[7_*4W`2b9T&C-/A&o$$'..*2,Am.&11%2iM;Hc~`QMRF 2! :K[ySjhO>l$1G=}?Mg [ hUEKCH9nJLt6Cc]x`@A/0?$#gN;$6TN$2 2$GJTiu|%2654'7#"&=4&#"#4&#"#"&5467&#"&54632632>32%2654'4632##"&547#7354&'4#"62654&"2>4'#"&5477#@4Hp ~bRES?) #*SJ4%lSBAO80%0I$_!k}]:81Jb=#6I[7_*4W`2p9T*3 4"4H3c&..*2,Am& %()'"0& 2iM;Hc~`QMRF 2! :K[ySjhO>l$1G=}?Mg [ hUEKCH9nJLt6Cc]x"> $,G4>").gN;$6TO $P '< ,4 '!/G,JTs~%2654'7#"&=4&#"#4&#"#"&5467&#"&54632632>32%2654'432#".54632&#"326=#7354&#'"654&@4Hp ~bRES?) #*SJ4%lSBAO80%0I$_!k}]:81Jb=#6I[7_*4W`2jCV37H7C;7N<(#$(30,_ t 2iM;Hc~`QMRF 2! :K[ySjhO>l$1G=}?Mg [ hUEKCH9nJLt6C㢱JM6: >%$bQA (1tS[!QH q%2654'#".5473267#"'.'&#"#4&#"#".547&#"&54632632>3232>54'#.KR+151Z{o܁Pi%^ 1Qj\bZ  09M<0]K=%5 Z!4aY$_jU9,1;\/ A3AR3 "&c7H6lHLo2E2j9&,UXJ:!2Noi=speo =E:8&/DL$j=5 :IZxRm-C6{Q eNKW^V8fN WK$H0?Qq}#"&547#".5473267#"'.'&#"#4&#"#".547&#"&54632632>3232>54'72654&#"%2654'%5*" 2D͑܁Pi%^ 1Qj\bZ  09M<0]K=%5 Z!4aY$_jU9,1;\/ A3AR3 "&c$152""  #.KR+=-"3 D2 =2Noi=speo =E:8&/DL$j=5 :IZxRm-C6{Q eNKW^V8fN WK$H0?2j9&!! 6H6lHLo2EQp{"&547#".5473267#"'.'&#"#4&#"#".547&#"&54632632>3232>54'72654&'"2654&'#".=2654'j(/!U|T܁Pi%^ 1Qj\bZ  09M<0]K=%5 Z!4aY$_jU9,1;\/ A3AR3 "&c$15!"G("8&$ $'##.KR+C<&=VU>("-2Noi=speo =E:8&/DL$j=5 :IZxRm-C6{Q eNKW^V8fN WK$H0?2j9&%.[02 75' & *\H6lHLo2EYB%#12##".547!3354>54#"2>54&#"T9T*!A3+9 T&?CΗ# )DE$,1C20,j6N'bǘΝ "+Y"$1C2##"&547!3354>54#"2654&#"2654'#"&'T9T*)- >*?Q/)T&?CΗ&%%+74&0 8)DE$&?-7&V?B(j6N'bǘ΋W:'" %5# )8M :2!33546"!54&2'654&#"#54&#"&546326 \uqTps@P#R 6H'$?(.!9"(1KUJ;7&$yciWg3YFιSa[WB,F *Z+Fѵ 'A0\#.hAZ10M 09C2!335462#"&547&#"#54#"&546326"!54&2654' \uqTpCZ5,*7D *97'4MYK74'-%@P#R6B#yciWg(iJ7ED6R6 ѵHC3Z!-hAZ0/YFιSaW)"O.4E#,MX Q\2!33546"!54&4>32632#"'732>54'#"&5467&#"#54#"&2654' \uqTps@P#R@ 0& 4'+",98  NZx/)yciWg3YFιSa.B 0.KS2Ih ':0P&J^`2!33546"!54&4632##"&547#7354&'4#"62654&#"2654'#"&5477# \uqTps@P#R9T*3$ 4H3c&..*2,AmL4)'"V yciWg3YFιSac]x">.G4>"*-gN;$6TN P." ,4 '!xM, 7BK2!33546"!54&4>32#".54632&#"326=#7354&#'"654& \uqTps@P#R,-CV37H7C;7N<($%&+8,_(t yciWg3YFιSa1D KL5;@&"bHJ!5?tS[!M=3;2#"&547&/32654&+532654&#"&546264&"23K"KO5>A31C-1;G4+*4==2M](4""4" .% @K:* G0DD0#7)"'2,)"$/yfO` rL{"4""4M1>RX2"&547/32654&+532654&#"&5462654&+"2654'#"&'7"#6323K"KOJMTzS3 -1;G4+*4==2M](|"%+75$1* .% @KJ(!XBYW?F(7)"'2,)"$/yfO` rL{X9)" '3"!  "MF:%#"&54632&#"32654&+532654&#"&54>32{54.#"&54>32'2'654&#"#465654#"&546326UqtYq?% U+IDS32:F'K+$M*?B4554A?299/:<0>i&,GJ&I_T/-Q(*X'1?!#!("/$"+/,"!0orIf {CKn9H5H A(T3MBM%#"&547&/32654&+532654&+532654&#"&54>322654&"(*02A31C0$M*?B4554A?299/:<0>i&,GJ&I_T/-q+#2#$30#=0DD0' ?!#!("/$"+/,"!0orIf {CKn9H5H A(T""!MEAOb%"&547&/32654&+532654&+532654&#"&54>322654'+2654'#"&'(*>AR~Q2$M*?B4554A?299/:<0>i&,GJ&I_T/-, )"G3&1 +'39#QAZW?F' ?!#!("/$"+/,"!0orIf {CKn9H5H A(T&  %X02  &4"! $. KH%#".54632&#"32654#523254&#"53254&"&54>32,/P_h8C/mO9K$&7pL$RH DT ;V@ & .N217& 7!d@>M!&"A+N'W1%#P#++FI&If {C$EJ6# 0 GMIn#".54632.#"32654&+53254&+57654&#"&54>322'654#"#465654#"&546326s.:(]EZ1 A$/@A2UjaM03 KL8`C-+@ & .N2:pA-.P\ l 3"8EB #0"&-hM@N*W3"# A!-+FI&If {C$EJ6#A3G# 7!d" %#  .% $IN#"'#"&54>54++53264&#"&546323265332654.'+< oSX;mLF=0906++/0(HY(}d>R? N6NXKS8+:J 3$AG7c}M40#"!, B(|eMb qMx>2< !J <C2>fM/;4IFYd#".547&'#"&54>54++53264&#"&546323265332654.'264&++< GDD0 "*J0mLF=0906++/0(HY(}d>R? N6NXKS8+:J 3$2##AG7r> J3A 2!  @40#"!, B(|eMb qMx>2< !J <C2>fM/;4"4" !IVbv"&547&'#"&54>54++53264&#"&546323265332654.'2654&#"2654'#"&'+< \[S|R0;(mLF=0906++/0(HY(}d>R? N6NXKS8+:J 3$%%$,65$".*AG7=aCXV@B)540#"!, B(|eMb qMx>2< !J <C2>fM/;4X:(  '3(  "Im#".54632&#"3267#"'#"&54>54++53264&#"&546323265332654.'.=Q8WEB3:6`rt:]X;mLF=0906++/0(HY(}d>R? N6NXKS8+:J 3$DK1-%LgX* *% %uOM40#"!, B(|eMb qMx>2< !J <C2>fM/;4Id%2654'7#".54632.#"3265#"'#"&54?654#"532654&#"&54632326532'654.#"#54#"&546326?Ox2KPDN6]zB' O;?XY?>_X;lLF=(I(K-+01'HY({f>R?/ #'NE^S6@&%  #"4fM398msU7 2"7FB '/F1OM30/ !#,#!(_Mb oOt@0< $  1#C1?% , ;% %INs#"'#"&54>54++53264&#"&546323265332654.'2'654&#"#54&#"&546326+< oSX;mLF=0906++/0(HY(}d>R? N6NXKS8+:J 3$6H -%?(. 9'(1KUK:7&%AG7c}M40#"!, B(|eMb qMx>2< !J <C2>fM/;4AWB1>*Z+Fѵ&!A0\#/gCX10INr|#"'#"&54>54++53264&#"&546323265332654.'2#"&547&#"#54#"&5463262654'+< oSX;mLF=0906++/0(HY(}d>R? N6NXKS8+:J 3$CZ6+*7D+97'4MYK74'-m6B$AG7c}M40#"!, B(|eMb qMx>2< !J <C2>fM/;4AgL7ED6R6 ѵHD2Z!-hAZ0/)"O.4E$+IXN#"'#"&54>54++53264&#"&546323265332654.'4>32632#"'732>54'#"&5467&#"#54#"&264'+< oSX;mLF=0906++/0(HY(}d>R? N6NXKS8+:J 3$n 0& 4'++>",98  NZx"$%%AG7c}M40#"!, B(|eMb qMx>2< !J <C2>fM/;4.B 0.KT2Kf '0# P&;L9.3A,"˶H 2!Y#-(\ +'!INVbi#"'#"&54>54++53264&#"&546323265332654.'4632!7354&'4#"6+< oSX;mLF=0906++/0(HY(}d>R? N6NXKS8+:J 3$9T&-/*2,AmAG7c}M40#"!, B(|eMb qMx>2< !J <C2>fM/;4c]x).gM<$6TNI N`ls~#"'#"&54>54++53264&#"&546323265332654.'4632##"&547#7354&'4#"62654'#+< oSX;mLF=0906++/0(HY(}d>R? N6NXKS8+:J 3$v9T&C-/A&o&..*2,Am.&11$AG7c}M40#"!, B(|eMb qMx>2< !J <C2>fM/;4c]x`@A/1*-gN;$6TO$2 2&INdpw#"'#"&54>54++53264&#"&546323265332654.'4632##"&547#7354&'4#"62654&#"2654'#"&5477#+< oSX;mLF=0906++/0(HY(}d>R? N6NXKS8+:J 3$v9T*3$ 4H3c&..*2,AmL4)'"V AG7c}M40#"!, B(|eMb qMx>2< !J <C2>fM/;4c]x">.G4>"*-gN;$6TO P." ,4 '!xI,Np{#"'#"&54>54++53264&#"&546323265332654.'4>32#".54632&#"326=#7354&#'"654&+< oSX;mLF=0906++/0(HY(}d>R? N6NXKS8+:J 3$x,-CV37H7C;7N9+$%&+8,_(t AG7c}M40#"!, B(|eMb qMx>2< !J <C2>fM/;41D KL1?@&"bHJ!5?tS[!J? ^#"$547327#"'#"54?654+53254&#"&54>323265332654&'9@VQֹ)h bJ:iJ m{#"&5465#"$547327#"'#"54?654+53254&#"&54>323265332654&'2654&#"9@\,/ 2"3Cg|VQֹ)h bJ:i" "J oy#"&547#"$547327#"'#"54?654+53254&#"&54>323265332654&'72654&'2654&'#"&=(/!7#=USfVQֹ)h bJ:i"%H #.y9)%358&( +7J<h3"&546732654&+532654&#"&54>32y .sVK>3551?:@N`"( !3T6Rg[^AEڹNi;\x]9;P0E&'@`t; @~&FH5!U>Q*7fU?EJh=K2#"&547#"&546732654&+532654&#"&54>2654&+Rg[^JGA31C   .sVK>3551?:@N`"( !3T{ "$U>Q*7f\AO0DD0ڹNi;\x]9;P0E&'@`t; @~&FH5!+#!JJi;FY2#"&547.546732654&+532654&#"&54>2654&#"2654'#"&'Rg[^bcS>?Q! .sVK>3551?:@N`"( !3T=.%C)95$1*(U>Q*7fmBfAZW?6'ڱNi;\x]9;P0E&'@`t; @~&FH5!""w6," '3"! $. ME:B%#".547&'#"'&54>732>5332654.'7264&"2E/ "*H48PJ9; <*#*0B9(,S2*9M0"&,4""4"& 7-3A 2! EM@Dc4F?o732>5332654.'2654&+#2654'#"&'a&,\\T=>R06'8PJ9; <*#*0B9(,S2*9M0"%&%+75$1* 6R0AbBYV@D'4M@Dc4F?o5#"'#"'&54>73265332>54'7Oy}Lc:4SjS"*MJ-7NX57PK9; >.",2I;'4S1!,3#j/<:ag4&!"%1aC9KL?Db2IBn>Ob.!C>4%K1@$Xb3'iN"MKp".54632.#"32>7#"'#"'&54>732>5332654.'7'2'654.#"#54#"&546326@N6]xD' O;?XN9Kp>)]CV98PU63 <*#ZC8)*S2*:L0"OX.G`[&%  #" 2!7FB '0"%05Ls[97MMMKCY4E@BOb + :3?hP+94w\X9% ,  ;% &M.S#"'#"'&54>732>5332654.'2'654&#"#54&#"&546326a&,nQV98PJ9; <*#*0B9(,S2*9M0"6H'$?(.!9"(1KUJ;7&$ 6R0gMM@Dc4F?o732>5332654.'2#"&547&#"#54#"&5463262654'a&,nQV98PJ9; <*#*0B9(,S2*9M0"CZ5,*7D *97'4MYK74'-m6B# 6R0gMM@Dc4F?o732>5332654.'4>32632#"'732>54'#"&5467&#"#54#"&2654'a&,nQV98PJ9; <*#*0B9(,S2*9M0"e 0& 4'+",98  NZx/) 6R0gMM@Dc4F?o732>5332654.'4632!7354&'4#"6a&,nQV98PJ9; <*#*0B9(,S2*9M0"9T&..*2,Am 6R0gMM@Dc4F?o732>5332654.'4632##"&547#7354&'4#"62654'#a&,nQV98PJ9; <*#*0B9(,S2*9M0"9T&C-1?&o&-/*2,Am.&11% 6R0gMM@Dc4F?o732>5332654.'4632##"&547#7354&'4#"62654&#"2654'#"&5477#a&,nQV98PJ9; <*#*0B9(,S2*9M0"9T*3$ 4H3c&-/*2,Am.0&4)'"0&  6R0gMM@Dc4F?o.G4>").gM<$6TN o." ,4 '!/M,.P[d#"'#"'&54>732>5332654.'4>32#".54632&#"326=#7354&#'"654&a&,nQV98PJ9; <*#*0B9(,S2*9M0",-CV37H7C;7N<($%&+8,_(t  6R0gMM@Dc4F?o73265332654&'7J"Ețz'%Z05QSm 4),gG:'5SQAOA'|禃hZs̈́KJa3U5 @Oe+#Cr`IQelGpEQ#".5465#"&547327#"'#"&54>73265332654&'72>54&"%7 2!"2 OYJ"Ețz'%Z05QSm 4),gG:'5SQAOA'|.!6!9>- "*+!   禃hZs̈́KJa3U5 @Oe+#Cr`IQel $$ GpBM_%4&'7#"&547#"&547327#"'#"&54>7326533262654&"2654'#"&'@A'|~#,U<@P >9J"Ețz'%Z05QSm 4),gG:'5SQAOr&%&%+72'#//Qeli 7%DWW? 禃hZs̈́KJa3U5 @Oe+#Cr`X9)" $6) @J%+6"&5467&#"#4&#".54632632'2654&'AQ:0/3@S5!

7&#"#4&#".54>326322654'"q:7&)_=8aPB9J E1'a6CS5!5*. 2#): "/;*P;@\)9:[W'-(1"/mn*QJ_-:ZsVF2?.F3)=304R,:5>D38X0 JH1$JM?%#".54732&#"32654&#"#4&#".54>32632=I3SJ&;KpI6mbM&1S5"3+.3%(."/;*P:%J2/?S6-=L 6.)7pXU:EV4R1 x&% #" 3"7FB '/#"1ġ7db;-$3326326~$:Wf6eq1WlN!$mSB@O80/3BS3" *#4%*: !/9+Q;>Y9/;5=DmKPp5DmJEmS[{RkgP=m$-%=3 &D+):5?E37W0 JJ GeJT%#!"3!!"&5463!2654&#"#"&5467&#"#54&#".546326326322654'rT6@72;.KL\hR!mSA?Q,<14@S5!6ME1'/lNR9BW4243!2654&+532654&#"#"&5467&#"#54&#".546326326322654'N@B6F/: -E:"#Wj"mSA?Q,<12BS5!5NE1;KlNR9BW424FHe0!=x*4Wf7p4@)@0' #3 9,'@= MgGWUE'`%%2+TB?W eGVk=<.-#+8;1]=B^-9HPZ%#".54632&#"32654&#"#"&5467&#"#4&#".546326326322654'ţ!Y\{[YK+Z~[$zp]#mSB@O803*GS3" *#4%*: sPQ;:X#J6Euk$:Wf6 $!+'v [{SjgP=m$&+=3 &D+):5?E3eJI=DmKPp5DH'_".54632.#"32>54.#"#"&5467&#"#4&#".54>32632632'2'654&#"#54#"&546326'2654'>N4]zB' N<@W%8,?c;' 0V7"mQD@O8012?S4!)< 2$*: &S9Q;:X'F8C|3O!&% #"^*4Wf4 3#7FB (/#$+CZT+LgS; [{QliN=m$,%=3-A6-93?E3DS9JIӛ5fkQ3% , ;% %G:nJPp3FJCIS".54732$54&#"#"&5467&#"#4&#".54632632632'2654'yZ!Q" rR mSB@O80.4@S5!5*.)"*: sPQ;D3eJJlG:mKPp4EJZdqu2#".5465#".54732$54&#"#"&5467&#"#4&#".5463263262654'2654.#"'6q]$5 2! "*Z!Q" rR mTA@O80.4@S5!5*.)"*: sPQ;" "!Šlb<- "* 1" ?`zxpbhű][{UhfQ=m$.$=305R*F,>D3eJJsG:mKPp4E$#$qJV`k}2"&547#".54732$54&#"#"&5467&#"#4&#".5463263262654'2654&"2654'#"&'q$,TzS {Z!Q" rR mTA@O80.4@S5!5*.)"*: sPQ;D3eJJsG:mKPp4EX:(" (2"! @H?"!54&'2!5>54&#"#4&#".546326323546!=L"TZ]qO,2N6&3S3" *#4%*: sPQ;8NRl\rWEϟ]o5vb*x54&#"#4&#".546326323546"!54&2>54&" ]qC1"2  ,2N6&3S3" *#4%*: sPQ;8NRl\rj=L"T #2#vb,1C+! +*x54&#"#4&#".546326323546"!54&2654&"2654'#"&' ]q.TzS10,2N6&3S3" *#4%*: sPQ;8NRl\rj=L"T&%&%+74%"./vb"ZUAC%*x32&#"325!5654&#"#4&#"&54632632354>54#"$:S*54&#"#4&#".5463263235462'654&#"#54#"&546326"!54& HÎBL3}_xD' Q;,A ZCv,2N6&3S3" *#4%*: sPQ;8NRl\r&% #~=L"Ty_{ 2!6GB (%.t*xP 3#): lWP;7J79#"I:J :.&(2,*$,+#<3hM,;5?E3cJHI;DL2#"&547&/32654&+532654&#"#4&#".546326264&"0GaCI:9A31C -*3?3%(7/:0/@S2">P 3#): lWP;72##2#J79#"IC$!C0DD0* :.&(2,*$,+#<3hM,;5?E3cJH"4""4IDPe2#"&547"/32654&+532654&#"#4&#".5463262654&#"2>54'#"&'0GaCIBPU<>R4 -*3?3%(7/:0/@S2">P 3#): lWP;7%:*5$"/J79#"IH$!YDWV@G':.&(2,*$,+#<3hM,;5?E3cJH"X$ " '3(  "IM%#"&54>32&#"32654.+532654&#"#4&#".54632632CeJ)CD#n?'3RzB1| :)""9DH:3DS2"=Q3%): mVP;9oOiS:( +KL,(  &Wq%'4;/2>.!=3gO*<5?D3cJHNAL<*CO?H2#"$54732>54.+532654&#"#4&#".546326ReTZ.G`Y-[&YRs7*# 221>C71@S3!U"@T5T3! ܯma} 53$5 78()2+"<4hO*;4@E3cJGOPb2#"&547#"$54732>54.+532654&#"#4&#".5463262654.#"#ReTZGGB21C;?[&YRs7*# 221>C71@S3!U"@T_:N/ED0 ܯma} 53$5 78()2+"<4hO*;4@E3cJG4##OaP\p2#"&547#"$54732>54.+532654&#"#4&#".5463262654&'2>54'#"&'ReTZa`S>=S!-[&YRs7*# 221>C71@S3!U"@To=dCXW?+!ܯma} 53$5 78()2+"<4hO*;4@E3cJG:X+'  &4$ $. IH#"'#"&=4&#"#4&#".546326323265332654.'h*: nST:-\BWA-)32&#"32>5#"'#"&'&54#"#4&#".546326323265332>D2.E_R,Ya_YkQ>\&YV)4\V33fd)2T?Ps)8S,#+@ v>HnTf'(b.D".:(6S%*,? 8m`R~G, %6$ & 9nLWJJW:T.#0@,@3pP(zD`II*?2/[b+$C+F,A3L3\#".547! 7#"'#".=4&#"#4&#"&54632632326533254.'~9>Q|τm~a9$ ,')UPp*U+'K)3#9'* M+2IhwdKC5*I,7&2) .M!/#%I8inQ4 4LO]Q*i]R[w =H ?+eUJ"" ;2dM8L]HF"K4k7A*">,1-?9Lhs#"&5465#".547! 7#"'#".=4&#"#4&#"&54632632326533254.'2654&#"~9>]$5 1!4Bm~a9$ ,')UPp*U+'K)3#9'* M+2IhwdKC5*I,7&2) .M!/#2"",%Ib>, "+F0 = 4LO]Q*i]R[w =H ?+eUJ"" ;2dM8L]HF"K4k7A*">,1-?9!!Lhr#"&547#".547! 7#"'#".=4&#"#4&#"&54632632326533254.'2654&'2654&'#".=~9>1S7#=Um~a9$ ,')UPp*U+'K)3#9'* M+2IhwdKC5*I,7&2) .M!/#", :A)9-8'#!, ;%IiN@ ,#V=$"- 4LO]Q*i]R[w =H ?+eUJ"" ;2dM8L]HF"K4k7A*">,1-?9 #/y9)%35& "  +7I62'654&#"#4&#"#4&#".546326326?Rm!3,'kK=&3SC2(2S2">P3B*: oTR:4^Y69Ça3V5=Ne,$4A)";4hL2p?E4eONIIHF D%2654&'"&5467&#"#4&#"#4&#".54632632632(0/$h98AP91/,GSB3'3S2">P3%*; pSS:6\Y6EY`FIR4?68kQl5E=gQ:p&'-5A*"=3iM);5@D3eNNJJLOoTmIa U%3254'#"'7327654&'#"&5467&#"#4&#"#4&#".54632632632R,#W8Rxq;7')^=89-RB;F`>.VA9SB3'3S2">P3%*: lVS:6\Y6AVtQ[Z2r׋``YOxh؞Oc25@.1?gJ:k(|E`MMIIp$0#""FP_v2#".547#"$&54732654&#"#4&#"#4&#".5463263262654.'2>54&'#".=WjKA(1"U>*4$ l-)+K=2,SA12+S-"?UB3=JoSg'.Xm.'{ " $-8+-!+ 9gT9=(>U ?,")r׋``YOxh؞Oc25@.1?gJ:k(|E`MMIIb [*%358"  )9I-(02!4&#".546326354#4&#"6O(HE)+3!=Q3%*: pTU6DRMFH, i8oM<4gO*;5@E3eTVEuD1<%3IB2*3;F2##"&547!4&#".546326354#4&#"62654&#"O(HE)B21C3!=Q3%*: pTU6DRMFH, iI>* 8oM,/ED0,<4gO*;5@E3eTVEuD1<%3*+I6*3;GY2##"&547#4&#".546326354#4&#"62654&#"2654'#"&'O(HE)%.T=?Q13!=Q3%*: pTU6DRMFH, iA&%&)92'1 78oM"ABYW?C%<4gO*;5@E3eTVEuD1<%3"X8*" %5 # %9M12;C746323632#".54632&#"326=!4&#"&%354#4&#"6MnTl!2܀AM5bXJ 6G+ac(vQ_,#A+(vUNQFH*"i`SSa ",^`0@92FmU^FoI1<$4J%9CK2#".546732>5!4&#"&5463236354+4&#"67=,Otd#bqX4 (.*ZCgDThGc.!?UuoRm!4PNFG,!i #9bA3N&2HLYK(Ff>gpVR4 E.0@gJwK^`SSFqG0=%3JDNVb2#"&547#".546732>5!4&#"&5463236354+4&#"62654&#"7=,AC 2"4B 82bqX4 (.*ZCgDThGc.!?UuoRm!4PNFG,!ib "$+ #9bA>0K #*F0 2HLYK(Ff>gpVR4 E.0@gJwK^`SSFqG0=%31$"! J?CMU`u"&547#".546732>5!4&#"&546323632354+4&#"6264&'2654&'#".=b')U|T'bqX4 (.*ZCgDThGc.!?UuoRm!47=,PNFG,!i .P:'#8'#!+ @*=VU>2'2HLYK(Ff>gpVR4 E.0@gJwK^`SS #9bANFqG0=%37,y8* 5 6& "  +IFr3"&54732654&#"#4&#"&54>32632A$:٠PA&3S3!+3#v!/:*P;:KSnѺgVjǰYw,%<4%K01C6V0 JKuIr?K2#"&547#"&54732654&#"#4&#"&54>3262654&#"Sn^+0F/0FELA$:٠PA&3S3!+3#v!/:*P;:y4!! Óuh A'4BB4gVjǰYw,%<4%K01C6V0 JKV## 2IsrBNd2#".547#"&54732654&#"#4&#"&54>3262654.'"2654&'#"&=SnD=1MU>+> 45A$:٠PA&3S3!+3#v!/:*P;:P.+A)9("8&/)9ÓuV4O<=V$5*(# gVjǰYw,%<4%K01C6V0 JKNz9)858 )9M[6NY#"'&547&#"#4&#"&54632632654&#"'6322'654&#"&5472654')4U?5&"sF*4S,#A+(vpRh%1UC+1#3!*ai|L+A7+-8H ['/8#D)!w54'#"&547')4U?5&"sF*4S,#A+(vpRh%1UC+1#3!*ai>9II98J-A7+-8H [V?>LL'/8#D)@.+,"*#$!w32&#"32>5!5654&#"&5463J"&>O?O6)BC"K?-Dv:D13JH071A5Dd*(:07,7 '&P9-R&?@5C#3XK\K <\2!33#".54632.#"326=!5654&#"&5462'654&#"#54#"&546326)A$&8TŐBL3}_zB'T9,A WFhQH071@4Dc8&% #")'1# 7,G{ 2!6GB )$/h -M&?A5B$5WK\L' ;;% %K >2!3!5654&#"&5464632&#";2#"'73254+"&)A$&8TH071@4DcU:DU/$C#6-?70N1V,&KS>@(/)'1# 7,G -M&?A5B$5WK\b&;0%&05./&5(,K GR2!3!5654&#"&5464632&#";2#"&547&'73254+"&264&#")A$&8TH071@4DcU:DU/$C#6-?7098B./A,1&KS>@(/#!$%)'1# 7,G -M&?A5B$5WK\b&;0%&0=>1??16 &5(,-&-&$K IVj2!3!5654&#"&5462#"&547&'73254+"&54632&#"32654'#"'2654'#"&547)A$&8TH071@4Dc70;=-# 4H7,&KS>@(/:DU/$C#6-  %533/)'1# 7,G -M&?A5B$5WK\E0>!D$5 G4?"&5(,%&;0%&P." '"#& '".KFP2!3!5654&#"&5462'654&#""&547&#"&5463262654')A$&8TH071@4DcL_Q$:H7F8V5C. ?HU;'$#3&8A")'1# 7,G -M&?A5B$5WK\aFZ0 .H=S=O7FD6P6 .'R* 3`EY',F04G#+KWU_2!3!5654&#"&5462#!"3!!"&546;2654&+""&547&#"&5463262654')A$&8TH071@4DcITB0((v"**"$1C7  G9T6B/:AIO>(!"2!7A")'1# 7,G -M&?A5B$5WK\UFAT3$$D3:F2D099-F+?.F 'P;O&:),;$KX^h2!3!5654&#"&5464632632#!"3!!"&546;254&+532654#""&547&#"&72654')A$&8TH071@4DcP:+!$@./*0''s ,#)WL-E8V5C/:@H!7B")'1# 7,G -M&?A5B$5WK\B;IS$.#73%0;!: 1C/::-?/>/G %&9)-9$K-Wa2!3!5654&#"&5462#"&54632&#"32654&#"#".547&#"&54>3262654')A$&8TH071@4DcQ`j@LO=?6$9QQOaG< F7.$. C1>?H&7-$/#8@*)'1# 7,G -M&?A5B$5WK\vYj0u\Ne3262'654#"#54#"&54632'2654')A$&8TH071@4DcQdnN.6%*:@'ThO?$I:+(E3>>G%. $! .#9C )'1# 7,G -M&?A5B$5WK\ˆew &$.+h[z=Q6H,# R6K8S) 2`%; z ' /'H15I !$KB2!3!5654&#"&5462'654&#"#54&#"&546326)A$&8TH071@4Dc6H -%?(. 9'(1KUJ;7&%)'1# 7,G -M&?A5B$5WK\WB1>*Z+Fѵ&!A0\#.hBY10K@J2!3!5654&#"&5462"&547&#"#54#"&5463262654')A$&8TH071@4DcCZ6V6D+97'4MYJ86%/k6B$)'1# 7,G -M&?A5B$5WK\iJ7EC7S5 ѵHB4Z!-hAZ0/)"O.4E$+KX"Xc2!3!5654&#"&5464>32632#"'7327654'#"&5467&#"#54#"&2654')A$&8TH071@4Dc8 /&5&,;R0<9bH'% <)$; 6+&2>+>",98  NZx"#')'1# 7,G -M&?A5B$5WK\'.B 0.KT2Kf 50=P&( # -M.7B4B$5WJ]K>CO2!3##"&547#5654&#"&54632!5!5654&#"&5462654&#")A$&8T*C-1?)/$*$/@4"1  BH071@4Dc..#-)'1# 7,D20@B.2 2'*!+#:/@( " -M&?A5B$5WK\Q!"-#KERf2!3##"&547#5654&#"&54632!5!5654&#"&5462>54&#"2>4'#"&547)A$&8T(3-# 4H3/$*$/@4"1  BH071@4Dc %(!'41)'1# 7,D%>$5 G4>% 2'*!+#:/@( " -M&?A5B$5WK\z P '< 4"' (".KZ O2!3#"&54632&#"3265!5654&#"&5463235!5654&#"&546)A$&8U`=+fU53*,L:K4/$ *#.AdAlJJ)26)'1# 7,G -M&?A5B$5WK\O@4%)",#:1=<1$9E&:+g;HKGP\2!3!5654&#"&5462##"&547!5654&#"&54623546"354&2654&#")A$&8TH071@4Dc>K)C-0@)/$ *#.AdAlJJ)26&.#$)'1# 7,G -M&?A5B$5WK\O@31?A/34%)",#:1=<1$9E&:+g;Hx$"-%KLU`t2!3!5654&#"&5462##".547!5654&#"&54623546"354&2654'#2654'#"&547)A$&8TH071@4Dc>K%3-# %3/$ *#.AdAlJJ)26.$&4350)'1# 7,G -M&?A5B$5WK\O@ <$5 .< 4%)",#:1=<1$9E&:+g;H  P." '"#& '!/H+/2!3# 47326=!5654&#"&546L^$9PpK[PAfg[QG8.3?4Dc*YJ;(@:b3}r_o@h]?%V8.N/9B3D"2YL[H=K2!3#".547# 4732>=!5654&#"&546264&+"L^$9P:DB2"2 /4[PCkqJX=!5654&#"&5462654&"2>54'#"&'L^$9PY`T=?Q [PCkqJX54')A$&8TH071@4Dc *C4.?.!N6%+6_F0N=54')A$&8TH071@4Dc *77C-1?04.!N6%+6_F0N=54'2654'#"&547)A$&8TH071@4Dc *CA-# 4HH3.!N6%+6_F0N=.c$+w>N@31)?&ѶH5'b$-u@O0.@18(3KVd2!3!5654&#"&5462654'7#"&547&=4&#"#54#"&546326322654&'+)A$&8TH071@4Dc!+Q^08C-0@+7"'"9: %&MWK39$"6.A(#&-$)'1# 7,G -M&?A5B$5WK\>.c$+wN' @1?A/6"E1)?&ѶH5'b$-u@O0.@18(3$$ 0%KXdy2!3!5654&#"&5462654'7#"&547&=4&#"#54#"&54632632264'#"'2654'#"&547)A$&8TH071@4Dc!+Q^5;-# 4H.c$+wS&#E$5 G4E$ ?1)?&ѶH5'b$-u@O0.@18(3v$ P-# '"#& '!/K+g2!3!5654&#"&5462654'7#"54632&#"32>5#"'&'&#"#54#"&54>32632)A$&8TH071@4Dc$0DZ&>; X4G'F4R+>!:^ 6"97'NZ .& 6&!61A)'1# 7,G -M&?A5B$5WK\C1U'LD_,2 341J1ҶH," Z!+m-B 0/Q4.#"#)A$&8TH071@4Dc:"(ZN'& 0!0 :A=9U, 6<:9.(KXI<2%!7p!0K  %)'1# 7,G -M&?A5B$5WK\2OBYb< 5 %$  kPA:C[nK,# F/B=&[(g=J+*`I%*, !Kix2!3!5654&#"&5464&'7"&547#".547327#".=4&#"#54#"&546326323262>54&#"2654'#"&547)A$&8TH071@4Dc<(U`$9DbD1;8jj@:6S&1 2976,&HTE9/$ 3k("g  .'"#'.)'1# 7,G -M&?A5B$5WK\<G?Qj95*,=<-# .\?J=7>UgG2.A,=9#U&`9E('YE#4 I0 -%  &KE,5@2##".547!5654&#"&546323546"!54&2654'#YvE/ "*H8.1A4D`MJc%rm=O#S #//"vb,2B 2!,-O.:B4B$5WK[ZJ9)Vi6WFΠ[p#0 1"K*3>R2##"&547!5654&#"&546323546"!54&2654&"2>54'#"&'Yv ,T=?Q/-H8.1A4D`MJc%rm=O#S %&$*2'1Evb#?AZW?A&-O.:B4B$5WK[ZJ9)Vi6WFΠ[pX# " %5"! 2+KDMS\e2!5654&#"&5463235462#"/32654&+#"'#"&54634632"!54&4&"325#32=#"YvGH8.1A4D`MJc%r0**#!*8.5)'0783+Z 3=O#SA%6 "A}j (?vb-O.:B4B$5WK[ZJ9)Vi7F2 # !!CS227(0!7HWFΠ[p%3/)1&6t#=7KNW^en2!5654&#"&5463235462#"/3254+53254+#"'#"&54634632"!54&4&#"325#32=#"YvGH8.1A4D`MJc%r #G"*8.6*(/6O4*'27=O#S=-  A}k (?vb-O.:B4B$5WK[ZJ9)Vi 6!CR226)27G73WFΠ[p/(/(8Ngi  CT447(0 9F.% WFΠ[p&54'5 %(x5# ?9K@I2!5654&#"&5463235464632&#";2#"'73254+"&"!54&YvGH8.1A4D`MJc%r':DU/$C$5-?70N1T.$MS>@'0F=O#Svb-O.:B4B$5WK[ZJ9)Vi&;0%&/5./&5(-&WFΠ[pK@NWb2!5654&#"&5463235464632&#";2#"'73254+"&2#"&46"!54&264&#"YvGH8.1A4D`MJc%r ;CT0$C#6-?61N1V,&KS>@'0*=*>=&=O#S"# #vb-O.:B4B$5WK[ZJ9)Vi&;0%&/5./&5(-:-&:Z:WFΠ[p"4"+"KKTa{2!5654&#"&546323546"&547&'732654+"&54632&#";2"!54&2654&#"2>54'#"&547#YvGH8.1A4D`MJc%r./IrI%C$%L"1>@'0M1U/$C(1-?+$=O#S$+ & -  $vb-O.:B4B$5WK[ZJ9)Vi)H'5MM56% $&(.#4-0% & $%WFΠ[p[$ % !, ,+K(Q[2!5654&#"&546323546"!54&2'654&#""&547&#"&5463262654'YvGH8.1A4D`MJc%rm=O#S:L_Q$:H7F8V5C. ?HU;'$"2'8A"vb-O.:B4B$5WK[ZJ9)Vi6WFΠ[pbaFZ0 .H=S=O7FD6P6 .'R* 3`EY)*F05F#+KW(`j2!5654&#"&546323546"!54&2#!"3!!"&546;2654&+""&547&#"&5463262654'YvGH8.1A4D`MJc%rm=O#S*IT@2((v"**"%0C7  G9T6B /:AIO>(!"2!7A"vb-O.:B4B$5WK[ZJ9)Vi6WFΠ[p`UF>W3$$D39G2D/:9-F+>/F 'P:P&:)-:$KX(is2!5654&#"&546323546"!54&4632632#!"3!!"&546;254&+532654#""&547&#"&72654'YvGH8.1A4D`MJc%rm=O#SP:+!$@./*0''s-, WL.E8V5C/:@H!7B"vb-O.:B4B$5WK[ZJ9)Vi6WFΠ[p;IS#.#73$';!%: 1C/::-@.>/G %&:(-9$K-(cm2!5654&#"&546323546"!54&2#"&54632&#"32654&#"#".547&#"&54>3262654'YvGH8.1A4D`MJc%rm=O#S?Paj@LO=?6$9QQOaG< F7.$. C1>?H%.! $/#8@*vb-O.:B4B$5WK[ZJ9)Vi6WFΠ[p`wXj0u\Ne32632#"'732>54'#"&5467&#"#54#"&2654'YvGH8.1A4D`MJc%rm=O#S7 /&5&,;R0<9bH&& (: ; 6+&2>+=",98  NZx"#'vb-O.:B4B$5WK[ZJ9)Vi6WFΠ[p.B 0.KT2Kf ':0P&K(S`2!5654&#"&546323546"!54&233##"&547#5654&#"&5462>54&#"YvGH8.1A4D`MJc%rm=O#S"1 ;%! 0@$/$*$/B* .$%vb-O.:B4B$5WK[ZJ9)Vi6WFΠ[p ( # 0*A/0 1#*!+#:1> "&$K(S^r2!5654&#"&546323546"!54&233##".547#5654&#"&5462654&#"2654'#"&547YvGH8.1A4D`MJc%rm=O#S"1 ;-5H3 %5/$*$/B0A!'(!0vb-O.:B4B$5WK[ZJ9)Vi6WFΠ[p ( # &?4G.?& 1#*!+#:1>e') 43 (".K(0<C2!5654&#"&546323546"!54&4632!7354&'4#"6YvGH8.1A4D`MJc%rm=O#S9T&-/*2,Amvb-O.:B4B$5WK[ZJ9)Vi6WFΠ[pc]x).gM<$6TNK (;GNY2!5654&#"&546323546"!54&4632##"&547#7354&'4#"62654'#YvGH8.1A4D`MJc%rm=O#S9T&A/1?&o&-/*2,Am.&11%vb-O.:B4B$5WK[ZJ9)Vi6WFΠ[pc]x0/AA/0).gM<$6TN$2 2$K(>JQ]qs2!5654&#"&546323546"!54&4632##".547#7354&'4#"62654&#"2654'#"&5477#YvGH8.1A4D`MJc%rm=O#S9T*3H3 %3c&-/*2,Am%535/' vb-O.:B4B$5WK[ZJ9)Vi6WFΠ[pc]x">4G.>").gM<$6TN P." '"#& '".JP:C2#".5473265!5654&#"&54623546"!54&^rOn^ 5itg_D(d*bGnDH8/2@4Dc`%oM>M#Tx`4R, +FX{Iwk|VQ5aP-O.:C2B$3XL[ZI9*Tk5[BΟZrJQFOY2#".547#".5473265!5654&#"&54623546"!54&264&#"^rCD*" #2 rl5itg_D(d*bGnDH8/2@4Dc`%oM>M#T2""*x`A4L"3 *"  +FX{Iwk|VQ5aP-O.:C2B$3XL[ZI9*Tk5[BΟZrK#2"J=REN\q#".547#".5473265!5654&#"&5462354632"!54&2654.'#2654&'#"&="GW<+> cW5itg_D(d*bGnDH8/2@4Dc`%oW^r>M#T #"G'#83%/)+( G=@S$5*0% +FX{Iwk|VQ5aP-O.:C2B$3XL[ZI9*Tkx`S[BΟZrL%[02 5 6!-8 %0 KIR[2!5654&#"&546323546#"&=4&#"#"&5463232>54'"!54&2654'YvGH8.1A4D`MJc%r*C4/>,#N5&+6^G:D= QU=O#S(E%vb-O.:B4B$5WK[ZJ9)Vi, ,1"@RA60.>?V.;I8NaH:+Z /!a"WFΠ[p_#&C6%NOKQZgp2!5654&#"&546323546#"&547&=4&#"#"&5463232>54'"!54&2654&#"'2654'YvGH8.1A4D`MJc%r*:5A/1?32,#N5&+6^G:D= QU=O#S &- %(E%vb-O.:B4B$5WK[ZJ9)Vi, ,1"W(!>/AA/=!!D0.>?V.;I8NaH:+Z /!a"WFΠ[p$! $#&C6%NOKW`mv2!5654&#"&546323546#".547&=4&#"#"&5463232>54'"!54&2654'#"''2654'2654'#"&547YvGH8.1A4D`MJc%r*?>$ %D0,#N5&+6^G:D= QU=O#S  "(E%%535/vb-O.:B4B$5WK[ZJ9)Vi, ,1"\'#G..L"!C0.>?V.;I8NaH:+Z /!a"WFΠ[p   !}#&C6%NO." '"#& '".KR[2!5654&#"&5463235462654'7#"&=4&#"#54#"&54>32632"!54&YvGH8.1A4D`MJc%r!+Q^@4/A"'"9: %&MW-% 7&"6.A'7=O#Svb-O.:B4B$5WK[ZJ9)Vi">.c$,v?M@31)?%ѶH5'b$-u*> 0.?28(3WFΠ[pKZcq2!5654&#"&5463235462654'7#"&547&=4&#"#54#"&54>32632"!54&2654'#"'YvGH8.1A4D`MJc%r!+Q^9/=*+=,7"'"9: %&MW-% 7&"6.A'7=O#S".  !vb-O.:B4B$5WK[ZJ9)Vi">.c$,vX$8-::-8E1)?%ѶH5'b$-u*> 0.?28(3WFΠ[p#0  $K\er2!5654&#"&5463235462654'7#"&547&=4&#"#54#"&54>32632"!54&2654'#"'2654'#".547YvGH8.1A4D`MJc%r!+Q^6: 8%6LE)"'"9: %&MW-% 7&"6.A'7=O#S #V: & "-vb-O.:B4B$5WK[ZJ9)Vi">.c$,vS'&F&. K7M&!91)?%ѶH5'b$-u*> 0.?28(3WFΠ[p   #[;*# ! %5*K+(m2!5654&#"&546323546"!54&2654'7#"54632&#"32>5#"'&'&#"#54#"&5462632YvGH8.1A4D`MJc%rm=O#S $0DZ&>; X4G'F/R+= !:]  6"97BNZKl&!61Avb-O.:B4B$5WK[ZJ9)Vi6WFΠ[pVC1U'LD_,2 341J1ҶH:=Z!+m@Z0/QLA$A6X9H [VT=O#Svb-O.:B4B$5WK[ZJ9)Vi'RD@K !L0;<1V*iEVRD@K !L0;<1V*iEVWFΠ[pKCYbn2!5654&#"&5463235462#"&547'654&#"&54622'654&#"&54"!54&2654&#"YvGH8.1A4D`MJc%r+<*> A6,-8H [W|L(|LA$A6,-8H [=O#S,#"+vb-O.:B4B$5WK[ZJ9)Vi#<+&:-+!L0;<1V*iEVRD@.RD@K !L0;=0V*iEWFΠ[p## KD[do2!5654&#"&5463235462#"&547'654&#"&54632%2'654&"&546"!54&2654#"2654'#"&5475YvGH8.1A4D`MJc%r%7 .&7K8A7+.7H [U@>L,>L*(A6X9H [U=O#S.V:" 8 *vb-O.:B4B$5WK[ZJ9)Vi$ .&&8 L6D' !L0;<1V*iEVRD@RD.G!L0;<1V*iEVWFΠ[p .[;*#% %'3*KB =GR233##"&547#5>54.#"#4.#"632#"&5463262654&"%2654&#"eTdUIB21C#? 6%)8S40-;/>=2>Kj\C4o2##2#h$%&'s`HG,/ED0,mQ44-!,$. HR<;IkRuQO#"".#%1.H1K =HZe233##"&547#5>54.#"#4.#"632#"&5463262654&"2654'#"&'%2654&#"eTdUI!-U<@P0#? 6%)8S40-;/>=2>Kj\C4_%&$)92'2Ec$%&'s`HG"ADWW?B&mQ44-!,$. HR<;IkRuQOX8*" %5!" 2+.#%1.H1MOZ%33#".54>32&#"3265!5654&#"#4&#">32#"&54632>322654&#",.4S ;iJBN5eb%?I)N'gP54.#"#4.#"632#"&5463262654&#"2'654&#"#"&54732=46eTdUIm#? 6%)8S40-;/>=2>Kj\C4$%&'4@bP-";<.8DUD&,9Cs`HGmQ44-!,$. HR<;IkRuQOn.#%1.H1EM?w-%Y1>e*/54.#"#4.#"632#"&5463262654&#"2+"3!!"&546;2654&#"#"&546732654&546eTdUIm#? 6%)8S40-;/>=2>Kj\C4$%&'$5  & $$H'!( /:)"6?+4G.1"/;!<s`HGmQ44-!,$. HR<;IkRuQOn.#%1.H1E++'>"20"L9.:` -4H;*H :+6-*#+4KZ2=233!5>54.#"#4.#"632#"&5463262654&#"2+"3!!"&546;254&+532654#"#"&5467326='46eTdUIm#? 6%)8S40-;/>=2>Kj\C4$%&'@:((@6$$Q '' Q D8;05F? #.<"?s`HGmQ44-!,$. HR<;IkRuQOn.#%1.H1F=$-'02(#6!8?70:H;6B  ;*5.#:'/K-2=n233!5>54.#"#4.#"632#"&5463262654&#"2#"5432&#"32654&#"#"&546732=4eTdUIm#? 6%)8S40-;/>=2>Kj\C4$%&'vN{fG4%5LQOa1';<+7E*5!' 0':s`HGmQ44-!,$. HR<;IkRuQOn.#%1.H1CmVo8*vaE\2FTA&] :*/@k1K 2}233!5>54.#"#4.#"632#"&5463262+"32632#"&547'#"&546;2654&"#54&#"632#"&5463264#"32$4#"3%2654&#"eTdUIm#? 6%)8S40-;/>=2>Kj\C4 !*?J$'.$%%  X]#%A8&1"4 6,( %#H6?$""$%&'s`HGmQ44-!,$. HR<;IkRuQO,)$;"L " ) #++##$9D .(+6#$DD.#%1.H1KA2233!5>54.#"#4.#"632#"&5463262#!"3!!"&5463!2654'#"&547'#"&54;2654&#"5#54&#"632#"&54>32>32+"3274#"32$4#"3%2654&#"eTdUIm#? 6%)8S40-;/>=2>Kj\C4Tb<6,&&j '!&'2>%%NJ(%1,' ;6*") $$31K :+ EQ#0:""s$%&'s`HGmQ44-!,$. HR<;IkRuQOn-"!+'!)   + *V/)W 4%.&$/ $$ (>DD.#%1.H1KN2233!5>54.#"#4.#"632#"&546326232#!"3!!"&5463!254#5254+"&547#".54;2654#"#4&#"632#"&54632>2654#"'4"2"3267+&%2654&#"eTdUIm#? 6%)8S40-;/>=2>Kj\C4z &(WoX!!#/!2  k yi9933+#  L@ 3 ..2&+m"$%&'s`HGmQ44-!,$. HR<;IkRuQO4 , L-  &  LV #?R I.-/2.#  !! 7I.#%1.H1K'2233!5>54.#"#4.#"632#"&5463262#"&54632&#"32654&'#"&547'#"&546;2654&#"#54&#"632#"&54>32>32+"3264#"32$4#"3%2654&#"eTdUIm#? 6%)8S40-;/>=2>Kj\C4u9Jt\$_P0H.%3O(+K[%. ()&@J(5!';7*!( $32I <,8G<'1)!!y$%&'s`HGmQ44-!,$. HR<;IkRuQOk@3AQI;0  R410"(N *%%,%#.$7(09V9DD.#%1.H1K 2Yd233!5>54.#"#4.#"632#"&5463262#"/3254&+53254&#"&546%2654&#"eTdUIm#? 6%)8S40-;/>=2>Kj\C4>5/1@6E+$I))DSq$%&'s`HGmQ44-!,$. HR<;IkRuQO-=(/%7 )/ /GJ4?K3Q`A.#%1.H1K 2cr}233!5>54.#"#4.#"632#"&5463262#"&547'62654&+53254&#"&5462654&'+2654&#"eTdUIm#? 6%)8S40-;/>=2>Kj\C4>5/1/1C-/A8 ++$I))DSK&" $B$%&'s`HGmQ44-!,$. HR<;IkRuQO-=(/0!;1?@0B  # /GJ4?K3Q`P$"%&.#%1.H1K2hv233!5>54.#"#4.#"632#"&5463262#".547'632654&+53254&#"&5462654'#"'2654'#"&5472654&#"eTdUIm#? 6%)8S40-;/>=2>Kj\C4>5/1.:-# %E -+$I))DS<  &4350V$%&'s`HGmQ44-!,$. HR<;IkRuQO-=(^$D$5 .L"  $ /GJ4?K3Q` P." '"#& '!/.#%1.H1KP2lw233!5>54.#"#4.#"632#"&546326#"&5432&#"32654&+532>54&#"&54>32%2654&#"eTdUIm#? 6%)8S40-;/>=2>Kj\C4($Q.0(Rq5$<&-72(% $*)4>*:D$%&'s`HGmQ44-!,$. HR<;IkRuQO4O$5 .  2+'3#! )4="6=K388!5s.#%1.H1K 2Wb233!5>54.#"#4.#"632#"&5463262654'7#"'#".547326=32654&#"eTdUIm#? 6%)8S40-;/>=2>Kj\C4%1JUJ58%$5 %-\<,#%:!F$%&'s`HGmQ44-!,$. HR<;IkRuQO+C4V$0gDU11 @,l,+Z3? ϶!(C.#%1.H1K 2cq|233!5>54.#"#4.#"632#"&5463262654'7#"&547&'#".547326=32654.'+2654&#"eTdUIm#? 6%)8S40-;/>=2>Kj\C4%1JU::,<%$5 %-\<,#%:!4" -d$%&'s`HGmQ44-!,$. HR<;IkRuQO+C4V$0gW+A&<+1 1 @,l,+Z3? ϶!("  ..#%1.H1K 2bn233!5>54.#"#4.#"632#"&5463262654'7#".547&'#".547326=32654'"'2654'#"&5472654&#"eTdUIm#? 6%)8S40-;/>=2>Kj\C4%1JUB@M5&8 G$5 %-\<,#%:! ,V: &*#-$%&'s`HGmQ44-!,$. HR<;IkRuQO+C4V$0g]*%L8J .&P$ 1 @,l,+Z3? ϶!( # *[:+# !65+.#%1.H1K8 2=}233!5>54.#"#4.#"632#"&5463262654&#""&5432&#"32>5#"'#".547326=332>54'7eTdUIm#? 6%)8S40-;/>=2>Kj\C4$%&'6N@'"7F230$3/'"77()F ( &@Ds`HGmQ44-!,$. HR<;IkRuQOn.#%1.H1 "/ !@-'22@*n*)]6?ֶL9+U*:BEd3K2r233!5>54.#"#4.#"632#"&546326#".54632.#"32#"'#".547326=332654'2'654#"#54"&546322654&#"eTdUIm#? 6%)8S40-;/>=2>Kj\C44:1_B<;S>N.6%*:2' B%7'$6%5 [;%,/6"'2JW( $%&'s`HGmQ44-!,$. HR<;IkRuQO'O-VT4 &$.+ -*33%7,m+,Y-H϶!+F4X$ ' .#%1.H1K 2=b233!5>54.#"#4.#"632#"&5463262654&#"2'654&#"#54&#"&546326eTdUIm#? 6%)8S40-;/>=2>Kj\C4$%&'6H -%?(. 9'(1KUJ;8%%s`HGmQ44-!,$. HR<;IkRuQOn.#%1.H1EWB1>*Z+Fѵ&!A0\#.hBY10K2=ak233!5>54.#"#4.#"632#"&5463262654&#"2#"&547&#"#54#"&5463262654'eTdUIm#? 6%)8S40-;/>=2>Kj\C4$%&'CZ5,*7D+97'4MYJ86%/k$6B$s`HGmQ44-!,$. HR<;IkRuQOn.#%1.H1EiJ7EC7R6 ѵHC3Z!-hAZ0/#(O.4E$+KX2={233!5>54.#"#4.#"632#"&5463262654&#"4>32632#"'732>54'#"&54>7&#"#54#"&2654'eTdUIm#? 6%)8S40-;/>=2>Kj\C4$%&') /&4'+",98  NZx"+ s`HGmQ44-!,$. HR<;IkRuQOn.#%1.H1.B 0.KS2Ih ':0P&7#5>54.#"#4.#"632#"&5463265#%2654&#"eTdUI)8\7 #? 6%)8S40-;/>=2>Kj\C4h%#$%&'s`H /:-mQ44-!,$. HR<;IkRuQO(:.#%1.H1K| FNZe233##".547!5>7#5>54.#"#4.#"632#"&5463265#2654&#"2654&#"eTdUIE/ ")8\7 #? 6%)8S40-;/>=2>Kj\C4h%##$ "C$%&'s`H,3A 1"- /:-mQ44-!,$. HR<;IkRuQO(:"!+"o.#%1.H1K; DLWju233##"&547#5>7#5>54.#"#4.#"632#"&5463265#2654&"2>54'#"&'2654&#"eTdUI",S>=S.8\7 #? 6%)8S40-;/>=2>Kj\C4h%#%&)(+3&3/{$%&'s`H#@AZW?A' /:-mQ44-!,$. HR<;IkRuQO(:%&X 0%$ &4"! A.#%1.H1K2=z233!5>54.#"#4.#"632#"&5463262654&#"2#"/3254.54>323254&#"&54>32#"&#"326eTdUIm#? 6%)8S40-;/>=2>Kj\C4$%&' %593-(1C0;02/%-E/0&7 ,+3 s`HGmQ44-!,$. HR<;IkRuQOn.#%1.H1!)  ! FP.ES+2J%!  JMY233# $546732>5!5654&#"#4&#"632#".5463262654&#" JcXIBex;(1(ZJsw}}gI<'3SJ4%=&-@1A?4.,f^H6 %( !',gSdC5U2! NuBk2^aF-(N4XGX+$,(6**4GO=;I'L2yPPm-#%0/"%/JXgs#"&547# $546732>5!5654&#"#4&#"632#".54632632332654&#"2654&#"N2 2"3Cq(1(ZJsw}}gI<'3SJ4%=&-@1A?4.,f^H6\JcXIl " Q %( !',8, #*D2 NuBk2^aF-(N4XGX+$,(6**4GO=;I'L2yPPgSdCL$"  O-#%0/"%/J?Ucx"&547# $546732>5!5654&#"#4&#"632#".54632632332654.'"2654&'#".=2654&#"&7;U|Tjw(1(ZJsw}}gI<'3SJ4%=&-@1A?4.,f^H6\JcXI !P:'#8'# $' %( !', T0=VU>1(NuBk2^aF-(N4XGX+$,(6**4GO=;I'L2yPPgSdC_[8* 5 6& & +w-#%0/"%/K 2Zcn233!5>54.#"#4.#"632#"&546326#"&=4&#"#"&5463232654'2654'2654&#"eTdUIm#? 6%)8S40-;/>=2>Kj\C4*C4/>.!N5&+6_F0N=>Q*E%S$%&'s`HGmQ44-!,$. HR<;IkRuQO. ,1"@RA60.>?V.;I8Mb54.#"#4.#"632#"&546326#"&547&=4&#"#"&5463232654'2654&#"'2654'2654&#"eTdUIm#? 6%)8S40-;/>=2>Kj\C4*::C-/A37.!N5&+6_F0N=>Q&."$*E%S$%&'s`HGmQ44-!,$. HR<;IkRuQO. ,1"X'C1?@0>J0.>?V.;I8Mb54.#"#4.#"632#"&546326#"&547&=4&#"#"&5463232654'2654'#"''2654'2654'#"&5472654&#"eTdUIm#? 6%)8S40-;/>=2>Kj\C4*?>$ 4HD0.!N5&+6_F0N=>Q "*E%L433$%&'s`HGmQ44-!,$. HR<;IkRuQO. ,1"\'#G.G4K#!C0.>?V.;I8Mb;254#"#"5463232654&#"&4>32#"&#"32636#Bf(!>.? /^= O W9#A R(*.A9D}8 C %L3$pE5' %K,K'"!/;XjlT/ K6!  JV%#"&5467327654+53254&'&5463232654&#"&54>32#"&#"32632ab(%&*@lD@8H"uZ[R=2) N E1*/@97Q%8;$K'&:M`߷Y{>6nT-W^G-9*102(0 !-FivIAc9# "2('%'$,2J \%2#"&54>32&#"32654.#""#"&5463232654&#"&54>32#"&#'"&#"376s%0'nH3L@@7/-:O]#MS73 .!*G7 :H:) 1D=!32#"&#"32632'2'654#"52#474654#"&54626MjaOt8"h5.I8czF8 2 % I8 60'5>V))6hH.@4%E*4%&5HWY  , 2(+41- #hV=L(&(070-JG&H`vO0VQ0">&7/+cJm(     6#K%2#"&54732>54&#"&546323254.#"&54>32#"&#"^Q "6a>F*I6N$;E=/.&E > 7%86 /,IJ':T',#J U8+>2$ݴj_#3('<'*-:< !1`BQZ 32#"&#"264&+^QEFE/ ") F*IL`;E=/.&E > 7%86 /,IJ':T',#J n4"# U8T>M3A 1"۶j_Q<'<'*-:< !1`BQZ 32#"&#"2654&'2654'#"&'^Q[\U<=SF*IL`;E=/.&E > 7%86 /,IJ':T',#J ]&(%(:3&$-EU8e=cDWW?3%رj_Q<'<'*-:< !1`BQZ ,E/ "*kiJ % 9 "@SFI &eu#//" $8dA-2B 2!,,/6 gp36 4݅{#0 1"M'/9L2##"&547#5463!54&+4&#"62654&"2>54'#"&'%5>,$-U32#"&4632.#"326=!54'%354&#'"654&H+<5dMroQ([ E "UI-[=8,-BUC&00I)}&2I+O^f2##".54632.#"3254'!5462'654#"5#465654#"&546326!54&+4&#"6!~ap7E/dI]6 F$3D 1&k_  d!'+@SFI'e§*:r 5$6HB!"/#% $$ %#2  -% !$0*+%(gp18&.݅{M #G2!546!54&+4&#"62'654&#"#54&#"&546326!7>.Nk % 9 "@SFI &eg6H> ?(. 9'(1KUK:7&$ $8dA,/6 gp36 4݅{WB>K*Z+Fѵ&!A0\#.hCX10M  #GQ2!546!54&+4&#"62#"&547&#"#54#"&5463262654'!7>.Nk % 9 "@SFI &eY=R2'&3?*52#0GRD31#*c 1=" $8dA,/6 gp36 4݅{hJ7DC6Q6 ϴGC2Y!-gBW//#'N.4D",LX  #^j2!546!54&+4&#"64>32632#"'7327654'#"&54>7&#"#54#"&2654'!7>.Nk % 9 "@SFI &e% )#-?''4L9 .!. *"% 0"-+2=F%  $8dA,/6 gp36 4݅{-C 0.K K=Le 5/>P&54&#"#4&#".546326Rl[Ik+3N6(1S3!=Q 3#): lWQ:7}]vOG*u>SG,$;4gN-94?E3dIIIB;H233##".547#5>54&#"#4&#".5463262>4.#"Rl[I A3"1 +3N6(1S3!=Q 3#): lWQ:7  }]vOG.0D)" .*u>SG,$;4gN-94?E3dII.+,I9DV233##"&547#5>54&#"#4&#".5463262654&"2654'#"&'Rl[I$-T=>R0+3N6(1S3!=Q 3#): lWQ:7Z%&$+73&"/E}]vOG$@AZTBC&*u>SG,$;4gN-94?E3dIIX:(" &4' 2+MB233#".54>32&#"326=!5654&#"#4&#"&546326"Sm^Nq?O7f` Q>&R;Qe'g5!5>54.#"#4&#".546326Rk[N)2*#X~*3 6&'1S3!20-$<4hO*;4@D2eJJJQVb#".547#"$&546732>5!5>54.#"#4&#".54632632332654&#"2*" #2 jv)2*#X~*3 6&'1S3!20-$<4hO*;4@D2eJJ}]wNEF$" #J?RTat#".547#"$&546732>5!5>54.#"#4&#".54632632332654.'"2654&'#"&=8 \_)2*#X~*3 6&'1S3!20-$<4hO*;4@D2eJJ}]wNEX%[8* 5 6!-8 +I&082!54>32>354+4&#"6%354+4&#"6c}(BC$4D>3OuMRFI+ jNQFI+ jÖzJl6 ?,,1!FnJ3;%4}FoI3;%4IA(0;EM2#"&547!54>32>354+4&#"6264&#"354+4&#"6c} CbC!W(BC$4D>3OuMRFI+ jz$$ +32>354+4&#"62654&"2654'#"&'354+4&#"6c}%0U<@P3(BC$4D>3OuMRFI+ jM%&$)92'2EfNQFI+ jÖz!BDWW?F"Jl6 ?,,1!FnJ3;%4X8*" %5!" 2+FoI3;%4P*3;DL2#".4>32&#"3265!5&>76326354#4&#"6%354#4&#"6ouCM44MBX82:*ef&U^/{+#LSFI*!jLSFI*!j|f ,! Tk%D99>GmJ49%3|GmJ3:%3EE+274>32#"&5473265!354&+4#"6+;6ݑiB$?Nm #5 ?REGBj<\4 Oi۴gZyG4!- .2 ku26N{E)9@O74>32#"&547"#"&5473265!354&+4#"62654&#"+;6@C*" 0F B$?Nm #5 ?REGBjk""<\4 M1K#3 B4۴gZyG4!- .2 ku26N{G!!$EI+;BNb#".547+"&5473265!54>32354&+4#"62654&'"2654&'#"&=2 $U>+> +B$?Nm+;6ݗ #5 ?REGBj@!")9,8+-/)8 6!=V$5*>+۴gZyG4<\4 `- .2 ku26N{H [9)#5588 (:M  0@HQ2!5462654'7#"&=4&#"#"&54632!54&+4&#"62654'!7>.Nk 0KY=2+;5I1$'4YB6@ % 9 "@SFI &el&A" $8dA(>1a"*rBPC40:2?V-.Nk:KY97B./A:-5I1$'4YB6@ % 9 "@SFI &ew#!$%&A" $8dA(69a"*rZ'A1??1C!C0:2?V-54'#"&547!7>.Nk:KY?;-# $5 3(5I1$'4YB6@ % 9 "@SFI &e\ &A"", 3&#/ $8dA(69a"*ra$$D$5 -# -: !?0:2?V-54&#"2654&#"327.54&#")*CbC  8*7VEK,@T*?WmL%X!-7-.>D"# #0`A1D1#&16 >$1CD0 sSoVV*=4Mx]nBN{vG4:)@UT54&#"2654&+2654'#"&'327.54&#"+;TzS-*7VEK,@T*?WmL%X!-7-.>D& %(:3&3E0`A1D1#&1% A6BYW?3% sSoVV*=4Mx]nBN{54:)@UT32&#"32>7#"'#"&5463263232654'>54&#"%327.54&#"9,0N{R>G3.JG#RH52>\4! F7*7{VEK,@T*?WmL!-7-.>D}i /F/%&11IEncB& !*#$5OE*a xSoVV*=4Mz[nB4:)@UT32'>54&#"%327.54&#"4&"325#32=#"!WmL%Xn8*7VEK,@T*?0*+" !*8.5)'0782*Z !-7-.>D0`A1D1#&1%6 "A}j (?"x]nBN{n sSoVV*=4M7#$1 # !!CS227(0!:E4:)@UT54&#"%327.54&#"4&#"325#32=#"!WmL%Xn8*7VEK,@T*? #G"*8.6*(/6O4*'2!-7-.>D0`A1D1#&1-  A}j (?"x]nBN{n sSoVV*=4M 6!CR226)27G734:)@UT54&#"%327.54&#"2!"&5473254&+532654&+#"'#"&54634632#4&#"325#32=#"!WmL%Xn8*7VEK,@T*?@!-7-.>D0`A1D1#&1V-$%A;" +8.6+'/9M3*-.&" Cl*A"x]nBN{n sSoVV*=4M4:)@UTNgi  DS447(0 9F.% &54'5 %(x5# ?9O.!/?ry%2654'7#"'#"&54632632'>54&#"%327.54&#"2#"&54632&#"32654&+#"'#".546;4632#4&#"26=#'32=#"!WmL%Xn8*7VEK,@T*?@!-7-.>D0`A1D1#&15,#86O!\jz%2654'7#"'#"&546326322'654&#"32#".547##"'#"&546;46323>'>54&#"%327.54&#"2654+'.#"327#32=#"!WmL%Xn8*7VEK,@T*?l ".%S$=?. 6 A;$*) 8.6)'1994**##,!-7-.>D0`A1D1#&11'{# !A~k(?"x]nBN{n sSoVV*=4M6 9$SG6I6G/(%6!420BT227(0!9E0 )7N4:)@UT54.#"32#"&547##"'#"&546;>326'>54&#"%327.54&#"2654&+'.#"327#32=#"!WmL%Xn8*7VEK,@T*?q>T,04( .% " ' 3#+, (/8.6+'08:3** #(!-7-.>D0`A1D1#&1(" !A~k'?"x]nBN{n sSoVV*=4M69*&'&- (1*% .&(1A2CS227(.#9E/"N4:)@UT54&#"%327.54&#"#"&54732654&+532654#"32#"&547##"'#"&546334632>32'4&+326'.#"327#32=#"!WmL%Xn8*7VEK,@T*?@!-7-.>D0`A1D1#&13/ǚ|I0@ ,,*#,2*/'#,43 /&Q  K?9J"%#9n`#7"x]nBN{n sSoVV*=4M4:)@UT54&#"%327.54&#"!WmL%Xn8*7VEK,@T*?,7"9Q%1 4 !-7-.>D0`A1D1#&1"x]nBN{n sSoVV*=4Ms5+- (9$ $14:)@UT54&#"%327.54&#"2654&#"!WmL%Xn8*7VEK,@T*?,7"9#=*+=#%1 4 !-7-.>D0`A1D1#&14"" "x]nBN{n sSoVV*=4Ms5+- /-::-/(9$ $14:)@UT54&#"%327.54&#"2654#"2654'#"&547!WmL%Xn8*7VEK,@T*?,7"9$4 /%&8 4%1 4 !-7-.>D0`A1D1#&1.V:,")$-"x]nBN{n sSoVV*=4Ms5+- 'A&8 /%A'(9$ $14:)@UT54&#"%327.54&#"2654'!WmL%Xn8*7VEK,@T*?^L_Q$:H7F8V5C. ?HU;'$#v!-7-.>D0`A1D1#&1&8A""x]nBN{n sSoVV*=4M3aFZ0 .H=S=O7FD6P6 .'R* 3`EYK4:)@UT54&#"%327.54&#"2654'!WmL%Xn8*7VEK,@T*?iITB0((v"**"$1C7  G9T6B/:AIO>(!"y!-7-.>D0`A1D1#&1!7A""x]nBN{n sSoVV*=4M5UFAT3$$D3:F2D099-F+?.F 'P;OM4:)@UT54&#"%327.54&#"2654'!WmL%Xn8*7VEK,@T*?P:+!$@./*0''s ,#)WL-E8V5C/:@H|!-7-.>D0`A1D1#&1!7B""x]nBN{n sSoVV*=4M;IS$.#73%0;!: 1C/::-?/>/G %&4:)@UT54&#"%327.54&#"2#"&54632&#"32654&#"#".547&#"&54>3262654'!WmL%Xn8*7VEK,@T*?@!-7-.>D0`A1D1#&1Q`j@LO=?6$9QQOaG< F7.$. C1>?H&7-$/#8@*"x]nBN{n sSoVV*=4M4:)@UT54&#"%327.54&#"2654'!2654'!WmL%Xn8*7VEK,@T*?~=RG5D6@/'&.=*1,!>/'%/<$17>I5%"@$<!-7-.>D0`A1D1#&1"3:#3:"x]nBN{n sSoVV*=4M4_E\/ -K=R=Q7EB7R6 ,#(2:R7ED5R676R+ 0bDW<;L4:)@UT54&#"%327.54&#"2654'2654'!WmL%Xn8*7VEK,@T*?LAD2%%s$#':@4 =.&$.:!*3,% <1#%-9)3:BI4# ">+&8!-7-.>D0`A1D1#&1/7 /7"x]nBN{n sSoVV*=4M8Y7B^61#)K97C-K.;;,K' %!)-I/;;-J(>-M %Y:H12P4:)@UT54&#"%327.54&#"2654'2654'!WmL%Xn8*7VEK,@T*? 03)(z (P &,##;.%$,9!*1." :.H,8 !8@F4"!;,$8#8.M!-7-.>D0`A1D1#&1-6-7"x]nBN{n sSoVV*=4M 8'41 $;',' -I/;;,G*$"*-J/;:.J) /K 'W:J32'w4:)@UT54&#"%327.54&#"2#"&54632&#"3254.#"#"&547&#"#54&#"#".547&#"&5463263263262654'!2654'!WmL%Xn8*7VEK,@T*?@!-7-.>D0`A1D1#&1AP&B@$7ET(7,16H 2! @2'"/< L0(! ?2'"< $17=F7# !&= H !/!3;'!3;'"x]nBN{n sSoVV*=4M4:)@UT54&#"%327.54&#"2'654&#"#54&#"&546326!WmL%Xn8*7VEK,@T*?@!-7-.>D0`A1D1#&16H -%?(. 9'(1KUJ;8%%"x]nBN{n sSoVV*=4M4:)@UT*Z+Fѵ&!A0\#.hBY10O!/?bl%2654'7#"'#"&54632632'>54&#"%327.54&#"2"&547&#"#54#"&5463262654'!WmL%Xn8*7VEK,@T*?@!-7-.>D0`A1D1#&1CZ6V6D+97'4MYJ86%/k6B$"x]nBN{n sSoVV*=4M4:)@UT54&#"%327.54&#"462632#"'732>54'#"&5467&#"#54#"&2654'!WmL%Xn8*7VEK,@T*?@!-7-.>D0`A1D1#&1`Nj&,;R0<9_K&& (: ; 6+&2>+>",98  NZx"#'"x]nBN{n sSoVV*=4M4:)@UT54&#"%327.54&#"233!5654&"&546!WmL%Xn8*7VEK,@T*?@!-7-.>D0`A1D1#&1="1 ;/$<+$/@"x]nBN{n sSoVV*=4M4:)@UT54&#"%327.54&#"233##"&547#5654&"&5462>54&#"!WmL%Xn8*7VEK,@T*?@!-7-.>D0`A1D1#&1="1 ;%! /A$/$<+$/@, .#%"x]nBN{n sSoVV*=4M4:)@UT54&#"%327.54&#"233##".547#5654&"&5462654&"2654'#"&547!WmL%Xn8*7VEK,@T*?@!-7-.>D0`A1D1#&1="1 ;-5-# %5/$<+$/@&0A!'40"x]nBN{n sSoVV*=4M4:)@UT54&#"%327.54&#"233#"&4632&#"3265!5654&#"&546!WmL%Xn8*7VEK,@T*?@!-7-.>D0`A1D1#&1?"1 002(iV43*+L/"54&#"%327.54&#"4632!7354&'4#"6!WmL%Xn8*7VEK,@T*?@!-7-.>D0`A1D1#&1r9T&-/*2,Am"x]nBN{n sSoVV*=4M4:)@UT54&#"%327.54&#"4632##"&547#7354&'4#"62654'#!WmL%Xn8*7VEK,@T*?@!-7-.>D0`A1D1#&1r9T&C-1?&o&-/*2,Am.&11%"x]nBN{n sSoVV*=4M4:)@UT54&#"%327.54&#"4632##"&547#7354&'4#"62654&#"2654'#"&5477#!WmL%Xn8*7VEK,@T*?@!-7-.>D0`A1D1#&1r9T*3-# 4H3c&-/*2,Am&4350& "x]nBN{n sSoVV*=4M4:)@UT$5 G4>").gM<$6TNP-# '"#& '!/O,!/?^is%2654'7#"'#"&54632632'>54&#"%327.54&#"432#".54632&#"326=#7354&#'"654&!WmL%Xn8*7VEK,@T*?@!-7-.>D0`A1D1#&1vCV37H7C;7N<(#$(30,_ t "x]nBN{n sSoVV*=4M4:)@UT%$bQA!(1tS[!O9'5<L%2654'73!5>7&'#"&54632632'>54&#"5327.54&#"!WmL%X`53Q**7VEK,@T*?@!-7-.>D*7#6#0`A1D1#&1"x]nBN{KYC sSoVV*=4M4:)@UT7&'#"&54632632'>54&#"5327.54&#"2654&'#!WmL%X`5 *" "1 Q**7VEK,@T*?@!-7-.>D*7#6#0`A1D1#&12#"x]nBN{K+"2 )" +YC sSoVV*=4M4:)@UT7&'#"&54632632'>54&#"5327.54&#"2654&#"2>54'#"&'!WmL%X`5,S>=S.Q**7VEK,@T*?@!-7-.>D*7#6#0`A1D1#&1.%%C*3&3E"x]nBN{K&?CXW?A)YC sSoVV*=4M4:)@UTH2#"/2654&+532654&#"#"&547&#"&5463262654'5:W'KQ4!(F)' !!%7A<6lSB?Qi $M`^!jua>8>W(6V\. /% :$S (! 44&#*-."$8\wSjeRvTrV}?Lg$$rI9lHIs7CJ4AK2#"$54732654+53254.#"#"&547&#"&5463262654'XsCGvnO E쯇7%%- 4#=6lTA@Pi!"N`^ kua?8K%#".54632&#"32>54'#"&546;&#"&546322654'&#"]x7@+fQO=.@kk>Z.SD9D[I0V3@+bwa9#+5;J"V  *!&';cg9Fa|NAMjL(V:y<Jk%#%!!,P;@Y/"3ME$/2!!3##".547!546"!54&2654'#^uSE/ "*Dsv@U(P#//"j/G,2B 2!,l0UC6%N[#0 1"M"-A2!!3##"&547!546"!54&2654&"2>54'#"&'^uS ,T=?Q/ksv@U(P%&$*2'1Ej/G#?AZW?A&l0UC6%N[ X# " %5"! 2+J-474632!!3#".54>32&#"326=4&5!"!4J[j^S6`M@L4bVKF&R%YZ$QONC)yB@O: % (*:Q_>6M4=CKT2!!3!5462#"/32654&+#"'#"&54634632"!54&4&"325#32=#"^uSs0*,!!*8.5)'0784*Z @U(P%6 "A}j (?j/Gl7#$1 # !!CS227(0!6I"UC6%N[%3/)1&6t )#=7M=FMU^2!!3!5462#"/3254+53254+#"'#"&54634632"!54&4&#"325#32=#"^uSs #G"*8.6+(/6O4*%3@U(P-! A}j(?j/Gl 6!BS226)27G64"UC6%N[/(2%9Ngi  CT447(0 9F.% &54'5 %(x5# ?9M.IPYb2!!3!546"!54&2#"&54632&#"32654&+#"'#"&546;4632#4&#"26=#'32=#"^uSsv@U(P,"86IGP[bir2!!3!5462'654&#"32#"&547##"'#"&546;46323>"!54&2654+'4&#"325#32=#"^uSs|-B S$=?. 6 A;*$+)8.6+'1994**# $+@U(P~1' % !B~k(?j/Gl+&7,SG6I5H/(%6&/S!CS228'0!9E0 )8UC6%N[T<*&%27 1'5s3%=6=Xalsz2!!3!5462#"/3254+57>54&#"32#"&547##"'#"&546;>326"!54&264&+'.#"327#32=#"^uSs>T,04( .% 7' 3#+*"(/8.6,'08:3** #@U(Pt(" !A~k'?j/Gl+8+''&- (1*%! .&(1A2AU227(.#9E/!UC6%N[T0! $,&16!1'5s3&=6K&bkry2!!3!546"!54&#"&54732654&+532654#"32#"&547##"'"&546;>32>32'#3254'4.#"325#32=#"^uSsv@U(PX.*l B2'## '.%*B'./)"I  M.0G!& 03bV 1j/Gl0UC6%N[TPoSM?OiT>&L(%0#)1@3 CQ//6)."8E}?A?2,=N57 "%T1)1p1";5M:2!!3!546"!54&2'654&#"#"&54732=46^uSsv@U(P5?bP-";=-8DUD&,9@j/Gl0UC6%N[YN>w-&X1>e*/54'#".547^uS'8I97K8%1 3&-6"sv@U(P$.+-! "-$j/'&E5MK7E&(9$ %06*/l0UC6%N[.[$ % , %5+M8AK2!!3!5462'654&#"#"&547&#"&546326"!54&2654'^uSsjL_Q$:H7F7,+5C. ?HT<'$!@U(PV'8A"j/Gl.aFZ0 .H=S/F 'P;OUC6%N[&;(-:$MXPYc2!!3!5464632632#!"3!!"&546;254&+532654#"#"&547&#"&"!54&2654'^uSsUN<+!$@./*0''s5#)W L.E7,+5C/:@H!@U(Pa!7B"j/Gl9KS#.#73#0;!: 1C09:-@.>/G %}UC6%N[&:(-9$M-PZ2!!3!546"!54&2#"&462&#"32654&#"#".547&#"&54>3262654'^uSsv@U(PPaj?MM~6$9QQOaG< F7.$. C2=?H%.! $/#8@*j/Gl0UC6%N[\wXj.0u\Ne.;08*"!)6 '*' 7*"!)5 ?07@/#95@U(Pw,-3-3j/Gl._F]/ -L?Q>Q7FD6U4 -"(2;R7FC7R7@CT* 0cEW==UC6%N[W.'I15J#./'I15J$-MUgpz2!!3!5462#!"3!!"&5463!2654&#"#"&547&#"#54&#"#"&547&#"&546326326326"!54&2654'2654'^uSs.: +.6#0.65(! '2 $,+ 3) '1 $,29>.6& 1@U(P)0((0j/Gl(1<"/9'60$%K80I-I.;8.K'$'"-H/::-J'<.M $Y9H12UC6%N[~!&A%(B%( B$*@MTqz2!!3!5462#!"3!!"&5463!254&#퀆&#"#"&547&#"#54&#"#"&547&#"&546326326326"!54&2654'2654'^uSs)B')-##0$"E !(3)'1 $+' 2' &0"/17;/5$ 1@U(P'/(/j/Gl)'.7&51$$;$,' -I/;9/G*%"*-J0::.J)?/L 'W;I32UC6%N["&B#)@'(!B%*A(M)22!!3!5654&#"&546323!546"!54&^uS/$*$/B2!2 sv@U(Pj/) 1#*!+#:1>' #l0UC6%N[M'6?L2!!3##"&47#5654&#"&546323!546"!54&2654&'#^uS&! /A%/$*$/B2!2 sv@U(P&%j/)0*@` 1#*!+#:1>' #l0UC6%N[$&$$M:COb2!!3##".547#5654&#"&546323!546"!54&2654&#"2654'"&547^uS(5$ %5/$*$/B2!2 sv@U(P &4)>*1j/)&?..@% 1#*!+#:1>' #l0UC6%N[ P." ,* &$,MP9B2!!3# 4732>=!5654&#"&546323!546"!54&^uSzV>5DE/$+$.@42?sv@U(Pj/5G SL@Gjt &2%*")";2=<0$l0UC6%N[MDMZ2!!3#".547# 47326=!5654&#"&5463235!546"!54&2654&+]vS0?25(3 * Qn/$ *$.@42?sv@U(P4"+l/Y,DK-* * !w]&2%*")";2=<0$l0UC6%N[# MCLVk2!!3#"&547# 47326=!5654&#"&5463235!546"!54&2654'2>54'"&547^uS:DC02@  Qn/$ *$.@42?sv@U(P&,$'&<& ?j/Y0K/CD.) * !w]&2%*")";2=<0$l0UC6%N[ & 'Q ," (' $0)M7@2!!3!546"!54&2!5654&#"&546323546"354&^uSsv@U(P>K4/$ *#.B12AlJJ)26j/Gl0UC6%N[[O@3%)"+";1=<1$7G&:+g;HMBKW2!!3!546"!54&2##"&547!5654&#"&546323546"354&2654&#"^uSsv@U(P>K)B.0@)/$ *#.B12AlJJ)26&.$%j/Gl0UC6%N[[O@31?@033%)"+";1=<1$7G&:+g;Hx$"&$MGP[p2!!3!546"!54&2##".547!5654&#"&546323546"354&2654'#2>54'#"&547^uSsv@U(P=L%3 4" %3/$ *#.B12AlJJ)26.$", 3&#/j/Gl0UC6%N[[O@ < $,.< 3%)"+";1=<1$7G&:+g;H  P#!  '"4 '".M?HQ2!!3!546233#5>54&#"#54&#"632#"&546326"!54&3254&"^uSs 4?6-'1 4+g &'&'/SB:*!^@U(P($j/Gl3M@W.F8:2#05)(0E8Ni65UC6%N[26!MKTaj2!!3!546233##".547#5>54&#"#54&#"632#"&546326"!54&2654&#"$3254&"^uSs 4?6-+25(3 +e'1 4+g &'&'/SB:*!^@U(P!"M($j/Gl3M@W.5K-*5F8:2#05)(0E8Ni65UC6%N[$+ #26!MR[f|2!!3!5462363233##".547#5>54&#"#54&#"632#"&546326"!54&2>54#"2654'#"&5473254&"^uSs 4?6; 4-*2H3 %2?'1 4+g &'&'/SB:*!^@U(P+/(84'"*)e($j/Gl3M@W.$@4G.@$F8:2#05)(0E8Ni65UC6%N[,*W8($ '!34 "%26!M+22!!3!5464632!"!54&354&'4#"6^uSs9Tr@U(P&-/*2,Amj/Glmc]xUC6%N[).gM<$6TNM !*6=H2!!3!5464632##"&547#"!54&354&'4#"62654'#^uSs9T%A/1?%nr@U(P&-/*2,Am.&11%j/Glmc]x0/AA/1UC6%N[).gM<$6TN$2 2$M$-9@L`b2!!3!5464632##".547#"!54&354&'4#"62654&#"2654'#"&5477#^uSs9T*3H3 %3cr@U(P&-/*2,Am%535/' j/Glmc]x">4G.>"UC6%N[).gM<$6TN P." '"#& '".M 7AJ2!!3!54#"&=4&#"#"&5463232>54'"!542654'~_S)*C4/>,#N5&+6^G:D= Q)<(`(E%G/ ,1"@RA60.>?V.;I8NaH:+Z /!a"136V#&C6%NOM >HV_2!!3!54"&547&=4&#"#"&5463232>54'"!542654&'+'2654'~_S)*38B\B,5,#N5&+6^G:D= Q)<(# .%(E% G/ ,1"S'B1??17" G0.>?V.;I8NaH:+Z /!a"136-& 0$#&C6%NOM EO\ey2!!3!54#".547&=4&#"#"&5463232>54'"!542654'#"''2654'2654'#"&547~_S)*??$ %D1,#N5&+6^G:D= Q)<( !(E%%53&#/ G/ ,1"]%$G..K"!D0.>?V.;I8NaH:+Z /!a"136   !}#&C6%NO." '"4 '".LB,8233##".547#5654&#".5462654&#")\{SSB2"1 kZBFT+ )7z +##y\G,/E)" +NcL_bJ'51!AD/d+ "#L*4H233##"&547#5654&#".5462654&"2>54'#"&')\{SS%-T=?Q/kZBFT+ )7zX.%&C*2'1Ey\G"AAZW?B&NcL_bJ'51!AD/dv# " %5"! 2+H9233#"5432&#"32>5!5>54.#".546*^rQS 1V9G912-< 09/0HV>$$,{p_uXG 9@.KJ%&'6?."i:*>bKEW 5P.fI/c2233#"$5473265!5>54.#".546aqQNXHj19?+CZA#(7s^tXC^p激m_qPB$j700]NFZ@C0jIl<I233"&547#"$5473265!5>54.#".5462654&#"aqQN?HCbC04XHj19?+CZA#(7!" s^tXCM5O1CD0 激m_qPB$j700]NFZ@C0j$#+IOm=J\233#"&547#"$5473265!5>54.#".5462654&#2654'#"&'aqQNV`U<>RXHj19?+CZA#(7e# $,65$#/Es^tXC[8eDWV@+"激m_qPB$j700]NFZ@C0j&X9)" '3) 2+LIR233!5654&#".546#"&=4&#"#"&5463232>54'2654')\{SSvkZBFT+ )7z*C4/>,#N5&+6^G:D= Q(E%y\GNcL_bJ'51!AD/d. ,1"@RA60.>?V.;I8NaH:+Z /!a"#&C6%NOLP^g233!5654&#".546"&547&=4&#"#"&5463232>54'2654&'+'2654')\{SSvkZBFT+ )7z*38B\B,5,#N5&+6^G:D= Q# .%(E%y\GNcL_bJ'51!AD/d. ,1"S'B1??17" G0.>?V.;I8NaH:+Z /!a"h-& 0$#&C6%NOLVcx233!5654&#".546#".547&=4&#"#"&5463232>54'2654'#"'2>54'#"&547'2654')\{SSvkZBFT+ )7z*=@ 4" %B2,#N5&+6^G:D= Q ", 3&#/(E%y\GNcL_bJ'51!AD/d. ,1"[&#I $,.J"!E0.>?V.;I8NaH:+Z /!a"   P#!  '"4 '".#&C6%NOL9&.233!5>7#5654&#".5465#)\{SS>9[8kZBFT+ )7zJ%#y\ /9.NcL_bJ'51!AD/d(:L}5=J233##".547#5>7#5654&#".5465#2654&'#)\{SS*" "1 9[8kZBFT+ )7zJ%##"y\+"2 )" + /9.NcL_bJ'51!AD/d(:###"L<08CW233##"&47#5>7#5654&#".5465#2654&"2>54'#"&')\{SS(T=AO+9[8kZBFT+ )7zJ%#%&$*3&3Ey\&32632#!"3!!"&5463!2654&'#"&5467&#"#"&54>732652654'[$;>"sJ]=?ZD" .?<-9>SL6PA;OPM-H8C[HRb >+'5!/' $:%,8S17Q)\FE_]zI6(*:lMF` 7kA\KIOe~_7HC:@,2J!BJD7G; G:1@I]g3!!"&5463!2654#5254&##"&54>7&#"#"&54>732654>32632#!"3254'|#,=15#/WXV>"U?:L 2++A.:[HQc =,&5 9'0.(O6gKA W:"5)I AFK9)G-%N(K.?7@_|\E+K1 6:F'IOe~_8H@9@.2>*Uz"@=$KTDA# /%:21D}M>OMUb%#".54>32&#"32654.'#"&5467&#"#"&54>732654>326322654'ަAN53L@dD8D=QK7<(N>8JHF!L<9ZIQc =,&5!/' 0.(O7oF g}$,)8*s!"$#;.'03]~]H?oBgNf~_8H@8A-2I"Uz"><$YK>A8)5"-=J^EP233!532654&#"#"&547&#"#"&54>7326=4>3262654'I\cSFUC6@@0*6H+.5TEUg =,&5I;#7+6'22)B.4DwXED#kXLc7d>SS>YAXJSSd`7JB8@+Ld:DN.J) 15U00U*-JCfO_j233#"&547!532654&#"#"&547&#"#"&54>7326=4>3262654.+"2654'I\cSCbCfFUC6@@0*6H+.5TEUg =,&5I;#7+6'22)Z"*{.4DwXED-1CD0+#kXLc7d>SS>YAXJSSd`7JB8@+Ld:DN.J) #  15U00U*-JgP[mx233##"&547!532654&#"#"&547&#"#"&54>7326=4>3262654&"2654'#"&'2654'I\cS$-U<@P/FUC6@@0*6H+.5TEUg =,&5I;#7+6'22)0%&$+72'#/E.4DwXED#@DWW?B&#kXLc7d>SS>YAXJSSd`7JB8@+Ld:DN.J) X:($ $6) 2+L15U00U*-I_i%!3#".54>32&#"3265!53>54&#"#"&547&#"#"'&546732674>76326322654'8+S~@K46N=PJ ]4JI5lU.9L?@@0+5H. *YDR63R>w 9'3%0V?%)?Rg$4D ;xGov  %b\#h9Ng7d9OM;YA$HO8LhE?TG&V|/:'RU+,?6t6'U00U'6J[fq%4632#"&547&#"532654&#"#"&547&#"#"&54>7326=4>326323&2654&'%2654'udaFCPB8Jo#Od_FUC6@@0*6H+.5TEUg =,&5I;#7+6'22)?I\c<'1%f0.4Df{QL`XtWGZpTy:#kXLc7d>SS>YAXJSSd`7JB8@+Ld:DN.J) wXETB@F>TTc2@Y15U00U*-Jh3!!".54>3!2>54.'#"&54>7&#"532654&#"#"&547&#"#"&54>7326=4>32632!&547632632#!"%2654'%2654':+--+>V);'&O;=P1#%-4L#_FUC6@@0*6H+.5TEUg =,&5I;#7+6'22)?I\c<@?Z\Cf*)#&SS>YAXJSSd`7JB8@+Ld:DN.J) wXETi[CCCi~`|R2S:X42AX15U00U*-JG2#!"3!!"&54>3!2654&+532654&+#"&54>7&#"!532654&#"#"&547&#"#"&54>7326=4>326323&54>3263254'2654'l]z@DM9%/ ) `&#% (Q: 'Q@9L1(%4*C&_FUC6@@0*6H+.5TEUg =,&5I;#7+6'22)?I\c< -R3_D-&M"A=.4D|YC<"`.8$I?. $&*!<*./@BMUs`F*H0 %"/:*y:#kXLc7d>SS>YAXJSSd`7JB8@+Ld:DN.J) wXETi1B7&H2CJ:QK15U00U*-J%4632#".54>32&#"32>54.'#".54>7&#"!532654&#"#"&547&#"#"&54>7326=4>326323&2654'%2654'fxB>T! _f4K@SM99+"\f'7V4" 1&RC %/ E3&HK547,FUC6@@0*6H+.5TEUg =,&5I;#7+6'22)?I\c>%#0#2 ,.4Dhr Q^3 %)>TO(=I 9Zy D/+>09:8O7k #kXLc7d>SS>YAXJSSd`7JB8@+Ld:DN.J) wXEXDM:82 4$(JW15U00U*-M-R\2#"&547&#"#"&54>7326=462'654&#"#54&#"&546326'3254&'iPA8Px(*4G[HRb >+'5!/' $:i6H'$?(. 9"(1KUJ;7&$7?MlÔtVnWG`"`GIOe~_7HC:@,2J!BJCZi'WB,F *Z+Fѵ 'A0\#.hAZ10:8{(lWM-Q[e2#"&547&#"#"&54>7326=462#"&547&#"#54#"&546326'3254&'2654'iPA8Px(*4G[HRb >+'5!/' $:iCZ5,*7D+97'4MYK74'-?Ml}6B#ÔtVnWG`"`GIOe~_7HC:@,2J!BJCZi'iJ7EC7R6 ѵHC3Z!-hCX0/:8{(lW)"O.4E"-MX"-hr}2#"&547&#"#"&54>7326=464>32632#"'7327654'#"&5467&#"#54#"&3254&'2654'iPA8Px(*4G[HRb >+'5!/' $:i /&5&,;R0<9bH'% <)$; 6+&2>+>",98  NZ9?Ml?"#'ÔtVnWG`"`GIOe~_7HC:@,2J!BJCZi.B 0.KT2Kf 50=P&7326=464632!3254&'354&'4#"6iPA8Px(*4G[HRb >+'5!/' $:i'9T4?Ml&..*2,AmÔtVnWG`"`GIOe~_7HC:@,2J!BJCZikc]x:8{(lWy*-gN;$6TNM ->HT[g2#"&547&#"#"&54>7326=464632##"&47#3254&'354&'4#"62654&#"iPA8Px(*4G[HRb >+'5!/' $:i'9T$C-/A#k4?Ml&..*2,Am-&-"$ÔtVnWG`"`GIOe~_7HC:@,2J!BJCZikc]x`@A^:8{(lWy*-gN;$6TN$"-&M-BL]do2#"&547&#"#"&54>7326=464632##"&547#3254&'3632354&'4#"62654&#"2654'#"&5477#iPA8Px(*4G[HRb >+'5!/' $:i'9T#/-# 4H/b4?Ml&N  ...*2,Am&4350& ÔtVnWG`"`GIOe~_7HC:@,2J!BJCZikc]x&:$5 G4:&:8{(lWy*-gN;$6TNP-# '"#& '!/M,-7Ydm2#"&547&#"#"&54>7326=463254&'4>32#".54632&#"326=#7354&#'"654&iPA8Px(*4G[HRb >+'5!/' $:i[?Ml7,-CV37H7C;7N<($%&+8,_(t ÔtVnWG`"`GIOe~_7HC:@,2J!BJCZi:8{(lWG1D KL5;@&"bHJ!5?tS[!H11LY4>32#".547327654'#"&5467&#"#"&54>732652654'&B+HR0-͘e!Zچvfa NA7Jh>$aC4YFOh :*$2 -&':)$&0 "07'p >;Pgz{tcokWbTon&*3_t`DHdIieQc|d4FB6>/0I#R]T3G) 7%,GH1Wdq4>32"&547#".547327654'#"&5467&#"#"&54>732652654'2654&#"&B+HR0-W**CbCbe!Zچvfa NA7Jh>$aC4YFOh :*$2 -&':)$&0 "+* #07'p >;PrY @$1CC1 %gz{tcokWbTon&*3_t`DHdIieQc|d4FB6>/0I#R]T3G) 7%,G 4"Hr1Zgt4>32#"&547#".547327654'#"&5467&#"#"&54>732652654'2654&#"2654'#"&'&B+HR0-{-S>?Q Oae!Zچvfa NA7Jh>$aC4YFOh :*$2 -&':)$&0 "%$+73&1 E07'p >;P^ 6%CXW?!gz{tcokWbTon&*3_t`DHdIieQc|d4FB6>/0I#R]T3G) 7%,GX:(  &4"! 2+M-U_h2#"&547&#"#"&54>7326=46#"&=4&#"#"&5463232654/3254&'2654'iPA8Px(*4G[HRb >+'5!/' $:i*C4/>-"N5&+6_F:D=>Qy?Ml)E%ÔtVnWG`"`GIOe~_7HC:@,2J!BJCZi, ,1"AQA60-??V.;I8MbH:+Z69a":8{(lW$%C6'LOM-]gs|2#"&547&#"#"&54>7326=46#"&547&=4&#"#"&5463232654/3254&'2654&#"'2654'iPA8Px(*4G[HRb >+'5!/' $:i*;9B./A46-"N5&+6_F:D=>Qy?Mlw$!$%)E%ÔtVnWG`"`GIOe~_7HC:@,2J!BJCZi, ,1"Z&B1??1=! H0-??V.;I8MbH:+Z69a":8{(lW3&.&$$%C6'LOM-_iw2#"&547&#"#"&54>7326=46#"&547&=4&#"#"&5463232654/3254&'2654'#"'2654'#"&547'2654'iPA8Px(*4G[HRb >+'5!/' $:i*9F-# 4H=7-"N5&+6_F:D=>Qy?Mlm &4350)E%ÔtVnWG`"`GIOe~_7HC:@,2J!BJCZi, ,1"X'!M$5 G4G"J0-??V.;I8MbH:+Z69a":8{(lWd   P-# '"#& '!/$%C6'LOM-R\e2#"&547&#"#"&54>7326=462#"&547&#"#"&54732=46'3254&'3254'iPA8Px(*4G[HRb >+'5!/' $:iDa5-'6L7?.6CbQ;9G?MlN&.!BÔtVnWG`"`GIOe~_7HC:@,2J!BJCZi'`N8J:0U=25/7APBr+"^92V+;G:8{(lW$$"KH&6Mc-q{2#"&547&#"#"&54>7326=464632#!"3!!"5463!2654'#"&5467&#"#"&54>732653254&'3254'"iPA8Px(*4G[HRb >+'5!/' $:iC4O0+?5*$$IF)5+57 *0".=')!,>.0:%# +(!"q?Ml 0 #%ÔtVnWG`"`GIOe~_7HC:@,2J!BJCZi-7<C61@*7'=+A,G1(+8'5+"+:D:(= <)*4(!J:8{(lWF"J# $M-72#"&547&#"#"&54>7326=463254&'#!"3!!".5463!2654#5254&##".54>7&#"#"&54673265462632%3254'iPA8Px(*4G[HRb >+'5!/' $:i[?Ml`Y'  " 09:7+9)", # ,%,;06A)5P +!:27326=463254&'#"&54>32&#"32654.'#"&5467&#"#"&5467326546326322654'iPA8Px(*4G[HRb >+'5!/' $:i[?Mlm*g#5(B-'*_VYq, 3*&/7&2(%L3H/ ER)*ÔtVnWG`"`GIOe~_7HC:@,2J!BJCZi:8{(lWg rS"/!! =S?.3B,EY5BQA'^#b=58QD;;Zr7#-#9#)M7-7s|2#"&547&#"#"&54>7326=463254&'32=432#"&54732654'#"&5467&#"#"&547%3254iPA8Px(*4G[HRb >+'5!/' $:i[?Ml<@uc0/DB;z@4*%0F'BN:/7BY,!v/)03ÔtVnWG`"`GIOe~_7HC:@,2J!BJCZi:8{(lWH;7sJI7326=46#".547#"&54732654'#"&5467&#"#"&54732=4323254&'32542654&#"iPA8Px(*4G[HRb >+'5!/' $:i#(7* #1:>8s=1(".A&T$ 97326=46#".547#"&54732654'#"&5467&#"#"&547325'4323254&'32542654&#"#2>54'#".547iPA8Px(*4G[HRb >+'5!/' $:i'*@. / #82rf7+$)8$6B3&-8JA37dS(+?Mlj5)+ *.  %#ÔtVnWG`"`GIOe~_7HC:@,2J!BJCZi :!,=& {cA> 5;UjZB:3>3%(3'n,4A6Z"N0-^h<( M:8{(lW$"=H' $J# ! ' KE;AKV%>73##".547!5654&#"&5463235".54>3273"542654'#SE/"1 .H8.1A4D`MJc%/9( 6&B2e5' #//"7G,2B)" ,-O.:B4B$5WK[ZJ9)?* #+RT# _%O g*<. w>#0 1"K9?ITh%>73##"&547!5654&#"&5463235".54>3273"542654&"2>54'#"&'S#-T=?Q0WH8.1A4D`MJc%/9( 6&B2e5' %&$*2'1 /7G"@AZW?A&-O.:B4B$5WK[ZJ9)?* #+RT# _%O g*<. w>X# " %5"! AMLR]%>73#".54>32&#"326='!5654&#"&5463235".54>3273"54=0\H@L4bVJ</C#\G8LKH8-2A4BaNK]$/9(.% B2u7' J1@4 % %193ESEU]F:)?*#4 WU K"Q f). w>K.TZdjr{%>73!5654&#"&5463235".54>322#"/32654&+#"'#"&546346323"544&"325#32=#"SpH8.1A4D`MJc%/9( 6&B20*+"!*8.4)'0784*Z *e5' %6 "A}j (?7G-O.:B4B$5WK[ZJ9)?* #+RT# 7#"3 # !!CS227(0!6I%O g*<. w>%3/)1&6t )#=7K.]cmt{%>73!5654&#"&5463235".54>322#"/3254+53254+#"'#"&546346323"544&#"325#32=#"SpH8.1A4D`MJc%/9( 6&B2 #G"*8.5*(/8M3+%3*e5' -  A}k (?7G-O.:B4B$5WK[ZJ9)?* #+RT#  6!CR226)26H55%O g*<. w>/(/(8v}%>73!5654&#"&5463235".54>3273"54232#!"3!!"&5463!254+53254+#"'#"&54;464&#"325#32=#"SpH8.1A4D`MJc%/9( 6&B2e5' y.9;A#$< w#$)4# +8.5*%1l3c%""Ck*A7G-O.:B4B$5WK[ZJ9)?* #+RT# _%O g*<. w>h=00+5 /%'$5B,,,#C0;k -0+ ,a 5,K..`fpw%>73!5654&#"&5463235".54>322#"&5462&#"32654&+#"'#".546;46323"54.#"26=#'32=#"SpH8.1A4D`MJc%/9( 6&B2,)/0(5, '1>#86K.gmw%>73!5654&#"&5463235".54>322'654&#"32#"&547##"'#"&546;46323>3"542654+'.#"327#32=#"SpH8.1A4D`MJc%/9( 6&B2w-B S$=?. 6 A;*$+)8.6+'1994**# $+Oe5' 1'  " !A~k(?7G-O.:B4B$5WK[ZJ9)?* #+RT# &7,SG6I5H/(%6&/S!CS228'0!9E0 )8L%O g*<. w>\<#&17 1(4s3$=6K.y%>73!5654&#"&5463235".54>322#"/3254+57>54&#"32#"&5465##"'#"&546;463263"542654&+'4&#"325#32=#"SpH8.1A4D`MJc%/9( 6&B2|+> ,04( .% - !43#+0(/8.6+'08:4+* #e5' j($ !B~k'?7G-O.:B4B$5WK[ZJ9)?* #+RT# $ &'&- (1*%#.&/*A2CS227(.#6H/!L%O g*<. w>\" $,$36!1(4s3%=6K`.4>%>73!5654&#"&5463235".54>3273"542#!"3!!"&5463!254&+532654&#"32"&57##"'#"&54;46323>2654&+'4&#"325#32=#"SpH8.1A4D`MJc%/9( 6&B2e5' :M43e ##Y%%Z  28I +3->07/5*%1n3*Z  \.#\&"#Ck *A7G-O.:B4B$5WK[ZJ9)?* #+RT# _%O g*<. w>k1(&2Q/$$:"6 %#*,49F,,+$D.=k/>Dt ,/)!.d5/K*.qw%>73!5654&#"&5463235".54>322#"&54632&#"32654&#"2#".547##"'#"&546;>323>3"542654+'.#"327#32=#"SpH8.1A4D`MJc%/9( 6&B2tC\j'gQ=66.$R6RbC5II9%)$8.6+'08<3*Y# Cye5' 0(z" !@~k'?7G-O.:B4B$5WK[ZJ9)?* #+RT# sXk q[MbW$6!5)# DS227(0!:E5KN%O g*<. w>X= 8'15#1(4t3 =7KG.\blrz%>73!5654&#"&5463235".54>322#"&54732>54&+#"'#"&54;46323"544&"325#32=#"SpH8.1A4D`MJc%/9( 6&B2'3r:.VL`?Z/8.6+&1Z+4+Z -e5' $8 !A|k'?7G-O.:B4B$5WK[ZJ9)?* #+RT# 5,YljfFJN\;435%DS227)P6I%O g*<. w>&20(1(4t%&=7K.ioy%>73!5654&#"&5463235".54>322"&547#"&54732>54&+#"'#"&54;46323"544&"325#2>54&+32=#"SpH8.1A4D`MJc%/9( 6&B2'3FH?b? :.,>L89<- 8.5*&1Z+4+Z -e5' %6!!A| - %'?7G-O.:B4B$5WK[ZJ9)?* #+RT# /'K0D(:9)}_Z>@F*C%3!;I,,.&G0?o%O g*<. w>"++",#.f    60 K.lr|%>73!5654&#"&5463235".54>322#".547#"&54732>54&+#"'#"&54;46323"544&#"325#2654&#'32=#"2654'#".547SpH8.1A4D`MJc%/9( 6&B2&0X(/ 1!"1  |8,WHV%CB'5,1("1V)1(U 'e5' "!>v  &*,)!*_  2-& *   K.OU_%>73!5654&#"&5463235".54>324632&#";2#"'73254+"&3"54SpH8.1A4D`MJc%/9( 6&B2:DT0$C#6-?70N1V,$MS>@'0e5' 7G-O.:B4B$5WK[ZJ9)?* #+RT# &;0%&05./&5(-%O g*<. w>K.X^ht%>73!5654&#"&5463235".54>324632&#";2#"&547&'73254+"&3"542654&#"SpH8.1A4D`MJc%/9( 6&B2:DT0$C#6-?7098B./A,1$MS>@'0e5' &.$%7G-O.:B4B$5WK[ZJ9)?* #+RT# &;0%&0=>1??16 &5(-%O g*<. w>$"&$K.^dn{%>73!5654&#"&5463235".54>322#".547&'73254+"&54632&#"33"542654'#"'2654'#"&547SpH8.1A4D`MJc%/9( 6&B270;=$ %7-$MS>@'0:DT0$C#6-Le5'   %533/7G-O.:B4B$5WK[ZJ9)?* #+RT# 0>"C..@!&5(-$&;0%&%O g*<. w> P." '"#& '".K9.4>m%>73!5654&#"&5463235".54>3273"544>32&#"#"&54632&#"32654/.SpH8.1A4D`MJc%/9( 6&B2e5' *8C%a:.Yl:K=H>K*9Q:?C/#0//#?6LS %7G-O.:B4B$5WK[ZJ9)?* #+RT# _%O g*<. w>,95)I;CjD$+! ='I/K.4>l%>73!5654&#"&5463235".54>3273"542#"&54632&#"32654+"&54632&#";2'654#"#465654#"&54632SpH8.1A4D`MJc%/9( 6&B2e5' EXf=KQ9K+G(7:,LbnT0CL[t;1fu@7G-O.:B4B$5WK[ZJ9)?* #+RT# _%O g*<. w>H;Xl+#!-)% UEe7(*?,'G7     K.Y_i%>73!5654&#"&5463235".54>322#".54732654+"54632&#"33"54SpH8.1A4D`MJc%/9( 6&B20<19?_.8,65M)6?zK-.#N.:0%#!%O g*<. w>K.`fp{%>73!5654&#"&5463235".54>322".547.54732654+"54632&#"33"542654'#SpH8.1A4D`MJc%/9( 6&B20<0.-* +-Ua8,65M)6?zK-.#N.:0%#!%O g*<. w>$0  +K.cis%>73!5654&#"&5463235".54>322#"&547.547;63654+"54632&#"33"542654'+2>54'#"&547#SpH8.1A4D`MJc%/9( 6&B20<.<-$ 4G)O[8,65M =?zK-. (#N.:0%#!%O g*<. w>   +V*&$ '!4.)K.4>JW%>73!5654&#"&5463235".54>3273"542#"&5462>54&#"SpH8.1A4D`MJc%/9( 6&B2e5' yNgiHKa]? &. K75ML7G-O.:B4B$5WK[ZJ9)?* #+RT# _%O g*<. w>^cOMbbHOh 8%8MHpOK.HNXkw%>73!5654&#"&5463235".54>322#"&547#"&5463233"542>54.#"2654&#"SpH8.1A4D`MJc%/9( 6&B23025,<Hd]KNg e5' Y0 8&5M 8#+#"7G-O.:B4B$5WK[ZJ9)?* #+RT# IK<+_KOhbP6-f%O g*<. w>( & &0!I7'1!v# #"K.IOYcp%>73!5654&#"&5463235".54>322#"&547#"&546323"542654#"'2>54&#"2>54'#".5SpH8.1A4D`MJc%/9( 6&B2&. K79IIc]KNg:e5' $.&7 K75ML+ && $7G-O.:B4B$5WK[ZJ9)?* #+RT#  8%6LM5 `JOhcO#!G%O g*<. w>.(< .&8MHpO$ % !!  +K.gmw%>73!5654&#"&5463235".54>322'654&#"#54&#"#54&#"632#"&54>3263263"542654#"SpH8.1A4D`MJc%/9( 6&B2 %-ZB,%7% 67d '*)#'/24@6BYe5' +7G-O.:B4B$5WK[ZJ9)?* #+RT#  C.q,,_9Bڽ!-!08*'3H84M)4301F%O g*<. w>W:8K.jpz%>73!5654&#"&5463235".54>322#"&547&#"#54&#"#54&"632#"&54>3263263"542654'%3254&#"SpH8.1A4D`MJc%/9( 6&B2]%)R18J#,5%6KW.|%>73!5654&#"&5463235".54>324>32632632#"'732>54'#"&467&#"#54&#"#54&"632#"&3"543254'3254#"SpH8.1A4D`MJc%/9( 6&B2k"2)7(53"6H41T=$  %-53 ,.--#2(2(>,"')%-Le5'  ,  B&%7G-O.:B4B$5WK[ZJ9)?* #+RT# ^6N$4301M Z5Lf B,K%F>8XM+%չ(#" 2"/:),(D9%O g*<. w>%U, +1'56KKQ[%>733!5654&#"&546323!5654&#"&5463235".54>3273"54S/$*$/B2!2 H8.1A4D`MJc%/9( 6&B2e5' 7J 1#*!+$91>' "-O.:B4B$5WK[ZJ9)?* #+RT# _%O g*<. w>K#Y_iv%>733##"&547#5654&#"&546323!5654&#"&5463235".54>3273"542>54&#"S(! /A'/$*$/B2!2 H8.1A4D`MJc%/9( 6&B2e5' .$%7J1*A/2 1#*!+$91>' "-O.:B4B$5WK[ZJ9)?* #+RT# _%O g*<. w> "&$K[akv%>733#".547#5654&#"&546323!5654&#"&5463235".54>3273"542654'#2654'#"&547S*1$%1/$*$/B2!2 H8.1A4D`MJc%/9( 6&B2e5'   &4) )17J%:..;$ 1#*!+$91>' "-O.:B4B$5WK[ZJ9)?* #+RT# _%O g*<. w> ! !P." ,+ &$,KM\bl%>73#"&54632&#"325!5654&#"&546323!5654&#"&5463235".54>3273"54S;VV43*+LQe/$*$/B2"1 H8.1A4D`MJc%/9( 6&B2e5' 7 z4'*"+#:3<' $-O.:B4B$5WK[ZJ9)?* #+RT# _%O g*<. w>KRY_i%>73# 4732>=!5654&#"&546323!5654&#"&5463235".54>3273"54SzV>5DE/)+$.@42?H8.1A4D`MJc%/9( 6&B2e5' 75G SL@Gjt &2$*")";2=<0$-O.:B4B$5WK[ZJ9)?* #+RT# _%O g*<. w>K.flv%>73!5654&#"&5463235".54>322353#"&547#"&547326=!5654&#"&5463"542>4.#"SpH8.1A4D`MJc%/9( 6&B2V2?77BA/0@>5~Qo/$ *$.C>e5'  %%7G-O.:B4B$5WK[ZJ9)?* #+RT# 7. /C,<<,!s`LG>?M^)!.")'!6/8|%O g*<. w>."!K.kq{%>73!5654&#"&5463235".54>32#".547#"&547326=!5654&#"&546323533"542654&#"2654'#"&547SpH8.1A4D`MJc%/9( 6&B27-# %-70sId+"&*;-.91Ne5' %535/7G-O.:B4B$5WK[ZJ9)?* #+RT#  :0$5 .:$cRB=47BQ#(!!/(1/'2B%O g*<. w> P." '"#& '".K.NT^g%>73!5654&#"&5463235".54>322!5654&#"&5463235463"54"354&SpH8.1A4D`MJc%/9( 6&B2{>K4/$ *#.B12AlHxe5' )267G-O.:B4B$5WK[ZJ9)?* #+RT# O@3%)"+";1=<1$6HL%O g*<. w>=:+g;HK.Z`js%>73!5654&#"&5463235".54>322##"&547!5654&#"&5463235463"54"354&2654&#"SpH8.1A4D`MJc%/9( 6&B2{>K#-*,<#/$ *#.B12AlHxe5' )26!"7G-O.:B4B$5WK[ZJ9)?* #+RT# O@/'3 <+03%)"+";1=<1$6HL%O g*<. w>=:+g;H$+ #K.[akt~%>73!5654&#"&5463235".54>322##"&547!5654&#"&5463235463"54"354&2654#"2654'"&547SpH8.1A4D`MJc%/9( 6&B2{>K,6 8%7J6/$ *#.B12AlHxe5' )268-2*:%P%,87G-O.:B4B$5WK[ZJ9)?* #+RT# O@"= #*E1="3%)"+";1=<1$6HL%O g*<. w>=:+g;H ))R5&  211&5K.6<FRY%>73!5654&#"&5463235".54>324632!3"54354&'4#"6SpH8.1A4D`MJc%/9( 6&B29Te5' &-/*2,Am7G-O.:B4B$5WK[ZJ9)?* #+RT# Uc]xr%O g*<. w>).gM<$6TNK.BHR^eq%>73!5654&#"&5463235".54>324632#".547#3"54354&'4#"62654&#"SpH8.1A4D`MJc%/9( 6&B29T!'-* +-'|e5' &-/*2,Am 6!7G-O.:B4B$5WK[ZJ9)?* #+RT# Uc]x 1'3 2'1 r%O g*<. w>).gM<$6TN$+  K.DJT`gq%>73!5654&#"&5463235".54>324632#".547#3"54354&'4#"62654#"2654'"&5477#SpH8.1A4D`MJc%/9( 6&B29T(1 6J5 1]e5' &-/*2,Am-1*74,5+78 7G-O.:B4B$5WK[ZJ9)?* #+RT# Uc]x&< #-,$ =%r%O g*<. w>).gM<$6TN +*V8'! '!!'2'8T;@FQ%>73# $54673265!5654&#"&5463235".54>3273"54&9z-0*$G:+1A3B`NK]$09(.% ut7' N5p<+AhA1:2ESEU]F9*?*#4 (P#P f). w>TGOU`m#".547# $54673265!5654&#"&5463235".54>32>733"542654&#"0 2"#3 hm-0*$G:+1A3B`NK]$09(.% u9Kt7' "## 8+ #*+" AhA1:2ESEU]F9*?*#4 (N5B#P f). w>V#!" TCCJP[i~"&547# $54673265!5654&#"&5463235".54>32>733"542654.'"2654&'#".=38U|TXS-0*$G:+1A3B`NK]$09(.% u9Kt7' ,P:-8'#!+ Q/=VU>0&AhA1:2ESEU]F9*?*#4 (N5T#P f). w>V[8*%36& "  +LEDQ#".547.=4&#"#4&#"&5463263232654.'2654&#H9S>AE/ "*8ND-)+S8"3',2%nOU91TDd<05A 4&6+* #~fn;J2B 2!$ WGKWK )<5,1J,?;E_yKI`KU>P_I0?7 "L?L_#"&547.=4&#"#4&#"&5463263232654.'2654&'"#2>54'#"&'H=OQSS>=S50=D-)+S8"3',snOU91TDd<05A 4& .&C&0 3&1 E|d9]CXUAH'T=KWK )<5,1JFE_yKI`KU>P_I0?7 $v+'  %5 # 2+IT%2654'7#"&54632&#"3265#"&'&'&#"#4&#".546326329Ig-G}R[}|_^>0@(cuL+CR P+5S3# )# 2$*: pRQ;2RIb52gLiTb.UbH/)"!-!t%+jWP6]yC' O;?X(;2|0RI`q3/S0*'9 slQU91TJ^l6@y0L&3N&&%  # 3#7FB '/#$?bK':3>)<15EZ~KIcD%]K6tF7jrT7' , ;% &L8^dlv#"&=4&#"#4&#"&5463263232654.'2#"/32654&+#"'#"&5463>32#4&"325#32=#"H/>^PGbD-)+S8"3',snOU91TDd<05A 4&O0*+"!*8.5+'0782*X0%6""A}j(?FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?77#$1 # !!AU227(0!:E%32&1&6t ) =7L8gpw#"&=4&#"#4&#"&5463263232654.'2#"/3254+53254+#"'#"&54634632#4.#"325#32=#"H/>^PGbD-)+S8"3',snOU91TDd<05A 4&n #G"*8.6*(/6O4*%30 ! A}k (?FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7 6!CR226)27G64 2%8P_I0?7>=00+5/''$5B,,,#C0;k!,/+ ,a !5,L.8ipy#"&=4&#"#4&#"&5463263232654.'2#"&5462&#"32654&+#"'#"&546;4632#.#"26=#'32=#"H/>^PGbD-)+S8"3',snOU91TDd<05A 4&B-;mp7JPz6"0*(?Sc& 9/5*:'.05+*:2!!;#{!&;FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7O9Dt ]F+5AP33/308GE:)/0(5, (0>#86L8ny#"&=4&#"#4&#"&5463263232654.'2'654&#"32#".547##"'#"&546;46323>2654+'4&#"325#32=#"H/>^PGbD-)+S8"3',snOU91TDd<05A 4& ".%S$=?.(1A;*$) 8.6+'1993+V# C1' % !B~k(?FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7C 9$TF6I5H;%6&/20CS228'0!9E~4J$<*&%27 1'5s3%=6L8#"&=4&#"#4&#"&5463263232654.'2#"/3254+57>54&#"32#"&547##"'#"&546;46326264&+'.#"327#32=#"H/>^PGbD-)+S8"3',snOU91TDd<05A 4&+> ,04( .% - (8! 3#+0'08.7+'08:4+* ##(" !A~k'?FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7C$ &'%. (1*%#'.&0)B1CS227(.#6H/!0! $,&16!1(4s3%=6LV8#"&=4&#"#4&#"&5463263232654.'2#!"3!!"&5463!254&+532654&#"32#"&57##"'#"&54;46323>2654&+'4&#"325#32=#"H-= ^PGbD-)+S8"3',snOU91TDd<05A 4& 9N43e ##Y'&Z 1!X+,&*"*%7/6,&0n3*Y ]/#\%"#Ck*ADP9_u`MKWK )<5,1JIE_yKI`KU>P_I0?7A1(&2Q/"$:#"&,*$);%9F,,+$D.=k/>Dt ,/)#,d "5/L*8{#"&=4&#"#4&#"&5463263232654.'2#"&54632&#"32654&#"2#".547##"'#"&546;>323>2654+'.#"327#32=#"H/>^PGbD-)+S8"3',snOU91TDd<05A 4&C\j'gQ=66.$R6RbC5IG;%)$8.6+'08<3*Y# C 0(z" !@~k'?FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7AsXk q[MbW%5!5*" DS227(0!:E5K= 8'15#1(4t3 =7LG8fmu#"&=4&#"#4&#"&5463263232654.'2#"&54732>54&+#"'#"&54;>32#4&#"325#32=#"H/>^PGbD-)+S8"3',snOU91TDd<05A 4&L(2r:.VL`?Z/8.5)&1Z+3*Z 1#!!A|k'?FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?77*YljfFGQ\;435%BU227)P:E%30(1(4t% =7L8qw#"&=4&#"#4&#"&5463263232654.'2"&547#"&54732>54&+#"'#"&54;>32#4&"325#2>54&+32=#"H/>^PGbD-)+S8"3',snOU91TDd<05A 4&L'3FH?b? :.?^J&GE* 8.4)%2Z+3*Z 1%6!!A| $ %'?FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7/'J1D(:9)}_Y>>H5L# ;):K--/%H1>o"++",$-f $   60L8u}#"&=4&#"#4&#"&5463263232654.'#"&547#"&54732>54&+#"'#"&54;463232'.#"327#2>54&#'32=#"2654'#"&547H/>^PGbD-)+S8"3',snOU91TDd<05A 4&S(, 0 1B y6+;WE#B@'5*2'"/T(0(S '$/;t %;F0$'FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7 9 $;+$wXT;=A2H! 8&5H**-#C/:i-$Q  -)!,` &3-%+# !L8[e#"&=4&#"#4&#"&5463263232654.'233!5654&#"632#"&546"3254&H/>^PGbD-)+S8"3',snOU91TDd<05A 4&?Z69CA.!0 ("-%+)2U,/FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7WS@E8 0K5C1#/6)!6C7Tc65L8kx#"&=4&#"#4&#"&5463263232654.'233##".547#5654&#"632#"&5462>54&#""3254&H/>^PGbD-)+S8"3',snOU91TDd<05A 4&?Z69&! !0 &CA.!0 ("-%+)2U, .",/FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7WS@E8 2*) 20K5C1#/6)!6C7TcV "-. 65L8kw#"&=4&#"#4&#"&5463263232654.'233##".547#5654&#"632#"&5462654&#"2654'#"&547"3254&H/>^PGbD-)+S8"3',snOU91TDd<05A 4&?Z69-7 4" %7mCA.!0 ("-%+)2U ?!'&#0,/FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7WS@E8 #@ $,.@#0K5C1#/6)!6C7Tc|P') 44 (#-565L8Y#"&=4&#"#4&#"&5463263232654.'4632&#";2#"'73254+"&H/>^PGbD-)+S8"3',snOU91TDd<05A 4&b:DT0$C$5-?70N1V,&KS>@'0FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7&;0%&05./&5(-L8ep#"&=4&#"#4&#"&5463263232654.'2#"&547&'73254+"&54632&#"3264&#"H/>^PGbD-)+S8"3',snOU91TDd<05A 4&8703<! .B*6&KS>@'0:DT0$C$5-?#!$%FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?709D*?16! &5(-$&;0%&-&-&$L8gt#"&=4&#"#4&#"&5463263232654.'2#".547&'73254+"&54632&#"32654'#"'2>54'#"&547H/>^PGbD-)+S8"3',snOU91TDd<05A 4&8708? 4" %6.&KS>@'0:DT0$C$5-$ ", )'"/FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?70;$G $,.?&&5(-$&;0%&   P#!  *4 &".L8c#"&=4&#"#4&#"&5463263232654.'2#".54732654+"54632&#"3H/>^PGbD-)+S8"3',snOU91TDd<05A 4&10<19?_.8,65M)6?zKP_I0?73#!*,?7D6+7>-.#N.:0%#!L8lx#"&=4&#"#4&#"&5463263232654.'2#"&547.54732654+"54632&#"32654&#"H/>^PGbD-)+S8"3',snOU91TDd<05A 4&10<34! /A$R]8,65M)6?zKP_I0?73#0"<*@01!h:D6+7>-.#N.:0%#!$"&$L8lz#"&=4&#"#4&#"&5463263232654.'2#".547.54732654+"54632&#"32654'#"'2654'#"&547H/>^PGbD-)+S8"3',snOU91TDd<05A 4&10<:9H3 %0LV8,65M)6?zKP_I0?73#3$C4G.=$d8D6+7>-.#N.:0%#!   P." 43 &"L;eo#"&=4&#"#4#"&54>;263232654.'2'654&#"#"&547&#"&5463262654'H/>^PGb>3)+SZ3',s,@4o%1TL\4'6@6'L_Q$:H7F6-+5C. ?HU;'$"2'8A"FO1_u`MUES );J,1J5E>\+KIhVU44`H,A;FaFZ0 .H=S^PGbD-)+S8"3',snOU91TDd<05A 4& ,@"B0((v"*)##2C7  G8+*6B .;AIN?(!#3!7A"FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7D12?V3$$C49G3C/:9-F+@-G 'P:P&;(-:$LX8z#"&=4&#"#4&#"&5463263232654.'4632632#!"3!!"&546;254&+532654#"#"&547&#"&72654'H/>^PGbD-)+S8"3',snOU91TDd<05A 4&N<+!$@./*0''s5#)W L.E7,+5C/:@H!7B"FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?79KS#.#73#0;!: 1C09:-@.>/G %&:(-9$L-8s}#"&=4&#"#4&#"&5463263232654.'2#"&54632&#"32654&#"#".547&#"&54>3262654'H/>^PGbD-)+S8"3',snOU91TDd<05A 4& Paj@LO=?6$9QQOaG<F8-$. C2=?H%.! $/#8@*FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7DwXj0u\Ne3262'654#"#54#"&546326'2654'H/>^PGbD-)+S8"3',snOU91TDd<05A 4&Qdm<N.5%*:@'ThN@$I9,(E2?>G%. $! 9"9C,FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7Aex &$.+hZ{=Q5I,# R6K8S) 2`%; z  ' 1%G24J,%LL8q{#"&=4&#"#4&#"&5463263232654.'2#"&54732>54.#""&547&#"&5463262654'H/>^PGbD-)+S8"3',snOU91TDd<05A 4&G^7mK5!3l>Y.*$ G8V5C/ACGU;)"*;"7>FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7DpS$GG,yNG54.#"#"&547&#"&54632632'2654'2654&#"H/>^PGbD-)+S8"3',snOU91TDd<05A 4&W#(=/.> ~3 2j;W-" E8)*3A-/AFQ<&"'(D\!6;",-#FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7 7)<9,lG?8>Zp15"7 6H2?<2G29*M$ /U=ReJ]#*!@+-B ')#L8#"&=4&#"#4&#"&5463263232654.'#".547#"&54732>54.#"#"&547&#"&54632632$2654'2654&#"2654'#"&547H/>^PGbD-)+S8"3',snOU91TDd<05A 4&Q*, 0 +8 y0/h:S*6(B5('2>(3 ?CO8!$'%BW0 3: !#1 #%-FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?79" $,*${dA;2;Sg.0:;2B/98-C-.+E$ *O:J]E`+&:)(? C&,, &L CL2!53546#"&=4&#"#4&#"&5463263232654.'"!54&\uדp/>^PGbD-)+S8"3',snOU91TDd<05A 4&@P#Ryc"WgFO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7YFιSaLEPYd2##".547!53546#"&=4&#"#4&#"&5463263232654.'"!54&2654'#\uE/ "*p/>^PGbD-)+S8"3',snOU91TDd<05A 4&@P#R "//#yc,3A 2!,"WgFO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7YFιSa"0 0#LNWdv2##"&547!53546#"&=4&#"#4&#"&5463263232654.'"!54&2654&#"2654'#"&'\u%-T=?Q0p/>^PGbD-)+S8"3',snOU91TDd<05A 4&@P#R%%")92'1 Eyc"ABYW?B&"WgFO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7YFιSa "X9)" %5 # 2+L Yb2#"&54632&#"3265!53546#"&=4&#"#4&#"&5463263232654.'"!54&\utb|KXI7F_'{^p/>^PGbD-)+S8"3',snOU91TDd<05A 4&@P#Rycvu-$ -"%a^"WgFO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7YFιSaL8]#"&=4&#"#4&#"&5463263232654.'2'654&#"#54&#"&546326H/>^PGbD-)+S8"3',snOU91TDd<05A 4&"6H -%?(. 9'(1KUK:7&%FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7AWB1>*Z+Fѵ&!A0\#/gCX10L8\f#"&=4&#"#4&#"&5463263232654.'2#"&547&#"#54#"&5463262654'H/>^PGbD-)+S8"3',snOU91TDd<05A 4&CZ6+*7D *97'4MYJ86%/k6B$FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7AgL7EC7R6 ѵHD2Z!-hAZ0/)"O.4E$+LX8v#"&=4&#"#4&#"&5463263232654.'4>32632#"'732>54'#"&54>7&#"#54#"&2654'H/>^PGbD-)+S8"3',snOU91TDd<05A 4&w /&4'+",98  NZx"+ FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7.B 0.KS2Ih ':0P&^PGbD-)+S8"3',snOU91TDd<05A 4&!2 ;/$*$/BFO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7' $ 1#*!+$91>L"8bn#"&=4&#"#4&#"&5463263232654.'233##"&47#5654&#"&5462654&#"H/>^PGbD-)+S8"3',snOU91TDd<05A 4&!2 ;%! /A$/$*$/B*"!$%FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7' $ /*A^ 1#*!+$91>.-&$L8eq#"&=4&#"#4&#"&5463263232654.'233##".547#5654&#"&5462654&#"2>54'#"&547H/>^PGbD-)+S8"3',snOU91TDd<05A 4&!2 ;-5 4" %5/$*$/B %&)'"1FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7' $ &? $,.?& 1#*!+$91> P ' ,4 '$,LZ8n#"&=4&#"#4&#"&5463263232654.'233#"&54632&#"3265!5654&#"&546H/>^PGbD-)+S8"3',snOU91TDd<05A 4&+002+fU54),L:P_I0?7  #(:  ?;4)*"+";2=L`8e#"&=4&#"#4&#"&5463263232654.'233# 4732>=!5654&#"&546H/>^PGbD-)+S8"3',snOU91TDd<05A 4&2?7u[>5DE/) *$.@FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7;1& 2J SL@Gjt &2$*")$92=L8s#"&=4&#"#4&#"&5463263232654.'2353#"&547#"&547326=!5654&#"&5462654&#"H/>^PGbD-)+S8"3',snOU91TDd<05A 4&2?78A! /A >5Pp/$ *$.?)"!$%FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?77;1&4!G*A/"{gRMAFRe-#2%*")";2=J.-&$Lv3#".547#"&54732>=!5654&#"&5463235#"&=4&#"#4&#"&5463263232654.'2654'2>54'#"&547H/>-$BJ 4" %! >5(G=/) *$.?52?.@GbD-)+S8"3',snOU91TDd<05A 4& ", 3&#/FO1[;>" P $,./$|fRMAFRe &3$*"+#:2=<0&)`MKWK )<5,1J5E_yKI`KU>P_I0?7  P#!  '"4 '".L8W`#"&=4&#"#4&#"&5463263232654.'2!5654&#"&54623546"354&H/>^PGbD-)+S8"3',snOU91TDd<05A 4&>K4/# *#.BbBlJJ)26FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7CO@3$)",";1=<1$7G&9,g;HL8bkw#"&=4&#"#4&#"&5463263232654.'2##"&547!5654&#"&54623546"354&2654&#"H/>^PGbD-)+S8"3',snOU91TDd<05A 4&>K)B./A)/# *#.BbBlJJ)26&."$FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7CO@41?@043$)",";1=<1$7G&9,g;Hx$"-&L8eny#"&=4&#"#4&#"&5463263232654.'2##"&547!5654&#"&54623546"354&2654'#2654'#"&547H/>^PGbD-)+S8"3',snOU91TDd<05A 4&>K%3$ 4H3/# *#.BbBlJJ)26.$ L433FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7CO@ <.G4< 3$)",";1=<1$7G&9,g;H  P-# '"#& '!L8@LS#"&=4&#"#4&#"&5463263232654.'4632!7354&'4#"6H/>^PGbD-)+S8"3',snOU91TDd<05A 4&9T&-/*2,AmFO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7c]x).gM<$6TNL 8JV]g#"&=4&#"#4&#"&5463263232654.'4632##"&47#7354&'4#"62654'#H/>^PGbD-)+S8"3',snOU91TDd<05A 4&9T&A/0@&o&-/*2,Am6%11FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7c]x1/A@`).gM<$6TN%2 2L8P\co#"&=4&#"#4&#"&5463263232654.'4632##".547#7354&'4#"62654&#"2>54'#"&5477#H/>^PGbD-)+S8"3',snOU91TDd<05A 4&9T*3 4" %3c&-/*2,Am", 3&#/' FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7c]x"> $,.>").gM<$6TN P#!  '"4 '".L,8Zen#"&=4&#"#4&#"&5463263232654.'4>32#".54632&#"326=#7354&#'"654&H/>^PGbD-)+S8"3',snOU91TDd<05A 4&},-CV38J5B;7N;)#$(30,_(t FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?71D KL6: >%$bPB!5?tS[!M1bH#"$5473 7#".=4.#"#4&#"&5463263232654'=IIov[$V %#.C 11$:S6#MgTcu#"&547#"$5473 7#".=4.#"#4&#"&5463263232654'72654&#"2654'#"&' &U<=Sh[$V %#.C 11$:S6#54'2654'H/>^PGbD-)+S8"3',snOU91TDd<05A 4&C*C4/>,#N5&+6^G:D= Q(E%FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7F ,1"@RA60.>?V.;I8NaH:+Z /!a"#&C6%NOL8jx#"&=4&#"#4&#"&5463263232654.'#"&547&=4&#"#"&5463232>54'2654&'+'2654'H/>^PGbD-)+S8"3',snOU91TDd<05A 4&C*49A/0@-6,#N5&+6^G:D= Q# 2%(E%FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7F ,1"R) A/A@08! H0.>?V.;I8NaH:+Z /!a"g-% 3$#&C6%NOL8o|#"&=4&#"#4&#"&5463263232654.'#".547&=4&#"#"&5463232>54'2654'#"'2>54'#"&547'2654'H/>^PGbD-)+S8"3',snOU91TDd<05A 4&C*=@ 4" %B2,#N5&+6^G:D= Q ", 3&#/(E%FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7F ,1"[&#I $,.J"!E0.>?V.;I8NaH:+Z /!a"   P#!  '"4 '".#&C6%NOL8k#"&=4&#"#4&#"&5463263232654.'2654'7#"&=4&#"#54#"&54>32632H/>^PGbD-)+S8"3',snOU91TDd<05A 4&3!+Q^@4/A"'"9: %&MW-% 8%"6.A'FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7<>.c$,v?M@31)?%ѶH5'b$-u*> 0.?28(3L8s#"&=4&#"#4&#"&5463263232654.'2654'7#"&547&=4&#"#54#"&54>326322654&'+H/>^PGbD-)+S8"3',snOU91TDd<05A 4&3!+Q^08B./A+7"'"9: %&MW-% 8%"6.A'$#-%FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7<>.c$,vN'A1??17!E1)?%ѶH5'b$-u*> 0.?28(3-& 0$L8x#"&=4&#"#4&#"&5463263232654.'2654'7#".547&=4&#"#54#"&54>326322654'#"'2>54'#"&547H/>^PGbD-)+S8"3',snOU91TDd<05A 4&3!+Q^5; 4" %P_I0?7<>.c$,vR'$D $,.E$!>1)?%ѶH5'b$-u*> 0.?28(3v 0P#!  '"4 '".L+8#"&54.#"#4&#"&5463263232654.'2654'7#"54632&#"32>5#"'&'&#"#54#"&54>32632H,< _OI`.%3/S*0'9 slQU91TJ^<05A 4%+$0DZ";>$X4G'D5R+>!:^4$97'NZ .& 5'!61ABK8_ubK`l!:,E)<15EZ~KIeFU=Q_I1?8:C1V&L@\02 251J1ҶH," Z!+m-B 0/Q^PGbD-)+S8"3',snOU91TDd<05A 4&0ZHaO~L2=9T-6 :9'/KXI<3$ 8=3$*$FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?77H K`,QN/#5HC"XG@IdyS )'6MҶH;1b$-pCR0/?+Q("=L8#"&=4&#"#4&#"&5463263232654.'4&'7#".547#"&547327#".=4&#"#54#"&546326323262654&#"#H/>^PGbD-)+S8"3',snOU91TDd<05A 4&1ZN'& 0!0 :A=9U, 6<:9.(KXI<3$9p%0K.-%FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?74@ BYb< 4 %%  kPA:C[nK,# F/B=&[(g54&#"2654'#"&547H/>^PGbD-)+S8"3',snOU91TDd<05A 4&(U`,1 2"1D1;:6R&1 (976,&HTE91" 3k("g  $1"#'.FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7G?Qj9<" &=,# xfJ=7>UgG2/A ,=9#U&`9E('YE'4 I' -%  'L8Mc#"&=4&#"#4&#"&5463263232654.'2'654&"&54'2'654&"&546H/>^PGbD-)+S8"3',snOU91TDd<05A 4&+|LA$A6X9H [>LA$A6X9H [VFO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7ARD@K !L0;<1V*iEVRD@K !L0;<1V*iEVL 8Wmy#"&=4&#"#4&#"&5463263232654.'"&54>54&#"&5462$2'654&#"&542654&#"H/>^PGbD-)+S8"3',snOU91TDd<05A 4&Y-,A^A%+%7+-8H [W|L|LA$A6,-8H [,&-.$FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7@ >%/AA/(04+0;<1V*iEVRD?RD@K !L0;=0V*iE$#!&L8]u#"&=4&#"#4&#"&5463263232654.'#"&547'654&#"&54632%2'654&#"&5462654&"2654'#"&547H/>^PGbD-)+S8"3',snOU91TDd<05A 4&> !)$ 4H?A7+.7H [V?>L,>L*(A7+.7H [U$L433FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?77 3".G4G$!L0;<1V*iEVRRD.G!L0;<1V*iEVP." '"#& '!L;8Zp#"&=4&#"#4&#"&5463263232654.'2#"&547 654&"&546#2'654&#"&546H/>^PGbD-)+S8"3',snOU91TDd<05A 4&': Ɨ@9@^9G ZS9Ne@5,/:H [TFO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7G':1|TIBKlj.>:1N,9XFXT?b:+B2=;0M-9XEYL8N~#"&=4&#"#4&#"&5463263232654.'2'654&#"&546!2#"&547#"&54732654&"&5462654&#"H/>^PGbD-)+S8"3',snOU91TDd<05A 4&;Le@5,09H [T': Z(+7*/A>@@9@^9G ZSY.!%%FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7GM7W6';+94,G'3P@N#4,iC 7 ),9+qJC:E]|u`)84,H&3P@N1(!2!L8N#"&=4&#"#4&#"&5463263232654.'2'654&#"&546#".547#"&54732654.#"&546322>54.+2654'#".547H/>^PGbD-)+S8"3',snOU91TDd<05A 4&7I`=4)*9E VO-39+"3 7<=6& -6D VPA&8   $1 "" .FO1_u`MKWK )<5,1J5E_yKI`KU>P_I0?7FG5S2%8)52)@'2I54&#"&546323&5462##?A,H#Rl ,7(AxL8@(!7,0=5D\KIa&M̕KIaM/T3:tx]3P, pQH^ E-6=.G!2[FVSE7.EjirnLKJM3!!"&5463%26544>54&#"!5>54&#"&54623&54632#"}!C0=>/}.?7*$/ UB\rM7@(!8+0=5D\_&Mw`I]5Qn*R<04C?#"';(&-RFE2#"54>32&#"3 4.#"!5654&#"&546323&546k.EbX2'@@ wN+8Y3B~ 44GV:04D_NLb&Dr¨\P1K$'K@^/[K>M/K$'1S3!:IeXH073>4D_M*B$&JeSQ97ƒb3U5 =Qb+$<2aHH/K&:B2F!3XH_'0# 7,OuaxHHL=H2#"&5467&#"#4&#"!5654&#"&54623&5463262654&'gQ@AQ:0.2CS7+8J5vG8-2@4C_d%AnRU9E(0,(g7ÝtRgfR>n$.&0=`OJa/K+6A4E"4XK[ZI:)FueJIs<1,}!Ql6DKccTa%4632632#"'7327654&'#"&54>7&#"#4&#"!5654&#"&546323&2654' jWL7@\:i"\Vr=5'(_=87+RC;F!=((b5BS'DP]vG7-1C5D`LKd&K,/)'2!,^|IH>4~Mm*QG`?Q -dMB/K,5B4C#2YJ\YJ6,O32#"&4632&#"326=!5654&#"&546323354+4&#"6 /X@bAAOB'M&XU)_BgH8-2A4BaNK]$'7'*FI*!j:VG%hO,>+%KP#-O-;>193ESEU]F;*'CF''2;%3Ja;2#".54732654&#"!5654&#"&546323&546yd[NZCDV@1PG7-4@4D`LJd&Dräwoчp `rWxcJB]/J+7D2B$3XL[YI:*AoiJcKZ#".=#".54732>54&#"!5654&#"&546323&546322654&#" $6E/ ")x[NebAZCAY@1PG7-2B4DcIJd&Ds\cr#$  C :/3A 1" 6m|p `r+CYT+Wx^OB]/J,6B4D"3XK\XJ:*Aokx"!JraLYk2#"&547#".54732>54&#"!5654&#"&546323&5462654&#"2654'#"&'yc#/T=@P e[NebAZCAY@1PG7-2B4DcIJd&Ds%(:3&1 /ãxn 8%BYY="m|p `r+CYT+Wx^OB]/J,6B4D"3XK\XJ:*AokG"X7+" &4"! CK2Zc2'654&#"!5>54&#"&546323&546#"&=4&#"#"&5463232654'2654'a|"6,aZHF\L8@(!7,0=5D\KIa&M*C4.?,#N5&+6^G:D=?V-54&#"&546323&546#"&547&=4&#"#"&5463232654'2654&'#'2654'a|"6,aZHF\L8@(!7,0=5D\KIa&M*/>B./A':,#N5&+6^G:D=?V-54&#"&546323&546#".547&=4&#"#"&5463232654'2654'#"'2>54'#"&547'2654'a|"6,aZHF\L8@(!7,0=5D\KIa&M*9F 4" %=7,#N5&+6^G:D=?V-54춮&#"632#"&54632#'2654&"2654'#!:wE01E1<=0 . =$)7QBRl$:/@B78LtAQ7II$4+"$4 !2"-.)I(3CB4(6V@#5/$*4L98G98J\Cg} ?+=+B$3 1#$/-H2i#. .JI6JT_t"3!##".547#"&46;2>54춮&#"632#"&54632#'2654&"2654'#2654&'#3#"&=!:w,4S@+> 41<=0 . =$)7QBRl$:/@B78LtAQ7II$4+"$4 !.""V7,73%/))I+F32+"3!&54>;254+53254#"632#"&54>2654&#"2654&#"2654&#"A`{=W6jvB31C, <,T:$6.=A0;F/>< ay=W6.*R:#7/32+"3!&54>;254+53254#"632#"&54>2654&#"2654&"2654'#"&'2654&#"A`{=W6jw+T=?R., <,T:$6.=A0;F/>< ay=W6.*R:#7/AZV@A'# *9US%MPo8InMZG0J- ?4I!\r$&1 US%MPo8I78LZG;V+1$!/,#%1xu/2# '""*71$!/-"%1MN2=I2#".547&'73254'"&5473&546>54&#"2654&#"o$9 PK ':D1#3 V"F>]xK%#G9+O"==/%#*"!!+!$, 7\<02D*" @6<mMT6#+=@W?PMDL-)75+K##$M7BNg2;2#"&547&'73254'"&5473&546>54&#"2654.'2>54&'#".=o$9 PK *= 7#=U!`%F>]xK%#G9+O"==/%#*):"*-83%$&#$, 7\$5+ ,#V=6(E6<mMT6#+=@W?PMDL-)75+K/[$ %35!- ' *M&LW]fo2#"'73254'"&5473&5462#"/32654&+#"'#"&5463>32>54&#"4&"325#32=#"o$9 PK ?4c%F>]xK%#G9+O1),! !*8.5)%2782*Z :==/%#*1%6 "A}j(?$, 7\+3F6<mMT6#+=@W?PMD6$%0 # !CS226)0!:E*L-)75+K%30(1'5t%=7F&U`hqz2#"'73254'"&5473&5462#"/3254+53254+#"'#"&54634632>54&#"4.#"325#32=#"o$9 PK ?4c%F>]xK%#G9+O #G"*8.5)(/6O4*%30==/%#*' ! A}j(?$, 7\+3F6<mMT6#+=@W?PMD 6!CR226)1 7G55*L-)75+K#&2%9 #%s%=696 &hs{2#"'73254'"&5473&5462#".54732654&+532654+#"'#"&54634632>54&#".#"327#32=#"o$9 PK ?4c%F>]xK%#G9+O+-Y>*PO181(CF(bT !$*"!(/?,#$@==/%#*= 0 3eY 3$, 7\+3F6<mMT6#+=@W?PMD"30;uPUI>MC`1B, .1007)1!6H-%1L-)75+K !U2 !q1-<5#]hu{2#"'73254'"&5473&5462'654&#"32#".547##"'#"&546;46323>'>54&#"2654+'."327#32=#"BVOL ?4c% H>_vK%#G9+O-B S$=?.8 E7*$) 8.5*%3994** # $+e==/%#*V 1'  %6!!A~k(?Y<7[*4F6<oKT6#+=@W=RNC5&7,UE4K5H/(&5&/11CS227(0!9E.")8L-)75+K<#'00'1)3s3$=6(#p{2#"'73254'"&5473&5462#"/3254+572654&#"32#"&5465##"'#"&546;>3267>54&#"2654&+'4&#"325#32=#"BVPK >5c% H>]xK%#G9+O*? ,05' .% - ' 3*$, %28.5*%28:3** #==0$#*E(%&!B~k'?Y<7\*4F6<mMT6#+=@W=RMD5$ ('$/ (1*%# 4 (1?4CS226).#9E/!K.+55+K" $,$3+,1)3s3%=6&`#ny2#"'73254'"&5473&5462#!"3!!"&5463!254&+532654#"32#"&547##"'#"&54;>323>'>54&#"2654&+'4&#"325#32=#"BVOL >5c% H>]xK%#G9+O:N10f !!X&'Y N7F)&-,!3/75*&1o2+Z  \g==0$#*`!^$ !B~k'?Y<7[*4F6<mMT6#+=@W=RMD31)&0S1#%8$!53&#,.4 0O++.#D0;k/>K.+55+K5 Cs+.)#+a* 4-M&BM2#"'73254'"&5473&546233!532654#"#&5467>54&#"o$9 PK ?4c%F>]xK%#G9+OV-6"9[%1 3==/%#*$, 7\+3F6<mMT6#+=@W?PMD 6*/ (9$ %0L-)75+KMM&P[hl2#"'73254'"&5473&546233##"&547#532654#"#&5467>54&#"2>54&#"7#62o$9 PK ?4c%F>]xK%#G9+OV-6"9&! /A%%1 3==/%#*] .$%! $, 7\+3F6<mMT6#+=@W?PMD 6*/ 0*A/0(9$ %0L-)75+K "&$M.&Q\g{2#"'73254'"&5473&546233##".547#532654#"#&5467>54&#"2654'#2654'#"&547o$9 PK ?4c%F>]xK%#G9+OV-6"9"2-# $5 2%1 3==/%#*E##1))'"1$, 7\+3F6<mMT6#+=@W?PMD 6*/ #<$5 -# <#(9$ %0L-)75+K ""P9 ,4 &$,M%&OZd2#"'73254'"&5473&5462'654&#""&547&#"&5463267>54&#"2654'o$9 PK ?4c%F>]xK%#G9+O54&#"2654'o$9 PK ?4c%F>]xK%#G9+O9ITB0((v"**"#2C7  G9T6B /:AIO>(!"==/%#*$!7A"$, 7\+3F6<mMT6#+=@W?PMD,UFAT3$$D39G3C099-F+A,F (O:PL-)75+K2&;(-:$KX&hs}2#"'73254'"&5473&5464632632#!"3!!"&546;254&+532654#"#"&547&#"&>54&#"2654'o$9 PK ?4c%F>]xK%#G9+OP:+!$@./*0''s ,#)WL.E6-+5C/:@H==/%#*'!7B"$, 7\+3F6<mMT6#+=@W?PMD;IS$/#73%0;!%: 1C-<:-?/>/F %L-)75+K6&:(-9$C##ju~2#"'73254'"&5473&5462'654&#"#"&547&#"#54&#"#"&547&#"&546326326326'>54&#"3254'2654'yBVOL >5c% H>]xK%#G9+O{)70#-$ + ")   * ) *% *0%*(@==/%#*#%"( "'Y<7[*4F6<mMT6#+=@W=RMD-SBT* (E6L8I2?3;N- )#.6I2?>0L/C4L% +Y?O87K.*65+Kj*MC,3+"C,2AD &|2#"'73254'"&5473&5462#!"3!!"5463!27654&#"#"&547&#"#54#"#"&547&#"&546326326326'>54&#"4'32'4'32o$9 PK ?4c%F>]xK%#G9+Ou0)5d)B"' &!$  3 %!$  % ),"'$;==/%#*f# !# !$, 7\+3F6<mMT6#+=@W?PMD1Q2NC,:"$%.+D)C2-2+C$ "C(C3-3+B%6*G#O4B-.L-)75+K=@;!%;>K$&2#"'73254'"&5473&5462#!"'#"3!!"&5463!254&'#53254&#"#"&547&#"#54&#"#"&547&#"&546326326326'>54&#"4'32'4'32o$9 PK ?4c%F>]xK%#G9+O2 $X "U5 '!% !  '!% $& *,$(%K==/%#*s$! #! $, 7\+3F6<mMT6#+=@W?PMD0$(1#0,"5(# )A)6+2@%"$ )B)6./C%8+E#N3D.-L-)75+K; $;>?54&#"o$9 PK ?4c%F>]xK%#G9+OO6H'$?(.!9"(1KUJ;9$$==/%#*$, 7\+3F6<mMT6#+=@W?PMD.WB,F *Z+Fѵ,A0[$.hAZ10L-)75+KF(&JU_2#"'73254'"&5473&5462#"&547&#"#54#"&5463267>54&#"2654'o$9 PK ?4c%F>]xK%#G9+OMCZ6+*7D!)97'4MYI96%.==/%#*6B$$, 7\+3F6<mMT6#+=@W?PMD3gL7ED6R6 ѵHB4Y"-hBY0/L-)75+K)"O.4E$+M&^iv2#"'73254'"&5473&546462632#"'732>54'#"&54>7&#"#54#"&>54&#"2654'o$9 PK ?4c%F>]xK%#G9+ON+*D G6C\ $4,H#A93*(5(A47Q)L-)75+K&+#(5 M &S^2#"'73254'"&5473&5462'654&#"#54&#"#54#"&546326326'>54&#"o$9 PK ?4c%F>]xK%#G9+Ot&4F2#)()('&7 @5'(,).==/%#*$, 7\+3F6<mMT6#+=@W?PMD-L8^$!S,:.$+>9-N%]7M,,))L-)75+KK&Wbk2#"'73254'"&5473&5462#"&547&#"#54&#"#54#"&546326326'>54&#"3254'o$9 PK ?4c%F>]xK%#G9+Os !&&&0 4'!)&&%5 ?4&%*)(==/%#*n(&/$, 7\+3F6<mMT6#+=@W?PMD)<(.;8,E+ -"(<7*I$W7H**((L-)75+Ku#?@(,B&kv~2#"'73254'"&5473&5464632632632#"'732>54'#"&54>7&#"#54&#"#54#"&>54&#"4'32e$9 NM ?4a' H>`uK%#G9+O.!"'#$/! *;-$) !""$"" / 7==/%#* 8 #$, 4^*4F6<nLT6#)?@W=RNC9J,,)(@ C6>T !1(G 1=0'#.& $)>:+M&L-)75+Kb,A=M&CN2#"'73254'"&5473&546233!5654&#"&5467>54&#"o$9 PK ?4c%F>]xK%#G9+Os- 5+!& *;==/%#*$, 7\+3F6<mMT6#+=@W?PMD ' # 2$*"*#;2>L-)75+KM[ &NYe2#"'73254'"&5473&546233##"&547#5654&#"&5467>54&#"2654&#"o$9 PK ?4c%F>]xK%#G9+Os- 4":*,9#* & ):==/%#*o!(*$, 7\+3F6<mMT6#+=@W?PMD' ! 31?@02 2$)"+ =2=L-)75+K%"!.M8&R]i}2#"'73254'"&5473&546233##".547#5654&#"&5467>54&#"2654&#"2654'"&547o$9 PK ?4c%F>]xK%#G9+Os, 5&0 0 !0 0+!& *;==/%#*\ #.%8&+$, 7\+3F6<mMT6#+=@W?PMD ( # &@ $--$ @& 2$*"+#;2>L-)75+K Q-$ *) &"/M&.9EL2#"'73254'"&5473&5464632!>54&#"354&'4#"6o$9 PK ?4c%F>]xK%#G9+Oa9T==/%#*a$-/*2,Am$, 7\+3F6<mMT6#+=@W?PMDwc]xL-)75+K),gM<!"6TNM &<GSZe2#"'73254'"&5473&5464632##"&547#>54&#"354&'4#"62654'#o$9 PK ?4c%F>]xK%#G9+Oa9T'! /A&r==/%#*a$-/*2,Am1"11%$, 7\+3F6<mMT6#+=@W?PMDwc]x0*A/0L-)75+K),gM<!"6TN.2 2$M&=HT[fz|2#"'73254'"&5473&5464632##".547#>54&#"354&'4#"62654&#"2654'#"&5477#o$9 PK ?4c%F>]xK%#G9+Oa9T(4-# $5 4g==/%#*a$-/*2,Am 0?!'&#0& $, 7\+3F6<mMT6#+=@W?PMDwc]x">$5 -# >"L-)75+K),gM<!"6TNe') 44 (#-MAL233!5654&#"&5462#"'73254'"&5473&546>54&#"=R59F8-,7C UO$9 PK ?4c%F>]xK%#G9+O"==/%#*QBA; 1A2=@/O!0eBY$, 7\+3F6<mMT6#+=@W?PMDL-)75+KM %1Xc233##"&547#5654&#"&5462654&#"2#"'73254'"&5473&546>54&#"=R59")B./A)UF:+-6C UO$!$%$9 PK ?4c%F>]xK%#G9+O"==/%#*QBA; 41??141A2=@/O!0eBYS&.&$$, 7\+3F6<mMT6#+=@W?PMDL-)75+KM&OZez2#"'73254'"&5473&546233##"&547#5654&#"&5467>54&#"2654'#2654'#"&547o$9 PK ?4c%F>]xK%#G9+OL=R59'3$ 4H3MF:+,7C UO==/%#*P$&4330$, 7\+3F6<mMT6#+=@W?PMD*QBA; <.G4< 1A2=@/O!0eBYL-)75+K P." '"#& '!/M &U`2#"'73254'"&5473&5462654'7#"&=4#"#54#"&54632632>54&#"o$9 PK ?4c%F>]xK%#G9+O9B,% /4(),6=4%((!.H==/%#*$, 7\+3F6<mMT6#+=@W?PMDV4&R$c5?4+)W <+.R%b4C(&6(."*L-)75+KMe&[fq2#"'73254'"&5473&5462654'7"&547&=4#"#54#"&5462632>54&#"2654&'#o$9 PK ?4c%F>]xK%#G9+O}9B%%8.7!$4 ()$6=3L%8I==/%#*m& &$, 7\+3F6<mMT6#+=@W?PMDZ2%N"_A/0)*/.3'S:0&O$]1A'%*0,'"L-)75+K,MC&do{2#"'73254'"&5473&5462654'7#".547&=4#"#54#"&54>32632>54&#"#"&#"32542654'#".547o$9 PK ?4c%F>]xK%#G9+O{9B)1%# -)3 ((6=  &' .G==/%#*}52& $ $, 7\+3F6<mMT6#+=@W?PMDX2&Q$aH?'1 +<;(V;&P$a"3 '&4).("L-)75+K$##%   LE(5%#".547'654&#".546322654&#"3E/ "*5bXADY0#*.b]t2#+ ' 7.2B 2!A!2vK\]M(82 5P/i~fl# !L'3FI%#"&5467'654&#".546322654&+"2>54'#"&'7333U<>R>,bXADY0#*.b]t.%"C&0 5$1/# I,DWV@8F 2vK\]M(82 5P/i~f|v+'  '3"! CL72'654&#".5462'654&".546/]t"4-bXADY0#*.U>L*(A6X9H $&V~f3V6)2vK\]M(82 5P/i5QE.G M0;<1VD+DWLAM2'654&#".5462#"&547'654&".546322654&#"/]t"4-bXADY0#*..BB./A5 A6X9H $&V?>L8&."$~f3V6)2vK\]M(82 5P/i!?01?@0?  M0;<1VD+DWQEN0$"-&LEPd2'654&#".5462#"&547'654&".546322654&#"2654'#"&547/]t"4-bXADY0#*.#4 -# 4HC A6X9H $&V?>L9 &4350~f3V6)2vK\]M(82 5P/i!,$ $5 G4K" M0;<1VD+DWQEN0rP." '"#& '!/ 2.7".5463&'632/G#x+'504 ;VJ2C*@"!5 $3 2&5432#.54?654&#".547373(=e1C i<H11$JBP1! (5# "6 <>Z@rp? 1$#B8WG,%!,Wz'5.''6?2'-=G( +`%-H E,M(! ,+w.+'675#5!#2#"&546326=4.#/.'=B%--{\54'"&547>7!Q=P5/6%G7(1!% 0H6"+UQ!& "*?b*,'&#632'6?>57654&#"#"&5>$<&! $A6((()53)1   *!L* <#6)-"\); .1Us.(27#""&547#5!#/.+"'767(*>H-{3 1HZ-3' ) =H )22w():4)dz. <&#"326326#"&'2654'#"&547#5!2"&'26J (%;  )[P:c| 1T4(2 -8)g!2)-a$m.TŭLcG7&!A4@F2I 0!,)p8. ""'"'"&/3>'"&5#5!:)=z.=<)7/A .8'>#K.5  _9K(22:w. 526=/&'7./32654''.=#5!!72_4" 5>7E,0C%"$2rAQ&/f! 0";K4 o &5B,:HG C.!B22 D.4327#"&'367#".52654'#"&54?67#5!$*&-: 4+#11:+L' G9 ( '") %, //&>+D`z3f_&22|w-'#"'6?675#5!;#'.'/.!3 4. 4'E$4A '"]  3%@@!2/R"22#>CB0h%274&'"&46332674&+37#&''.#"+"&547;25'&#632+"'#"=46;>324   6?H%X">Q  [ 8F!L4Q$>  * $K): 'W   M=8,(_& LC.l V-=1$* O?23!;3267+"&=>;+"&/5#536=4&+"".5472=:V #Ai:&-,13 !;22S">9u,2 '! E87>54'#".547>=4'#53.=473{$0/,!{,$ 0( 0 'Ss8(.6'7(== *R 9D0tV@,% `#!2 l!/' &A2.%&'5#5!#67+.'2654'#&13 &M;.F(&@( Q >-.22MH%=U?bd6 *LK/-/6J.7"'#5!#>7#"&=>732}&9J&> #&X=22 D%5Rw,.+#"&54636;2,]+ &(%H(E-%Y$42,$9/ }yv53#.+'2674&#+"&54>;2) CA 0(A# = 't" ( :6&7$ OV 3;P82 &0 @!- @":.'5#5!#>7'&54+C+': .,@) 7#%33p#*@=((;4%fb.*3273753#&/./7#"&54632#"'J@]- `gA !c8-a") &  ;/J8@2j6G=H%&  $/.&+"+.54632%3#*;;!0(.W$e$ )2K22(%'&'"'7654'""&5>327'&#"rR 2+<  p5M&c#%/(: !* 3^x%o +u.74&#"/.#'6?.'&'#5!!632#".'4?2325+$ ,A%-9P 43_!P76=4&+5!#2654&'#t+","'<z&#g,2 #,,+ %22 h0 8/qp. .'#5!#'.+#'67s30KAk>( pCb5 4<]&C 22u=VA!WG,%!,W~.+/.#"&#"&5462#".5463254632'!5~$-N-809+:>34!'-#vV !  `%,0'" ><4?#422=p&&#"#"&'"&54>74/6;2>;2d67 !!-+*,- o *$S|m,0$2""#">%S*h. %32?4'72654&#"7#"&547#5!   '}_B+<8y| %"2^G&1422H.!.".5#"&'7326=4+5!#'2654&+3b(=7<  40 .3% 4X*" &S 1D22 #(/:%  83p.34&'#5!#&/32>754&#"#"&=>76oY) l"C'*0C14&  922 "I* :.5"h$ %$.. 6%#"&54>72'"'5#5!#>7+.'32654'  5- #'CN>1M* )C*1A7#"&=6732#$> :O!> "*g/_%C22D'2$3xny. .2#"&546'.+"'67.'&'#5!#{' /X3v b644> &yK*-U) l=XA5.  22WG,%!,W[c. "7.'"54637'675#5!#'.'N"j[3 54/&=467#53T b0!(! &$`-,'[+ L8-I/22.U!!"'.'&#"#"&54732632'&'7#"&5>7>32#"&5463232654&F.C$(| )9*C0J  ":(2E?<H"e D),*.23; YJN<#9=5!  A, . ...M,,;&o#D%$ $.>G%25&/675!5!#2#"&546326=4&+"/&#".547;6=HE|By1#% X02e%JCOT" jIj##+J4E Us#'22&vU(4,$3H$&=N)!   4#GL 5$G3#/&+""#".547325&/32>54'#"&54726?67VV"J " /B ]{865S6>+B])30!>F(Z=d%2&,+))3&Dn!g +O"=- 4B#N +^ N3#/&+###".54732.#"632'7674&#"#"&5>32/&5&= V[$J /B `zg h9*5(2, :X  *!Q>: c!2&.+)&2';G_*6!2-AZ .2S=*  .F267#"'47#5!#/&#""##".547325.+"'>?67#"&- 6RfA"$xL^!3# -> Xt54 l9B% +< 5 Njx,B22'.,$,4&D2BD' ?s.87>7&'"&5#5!!/&#".547;25 +dy+ 9*,7a/B qFZA  cK&VDq22   $:@%***,V36323.54732654&'#"&'47#5!!327./&#"&54 :&G6J@!;.  8i6%K ($ dN&K " .DIs -";0KP#"#:HZ &. 6 $( ::a9HB6+ I!#(QN44# N' S+6K22  MVsNY-QC#zV23!267#"&54632/&#"#"547325.5#5!754#"".5473$': L'q-1"25@Vr" )>,(.b6-B % '&  /& 2k+# 454'.5473#/.#"&5473325#".547>54'#53+A=#5/!$+5;Fа&B !9M94 90 #-%5j T,@7gK0R42/o"<(3 )[$2,T= & L?,)X/";% . '2w.L#"./5#5!!>7'.+"'#".547;25#".'32>54R% #%H*0#x3G" XV*:8/H5U0" #*?$(>RE 22E!]5@8.+-% 5$"GbT$"E6@,+$ "p.:%25"'#5!!>7#"&54632/&#".547;6#D2A+,12P ) $) !2=ZZAIi& ;- Od22 X1$&//95&HD&#  ,+.48'.'&#"#"&54732632.'632"&'>%!!k4 $o%:H+<(8b1 0J *1&$09/ .X; ZHO;/ O6M2(Wn3$("6-+<$2>-O8&8+&#  +,;Y2M3#/&#&#".547;25.+'232654&##"&54>32WT( s0E TR)45%GOC, #+?3+Q*"`#b,2&.+-%3$%@MhS7   (%7 N8$:( N2 .0'#5!!767'.#"#".=4737&54{=j Eo4^NU(,%*|,,!9.yR[dDJ22,R@EmKR= !E1%- (MTD4A32?53#/&+""#"&547;225./7#"&'4632#"'FeN}6! }Ta  J@NP! 1 5gH;~+3*10 +H@]T&IB2%Q6(*5$4BCO^1( 0 .3%25&'#"&54632!5!#/&#".547327%D 2r#*.(M:/]kV6_9OKNe b; &':$5?bA 22&9R&#  ,+.D%25#"&'#"&54632>54&#!5!#/&#".547327"D "X$!$0(#I  2s!7=ZQJMf ;S-.#,%(226'!&=N$%  ,+#pE.#"272'53#/&#&#".547;2&''764&#""&54>;4Q %!5'   DO+ x3G" NV"'G+ " +N@9 !/,~ 2&.+)) X6V.*  ,3$.I".'#5!!72#"'46725674&#"'.#"&5473725.+'6?&*'%@E{V./32'.#".547;25"&546322676%!!n<  ;:# 3]2$,/#O*!%T /3} "$G1:( y7"02'3&Lf2".AE%25#./32654'#"&54632767/&#".547;6!!"D&*[- @8C*8NP>,?&1$BnB6^9VEMf% 1;~[ Ot;"\2-!>:./$8#>4.'#5!#./&#"#"547327325.'#"&54>32BS9);;-G,]"G< ' ICAT A 3-'+*-vA9+]+722-$! .#%7!64"* . <.#""'>7'.'#5!#.'&#"+.547;2O2  ^Y0]:D3C . B4 \)W&yA7C '-2L$b0C z~O@FT-3 22NS?! & V3#/&+"""#".547;24&#"#"&'"&547'&+'32>?'5"CV$T  /B YU*79 EJ,-F!V  A2gK& !'  K 2&-*-% 2';^ 22!-.;('2] =$u+.E5&'".'#5!#./&##".547;25.#'76?67&#= &+%&hKY+[")*EH/B ' CD2? D& %0)#0-2_7  22 -#// #  #!> 'fX   .F>35#.#"/#5!#./&##"547;25.#""/7270 $'* f")*@M ' CA7%."0:$! |" < %( 22-#*  #!=.2<3G& @ !.:E%25#"&'"&'732654+5!#/&#".54732?>54&+ D4T"< 3  9%8=ZQJMf l- x ,;O)'7!2 E22.$#&=N#&  ,+!#-\.I'./&##"547;25&/32674&#""&546765.'#5!#2|EBeq ")*EH ' @ ?Hc7?W<_*- 7'!P! -1DB@ 0D$t -#""  ((B/<&4!;!%4 22 -). 6&'%675!5!#./&##".547;25.''906T7{F֘e)]")*HE22 ' ?!?DV E @H)$3pk."22-#=*( (8AWE".;4.'"546;#%675!5!#'.##".547325.'l3U/ Hi']dwJ֗l"]-[(-A!.yA4RH" *2* "!b9H2qk."22I-01#! )<>V.o3275#""&'#4'#5!#632"&=4632654&#"/&+""".547325&'#"&546;2654&#""&546;2$R^ i2Z {/8*0!'H4[9%0% .53 0B22PlDG$<7)0) "$ @PNE1*L/E"22PN8? $@& :(+'4#^W+''1 &*+L. #O%2?254&#3&546.#'6?5!5!#+#&'4632.#/./)(#E 0 Ph w `  + @:ML573##"&54672654&'3267"&54632".56?&+4/&/7675#5!654##"54732632b#/j-Q" #7#',#$[ &'".vJ(4,N +]9F1$ !-916@l !R/% 2I;2 '8nFH12*(!G\(1#:(   > 2 X& -D  >=73##"&5467265654'3267"&54632/&+###"5473225"56?&'#4/&/7675!5!654&+"#"5467;2%.5j.P$ #ZJ)%] ') !*$( Zx7#7z,*' +]9C( !7T2,JQ(% 2I6!38M7&33$* '&1"7#: s&9$   > 2 P+ '.e!!2#"&547232654&#6"'&'4'32654'"&54632>54&##"&54632>PV84(12 .$ (RGo" 6;V,/>!%!)? 2%D4GC.2db N *! (#   "M4A>XDcM73%! ) " -)!?VJ' .KQ%2#".'32654&+#"&547'./675!5!#2#"&54626=4&#632'SB <)3^A' *A<,.;# @)5|[:p! !#*?C H@?%1)J844 Nvb( Jf-> .*&( AY22XE( ;.Gt. y5""!!/&/767&/&/32654'#"&54632>54&##"&54632>?632#"&5467232654&#6)$ (  ;,%&$#0.F3"(W/>-)!)?2%D4G *70:>--2 .$ ,<$Z2+(-  2TY3%!"# "+-)!?VJ'!=.$F#(#   *+. \b35#"#'67.'32654&+#"&547'./675!5!#2#"&54626=4&#6322'.   &)+O4*bw.;# @)5|[:p! !#*?C BA M E:%0*v <"-[nO > .*&( AY22XE( !;J8b+7,FF.!!#".'32654'"&54>7>54&#"#"&54632>?632#"&'472232654&#6/&#"###".547322,&G54 $ " 6;V,/>! !%@2%D6A *70:D#(02.$ )$.02Xz7#.2% %4WAd+&DcM73%!   "(-)!?VH!=.,>9(#   *$N& 9)1"9#:p.Z`%'&#"#.5473272>73254&#"632#"&5467./675#5!#2#"&546326=4.#2'+ %5J+; P 0 + !2'0$"?55{\ )"=(!D/'AZ22[B:! ) 0H.dl25#".'32654&+#"&547'./675!5!#2#"&546326=4&#6322'&/&/##"&547l(&3^A' *bw.; " @)4z\ =n%&!#@C B +0KL ! (!t:E!oD~Nvb( > .)') AY22[B8!<J8A, - BU" $ 0 #F. F74&#&/.'"#"&546325./675!5!#72#"&5463*Kh !#Y1 . %6B4!G;?#EL ;v1#)# J.6I 46  ')%2)L)8 Ug/'22&|Q(4'" .E2#72#"&5463274&#/./675!5!#'.'"#".546*Ij+A!"7$ ;v0!+&Y1 4Y5EI(   2L.(*9+&|Q)3%% 6Iq,,7/Ug/'22+I  .F.Z74&#'.#""5.#"&54632#"&546326325./675!5!#72#"&'4632*Kh+A!Y1 #  -*  2,?# ';?#EL ;v2!$$J.(*6I#+. $+    A)-,-71)8 Ug/'22&|Q*2)$. Q"&'#323275#"&'#5!#632#"&'54632654&#"/&'"&546374&#""&54721^ {&|0!iR] $H 2]=" & 8+!F6-&' "$3 iNE1uLE?@P322PK6/)  6f+!# 0. &*3 ~.f3275#"&'#7"/.##"546325&'#"&5463654&#"#"&5473254'#5!#632#"&54632654&$#&] i2Z {/8*0![#0%J3=N2$<#%*) "## 'R:U,!%& 8&PNE1*L/E $+7<%I$7QHW$*1 *&/ 22PU+'3  .6n3275#"&'#2#632#"&=4632654&#"64&'#5!#'.'"#".=/&'#"&546;654&#"#"&54732$#&] i2Z {/8*0!"B 0_-"#& 8+ HJ&# !F,$$) "$# &PNE1*L/EV'PI2'7  @w 220D#6f'.1 *'/."C27#"&5463254&'632#3267./7675!5!#'5.#"#"&'|Y)X & ,,:(+ ,#oF/DuWR5;9:"CW&V R= #; 80!@LP&D22.700?*Ic%.#"632'767."#"&54632654&#"#"&54632&=&53#'32654.#"632V1C",;?:8'!N7   c4#;%'"C[9k '5 @*- & J +"4R"A4* .,W 37M6!!S3z  2<=GV<  .?'5'&#"632'>54#"#"&54>325!!767'&54j>k C!A9  ,=?2M ' #4,6$! 4_MWA#+[iFE 9  ,!0O#; Z3%8  Z2,QAzrLJtcBX>SX"'.+#'7'>54#"#"&54632'5;#7'&'54%2>7.#"6  o= B%P %V= 7'!"'O+,,<&< O>+W?MI  D^S*W 01T!$$ /22M&aZ *+"%-Ap 0SC? _3274&#764''./>3'&+'7'764&#"#"&54632'53#7'&'c Z<*R0,._@+&c( M0&p*COB%:/ K !Q8 :-0 O5.8e!/ Cw5TG7y) H-<,=S*=3 */-Y%L5 2:%\Xk +K3#'&/.#"#".54632.#"632'6?654&#"#"&54>32'&=W[> $ C3&G e9,8%@:+ K &>)= a* 3 7 %3/Ea)%' $$&A- *((/ 79'S%2#3#'.#"#"&547.'&#632'6?654&#"#"&54>32'&=64tI  #& ,,*)6:+ K &>)Bp QEW) 3'&  !-+)" *, $$&A- *((0 ML79'e>32'&=3#/.#"'&/&#"&5463632#"&54632>32.'&#7632'6?654&#"#"&U-= C[#  !(   *4+-, :-  0-[:+ K &:L79% * 10    +   ';/?#&6B 6!$v3^  < - - # Fl: BF#D 5Wix+=22 !8 .", &>2BDH 5.V654/3#".'#22#"546327&/#/.+'674'"#"&546?&'#5! ?EF>  -!1*8 ~+$P $l(3" V s0B~f9*",$/E-0S  & ? 97 0h",0 @-PLS'3) %) '22R. u654'#".'##".'463254.+/&+"".5472;5/&+'674&'"#"&54746?.'#5!e  - 7M(J'-5 ~QKGS' (# >$3+,4I85 LCB~f&*#5 t\  4B!!> 0<`8!- * ' <*-$1"*< FLS'$) ( 22.*72654.''#275#"3"&'3265#"&'#%47#5!#632#"&54632654&#"'.'"&5463654&#"#"&'2>54'#"&,  < H ] 2'$3l72654&#"./&#"'#"&'32747>54'#"&R] &  4?R{07*.#+>GX4 47.*( %%=R# "  J "Bus'e}+++  ' '> @P  ,#]61*L/ 7!>:,A%A+!#( 1 %)e2Q22PR-'3  X-Oϣ`]%)%  *4 )f"567?>54/#"'"&'3267'2?#/&/#"&'>54'#"&547#5*% '*&(> +8(2 (&80L<*=[< SV < W3b@-7 ,9%  / (   5-H4*-<- *_2!6L˧ 0)8.BS2.k32654'#"&5?6?37'#5!#+"/#""3376?67/47"&=?376?4/" % 'f--? "  +R2  * ) ;%;()6   &  % )22 $S '#! 63:)&"21E7>HX D27 E"74   .1D}&'#5##3>3547767"&'"&'326?267#"#"/3272654'#"&=>54?67#5!#/./O(  $ ;2 (', 6S$(I!$-[/pE  98'6+9  ^\1  k ! &  5- 5 O Lx+7K1>BT+ @;  8.#  224,J .1J]&'#5##3>3547767"&'"&'32673335./7267#"!>54?67#5!#'./&/#"&'./4?>54'#"&5O(  $ ;2 ('h,) g$(\4#, 6S$(I!$  ^"4o3?#=+   70'3+9  k ! &  5w$; N"P 5 O Lx+  22Y- E0$1>BT+ :"  2# 8..0@~27&5/&/#>724&/"'"&'326?>54?67#5!#/&/".'#"/3272654'#"&5&  "$  + *&2 ('oC    X L  G!pE  98'6+9    !  /8   59 5%  &\r  22-P,    )1>BT+ @;  8.;.'i##"'67&#326=##".'32654'"'5&'7>325!#/&/&#&#"#'"/?>;&"5-  |E# ( >0;a/ )P3'6&6S$J8)I   "$S)>!'#  ,5 (  xA9aI(*QQ14 02-,  * 20e.'2_5#2636?>?65"'"'"&'26=/&'7#'.=#'.5#5!!h       J#p"^%> 5  '6e ^    CEv1 (IV>Q%   ;(22   !! .2{;6?65/&/335>?65"'"'"&'326%2&/&/;272>?654/#'&'#'.5#5!!;7;  .   z J _%,(8-'96bt<)910%?* &u%(4  '32  " : C >)-8"76'h& \  3OM#   ;(22 . +?5;6?65/&/335>?65"'"'"&'326%2&//.#'76?&/&/;272>?654/#'&'#'.5#5!!;7=?    .   z J _%,(8-'96 M0+<((#3<)910%?* &u%(4  '3'  K  " : C >)-8"76' &/< - \  3OM#   ;(22 _.2;6?65/&/335>?65"'"'"&'326%2'&'./&/#&#.'&=46?32225&/&/;272>?654/#'&'#'.5#5!!;7;  .   z J _%,(8-'96 "4o/' gDC@<)910%?* &u%(4  '32  " : C >)-8"76' z-  #>"  E/ \  3OM#   ;(22 0)s732?2'&#"6"&'#"/&'"&=47'#'3#6?6;7>32#"&/'./""#%2654/".5463263654&#"%32?6565'&/&/+3v ";#  8 !#  > f;G &30$" % 41#  P%H' #*f #  i! " %%i[   ': )K#+$ #  VF20* *.&   l 65H.4,:!I11 # O  " +f*V   K.T726?6?6=/&/&'#'.5#5!!./&+"+"&546?632x1  "$-62 .H^  ,/ $-!#H7 /3Fn22  !  @  !V/!, I.%"&'32?22?65254'#"&54?%47#5!!&#"327?6323'&/&5'&54?"/&'326;2+'&/&'#"/./37>54&##"&^f!$' * N) 8 !)7 3 *+ %/ *16! 54&##"&547#5!!&#"327?6323O" $f!$' * N) 8 !)7 xN %%& ! +9! (<$ A7 !(3/$$(   *$1":3 *+ %/ *16! X<E"& .+-(C3 6,! 5`T. -  )#HJ&%# % 6I !4#%B<)_&%4'  4;@,22   5  Di. 8%57467'"&/&'326?5'465%467#5!!";267/&//&/&#'2?'./532654/#'.4< %  a %#N %.' ,)   -i7%9 L*   (:@(L ! /? - >Y#   P4 & )* U'P33 ' OM1&   %F ?$ C*Ia(-#* $ /?Y.$~$274'#"&54>32654&#"'32?/&'467#5!!32?6?6?2#'./#"/&/2654'4#"#"'"/&l4"`(% 6.3 N  15! 1 ,R>%  !(L *' 3 X3}?+& *-+[22   1 ' 7 7.&I'88.A6&"`` Z75%4'"32654'#"5463276#"'/./?.#"2#"/&/463256?632) "?0_[(/!0$&8(n;\&9;]+ 5 !  ]A(O /9<*2'+ !%F( R0(p#8, .9:$: a@N" % %#(G5"9"?D4A$<D-765'64/%26=4'#"&57>3267'&#"'#"./463?6?2'.'./&/25&/"&'54?6?654&"P }5  &Fm7>((' @4S ( 2. , _)9.!G;+.+*3OV0"*C  ! O b %    V 3MC)A#  ?R53(#(  "  H$,,)f_  5E#0   !'*+2654/&#""#".54632654/"'&/5?"/&'3267#"&/;265'4.'"&54?65654'""&546323?6?32722%"  "" #Z  (2$($ #GL\ HI  #)  &!Z6(%3 '   $  F>\*4)5 & 28 9(7nKS8W$92-!  1&4+ , -]&% .2}4I7"&/74/&'"/46?67226?'4/&/2?6?/&/'./?654/&'""672"/&5&546?256?6?22r*'D $"/A &    "    *  ,""3;4vn        R"$/[4 &", 22/-I"      <8  S ) v j,`H>F  "   /=C= f  i23!32?6?6?'.5467"&/&532654'#"&/&=#5!7654/#"&5463732 '. _% ! Y^a  !23(R&$9 g< &> 1-N . ""1)&  !23'S,9  &> B )_& Ij C[-.-)1 !%!"U9#8A3T q8C1 !%7 EP$2Vc79& -2-!+"+++$4."%]?K0>K9"#:;!<}.!a#"'4'5!32?326?674%#"/5#5!!2?+'&/#'./&/326?4&a$, % '%5#$Cy_'+}"J#&XHG:. Y,":#   B7K RPCć. 6`"&/& "LO@22K a#Rn ZT8"7 !-/:6.,1%A (x.U26?7322#"/5#5!#/&/&#&#"#'"/?67#"/&/32675&B 0_ #  k_& xI    %$9U9#8A3T 7 ?E|/ P$22-.  * ]?K0>K9"#:;!J|d&#"7'4632#.=>;25!74+"#".546?723!3267"&57632#"&/!A&  %&(5 #0$ /)DO -B   ?QL&'e%4"2S3 2 - 0&5,) $4 ,,2' '    G52$f038.%<U8 ~|72;25#"&/5&#"7'4632#.=>;25!74+"#".546?723!3267"&57632/&+###".=4674?363*7# 2 !A&  %&(5 #0$ /)DO -B   ?QL&'e%4"2 "n  024/: 8 - 0&5,) $4 ,,2' '    G52$f038.%<& :)8  'W|&'2>?653#+"&5&54>?6?6?/74/&'"7'4632#'.546?2765'4&'4/&/&5467- 6 5#$)ͧ " 2@+,a+/ 4 )   %&#*@%%)5  C !5#&K92&" "%2% 1L02/2z+(6J T$    0&5C9N Y/$")5E4b46;37#".'&543573265"'#"&=463263654&''54&#"3274;#".W;*$,1  ?07[<2 /^_%++  45( %&C! ,V$P3+7C$01Jn`; ! '  4 O!,# !6$A.^46;25!!;26?#"&/&/./&';2?6?>="5&'#".#&/&5'*.  X  6%.0\6r   91LZA&   ,!0%  % 52&4$m$U2F ( F/ e37L5  1 # % @L@  s4~%25#".'&543573265"'#"&=463263654&''54&#"3274;#".546;37/&#".547327>7[<2 /^_%++  45( %&C! ;*$,1  3i%LDG` <~1Jn`; ! '  4 O!,# !6$A,V$P3+7C'?O,.+F/2;25#"&/&/./&';2?6?>="5&'#".#&/&=46;25!!;26?/&+"###".5474?327*6$(6r   91LZA&   ,!0%  % '*.  X  6%. $T  /A 4/%:F ( F/ e37L5  1 # % @L@   52&4$m$U &-* 8 [I.B.#"7'4632#.=>;25!!26?"&57>32"'J98  %&(5 #0$ 5'c] $ $H;*+-/ 0&5,) $4 002 Q##  6Bl$Pe7"&546?2'&547'3#'54/./"'432+".54>?2354&/"/4632#5HE2%    D[7 8!/,/'&" $-4&%  C,'5%0&ZD>L   2= 28K .5 #" 8' *"9V 9* '-O X32"&546?2'&=7'3#/&/&#&#"#'"/?674&/"/4632#r#  5HE2%    I    % C,'5%0&U ZD>L   2KH 22-0 *9V 9* '- .TX4632#"/&/&/&/326?4/"&54>7>54&#"#"&!!zQ4G+:"# 4" ""!<8+: !! %  + Q3bJ'I:2 5$B4 'lC+0&!4+   "  $2f . n25#2!!/&/&/>7&/&/&/&/326?4/"&54>7>54&#"#"&54632E  !    "%&-= 4" ""!<8+: !! %  +zQ4G@<h2"1-( 5$B4 'lC+0&!4+   "  $&3bJ'I}P#"/7>?27;#/&/&/./2?6?654/'74&'"&0  ( $ =0$ 63  >:FS36,!% R"% + 8"6!")B.".36# #5"43%$ p  ( A.  e=.e!!.#'.+"+"&546325#"/&/&/&/&'2>=4/.#""/4?63@K4 $.D2&F &$$ ' 0.' F9"  + 2=!3x+' j A "(  % 8 O!q.Hq$2>=4/.#""/4?63#"/&/&/&/&'5!#/&/&#&#"#'"/?6;22F9"  + 2=!3x+' j A Y22-.  *) .E2!5!#'.'#"&546324'#".'32654.#"#"&54>C3F0) <XY 3.#H(,P6/ 0YwN !*'TDJ+?D  , 22 (?5"+) ,3F]@13 32+T=.|!!/&#"/&+"2&5463632#"&5463246;25#"/&/&/&/&'2>=4/.#""/4?63@=# (   2,2&4! &$$ ' 0.' F9"  + 2=!3x+' j A "(  % 8 O!q4 b>?6?!'#5!'&=3#'./&/&#?'>54&"/&/54iEB%& AmC3I3" C[-   *2 .:RB # ) =/ kBE23"S7:% ,2-)*) **"."AX&F*#5  3'%<*&. 'R767#"'>754?#267#"'#5!#/.//&/54}% QR2 f- 6H$(F!$}AmC3^\0=# 0'! H5 r 5 B$ H"x+/kBE224/G>#5  3'%<*&<.?76?6?67'.54754747'&/47'#5!!YC(G ,,$L%&' D , "/( <'<?6vC1&  >> #  "    $J$.(Eo*N*TX.  '1   N$#!-@|D"&" > (0$ .2G +,@44  .5/&#+"&546326='47'#5!!>?@-S#-08*AmCPuCC%&~f$6v&!($7 93kBE22 ;0Q*`2;?/&54?'5#5!!?6?+"'"&/&/;26?5'+'.546?2# #   "*,_B&L /*+)."/`!!  k#R  "&60      + 044|09(2 B:>=PD"306=,-(1#!- $+"!*X2/&/#'.=656?6?325"/&5474?63227&547'5#5!!7676Z % 'W +  - I%)#+'   %!" ):,v= #L0 ) "- %2 !# +   ,"9*'*044|, 9?C Q*2;25+"'"&/&/;26?5'+'.546?22;?/&54?'5#5!!?6?/&+""#".5474?363+ 7#@ /`!!  k#R  "&60  #   "*,_B&L /*?"n /A 4/ X:D"306=,-(1#!- $+"!    + 044|09(2 B:>e6&,* : f.F%6;22!>?''#5!#/&/&#&#"#'"/?67&/54b +|CC%&W AmC3fI      l  + ;0A5F*#5kBE22-0   /<*&'4M'32?53#/.+"+"&546325'./7"/474632#"'"/1(&WA! }T 3 -D2L,<:;~C+/ y!+d N&IB2 !"4 0 &1E;!-O^. / 'X4Q73232?5!#/&/&#&#"#'"/?67.'&/7"/474632#"'"/1(&WAK2! }I    !`"<;~C+/ y!+d uU '&IB2-.  * UO^. / JZ23!3267"&57632#"&/5.+"#"&546325!5!74+"#".546??QL&'e%4"2S3 2 %1&0(3- )DO -B   G52$f038.%<U8 y% 0+*1- 22' &   %2;25#"&/5.+"#"&546325!5!74+"#".546?723!3267"&57632/&+""##".5474?327*6$ 2 %1&0(3- )DO -B   ?QL&'e%4"2 $$T /A 4/:8 y% 0+*1- 22' &    G52$f038.1'!&-* 8 'Wp.'2?6?653#+"&5&54>57>=&/&/#"&54632>5'4'!53/&5467r)6  /& f;     F4+\&%   "&7); " !&M'C)* "!&' -( 20 /&*6!")L2#6"*!&03  G&2',#)()8;.W"&576325!5!!32?#"./&/.'2?4'#"/&/&/  2  = +  kW?T'  '  )A*L+X * B 9 22 C/!&Yo=.K>9#8G 21.I:    u;.72;25#"./&/.'2?4'#"/&/&/"&576325!5!!32?/&+"""#".5474?3327*6$'7?T'  '  )A*L+X *   2  = +  7$T  /A 4/ :~=.K>9#8G 21.I:     9 22 C/!&V=&,* 7 I.746325!5!!26?"&57>32"'5'&+"#"&F0(3- `$  $ G<*+--+1&q*1- ~22 T # ' @n$P : 0+D.Z#"'"&/3264/##"&/46?&=&/&'#"&54632>5654.#!5!#(*'  *: 0(  -**D@3)(  )&*2&*g D!V@9$=&ce +722L>% "+ '#(#,@ 226')qD.m25#27/././>7"'"&/3264/##"&/46?&=&/&'#"&54632>5654.#!5!#N% !3 %%&'" *{< 0(  -**D@3)(  )&*2&*g D! (*0<8L  -`h +722L>% "+ '#(#,@ 226') @'.k#/&#""&/&=74?72?254&+'#72"&/4?'&'#"&54632>54.#!5!!@3N  A*6 )#    &  /!)0(*k'6'  =%"   E  ! '  ".  ")#,A 22]D.j25+".'26=4.+#"&=46?.+#.=654632654'!5!#/.#".547327KE/'5cC< (21M*8L #3#+ J# 2&FT4.D R# =ZPKPb ;AWtF 3!J,'E&  %-#7 2.#,T2-22&72$g@+& =N(!*-V. \6;7&/&'7&/&/&/326=4'7'&#"#"&547567#"&54632>54.#!5!#$'/=O $"O/BB; , W28v&T  @!$ )0(*ks!O 33 <7K(B.-B("  w&<% ': ")#,A 226' .>46325!5!!>?/&/547'5'&+"#"&F0(3- u FI"&W# BmC "*1&q*1- u22<5A5F*#5 3'%<*&EkAEu * 0+x.@%'%46325!5!!7>32/&/&#'?'&'"'5'&+"#"&! 90(3- x[; #7[7'$-70 "*1& *1- u22$7T $  ?'"/&#"#"/&/57?3'&/47'5.+"#"&F0(3- o FI"&U8 )z@ !  K 4- A! .E1&r*1- 23<5@)8, ,9  $=MG!15JR  0+2.D7/46325!5!#?6372/&'5/.#'?.#"#"&C6*&Q2  & $  U:0@`< +7f,52"22 ~wI  0@@,33  t2. Z25#22'/46325!5!#?6372/&'5'/./67'.#'?.#"#"&  ! AC6*&Q2  & $  %%&QK U:0@`< +2<7f,52"22 ~wI  u-H @@,33  [.q7'2;25.#'?.#"#"&546325!5!#?6372/&'5/&+"""#".5474?3327C%  A50@`< +6*'P[  & $ G  (7 ,(7  ;&0 @,33  !,51#22 ~w/9  {%,* 7 .C746;25&/.##"&/46;35!5!#/&/.##"'E4  &aP'"))G2  %'b P(& F2A~ 4E" "&4? %= 22*'2E+>X.C3246;3!5!#/&/&#&#"#'"/?6;.##'&'{2

3253#/&/./&/&5372654/".57463'&/'6?'&,  <Y-  Y$J[-E4:$*# /" $1)9&7(A '?^ 2B!:D%2{6)7  2() ) 3#  #p S'&#"27&&#'&+"+"&546325&5./'764&#"#"&54?>32'53#/O"> v*1 $.D2$F! G+   ,A)*I,  DO @M u!V/!&1)E.* ,$4. ~  2y<GU`3#'54/'7654&#"54?>?654&#"#"&54?>32'&=254&//""27&/&#"27& DQ26+  D-%    ,A)A} );" 7  8H vO"> v`2)c .' /  ,E6d{/.'1w  M u @M up d'&#"27&7332"&54?>32'53#/&/&#&#"#'"/?6727675&5./'764&#"/O"> v#    ,A)*I,  I     ! G+  @M u*V ,$4. ~  2-0   E.* #p m'&#"27&"&54?>32'53#/.#"'.+"&546732#"./&54632>;25&5./'764&#"/O"> v  ,A)*I,  DO# # ' %!, +-&! G+  @M ub,$4. ~  20 + $#  A$7E.*  /. ;h27'&/"%76?2'4632'&/#"'7654'""&%.#"/#5!#'5/&#""/&/72?&!&c#"/6-nH'O 2+ <  '* f0  !(.  !  A,o-d 6  4 r.#:  !* '  229 #:A&%  Wj"&'5.#'6?.'&'#5!74+"#".'473723!563#".'4?23257.#">7#"&546;2c: Z0-9P D@2 *2$% 5@PY43_i @J' +#0Q!+)rS,)2G. 22 /2   H42"FO*:G6$    J*!B=tr.s232?4&/"/.#"&/&+"2&546732#"&5463246;25&/&#'?'&/&/#5!!6;2#".'47  ?$  '  $2,1'& #"4H:._" r5H={,5" 0;(/%$H ,0   +  $C';   .2%S1M 22 & C `&+#FQ'.ja=) 6 S    MkC1/OD,22- ,=$()*V& "9*66=. _'/.#'?5#5!!76?673./&/#"&/&54?3337/&5'4"%Y>Q'.ja=) 6 S  "4o5' 1g   MkC1/OD,22- ,=$()*V5- #= " *  6"9*66L. J%577%>75!5!#72/54&/"/&/&'#'7/#%(6, &?)-KZLO  , A  ;B!BS% 75<)22! S   %ES2 ./4725./675!5!##/./.+"+"&546I6!uT@\ %  &.C]dwJjI-:Y[k."22     .#%1 H2q(.9767#"./32654'#"&'5467&/7675!5!#"2!2%23b[I;mL>! Si,A;+8.:`14UP2.%s.3SOa8QcKu09!;7%"RF$822 .N>;25'&/.#'?675!5!#/.#"/&+"&546732#"&54632RK*" >  !+0#@;25##"&'&/2?4&"B#+GH " B:6F #  ( %2,-+&'Dd< 9.0"[+.2&225;#>2F,j< 0  +   $C'B#C  *: 0(2J%**D@3(*0*#0:t.L$0 0cY1 ce heL>%+!. 4  ,22 l672654&'#%3#'./7>54&#""'+"/+#"&54727256=4&+5!637632Q Z %WT>n+0O&HC- /   *(&*'0<z 16+Q-  R  0L,2X4;h!>"  #%4 -2%K;4$  P . P2654&'#'4&+5!!>?/&/547'5+"/+#"&547272565  %<u BD&'W# AmC(&*'0t0LI-22 ;2A5F*#5   43'%<*&EkBE_#%4 &. T2654&'#.#'.+"+"&546325#"/+#"&54727256=4&+5!#  %`5 .D2&F&(&*'0<R" t0L!,* /!&1,#%4 -22$0 *.<F74>325.'#"&54>324.'&/#5!##&/&/&+"+"&w+" G8;'0-%$ -6A  #]   " $- ?U9 %JH&6,4#$ ,:22   %/+wA9+\Dp `'&#"27&2654&'#7632'53#''&/'764&#"+"/+#"&54727256=4&+5!#PO"> v %r3f*I,  DO0 G+  @(&*'0<z&  @M u^0LkG$4. ~  2-21.* C#%4 -22Dp '&#"27&2754754&'#4&#"+"/+#"&54727256=4&+5!#632'53#/&+"""#".5474?332732;2'&/'7PO"> v$  %A)&*#0<z& 6b*I,  DO$T  /A 4/, 0 G+ @M u` .L6*F#% 4 -22F$4. ~  1&,* 7 21.Jp '&#"27&2654&'#+"/+#"&54727256=4.+5!#632'53#/.#"./&+"&546732#"./&54632>;25&5./'764&#"VO"# v %v.&)&*#0<z&8cv@  DO# *  *3%&! G+  @" u_.L-#% 3  22I ~  20  #+" $  :%7E.* q. r254/#'4&+5!!6;2#"&'4?232?4&/"/.#'?'&/"&'"'+"/+#"&547272565 3 %<t5 &={,6!0;(/%$ ? ":T0:._" 0!(&*'0t<&LI-22 Kg &9X"F/(0(#  ,x,:#S1M  **#%4 / 2654'#7+"/+#"&547263656=4.+5!!72#"&'4?232?4&/'./#".54??2325'&#'?'&/"&'"' %}20)&*'0 <%H={$-,)k[0$$! %#?O(9  !F  Sy:._"u0 '%G#%3  2354'#"/&/4747467#"/"&54?636=&/&+5!#+"'< *&72.4cQ_U& 164SZE!'+ 5!6" f$> 1.   " 1;Q;RdI9-6#_>&"1*1  5 "!  22 ,   *  .[m/&/#'.=46?325"&=6?632267&/+".54?654&+5!#'2654&+L&  V + - I%)$() &.  $K :0&1 Jc" 4  2)! !.5%2 !"/$  =!(%*/'22$6 * @%#: #7.%2672/&#".547327325#"/&/&/2>54'#"/&/4747467#"/"&54?636=&/&+5!#+"'74&+32?62.495=ZOLNd "D )_U& 164SZE!'+ 5!6" f$> R< *&1;Q;X3&:Q(! ,+;y I9-6#_>&"1*1  5 "!  22 ,   *  1.   " F. #]2654&'#7#4'#"/+#"&54727256=4&+5!#/./"/4?672  %}  m">&(&*'0<IX -,, 9t0L4  % &$00#%4 -22-+4 3.cp%25+"/+#"&54727256=4&+5!#/.#"./&+"&5463632#"&5463246372654&'#  (&*'0<b"# *  2,1'4! %|#%4 -22$00  +    B(;? 0L.Xb%25.'#"&54>324.'&/#5!#/&/&#"./&+"3&546732#"&546324639 ;'0-%$ -6A  #]%     (+2,,%?U9KR&6,4#$ ,:220    %<.A%+wA9+\6.k76?2'2654&'#7+"/+#"&54727256=4.+5!#'5/&#""/&/72?/.+"'-q %}20)&*(0<6f0 F   !  A ' 6  4.LH#%4  229 #b&%  W 6.76?2'2654&'#2;2/&#""/&/72?/.+"'+"/+#"&54727256=4.+5!#/&+""##".5474?327-q %*0 F   !  A '20)&*(0<6f$T /B 4/ 6  4.L #b&%  W H#%4  22&-) 8 Y. m%5'246725!5!#32#"/46?274&#/&#'?4&'#"'4&#"&5432#&/&574>748 `  E* G1fj #%N  /4 $(  +  $  33Q<6 %2'^HI7 ) .!  *.   2j26?!5!>32/&=3#'.'.#?'>54&#"+.'&+.#"&5462#"&546326.$W8" W[- ! / *1 +!:S K   7()#80:)N?2/%!  2) 8"S77 * 2-) %*($4."AY*+ 7)1 0'#P?4? #;Jn25!5!74+"#".546?723!3267"&57632#"&/5.+."&5462#"&546326<+vDO-B   @PL&%h%4"2Q5 3  ! 7R#80#! )N@15!  k22( '    H42$f039-&<U8  + 5+1 0&  Q>4?#;w%2;25#"&/5.+."&5462#"&546326325!5!74+"#".546?723!3267"&57632/&+"""#".5474?363]+ 6$  3  ! 7R#80#! )N@15! -+vDO-B   @PL&%h%4"2 $T  /A 4/ :8  + 5+1 0&  Q>4?#; k22( '    H42$f039-&<&,* 9 8~.x#&/&574>?246?25!5!#32?#"&/54?2?4'#"&57'654&'#"'&/&+"&5432 $0    ! +  kW7p D*L+V# !   3 /45    " .{22 C/#$YoG7)  %1.F /  & $*f~.2;25#"&/54?2?4'#"&57'654&'#"'&/&+"&5432#&/&574>?246?25!5!#32?/&+"#".5474?363*7# /7p D*L+V# !   3 /4 $0    ! +  '"n /A 4/: G7)  %1.F /  & $*.    " .{22 C/#$1V&,* 9 G/y632767325!5!##"'"&/././.'3264/##"&/467>3735&#"'&/"&'4632#"/.5t Y4   BGY 5B -j$   (  ;7**D@3&( &# +:/ ,$p`&  t33%8O!T#5 #  (d)L>%"+   A<**%$1D.Q6325!5!!>?6?/&/547'5&+."&5462#"&54632 - }DuJ$'W#AmC 7R#80#! )N@15;`22B A5F*#5 !?3($<*&EkBE+ 5+1 0&  Q>4?/ s%46725!5!#7632/754#"./6?6754&#'./"&54632#"/.57>32 &,, `    +79" )! 1  % )&(9?"$ !  l)'33 +J0$  ^  /&(F,3"$ &" + C7!1;Jp Z'&#"27&'!5.+.#"&5462#"&5463263262'53#'&5./'764&#VO"# vv*  7()#80:)N?2/%! ->@  DO0! G+ / @" u\22+ 7)1 0'#P?4? #; m ~  2-E.*O.i6327'&/&/!5!!6;2#"&'4?232?4&/"/.#'?&+.#"&5462#"&54632 -  5" ]5H={,6!0;(/%$ ? ":U0:. 7()#80:)N?2/%;  + 2232#  `, aI    $ )  0 %!)&)8>#$ R n)'32-,  *, !"$?+ B7!0</u25!5!#/.#"'&/"&'4632#"/.=632767325'&/&+/&'"/"&54632+/&57>3246*8zY % +:/  %" Y5  0 !&"AMF($ ,433 #**% : `& B  > 5 0' 7 -P3;)~4&#"#"/"/4?67/&+'32>?2'5#+"/./&'32>54./##"&/4636732D % /# &'  A2g#  1  MS*%J3  -I 4 >>**$8 4!$8  gZ  # !"  .* 1 E'#u   2*>75 H: 2 2&H%! ! %"%6 00 R%26=/&'76325!!#'.5&#""#"/#"&54?4/#p".-+&)0 Y^> 517 !!&0,- sv1 /'0 J2   !! V>c'5"+" 0t;6?65/&/2&/&/;2726?654/#'.='&+""#"/#"&54?4/376325!!;7  . %,(8-'46bt<)910%+J1 &u%' // !!&0,- :+&? >2  "   >)-8"46'h& \+, 3O"qP'5"+"'%+N2 c.#'.+"#"&546324&#"#"/#"&/46?67/&+'32>?2'53#5 '$D2#BD % +#  1  A2g#  1 CVC!,* 8&1''Z  #"   * 2 E'#u  2 m3324&#"#"/#"&/46?67/&+'32>?2'53#/&/&#&#"#'"/?67  D % +#  1  A2g#  1 I    !V Z  #"   * 2 E'#u  2-.  * 4&#"#"/#"&/46?67/&+'32>?2'53#/.#"./&+"&5463632#"./&5463246;2D % +#  1  A2g#  1 CV#  *  "!1'4! gZ  #"   * 2 E'#u  20   +"    ;? . ",\2654/&'"#"32?654/&7#"&/46?274&#/.#'?'&547#5!#   '    Be8! B *G cO016,8  N$  2+=W6  $3/-GG%$ !81422 &,.!2>54/&'""32?654/&#7>;2+"/&'4>72326=4&'#/&#""&/&=74?72?254&+'#72"&/4>7#"'".547#5!!3  '" B (      2 (%$@3N  A*6 )#  ' ()8      2F         ( ! =%#   E  !$  "4'4122 M 2654/7>54/"3723#3?>5.5467#'"&547474?'#"/.=76?#5!656574&/#".547$H z( %# f=?Sk   + !H 4-'+5)   8  T(%9 K [  #;&+,s (2|" ' !!   .$ / & &2% *p >54/"2654/2;25#'"&5474?'#"/&=76?67#5!67574&/#".54673723#3?>5.5467/&+###"&'&5474?327R( %# B%H *6#-'+5>   | T)%9   f=@Sk    !H  #l  G%4.&+,R [  #: .$!8) % 2% '  (2  & #!  %%? 8 $N -c7265'4''2?65&7#6?'43##'.'&=?&/&'465'&+53/&5671f.8=6    0!" #2Ĩ D8.$J 69(#(TwMDBWc&!%6     ("'&J##22<2'F4!.#$6#  -:  X 22<>D+%w/:o5'&'?46327654&+"";2654/&'#.72#"&'/.#&+'?/#".'4.'#5!#>8)(# /'/!  (0SU!&#  1*5  7#'W{3 D|&+ Y'$% 1!( !o!c,  ?/ $  5)V%4(^Xk  33ZP p$/j672654/&'""32?654/&#%'&#"27&47#5!632'53#'&5./'764&#"#"'#"'".% _   '" BO"= v8y|&8v@  DO0! G+ 6() _   2 @M u;142 ~  2-E.* &4p#.72654/&'""32?654/&#%'&#"27&"#"'#"'".547#5!632'53#/&+"""#".5474?332732;2'&/'764&9 [   '"  BO"= v6()8y|)2*I,  DO$T  /A 4/*0 G+ _ # 2 @M uO &4'142$4. ~  2&,* 8 21.*J. n2654/&'""32?654/&#47#5!!6;2#"&'4?232?4&/"/.#'?'&/&'#"'".   '" B[8y^5H={,6! 0;(0$$? %9U/:._"  #()   2$1422?2732/&5472326?'4&//.#"#'".5474?32?24'672"54>7"/.5#"/&5732654'#5!o% 5(N  " :,  #-    1#5..B! -%#$K9 !(  3`$/  0 m#"Ac-  6R:)   )$  $ +"  58 &5#4D   3 , f," < !#D22 e3?654#'&/./37>54&'#"&5432?.5#"/&5732654+5!)+ !< %(:@ SV  `;PL$%< (   $!0/&6K  $ 0 ;  $-% (/& +$_2 7+Q ' ! "3$Y !#D22M 3?654&'3723#3?>5.5467#'"&5474746?67&/&5#"/&5732654'#5!2574&/#".5467)+ ! f=@Sj    !H 2-'+5)6  D  $ 0   T)%9 ;   & (2     & #!   .$ ;#4/!#D2 % '~. 2654&'#"&5474?36;2;25#'"&54746?67&/&5#"/&5732654'#5!2574&/#".54673723#3?>5.5467#/&+##x *{**SH4/*7# -'+5)6  D  '0   T)%9   f=?Sj    !H "n   &; 6Q7 8 : .$;#4.!#D2 % *  +2     & #!  &@. f2654&+7#"'"&/./3264/##"&/4672637'.5#"/&5732654+5! )x)+`DC  -i$  0(  <6*+D@3&1 ;  $ 0 @$; d-%  "bW3S$5   (e(L>%%. F !#D22x@.t25#22654&+/./>?"&/./3264/##"&/4672637'.5#"/&5732654+5!#}  ! 7 )x)+D  ; %&40i$  0(  <6*+D@3&1 9  $ 0 @VD.<$; Y2 -(P(5   (e(L>%%. D!#D22-%  ". r3?654/&#""&/&=74?72?254&+'#72"&/4?>7.5#"/&5732654+5!)+ !< @3O  A*6 )#   )     $ 0 ;  $-%  =%"   E  ! '  ".*!#D22J@.v25#"'"&/./3264/##"&/4672637'.5#"/&5732654+5!#/&#".5473272654&+:F -i$  0(  <6*+D@3&1 ;  $ 0 @VD=7i.QJMf )x)+";S$5   (e(L>%%. F !#D22-%  "bT1&=N$% ,+$; `. f3?654&#>7327327.5#"/&5732654+5!#+&/&/326=4'7'&#"#"&547)+ ! 00'   $ 0 V$&!?M$ b/BB;:=W26x&T! A $;  $& & !#D22-% = 8K'  Q.-B(""w&<% ': /. O3?654./&/&+"+"&546?6325#"&5#"/&5732654+5!(, ! <   $-!#&F6M  $ 0 =  &-'   ! %/!, ,X!#D00pc67#3?654&#'&#"27&%4+5!632'53#'./'764&#"#&#&##"&5#"/&57326)+ !. !O"# v )?v@  DO0$ G+ .6M  $ 0 ;  $$ @! u2# ~  2- W.* Y !#Dp>7#'3?654&#'&#"27&2;2&5./'7654&#"##"&'#"/&5732654+5!632'53#/&+"""#".5474?3327 )+ !) O"# vO*1 ! G+    !]  $ 0 ):v@  DO$T  /A 4/  ;  $$ @" uE.  ?5!#D2  ~  2&,* 8 p7264&+%'&#"27&%4+5!632'53#/.#"'.+"&546732#"./&54632>;25&5./'764&#"##"&5#"/&57326e *x)+HO"> v %9*I,  DO# $ * %!, +-&! G+   6M  $ 0d"$; @ @M u2$4. ~  20 +" $#  A$7E.*  X!#D. d3?654/4+5!!6;2#"&'4?232?4&/"/.#'?'&/&'#"&5#"/&57326)+ ! 5H={,6! 0;(0$$? #:T/:._" $&6M  $ 0;  221F  HD" 6v&!(1*7Q 4 &$&1  22S.{272?6;2+"/&'4>72326=4&'#'&/&/;726?654&#"#"&=46?654&'#5!![ ,2.   2 (%$?D2, D6I6Xh7!V = @)"& 5=9!#5   (  +:  HD80 4 &$&1  22.#0r5"/&'"''3275#"&546?674/#5!#754747/.'+&#&5463654&+  !B/ <  3%  MX48W"3$ &"' ( C   2   #*F"0 22F5< |L  !D!E  *1 "+  T.g25!66;2467>7.#""&5>?654'#5!#'.+.'"&54632+"''&/3l/ !4 9%]$2#)- 7''1&*Ta3,!4)D!$,R&!Seq7!["'   @" - '1!; #) 221&. 0'F  @?* 0D$P.w//&#"'.#"'6=>32#"&=>3226325/&/;726?654&#"#"&=46?654&'#5!#2|AK2, D( '!+;3*- ".Xh7!V = @)"& !i>1F  HD(3  @ #:!344 &$&1  22S_ +4&#"76#"&54>7254?>7#76?%3#'.'.#?'+"'#"&/&/326?654'#"/5#5!'&=/ !;#% &W[- ! / *1 !%!`5>P2  $D#)M",5"I0" p %-@b     "$ #,2- %*+$4." IGNb%&$JK)3B2) %"K 20"S79&aF. P%4&#/.#&#'>7./76?6?675!5!#72#"/4?2*!) ! 6@?P$P:  J+#"7L8E,2 *'L :w0!   T   )  -G?}-R &1<$ " U  '22&wV)3 H%4>32/&=7#'&#'76375./&#?'>54&#"#"&l4*<">)W8% C[!2Z$5Y.-*1 !%  :R K &-*(/ 8%P77 -2 h?(Gi4+*+ ."AY*)`.7%7267#""&54?#5!#'&#'>7&/7673> , 61J$(E!$#B 3^!0\$45   $@  "  >)-8"76' &0<(  \0' 3O"22 3d.25#2/./6?>?67'&5467'"&/&#"376?6363232#"./&/5732>54&'#"&546?#5!!3732?" $7& %%&    "^ 3 % :  :&'D,   _/01  *2@n/2  /n<e*&7U -   {2Y &C& # G &. 4++3a 93R " T,&22)M777'&#'767./#5!74+"#".546?723!3267"&57632 ?^-!0\$ #;;DO -B   @PL%h%4"2Z(Q1 h? 2;22' %    H42f038#.B25""#"/5#5!!26?/./>7#"/&/32675&< #w_& #B 0N  >%&H U9#8A3T <<P$227 ?Et. -0]?K0>K9"#:;!H%5'"&546?2'&=7'3#'&#'>?6754&/"/4632# <"5HE2%    G^!0\$/(C,'5%0&*VZD>L   2KH 22 h?%  c9V 9* '-=. a25""!!#/./&/>?67#"/&/&/&/&'2>=4/.#""/4?632< #@  ,%&3 $$ ' 0.' F9"  + 2=!3&-&>x+' j A "(  % 8 O!q HJ%73#'&#'6?./7>54&#""&5?>32@ <"!WT!2Z$k \60O&ID, /  $ .5)+Q- R *1,2L h?Q ': h?# ))K;!8+   P .+7/7>32/&/&#'?'&'"'5#5!!! [; #7[7'$-70/ӷ {&5T $  ?675#%32?5!#/.#'/.'&/7"/474632#"'"/x 4V(1f1(&WARK*" >F! }] "L  n"<;~C+/ c *"!+d ,5 * -a&IB2&Jf3!dO^. / .<'&#'76?&=&/&'#"&54632>5654&#!5!#AL!0 R &32'53#'&#'6;5&5./'764&#"~ <"pO"> v  ,A)*I,  DO!2Z$! G+ *+ @M ub,$4. ~  2 h?oBE.* 0!-8/./&#'/&/&#'?5!5!?5#25 B6" /+ "7Xvi8R U+  K!2"&.:  9#P6R0228@,55*1 !9'. =A%"25"./6?&'32654'#"&54632767'!!k   >%& P @8C*8NP>,?&1$Bn/) \66 :./$8#>%" ,&1 Lϱ    )",# &$6  !"[e"%*/ 22%#*%   &2.r%5'254&'#"&5474?;2325/&#'7#&/+".54?'4/&+5!#7/&+"##,# &:  (I>.)# 3  1F" ,&1 }e"J &2}H*%   qP7 9    #:[e"%*0  22"8  U%1/J%46725!5!#'&#'?6754&#'./"&54632#"/.57>32% <", c1`!2Z$[*)! 0  %!)&)8>#$  *Z)'33 h?E Y-2!"$ ?+ A8!0<V%574&#"#"/#"&/46?67/&+'32>?2'53#'.#'7671>""AD % +#  1  A2g#  1 CV M,,Y7d+Z  #"   * 2 E'#u  2,5LA$ './:@2654'#5!#'&/&#'73.5#"/&57%2654&'#35q0 )c$! 1F#>A   % 5(C,!"&D22*):]x D% !# #"A'2.M%?675!4&'#5!#/&/&#''&/;>754&#""&5>?6 RK*" >3+PV(1_ ] %2!"/-feq7![" "1#*- 7''  &[5 * -~ "./*"$ 22&P!'=' 0D$ &3!; ' .. Y%5'.'/.#'>?'&/;726?654&#"#"&=46?654&'#5!#2+? % LAK2, D? K3+*/# Xh7!V = @)"& !i' )1F  HD 0 &0<" 4 &$&1  22S4>72"/&//&+"#".547474?36;2;25&/&/&/?>54/#"&=632?3!2?4'#"&"%!"n /A 4/*6  MvS*%&)= +C'!+0L< = - S +4, :8{&,* 8 5D   Lg / ( *0-H4 3<- #(27 /$y2?3##7/&=4'4'/&+"#".547474?36;2;25&/&/&/?>54/#"&=6C0L< = -V:   : 8"n /A 4/*6  MvS*%&)= +C'! -H4 3<- #( 0 *_T 5%$0  &,* 8 5D   Lg / ( *03.b46327#"&'./3265'#".'4632>54&'.#"?32'7674#"'XL+ ,\ 5/"=3%Ia$ <1&('/ '  ( 3=   %>M*'L &n0*$/1*QZ ,503( YQ1H >5?   4>72"/&//&+###".5474?32732;2.'.#?'>54&#"#"&54>32'&=753!2?4'#"&"%!$n  /A 4/ *7# %)4 )1 !%!:R J &>)< 35, :8&-* 7 :%-!++$4."AX*)(/ 79& -2)/$ v4>32'&=353#7/&=4'4'/&+###".5474?32732;2.'.#?'>54&#"#"&>)< 7   :3$n  /A 4/ *7# %)4 )1 !%!:R J &(/ 79& -2 *_T 5%$ &-* 7 :%-!++$4."AX*)4>32/&=753!2?4'#"&54>72"/&//&"'&/&+"&5463632#"&54632>;2535./&#?'>54&#"#"&>)W8% 3+4, "%!# (   +33%4!.-*1 !%  :R K &(/ 8%P77 -27 /$:80)   +    :0:?<34+*+ ."AY*){3#7/&=4'4'/&"'&/&+"&5463632#"&54632>;2535./&#?'>54&#"#"&54>32/&=9   :6# (   +33%4!.-*1 !%  :R K &>)W8% c* 2 *_&@ 5%$0 0)   +    :0:?<34+*+ ."AY*)(/ 8%P77}J.>%#"'333/&5467'"&/&#"376?636323274>72"/&/./&/#"&/&54?&/&/5732>54&'#"&546?#5!!3732?"2?4'#"& :&G61g    "^ 3 % : "%! !&"4o5   _/01  *2@T/2  /K 5,  &.6 )  :{2Y &C& # G:8 L &7U- )8 " "+3a 93R " T,&22)M  )/$ }.>%#"'333/&5467'"&/&#"376?6363232/&=4'4'./&/#"&/&54?&/&/5732>54&'#"&546?#5!!3732?7 :&G61g    "^ 3 % :  :6&"4o5   _/01  *2@g/2  /F   &.6 )  :{2Y &C& # G:&@ 5%$0  $&7U- )8 " "+3a 93R " T,&22)I *.x!!4>72"/&/'.'&++".546?3237632'&'7#"&54746?6?22?4'#"&"%! $o 6D C  '<%4   021( @5, .2|:8;  6D*: Y&!  $% (4>*/()/$ .i!!'.'&++".546?3237632'&'7#"&54746?6?27/&=4'4e/ $o 6D C  '<%4   021( @4   :.2 ;  6D*: Y&!  $% (4>*/9 *_T 5%$0 4>72"/&//&+""#"&5474?36;2;25'./7>54&#""&5?>32!!2?4'#"&"%!#i PD2-(2 e;0O&ID, /  $ .5)+Q- R )+4, :8s&Q7 : 2%(D h?# ))K;!8+   P ,27 /$jz%/&=4'4'/&+""#"&5474?36;2;25'./7>54&#""&5?>323#7 : +#i PD2-(2 e;0O&ID, /  $ .5)+Q- R +  &@ 5%$0  &Q7 : 2%(D h?# ))K;!8+   P ,2 *. T7654'5.#"&/./#"&/46?23257>54'#"&547#5!!>763 c8 48 >!#6' 2)19ES722W(:7/k7?3'&/47'#5!!>?2?4'#"&54>72"/&/'"/&#"#"/&/57)  K 4- A! .Eo FI"&U 6, #%!& ({@   $=GM!15J33<5@*/$ :6n)8, ,9/]7?3'&/47'#5!!>?7/&=4'4''"/&#"#"/&/57)  K 4- A! .Eo FI"&U   : 5 ({@   $=GM!15J22<5@  *_S 5%$0 9)8, ,9474672"/&//&+""#".547474?23;25'./7"/474632#"'"/32?5!!2?4'#"&541(&WA~*"%!a  *-.* I <:;~C+/ ! }V0/, y!+d !:6u% 9)  9 4!-O^. / &IB2:/$P4w/&=4'4'/&+""#".547474?23;25'./7"/474632#"'"/32?5!#71(&WA : .a  *-.* I <:;~C+/ ! } /  y!+d &@ 5%$% 9)  9 4!-O^. / &IB2 *1.##"/&/./&'3;2?674&'"&5463273265./##"&467'&'#"&54632>5654.#!5!! )  /. <.,-"%. '( !!  #)D>)&*2&*g 16'5#,&  - a\)(" )"  $#JI'#(#,@ 22/4>72"/./'"/&#"#"/&/57?3'&/47'5.+"#"&546325!5!!>?2?4'#"&#% !0$ )z@ !  K 4- A! .E1&0(3-  FI"&U 6,  :8-i)8, ,9  $=MG!15JR  0+*1- 22<5@ */$U/v46325!5!!>?7/&=4'4''"/&#"#"/&/57?3'&/47'5.+"#"&F0(3- U FI"&U   : ; )z@ !  K 4- A! .E1&r*1- 22<5@ *_S 5%$0 7)8, ,9  $=MG!15JR  0+p '&#"27&4>72"/&'/&+"""#".5474?332732;2&5./'764&#"#"&54?>32'5!!2?4'#"&/O"> v#%!&$T  /A 4/*1 ! G+   ,A)*I,  9,  @M uZ:6&-* 8 E.* ,$4. ~  2-/$ p ~'&#"27&"&54?>32'53#7/&=4'4'/&+"""#".5474?332732;2&5./'764&#"/O"> v  ,A)*I,  7   :3$T  /A 4/*1 ! G+  @M ub,$4. ~  2 *_T 5%$ &-* 8 E.* p '&#"27&"&54?>32'5!!2?4'#"&54>72"/&//.#"'.+"&546732#"./&54632>;25&5./'764&#"/O"> v  ,A)*I,   /0, "%!# # ' %!, +-&! G+  @M ub,$4. ~  2 :/$ :60 + $#  A$7E.* p '&#"27&"&54?>32'53#7/&=4'4'/.#"'.+"&546732#"./&54632>;25&5./'764&#"/O"> v  ,A)*I,  7   :3# # ' %!, +-&! G+  @M ub,$4. ~  2 *_T 5%$ 0 + $#  A$7E.* .s74>72"/&//&+"#".547474?36;2;2335'&/.#'?675!5!!2?4'#"&RK*" >#%!`  )9 -)&    !+0#@   !+0#@;25'&/.#'?675!5!!2?4'#"&54>72"/&//.#"/&+"&546732#"&54632RK*" >  !+0#@;25'&/.#'?675!5!#7/&=4'4'/.#"/&+"&546732#"&54632RK*" >  !+0#@72"/&//./#".=46?725#"/&54?6322?6322?4'#"&"%! 3L' )g'; 0 =C"  89  5 5, .2|:8!56& 0 & 1+  :?  +  )/$ .a!!/./#".=46?725#"/&54?6322?6327/&=4'4b6 3L' )g'; 0 =C"  89  5 9   :.2!56& 0 & 1+  :?  +  *_T 5%$p '&#"27&2754754&'#%472"/&'/&+"""#".5474?332732;2'&/'764&#"+"/+#"&54727256=4&+5!#632'5!!2?4'#"&PO"> v$  %.M%!1$T  /A 4/, 0 G+ A)&*#0<z& 6b*I,  6,  @M u` .L 2:6'&,* 7 21.*F#% 4 -22F$4. ~  2*/$ p '&#"27&2754754&'#7632'53#7/&=4'4'/&+"""#".5474?332732;2'&/'764&#"+"/+#"&54727256=4&+5!#PO"> v$  %p6b*I,  5   :1$T  /A 4/, 0 G+ A)&*#0<z& @M u` .LnF$4. ~  2 *_S 5%$0  &,* 7 21.*F#% 4 -22.4>72"/&/./&/#&#.'&=46?32225'./"/4?6724&/&/&/#5!!2?4'#"&D   a"%!"4o/' gH 3 , 9+ *-  85, : %  &]|:8-  #>"  7 ,   /8 22)/$ .{./&/#&#.'&=46?32225'./"/4?6724&/&/&/#5!#7/&=4'4D   n."4o/' gH 3 , 9+ *-  83   :: %  &] -  #>"  7 ,   /8 22 *_T 5%$0 {. S72#"&54674>72"/&//./&#'76?675!5!!2?4'#"&'5,'D4*V"%! -4.%-AZ U(1{40, $#4- :8 S6Y; (!22> /$ ?. H72#"&5467/&=4'4'/./&#'76?675!5!#7'5,'D4* : /-4.%-AZ U(1?1  $#4- &@ 5%$0  S6Y; (!22 */'463275.#"'&/"&725!5!##".'&/3265'#"'46;3>54&'.#"73'7674#".54>7.=632767   (%* +:/ /zY 1*-7P<#$!# 3-$$#-5  & /7 !   $7:G A() Y4  2%    R8%** Bt33 + </+)7EC 69$%  0  A=&4 1(/    9 `& YU2?674&'&/&/+"/+&54?67//724?6;37#"&/&/&/&/32>?'#"&'4>n%.    1+ ?    + #  ^  ; $#RK", )f HR    &  '   0h& ; 2E&(,.#NEF+b0*K "4>72"/&//&+"""#".5474?36;2;24&#"#"/#"&/46?67/&+'32>?2'5!!2?4'#"&"%!$T  /A 4/ *3D % +#  1  A2g#  1  4, :8&,* 8 1;Z  #"   * 2 E'#u  2)/$ %/&=4'4'/&+"""#".5474?36;2;24&#"#"/#"&/46?67/&+'32>?2'53#75 :-$T  /A 4/ *3D % +#  1  A2g#  1 1  &@ 5%$ &,* 8 1;Z  #"   * 2 E'#u  2 *4&#"#"/#"&/46?67/&+'32>?2'5!!2?4'#"&54>72"/&//.#"./&+"&5463632#"./&5463246;2D % +#  1  A2g#  1  5, "%!#  *  "!1'4! gZ  #"   * 2 E'#u  2 )/$ :80   +"    ;?4&#"#"/#"&/46?67/&+'32>?2'53#7/&=4'4'/.#"./&+"&5463632#"./&5463246;2D % +#  1  A2g#  1 4   :.#  *  "!1'4! gZ  #"   * 2 E'#u  2 *_&@ 5%$ 0   +"    ;?p#.72654/&'""32?654/&#%'&#"27&4>72"/&//&+"""#".5474?332732;2'&/'764&#"#"'#"'".547#5!632'5!!2?4'#"&549 [   '"  BO"= v %%!$T  /A 4/*0 G+ 6()8y|)2*I,   .1, _ # 2 @M uH:6&,* 8 21.* &4'142$4. ~  2 :/$p#.72654/&'""32?654/&#%'&#"27&'632'53#7/&=4'4'/&+"""#".5474?332732;2'&/'764&#"#"'#"'".547#5!9 [   '"  BO"= v)2*I,  5   :1$T  /A 4/*0 G+ 6()8y|_ # 2 @M uA$4. ~  2 *_S 5%$0  &,* 8 21.* &4'142:. ~2654&+7###"&'3;2>74&'"&5463273265./#"#"&5467&5#"/&5732654+5! *x**`$  /YC,- 1-, '!! 4"'QC4  '0 :$; d-%  1# i \ /( " -""*(N -(!#D22.76?2'4>72"/&'./&/#"&/.54?3225/&#""/&/72?&5.#"/#5!!2?4'#"&-^#%!(""4o5' KgA&  (.  !  A '* 6,  7  4|:8l- < " 0! #:A&%  W  22*/$.x76?2'/&=4'4'./&/#"&/.54?3225/&#""/&/72?&5.#"/#5!#7- : 3""4o5' KgA&  (.  !  A '* 3  7  4&@ 5%$0 - < " 0! #:A&%  W  22 *.76?2'.#"/#5!!2?4'#"&54>72"/&//.#"/&+"&5463632#".5&5463246;25/&#""/&/72?&- '* 6, #%!#  '  )-+4!  (.  !  A7  4{  22*/$ :6z0   +   !  B?* #:A&%  W.76?2'.#"/#5!#7/&=4'4'/.#"/&+"&5463632#".5&5463246;25/&#""/&/72?&- '* ,   : +#  '  )-+4!  (.  !  A7  4{  22 *_T 5%$ 0   +   !  B?* #:A&%  W\p>7#'3?654&#'&#"27&4>72"/&//&+"""#".5474?332732;2&5./'7654&#"##".'#"/&5732654+5!632'5!!2?4'#"& )+ !) O"# v"%!$T  /A 4/*1 ! G+    67  $ 0 ):v@  +4,   ;  $$ @" uR:8&,* 8 E.  8% !#D2  ~  27 /$p>7#'3?654&#'&#"27&&#".'#"/&5732654+5!632'53#72/&=4'4'/&+"""#".5474?332732;2&5./'7654&#" )+ !) O"# v#67 < $ 0 ):v@  76 :3$T  /A 4/*1 ! G+    ;  $$ @" ub 8%*VD2  ~  2-&@ 5%$0  &,* 8 E. \p7264&+%'&#"27&%4+5!632'5!!2?4'#"&54>72"/&//.#"'.+"&546732#"./&54632>;25&5./'764&#"##"&5#"/&57326e *x)+HO"> v %9*I,  +4, "%!# $ * %!, +-&! G+   6M  $ 0d"$; @ @M u2$4. ~  27 /$:80 +" $#  A$7E.*  W!#Dp7264&+%'&#"27&%4+5!632'53#7/&=4'4'/.#"'.+"&546732#"./&54632>;25&5./'764&#"##"&5#"/&57326e *x)+HO"> v %9*I,  5   :1# $ * %!, +-&! G+   6M  $ 0d"$; @ @M u2$4. ~  2 *_T 5%$ 0 +" $#  A$7E.*  W!#Dw.GK'&/&/&/32?6?654&//674&/"2+&#.5?6?27%!!HW$>"EH&M31FF&%  I  -  KINe3;K! +u= 10 }   0 _    > XI2X.W27/&=4'4''&/&/;726?654&#"#"&=46?654&'#5!!V8   :7 ?82, D6I6Xh7!V = @)"& X:9 *_T 5%$0 %.  HD80 4 &$&1  22.M&/.'574>72"/&'/&/.#'?675!5!!2?4'#"&@(81' &7K*" e#%! + %2!+0#@72"/&//&/.#'?675!5!!2?4'#"&= >!B%'RK*" >"%! %2!+0#@!B%'RK*" > :2 %2!+0#@72"/&/./&/#&#&5?35'&/.#'?675!5!!2?4'#"& >!!S:RK*" >#%! (y. %8g82  !+0#@!!S:RK*" >%8g82  !+0#@54'#"&547#5!K$.?4Mi /H '7(/ }[*FJ)<,$9S2 %,9E?!5!#"+&+"#"'#"&#"'546?65'&/.+"#"&54: *  /P!,PS/tE*3') -*!'$3n3$? B&!g P;>+: B222& h !"'@& $3n   -).'#326?65'&546?#76325!#"+&+"#"'#"&#"'546?65'&5467.'#5"'#""#"/#"&54?4/A  / *  /P!,,% B*(") -*    !!&0,-  A$3n1&? B&!g P8'22& h !"8@$3n3$8  '5"+"3.$G72654/&'""32?654/&#326?65'&546?#47#5!#"+&+"#"'#"&#"'546?65'&5#"'".% S   '" B / *  /P" 8yGB*(") -* 8()_   2U$3n3$> B& h P|14213&!g # 8@$3n()4.-g7#3?654&#4>7#32>5'&/&7"#"'"'54>5/&=#"&5#"/&5732654+5!)+ !0P!$) &.  Z (AB"0 !(!  6M  $ 0  ;  $*8?& +@> 2! 25[+>Q%2J% ."n1&Y !#D22.U3274&=4>7!2%"#"'./;726?654&#"#"&546?654'#5!|7-A*$!i *#[EJE KB}7W) 9+/!%&&*>B' 7S %U~ V7C[^DH 4!2 22^F. <3#4&#/./76?6?675!5!#72#"/4?2[N3 6@?P$P: 4W4E,2 *'L :w0!   !&-G?}-Rq,-6-U  '22&wV)3 ^>3#2?#/&/&/?>54/#"&=6N30L< = - SV   MvS*%&)= +C'!!-H4 3<- #(2 Lg / ( *0E?3#3#'./&#?'>54&#"#"&54>32/&=N3W[-.-*1 !%  :R K &>)W8% :-2-)4+*+ ."AY*)(/ 8%P77Lt..3#267#""&54?#5!#/./767N3i, 61J$(E!$#B 3^]0B03> 5W G#x+"4) 224.HD2GZ3#4#"37>#"'#'./32654'#"&'5./7632#"'2?,N3 0 '- "2'%'_# Lt7D #, ;CJ) (U3K;"80 g 19,+? GK-50vD;7- 9y :M b %2 Z"^.63#26?6?6=/&/&'#'.5#5!!N31  "$-? .H^!1 /CFn22  !  3.P3#;6?65/&/2&/&/;272?654/#'.=#5!!;7,N3  . %,(8-'96btL  "  >)-8"76'h& \0' 3O"22 ^.p3#"&546?#5!!3732?"/&5467'"&/&#"376?6363232#"./&/5732>54&'N3G2@p/2  /K7&(   "^ 3 % :  :&'D,   _/01  *!T,&22)Me*&7U z2Y &C& # G &. 4++3a 93R " ^73#/&/&'/.'&/76?5!5!;#N3 U#5! l6Ce.,[d 9S!7 4074/"&46327654&+"7#"&//./#+"&/&=?32'&#"72+"5463>32N3 #  #&  !u L' #*e!?(LeMB+9 !+ TD9c0$I8V  .!##f. &Q4,: H, -#+- &&4""H 0( \> &p!jH^I3#23!3267"&57632#"&/#5!74+"#".546?N3@PO%h%4"2 /( 4 ;;DO -B   !]H42f038.6#  +/);22' %   ^_O3#4'32>3##'.547>54'#535./.547N3|=  '2#y '$а  @7$617& 5!RM*A #)UF )413 D'A%*; #- .E%'3  #Z:*^#.53##"/5#5!!26?#"/&/32675&,N3N_& #B 0'TK9"#:;!^.$3#26?"&57>32"'#5!!N3] $ $H;*+-J!N Q##  6Bl$Pc22^$;3#"&546?2'&=7'3#'4&/"/4632#;N35HE2%    G^6C,'5%0&!ZD>L   2KH 2289V 9* '-^y.P3#!!2>=4/.#""/4?63#"/&/&/&/&'N3@F9"  + 2=!3x+' j A  XN?3#3#'./7>54&#""&5?>32eN3WT>e;0O&ID, /  $ .5)+Q- R ' ,2X(D h?# ))K;!8+   P [I.-3#'#5!!>?/&/54`N3AmC3uCC%&W# $kBE22 ;0A5F*#5  3'%<*&'=/4 73#'32?53#/.'&/7"/474632#"'"/FN31(&WA! }T  n"<;~C+/ B<!+d N&IB23!dO^. / D3.)3#46;3!5!#'74.##'&'JN3H1  %'W1^4 "8 ;3@ %=  228p % #@Dp@3#'&#"27&"&54?>32'53#'&5./'764&#"N3O"> v  ,A)*I,  DO0! G+ ; @M ub,$4. ~  2-E.* Nr.C3#232?4&/"/&/&#'?'&/&/#5!!6;2#".'47_N3/  ?#24H:._" r5H={,5" 0;(/%$1 ,x?)%S1M 22N3RK*" >o %2!+0#@2F,j<  MC %=X(]'!NU.93#/&/"/4?6724&/&/&/#5!#lN3bC   0 L , 9+ *.  X19 5%  &\-P,   /8 22DA.+3#'.'&#'?'&/#5!#XN3 " ! & 5)2X99D+k.&"W; &! * !3~/n T-U  22N.33#2#"&546/./&#'76?675!5!#3N35,'D4*'-4.%-AZ U(1X184- $#S6Y; (!22Hj/B3#46725!5!#'4&#'./"&54632#"/.57>32N3, `4)! 1  % )&(9?"$ 7F)'331,3"$ &" + C7!1;N{M3#4&#"#"/#"&/46?67/&+'32>?2'53#'N3D % +#  1  A2g#  1 CV61Z  #"   * 2 E'#u  2.LC/73#'&'7'54.'#5!#/.#&+'?/#".ZN3# /'/8)[{3 D|&3 1!'$% 334(^Xk Hq.?3#76?2'.#"/#5!#'5/&#""/&/72?&N3p- '* f0  (.  !  A77  4{  229 #:A&%  W[.D3#'&/&/;726?654&#"#"&=46?654&'#5!#2N34AK2, D6I6Xh7!V = @)"& !i$1F  HD80 4 &$&1  22S^y.P3#'#"&54>72+"'#"&/&/326?654'#"/5#5!!76?63N3#%eH>P2  $D#)M",5" &# A!n    YqNb%&$JK)3B2) %"K 22#- q^.13#'#"&54632'326?"&5763"/#5!!/N3! * o W$ 1! eA,$K!)!$! M'!4H6sX>22K?.23##"&54632'&#'76?.'&'#5!#VN3 J $, b'b #'OC.7$?b4M 2;HT'$sU,+*22K). -3#&/.'5/&/.#'?675!5!#@N3(81' &7K*" 1 %2!+0#@!B%'RK*" >o %2!+0#@3>32.   %  &  &9  %. ,+ L   2 !H `'??M  n  -$ ( ,Y &. ?$   $<  |;2`753##"/&/&'46?27654/./57672"&54?>3632#"&/2654.'4X"*   $2 G" ! $G  4,1] L*+6 ??R$/  ": 1  PB!2E,0@D#'/ +o!  Lh7"7654&#"4&#"#32753'27654/./57672#"/&'467"&5467&54>372&1"/O=6 .. $[+, L $V(- /;'%B8)&5$#. &"1?? 'H  '->% .'': 1>+,0" 't@,or7"&54?>;2#"&/2654.'2'#53'&/&/&/3272?654'4&/&54>?6;'! $E ;(/] @.+7  "P % !.$ #"# &  "9 k)0 OB -}G,0Nt E"(hQ3  )', ,? m   *  n!  Tp7"7654&#"4&#"#32753&54?>;2#"&/2654.'".'"&5467&54>372&1"/O=6 . $E  7+._ K,2/  w(- %E'%B8)&5$#. &"1??=  MD!5~F,0' J(  .''4'1>+,0" 'h'L732?654/"723275'7&/"&/4?67 ++* 4  3=*!,7  +' 12*1 " .'+4>72"/&/52?4'#"&73##%!# 6, :6#5*/$ 2W'%27&#"2?67'"/"&5746 7   ';!;! ' vy+ 2.7/&=4'4'573#0 :;>  \&@ 5%$0 J *!2{|=&/?@8n)q*#0!?k2QP! $.594&'#'72?6;2+"/&'4>723265!!(%$  ,2.   2 4(  !!#5   (26/C3#26373#"'"&/./&/.'32>54/##"&/4666 &*M* .j$   (  <6*+ '/!3&1/2  !:'FRT#5 ;#  (e( -%%.60T3##"/&'3;2>74'"&54636;65./#"#"&54>72#66:/FB3K,- 1,- '!  4")"J45N 02Yi ;<\/( " - ##%"-!:.$ 16/;3#2/&#".5473263254&#"632+"&5467266.@ U .3 793$ >  +TD/2! =  ;*/142! *+)-8gE05&/47'5376?   $& <80).8!  4&+,>B#!R&Ф4)?6wE-8'4#"./6?6=37632/7'p + @9" * % ^&,0 / /( EQ -+J0$  U !  4.,"=&/&'#"&54632>5654.#!5!#":+ )&*2&*g !I'#(#,@ 226' %j*|%257/&/.#+"&546p6F0 '$-0_7X6( &!(#8.#'&+"#"&5463257H*1 $(#B4G8+,!V 9%2IPQ 25""&/&/6?637'<   X 4%& 6" !<d -fx7%7&#'763767 <"2Z$[9 G* h?E* N. /./&#'?675#5!#8RK*" L 6,"/-@3.# (  *43%4!n<30)  #+    :0:?f0'25/&#".#"'6=>32#"&=>;6.(  9 %!,:3*) )"(30 7@ #:%3/;25!5!#/.#"'&/"&'4632#"&'.=6327679/zY * +:/  : Y4  Bt33  ** %  `& .167';267'&'"6?4467#53##"/&F   #2 H6m)  T7 +V D  x  H >$J33 2"UH. .3?654#"&5#"/&5732654+5!)+ !<$&6M  $ 0 ;  $-% Z !#D22ea6/:3#2&/&/326=4'7'&#"#"&5475>?363666%P>N$ b/BB;:=W26x&T! @!$ 1'/2J75P%  Q.-B(""w&<% &; +-&( C%2674#""&54632;#"=4#"#"=4#6232>7>320,+"&;;.$:8 $& ""%F  %"'3.$*1)9"'1CI8Sd+0 O&6H-0 :! K-' )932?>74#""&54632;#"54#632;#"54#632E ) +4&;;.*48 &(&% &(&% 3.l*1)9(!4@K9TG&7N9TG&7N/T',32?>74#""&54632;#"54#632 ) 4':;.*48 &(&% 3 m*1)9(!1CH9TG&7N &.(7"&546?2&/&/"/4632#5H;<% '5%*,ZD2V  =9* '1.r +2#"/46?274&#/.#'6?F07'* G cO0-`i 8!!! r#E+6 %2/-GG#@!>+M_7"&54747467>7!5!656574&/#".5473723#3?>5.5467#+5)\h8  T(%9  f=?Sk   + !H 4-'N.$ ;8nG2% * (2|" ' !!   .D232>5'&/&'546?3#"'"'54>5&/&54?#5!B  N &.   /VY +84/!!(! /N<.;9e( 2! % 35- 8 BC)X@#)@& ."4B'82B22L.0%"#"'>54'#"&547#5!!>767  7@,2)19ES722W(:7 "8 ?r.FX"=&/&'#"&54632>5654.#!5!#/&/&/"/4?>724'"7#:+ )&*2&*g X > )  #6  !I'#(#,@ 22-*%     8" . %  &6'%; ,4&#".546323?632#"5pZlb% TB|&DK6#" &GfxJ2   O6J\ $8dA&# $Yt 7254&#"&54632#"&54&"!A-jAYxW6N4;6D*(*;*3V([!Z@1l*8;1(4'C'D','L'@'C'|')''"#'T''ez' ''P'_'\/:%+#"'>?67!"&54>73!.54632"7654&  F:# 9A =))GRq\68"@)Q9Fb8'.=2/(!% FVP&/5  #hUNd D0 NcMrLV=2B\)7%#!"&54>7;.54>2#"&746732>76&#" =))7>L~TP:=d%Kq2+h/*)2//5  2?6bHUMLIKJG aL>)!2+/ 41GX P%3276=!"%547#2>54&+#".54;547!"#32#"'&5&76.hMP;)Trb\<PM`Op4|8  $A=#Ӕr F(8J5{=K2Do-_++.G_Y.p`(CA$W 0 '2aBsdE}UJ%D [V7#"547!"#>3232654>732?2#"=!"54;>54&#"547#32?2.,G8  D-+3#M+!.,G#$5G7) #-%*!fMYW 0 '>4#I0Um &MYeA6H ,0&%&+*r&X+3?+327#"=47##".54;547!"+#547#3276=!" )Ds@b8# |8  OhMP;)`0##1/R ):4W 2 '++=K2Do-Xx327!32>54#"".543!654.#"3267#"&5463#"632#".54>3!+"6323254>7+byd[7)% VH&ZN1v33!+!1 1O, 'd &bJ,E$-BqE V ;FUV%^$)>+L:N58(.r.&4,49BCa2w1!-<3<.=S3S#;%bn/@O5LcR9.wbR7= >,EV@lX2#"'&54>76323276#"54&#"32>54&#"3267#"&54>76OAQ/G{NR)P_AX'p$G "4!DƢ.JQ*<9i?D3!8/F&' *!1)/u`-ZfM3gu}R!,I4ios&(2R5*326326323254>7+! '&543!6=4#"#".54>7&#"#".5467&#">32%"32654'&32>7!""32654'&E 0)# )!fEOj1JWknVk[mTr6$*=TqTpV4kP7P#9+M[&(kP7P#?:IUAi=*[5 &g!I 6$.:oo1BM!I 6$/9o.3 &- G(/'NellJgS<..//rQ47= ?+&3\4no Yp@^INo'& Yo@^IK0$*=L::#;C7+#"'&543!6!"32#9; R9J^&"BKm7|8  iN$ ))>GsFqFm3M>WN]++.C"2Do4B )BC"U2 'z7= >,Va&=R4g&( YKT23254>7+#".543!654&#"#"547#3262#"547!"+>!"326;:^$ ))>7qHr@)C+*.%*!.,G8  ZIEM5fcreB7= >,Wb-6'4;K_K )!X($+*r&(MYW 2 '/-R&)8C^\#"=#!"&54>73!2654>7327D =))D)R/5   ##1/Z\D%265#"#432+#"'&<>7632765!"&54>737MRNC^2dU,JzT 1 Z-_\*=)2Rvr'IV8Dfb>&{K)J2< eʌbj/04 !\5"=!"&'#"54>73274>7;2654>767326?D4,;Xh)AB))( -R"%Gd KeI   #  ,&XL%262#"547!"+632#"'&547632654&#"#"547#.,G8  )rBVCgv6i .Z;ui6" #-%*A(LYW 2 'krN^]?л #:V>aV^$EȝG7-X($+*r&X Zc%4#"3267#".54763232=4./632!254>7#!!"'&543!65&=4#">32!"326Z& :6)#Of=/J(HXR/tX%$*AC$)>BFqvq [51TyM9gpq!_GKhi,>N9ji5"ǭBI ^t{F7= ?+&>Q4+8؇z:KM&,7F[HT"=!"54>54.#">32#".54>32!2654>73274#"326pE@080*V91F:/G01U#99-F$/J\Z(;]7# -(7 ))Y'0 :7)"R )3pIKU: %:jD7,KV;V,/@P3BsM8#5HC#8dG- ##1/r)'$\F ]Q%265#"2>54&#""=!"&54>7;432+632#".54>>7MR#]lH-&%4=)D^1dV6Bu׵NqG"/2" W!7NSaU3Rv=)))(3r05 !r(JU7V32#".54>32>3!+"632#".5476! 7654&#"Z+ /)#C.,G _!.,Gq] [5*,#998N! 2L^W$u#22sV/U@WNcnjC,i S;v*09r" '- GD(LYv&(LZZru:!C.;V,BaGFvL6K&$, =pPciG#:RZf]0f  ,<}Ny1O[5]BK623254326323254>7+#"'&543!>54#"#"54#"#".53267!"O`%'N $ ))>Dq \*2&(QLF - 5[/DMh(0h44L[*7= >,&>Q4!Qk:;43yxw[/* )8DCY ]lv%4&#"32>6=4#"#".5467&#">32#".54>326323254>7+# 543"32654'&!"3 +/E7&% TpV4qP5L#=8JZBi<*[5 &iS8P 1JWpoUnY$ ))>Lt"G 6$/9o MFkR#2>.377(/o Zo@^IJ0'+,X_40D>H1iUB&*Z[547#"3276="+32>32!"#!"&54>7654&#""=&+#".54;547>)$. .>E2  KgT.9T44""-6*-DVQ$.=7<`9%|8b++25_2Co*2 'U83VD1L-  ("$$A>HoDPwi*@%+:5W ["=!"54;>54&#"#"547#32?2#"547!"+>3232654>7632#".546;2+"3 7654.#"327mD#$5G7) #-%*!.,G8  D-+3#M+>U$4 Ozʂ{.DP3-I J[V," &,)RFeA6H ,0($&+*r&MYW 2 '>4#I0Um @41/WZA*3=-(>!I3(F6* B##1/Xdlx%# '&54>32#"'32>54&#"32>75#"=47##".54;547!"+!+632%547#3276=!"%2654#"#^%>C%)*JBQ,cB%\kU1! 2$7 &Ds,LK,Op4|8   -R>RhMP;)%7M*;51eqW9bI! 8(HK<+&c0??A.&G 2.R 4H"(CA$W 2 '0~Jb++=K2Eo-)(4^V"BX2632#"5467#"+#".5463!654.#"3267#"&5463#"632#".54>3!+"632325463!+"32>54#"!"32>--H -)>!dvu?ZN1AAv 9',(+!1 1O, 'd &bJ,E$-BqE V 9S%:#%^$#P97)% VHMyS)MY06>,4K(&3*9B$IK.&]1! -<3<.=S3S#;%bn/@O5LcR9= 2FC%aR7,!4, '58(.r.L:6/^GW46&#"32>54&#"32673#"&54>7632#"'&5%632#"&74&#"#"326 ];Lյ+PO/9.<' /!10^EM,D]T-RMV ?.DN% 0('$+T;TI:rNI`v0E>3= K~^UL0g(g)8%RDA<%& &X%4&#"326262#"5&63#"+! '&543!6=4#"#".5467&#"#".5467&#">32#"&54>32632632325463!+"4&#"32632$7!""32654&(-.& 7'#)5--H -)>Wq8QXU!(?=-E$?:HV[8 W8;KhDOj 7LxIipWj^mVm6$$P"[%"GH9,68?)MY-6>,&3\4mo Yq@^IJ1&ZGh4-=N5J1#d>c9XHfll;QMC)..00rV37&9, 'A\CFr!(6QbCFuFqF0FBKm7|8  iN$$P3M=WNa++.C"2Do)+-Y-6>,Va&=R4gOM)CC"W 2 '{7&9, '?&( nYir%4&#"#"547#3262#"547!"+>3232547!+"3262#"5463#"+#"'&543!6!"326;2*.%*!--G8  Z!10$B P#,H-)>2VKFq%EM5djU )!X'#+*r&(NZW 2 '/--Z>d@7W ')+-Y-6>,5@(&=R40b&)8Ck\X3 7654.#"326?#"=!"&54>73!2654>7>32!"'.6'6;2+"[7[^4X#" .: -D=)D)+()< OR$0  3-! . ?/)4.#  ,&R<04 ! #  59\S&# ^!\CM%265#"%32767!"&54>7;432+#".54632#"'72654#"7MRuU1=)D^1dU.^1[jYU;$_VHJR:G-f$9M)92RvuL,04 !r(JU7Š7q 2Tm_D@PD= +2^O.> \[3 7654.#"32>7#"=!"&'#"54>73274>7;2654>7>32#".54;2+"\?ʻV#" ), )D4,;XhAB) (6άv,3-?(.?/)#I# 10RF"%Gd KeI ! ,7(s!X W2654#""'32654&#"#"547#3262#"547!"+632#"$&54>32$9M)7MI* .Urh5$ $-%*!.,G8  *u4Wѥ%>C%U)+2^N/>-=f*Zg[J,ˡC9-X($+*r&(LYW 2 'lZcybI!@IXv2632#"5463#"#!.'&543!65&=4&#">32#".54>3232=4./632!25463!+"%4&#"32>!"326=--H -)>rbq;P7W/! [5 &$99:V%=ds=2F&tW $*G=$$P+/E7&% zMagepP)MY-6?+GW =R4*7؇XQ-=Q3:#;%;V,Ws:VP("?9-ǭ$3& aq{>#7$;, '2>.377(/&0F[ %4#"3264>54.#">32#".547632!2654>7>32#"$&546;2+"3 7654.#"326?3#"=!"Y'0 :7)"a -, *V91F:/G01U#99-F$?m;\8# Y-7(4+; Oz˂_FO3-? \V#" &, -DAr)'$\Fs):`:KU: %:jD7,KV;V,/@P3eV"6KG&U# 53-UZB*+F8)I!7"(=0( B# 10RF\P\%265#"4&#""=!"&54>7;432+632# 54>32#"'3262654#"7MR.#%4=))hdV6Niw%>B&)*ICJ* e(v)$9M( 2Sv6&(3}.6  rvaX%32>54&#"%"3262#"5467#"3262#"54#"632#"&547632>3!+"632#".54>32#"'! $54&%2654#"7'% &0, 45!"/+G _!.,Es5L?3;^;K$K5SdCds%14sV /N>-!/GrvxB*92)*N>Q,rP5b%7M*;68'-.E#1&^7*LXx(*MY\r $8gAYXH!AE*mhaJ%%,CF3K/]eYR:"1Vk~u54#"#"54#"#".542325432632325463!+"3267!",H-)>GiqIq\*2&(QLF ,!a$&O$# P5\0GMQ)+-Y-6>,aX(=R4"Ir>;43vu[0+ (0h42ƎC7)7 'e)8AFBZ |%4#"3267#"&54>32632325463!+"32632#"5463#"+# 543!6=4&#"#".5467&#">324.#"326!"3 ZE 0)#OmONZ1JWpoUnY$# P%,H -)>LtUEC@2(?=-E$=8JZBi<*[5 &a)+"GH8-=:MFkR#q.3 &- GKR~\JgS<11r7'7')+-Y56>,X_4oj!ZGh4-=N5I1'+7;254326;.54>32#"&5473+">32#".546;2.+"!2>54&#"3254&, H Yc &(QL*E=))3n!CL=$$BrC[16D*AWI u'>+,@!8[}u8/8nGa?<DQ`B"x&"`ʹwP*,4(BA-E( +.Y@U43yvu4(/6  ?hE?R1;:'F?D8.9b/L+ )'@C$MYE)  $5 .?<<&+ !s-U]:Q,$'2%/]D0;X (4%4&#"326">54&547#3276=!"%+#"'676?#"54>54.#"632#"&547##".54;547!"+36323767.54>323254.9+/+ 0)#&8 O7 - A3jKP;(  $5Q< ." d 0!.D*6,>'=;H4( 4H" bML^G@b8# |8  [E$?F2 F(1='/E8-G'" b; 3@# &- F#3)Bc ,&)=Mʗ++=K2Do.(H'2 16'"&l#)P/:U*Q1.\pya$0):4V 2 ' #8b@M`*70 6Q.5M$*3%468  F'h$'('$','bY%7262#"54'&#"#"&54632y.,G:q&% IQ|vA]D!A(LYq#]n =  MGN[BoQ-&bD$7262#"54'&#"#"&54632y.,G:^TQ!"ObjucA(LY]#^;(0 E=J^-&&3h ' ]  Fe$,u f    N G 4h   H X$$ $H:$TCopyleft 2002, 2003, 2005 Free Software Foundation.Copyleft 2002, 2003, 2005 Free Software Foundation.FreeSerifFreeSerifMediumMediumFontForge 1.0 : Free Serif : 28-11-2006FontForge 1.0 : Free Serif : 28-11-2006Free SerifFree SerifVersion $Revision: 1.56 $ Version $Revision: 1.56 $ FreeSerifFreeSerifThe use of this font is granted subject to GNU General Public License.The use of this font is granted subject to GNU General Public License.http://www.gnu.org/copyleft/gpl.htmlhttp://www.gnu.org/copyleft/gpl.htmlThe quick brown fox jumps over the lazy dog.The quick brown fox jumps over the lazy dog.navadnoDovoljena je uporaba v skladu z licenco GNU General Public License.http://www.gnu.org/copyleft/gpl.html`erif bo za vajo spet kuhal doma e ~gance.2  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghjikmlnoqprsutvwxzy{}|~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~                           ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~        !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ softhyphenAmacronamacronAbreveabreveAogonekaogonek Ccircumflex ccircumflex Cdotaccent cdotaccentDcarondcaronDcroatEmacronemacronEbreveebreve Edotaccent edotaccentEogonekeogonekEcaronecaron Gcircumflex gcircumflex Gdotaccent gdotaccent Gcommaaccent gcommaaccent Hcircumflex hcircumflexHbarhbarItildeitildeImacronimacronIbreveibreveIogonekiogonekIJij Jcircumflex jcircumflex Kcommaaccent kcommaaccent kgreenlandicLacutelacute Lcommaaccent lcommaaccentLcaronlcaronLdotldotNacutenacute Ncommaaccent ncommaaccentNcaronncaron napostropheEngengOmacronomacronObreveobreve Ohungarumlaut ohungarumlautRacuteracute Rcommaaccent rcommaaccentRcaronrcaronSacutesacute Scircumflex scircumflexuni0162uni0163TcarontcaronTbartbarUtildeutildeUmacronumacronUbreveubreveUringuring Uhungarumlaut uhungarumlautUogonekuogonek Wcircumflex wcircumflex Ycircumflex ycircumflexZacutezacute Zdotaccent zdotaccentlongsuni0180uni0181uni0182uni0183uni0184uni0185uni0186uni0187uni0188uni0189uni018Auni018Buni018Cuni018Duni018Euni018Funi0190uni0191uni0193uni0194uni0195uni0196uni0197uni0198uni0199uni019Auni019Buni019Cuni019Duni019Euni019FOhornohornuni01A2uni01A3uni01A4uni01A5uni01A6uni01A7uni01A8uni01A9uni01AAuni01ABuni01ACuni01ADuni01AEUhornuhornuni01B1uni01B2uni01B3uni01B4uni01B5uni01B6uni01B7uni01B8uni01B9uni01BAuni01BBuni01BCuni01BDuni01BEuni01BFuni01C0uni01C1uni01C2uni01C3uni01C4uni01C5uni01C6uni01C7uni01C8uni01C9uni01CAuni01CBuni01CCuni01CDuni01CEuni01CFuni01D0uni01D1uni01D2uni01D3uni01D4uni01D5uni01D6uni01D7uni01D8uni01D9uni01DAuni01DBuni01DCuni01DDuni01DEuni01DFuni01E0uni01E1uni01E2uni01E3uni01E4uni01E5Gcarongcaronuni01E8uni01E9uni01EAuni01EBuni01ECuni01EDuni01EEuni01EFuni01F0uni01F1uni01F2uni01F3uni01F4uni01F5uni01F6uni01F8uni01F9 Aringacute aringacuteAEacuteaeacute Oslashacute oslashacuteuni0200uni0201uni0202uni0203uni0204uni0205uni0206uni0207uni0208uni0209uni020Auni020Buni020Cuni020Duni020Euni020Funi0210uni0211uni0212uni0213uni0214uni0215uni0216uni0217 Scommaaccent scommaaccent Tcommaaccent tcommaaccentuni021Euni021Funi0226uni0227uni0228uni0229uni022Auni022Buni022Cuni022Duni022Euni022Funi0230uni0231uni0232uni0233uni0235uni0237uni0250uni0251uni0252uni0253uni0254uni0255uni0256uni0257uni0258uni0259uni025Auni025Buni025Cuni025Duni025Euni025Funi0260uni0261uni0262uni0263uni0264uni0265uni0266uni0267uni0268uni0269uni026Auni026Buni026Cuni026Duni026Euni026Funi0270uni0271uni0272uni0273uni0274uni0275uni0276uni0277uni0278uni0279uni027Auni027Buni027Cuni027Duni027Euni027Funi0280uni0281uni0282uni0283uni0284uni0285uni0286uni0287uni0288uni0289uni028Auni028Buni028Cuni028Duni028Euni028Funi0290uni0291uni0292uni0293uni0294uni0295uni0296uni0297uni0298uni0299uni029Auni029Buni029Cuni029Duni029Euni029Funi02A0uni02A1uni02A2uni02A3uni02A4uni02A5uni02A6uni02A7uni02A8uni02A9uni02AAuni02ABuni02ACuni02ADuni02AEuni02AFuni02B0uni02B1uni02B2uni02BAuni02BB afii57929 afii64937uni02BEuni02BFuni02C9uni02CAuni02CBuni02CDuni02CEuni02CFuni02D4uni02D5uni02D6uni02D7uni02EE gravecomb acutecombuni0302 tildecombuni0304uni0305uni0306uni0307uni0308 hookabovecombuni030Auni030Buni030Cuni030Duni030Euni030Funi0310uni0311uni0312uni0313uni0314uni0315uni0316uni0317uni0318uni0319uni031Auni031Buni031Cuni031Duni031Euni031Funi0320uni0321uni0322 dotbelowcombuni0324uni0325uni0326uni0327uni0328uni0329uni032Auni032Buni032Cuni032Duni032Euni032Funi0330uni0331uni0332uni0333uni0334uni0335uni0336uni0337uni0338uni0339uni033Auni033Buni033Cuni033Duni033Euni033Funi0340uni0341uni0342uni0343uni0344uni0345uni0360uni0361uni0374uni0375uni037Auni037Etonos dieresistonos Alphatonos anoteleia EpsilontonosEtatonos Iotatonos Omicrontonos Upsilontonos OmegatonosiotadieresistonosAlphaBetaGammauni0394EpsilonZetaEtaThetaIotaKappaLambdaMuNuXiOmicronPiRhoSigmaTauUpsilonPhiChiPsiuni03A9 IotadieresisUpsilondieresis alphatonos epsilontonosetatonos iotatonosupsilondieresistonosalphabetagammadeltaepsilonzetaetathetaiotakappalambdauni03BCnuxiomicronrhosigma1sigmatauupsilonphichipsiomega iotadieresisupsilondieresis omicrontonos upsilontonos omegatonosuni03D0theta1Upsilon1uni03D3uni03D4phi1omega1uni03D7uni03DAuni03DBuni03DCuni03DDuni03DEuni03DFuni03E0uni03E1uni03F0uni03F1uni03F2uni0400 afii10023 afii10051 afii10052 afii10053 afii10054 afii10055 afii10056 afii10057 afii10058 afii10059 afii10060 afii10061uni040D afii10062 afii10145 afii10017 afii10018 afii10019 afii10020 afii10021 afii10022 afii10024 afii10025 afii10026 afii10027 afii10028 afii10029 afii10030 afii10031 afii10032 afii10033 afii10034 afii10035 afii10036 afii10037 afii10038 afii10039 afii10040 afii10041 afii10042 afii10043 afii10044 afii10045 afii10046 afii10047 afii10048 afii10049 afii10065 afii10066 afii10067 afii10068 afii10069 afii10070 afii10072 afii10073 afii10074 afii10075 afii10076 afii10077 afii10078 afii10079 afii10080 afii10081 afii10082 afii10083 afii10084 afii10085 afii10086 afii10087 afii10088 afii10089 afii10090 afii10091 afii10092 afii10093 afii10094 afii10095 afii10096 afii10097uni0450 afii10071 afii10099 afii10100 afii10101 afii10102 afii10103 afii10104 afii10105 afii10106 afii10107 afii10108 afii10109uni045D afii10110 afii10193FL96FL0461hFL0462hFL0463hFL0464hFL0465hFL0466hFL0467hFL0468hFL106FL046ChFL105FL046DhFL046FhFL046EhFL109FL046BhFL0471hFL0472hFL0473hFL0474hFL0475hFL0476hFL0477hFL0478hFL0479hFL047AhFL047BhFL124FL047DhFL126FL047FhFL0480hFL0481hFL0482hFL0483hFL0484hFL0485hFL0486hFL137FL0488hFL0489hFL048Ahuni048Cuni048Duni048Euni048F afii10050 afii10098uni0492uni0493uni0494uni0495uni0496uni0497uni0498uni0499uni049Auni049Buni049Cuni049Duni049Euni049Funi04A0uni04A1uni04A2uni04A3uni04A4uni04A5uni04A6uni04A7uni04A8uni04A9uni04AAuni04ABuni04ACuni04ADuni04AEuni04AFuni04B0uni04B1uni04B2uni04B3uni04B4uni04B5uni04B6uni04B7uni04B8uni04B9uni04BAuni04BBuni04BCuni04BDuni04BEuni04BFuni04C0uni04C1uni04C2uni04C3uni04C4FL04C5hFL198uni04C7uni04C8FL201FL202uni04CBuni04CCFL04CDhFL04CEhFL207uni04D0uni04D1uni04D2uni04D3uni04D4uni04D5uni04D6uni04D7uni04D8 afii10846uni04DAuni04DBuni04DCuni04DDuni04DEuni04DFuni04E0uni04E1uni04E2uni04E3uni04E4uni04E5uni04E6uni04E7uni04E8uni04E9uni04EAuni04EBuni04ECuni04EDuni04EEuni04EFuni04F0uni04F1uni04F2uni04F3uni04F4uni04F5uni04F8uni04F9FL0500hFL0501hFL0502hFL0503hFL0506hFL0507hFL0504hFL0505hFL0508hFL0509hFL050AhFL050BhFL050ChFL050DhFL050FhFL050Eh afii57801 afii57800 afii57793 afii57794 afii57795 afii57798 afii57797 afii57806 afii57796 afii57807 afii57842 afii57658 afii57664 afii57665 afii57666 afii57667 afii57668 afii57669 afii57670 afii57671 afii57672 afii57673 afii57674 afii57675 afii57676 afii57677 afii57678 afii57679 afii57680 afii57681 afii57682 afii57683 afii57684 afii57685 afii57686 afii57687 afii57688 afii57689 afii57690 afii57716 afii57717 afii57718uni05F3uni05F4 afii57388 afii57403 afii57407 afii57409 afii57410 afii57411 afii57412 afii57413 afii57414 afii57415 afii57416 afii57417 afii57418 afii57419 afii57420 afii57421 afii57422 afii57423 afii57424 afii57425 afii57426 afii57427 afii57428 afii57429 afii57430 afii57431 afii57432 afii57433 afii57434 afii57441 afii57442 afii57443 afii57444 afii57445 afii57446 afii57470 afii57448 afii57449 afii57450 afii57451 afii57453 afii57454 afii57455 afii57456 afii57457 afii57392 afii57393 afii57394 afii57395 afii57396 afii57397 afii57398 afii57399 afii57400 afii57401uni066Buni0674 afii57506 afii57507 afii57508 afii57509uni06CCuni06D4uni0780uni0781uni0782uni0783uni0784uni0785uni0786uni0787uni0788uni0789uni078Auni078Buni078Cuni078Duni078Euni078Funi0790uni0791uni0792uni0793uni0794uni0795uni0796uni0797uni0798uni0799uni079Auni079Buni079Cuni079Duni079Euni079Funi07A0uni07A1uni07A2uni07A3uni07A4uni07A5uni07A6uni07A7uni07A8uni07A9uni07AAuni07ABuni07ACuni07ADuni07AEuni07AFuni07B0uni0901uni0902uni0903uni0905uni0906uni0907uni0908uni0909uni090Auni090Buni090Cuni090Duni090Funi0911uni0913uni0914uni0915uni0916uni0917uni0918uni0919uni091Auni091Buni091Cuni091Duni091Euni091Funi0920uni0921uni0922uni0923uni0924uni0925uni0926uni0927uni0928uni0929uni092Auni092Buni092Cuni092Duni092Euni092Funi0930uni0931uni0932uni0933uni0934uni0935uni0937uni0938uni0939uni093Cuni093Duni093Euni093Funi0940uni0941uni0942uni0943uni0944uni0945uni0947uni0948uni0949uni094Buni094Cuni094Duni0950uni0958uni0959uni095Auni095Buni095Cuni095Duni095Euni0960uni0961uni0962uni0963uni0964uni0965uni0966uni0967uni0968uni0969uni096Auni096Buni096Cuni096Duni096Euni096Funi0970bn_candrabindu bn_anusvara bn_visargabn_abn_aabn_ibn_iibn_ubn_uubn_ribn_libn_ebn_aibn_obn_aubn_kabn_khabn_gabn_ghabn_ngabn_cabn_chabn_jabn_jhabn_nyabn_ttabn_tthabn_ddabn_ddhabn_nnabn_tabn_thabn_dabn_dhabn_nabn_pabn_phabn_babn_bhabn_mabn_yabn_rabn_labn_shabn_ssabn_sabn_habn_nukta bn_avagraha bn_aakaarbn_ikaar bn_iikaarbn_ukaar bn_uukaar bn_rikaar bn_rrikaarbn_ekaar bn_aikaarbn_okaar bn_aukaar bn_hasanta Khanda_Ta bn_aumarkbn_rrabn_rhabn_yyabn_rribn_lli bn_likaar bn_llikaarbn_zerobn_onebn_twobn_threebn_fourbn_fivebn_sixbn_sevenbn_eightbn_nine bn_asamira bn_asamiba bn_rupeemark bn_rupeesign bn_currency1 bn_currency2 bn_currency3 bn_currency4bn_currencyless bn_currency16 bn_issharuni0A05uni0A06uni0A07uni0A08uni0A09uni0A0Auni0A0Funi0A10uni0A13uni0A14uni0A15uni0A16uni0A17uni0A18uni0A19uni0A1Auni0A1Buni0A1Cuni0A1Duni0A1Euni0A1Funi0A20uni0A21uni0A22uni0A23uni0A24uni0A25uni0A26uni0A27uni0A28uni0A2Auni0A2Buni0A2Cuni0A2Duni0A2Euni0A2Funi0A30uni0A32uni0A33uni0A35uni0A36uni0A38uni0A39uni0A3Cuni0A3Euni0A3Funi0A40uni0A41uni0A42uni0A47uni0A48uni0A4Buni0A4Cuni0A4Duni0A59uni0A5Auni0A5Buni0A5Cuni0A5Euni0A66uni0A67uni0A68uni0A69uni0A6Auni0A6Buni0A6Cuni0A6Duni0A6Euni0A6Funi0A70uni0A72uni0A73uni0A74PulliAyuthamTamlATamlAATaml_ITaml_IITamlUTamlUUTamlETamlEETamlAITamlOTamlOOTamlAUTamlKATamlNGATamlCATamlJATamlNYATamlTTATamlNNATamlTATamlNATamlNNNATamlPATamlMATamlYATamlRATamlRRATamlLATamlLLATamlLLLATamlVATamlSSATamlSATamlHATaml_v_ATaml_v_I Taml_v_IITaml_v_U Taml_v_UUTaml_v_E Taml_v_EE Taml_v_AI Taml_vow_O Taml_vow_OOTaml_AUsTaml_pulTaml_AUuni0C02uni0C03uni0C05uni0C06uni0C07uni0C08uni0C09uni0C0Auni0C0Buni0C0Cuni0C0Euni0C0Funi0C10uni0C12uni0C13uni0C14uni0C15uni0C16uni0C17uni0C18uni0C19uni0C1Auni0C1Buni0C1Cuni0C1Duni0C1Euni0C1Funi0C20uni0C21uni0C22uni0C23uni0C24uni0C25uni0C26uni0C27uni0C28uni0C2Auni0C2Buni0C2Cuni0C2Duni0C30uni0C32uni0D02uni0D03uni0D05uni0D06uni0D07uni0D08uni0D09uni0D0Auni0D0Bl1uni0D0Euni0D0Funi0D10uni0D12uni0D13uni0D14k1k2k3k4ngch1ch2ch3ch4njt1t2t3t4nhth1th2th3th4n1p1p2p3p4m1y1r3rhl3lhzhv1z1shs1h1uni0D3Euni0D3Funi0D40u1u2r1uni0D46uni0D47uni0D48uni0D4Auni0D4Buni0D4Cxxuni0D57r2l2uni0D66uni0D67uni0D68uni0D69uni0D6Auni0D6Buni0D6Cuni0D6Duni0D6Euni0D6Funi0D70uni0D82uni0D83uni0D85uni0D89uni0D8Auni0D8Buni0D91uni0D94uni0D99uni0D9Auni0D9Buni0D9Cuni0D9Euni0DA0uni0DA1uni0DA2uni0DA4uni0DA5uni0DA7uni0DA8uni0DA9uni0DAAuni0DABuni0DADuni0DAEuni0DAFuni0DB0uni0DB1uni0DB3uni0DB4uni0DB5uni0DB6uni0DB7uni0DB8uni0DB9uni0DBAuni0DBBuni0DBDuni0DC0uni0DC1uni0DC2uni0DC3uni0DC4uni0DC5uni0DC6uni0DCAuni0DCFuni0DD0uni0DD1uni0DD2uni0DD3uni0DD4uni0DD6uni0DD8uni0DD9uni0DDFuni0E01uni0E02uni0E03uni0E04uni0E05uni0E06uni0E07uni0E08uni0E09uni0E0Auni0E0Buni0E0Cuni0E0Duni0E0Euni0E0Funi0E10uni0E11uni0E12uni0E13uni0E14uni0E15uni0E16uni0E17uni0E18uni0E19uni0E1Auni0E1Buni0E1Cuni0E1Duni0E1Euni0E1Funi0E20uni0E21uni0E22uni0E23uni0E24uni0E25uni0E26uni0E27uni0E28uni0E29uni0E2Auni0E2Buni0E2Cuni0E2Duni0E2Euni0E2Funi0E30uni0E31uni0E32uni0E33uni0E34uni0E35uni0E36uni0E37uni0E38uni0E39uni0E3Auni0E3Funi0E40uni0E41uni0E42uni0E43uni0E44uni0E45uni0E46uni0E47uni0E48uni0E49uni0E4Auni0E4Buni0E4Cuni0E4Duni0E4Euni0E4Funi0E50uni0E51uni0E52uni0E53uni0E54uni0E55uni0E56uni0E57uni0E58uni0E59uni0E5Auni0E5Buni10A0uni10A1uni10A2uni10A3uni10A4uni10A5uni10A6uni10A7uni10A8uni10A9uni10AAuni10ABuni10ACuni10ADuni10AEuni10AFuni10B0uni10B1uni10B2uni10B3uni10B4uni10B5uni10B6uni10B7uni10B8uni10B9uni10BAuni10BBuni10BCuni10BDuni10BEuni10BFuni10C0uni10C1uni10C2uni10C3uni10C4uni10C5uni10D0uni10D1uni10D2uni10D3uni10D4uni10D5uni10D6uni10D7uni10D8uni10D9uni10DAuni10DBuni10DCuni10DDuni10DEuni10DFuni10E0uni10E1uni10E2uni10E3uni10E4uni10E5uni10E6uni10E7uni10E8uni10E9uni10EAuni10EBuni10ECuni10EDuni10EEuni10EFuni10F0uni10F1uni10F2uni10F3uni10F4uni10F5uni1200uni1201uni1202uni1203uni1204uni1205uni1206uni1208uni1209uni120Auni120Buni120Cuni120Duni120Euni120Funi1210uni1211uni1212uni1213uni1214uni1215uni1216uni1217uni1218uni1219uni121Auni121Buni121Cuni121Duni121Euni121Funi1220uni1221uni1222uni1223uni1224uni1225uni1226uni1227uni1228uni1229uni122Auni122Buni122Cuni122Duni122Euni122Funi1230uni1231uni1232uni1233uni1234uni1235uni1236uni1237uni1238uni1239uni123Auni123Buni123Cuni123Duni123Euni123Funi1240uni1241uni1242uni1243uni1244uni1245uni1246uni1248uni124Auni124Buni124Cuni124Duni1250uni1251uni1252uni1253uni1254uni1255uni1256uni1258uni125Auni125Buni125Cuni125Duni1260uni1261uni1262uni1263uni1264uni1265uni1266uni1267uni1268uni1269uni126Auni126Buni126Cuni126Duni126Euni126Funi1270uni1271uni1272uni1273uni1274uni1275uni1276uni1277uni1278uni1279uni127Auni127Buni127Cuni127Duni127Euni127Funi1280uni1281uni1282uni1283uni1284uni1285uni1286uni1288uni128Auni128Buni128Cuni128Duni1290uni1291uni1292uni1293uni1294uni1295uni1296uni1297uni1298uni1299uni129Auni129Buni129Cuni129Duni129Euni129Funi12A0uni12A1uni12A2uni12A3uni12A4uni12A5uni12A6uni12A7uni12A8uni12A9uni12AAuni12ABuni12ACuni12ADuni12AEuni12B0uni12B2uni12B3uni12B4uni12B5uni12B8uni12B9uni12BAuni12BBuni12BCuni12BDuni12BEuni12C0uni12C1uni12C2uni12C3uni12C4uni12C5uni12C8uni12C9uni12CAuni12CBuni12CCuni12CDuni12CEuni12D0uni12D1uni12D2uni12D3uni12D4uni12D5uni12D6uni12D8uni12D9uni12DAuni12DBuni12DCuni12DDuni12DEuni12DFuni12E0uni12E1uni12E2uni12E3uni12E4uni12E5uni12E6uni12E7uni12E8uni12E9uni12EAuni12EBuni12ECuni12EDuni12EEuni12F0uni12F1uni12F2uni12F3uni12F4uni12F5uni12F6uni12F7uni12F8uni12F9uni12FAuni12FBuni12FCuni12FDuni12FEuni12FFuni1300uni1301uni1302uni1303uni1304uni1305uni1306uni1307uni1308uni1309uni130Auni130Buni130Cuni130Duni130Euni1310uni1312uni1313uni1314uni1315uni1318uni1319uni131Auni131Buni131Cuni131Duni131Euni1320uni1321uni1322uni1323uni1324uni1325uni1326uni1327uni1328uni1329uni132Auni132Buni132Cuni132Duni132Euni132Funi1330uni1331uni1332uni1333uni1334uni1335uni1336uni1337uni1338uni1339uni133Auni133Buni133Cuni133Duni133Euni133Funi1340uni1341uni1342uni1343uni1344uni1345uni1346uni1348uni1349uni134Auni134Buni134Cuni134Duni134Euni134Funi1350uni1351uni1352uni1353uni1354uni1355uni1356uni1357uni1358uni1359uni135Auni1361uni1362uni1363uni1364uni1365uni1366uni1367uni1368uni1369uni136Auni136Buni136Cuni136Duni136Euni136Funi1370uni1371uni1372uni1373uni1374uni1375uni1376uni1377uni1378uni1379uni137Auni137Buni137Cuni1D00uni1D03uni1D05uni1D07uni1D0Buni1D0Cuni1D0Duni1D0Euni1D1Buni1D1Cuni1D20uni1D21uni1D22uni1D29uni1D81uni1D84uni1D85uni1D87uni1D8Duni1E00uni1E01uni1E02uni1E03uni1E04uni1E05uni1E06uni1E07uni1E08uni1E09uni1E0Auni1E0Buni1E0Cuni1E0Duni1E0Euni1E0Funi1E10uni1E11uni1E12uni1E13uni1E14uni1E15uni1E16uni1E17uni1E18uni1E19uni1E1Auni1E1Buni1E1Cuni1E1Duni1E1Euni1E1Funi1E20uni1E21uni1E22uni1E23uni1E24uni1E25uni1E26uni1E27uni1E28uni1E29uni1E2Auni1E2Buni1E2Cuni1E2Duni1E2Euni1E2Funi1E30uni1E31uni1E32uni1E33uni1E34uni1E35uni1E36uni1E37uni1E38uni1E39uni1E3Auni1E3Buni1E3Cuni1E3Duni1E3Euni1E3Funi1E40uni1E41uni1E42uni1E43uni1E44uni1E45uni1E46uni1E47uni1E48uni1E49uni1E4Auni1E4Buni1E4Cuni1E4Duni1E4Euni1E4Funi1E50uni1E51uni1E52uni1E53uni1E54uni1E55uni1E56uni1E57uni1E58uni1E59uni1E5Auni1E5Buni1E5Cuni1E5Duni1E5Euni1E5Funi1E60uni1E61uni1E62uni1E63uni1E64uni1E65uni1E66uni1E67uni1E68uni1E69uni1E6Auni1E6Buni1E6Cuni1E6Duni1E6Euni1E6Funi1E70uni1E71uni1E72uni1E73uni1E74uni1E75uni1E76uni1E77uni1E78uni1E79uni1E7Auni1E7Buni1E7Cuni1E7Duni1E7Euni1E7FWgravewgraveWacutewacute Wdieresis wdieresisuni1E86uni1E87uni1E88uni1E89uni1E8Auni1E8Buni1E8Cuni1E8Duni1E8Euni1E8Funi1E90uni1E91uni1E92uni1E93uni1E94uni1E95uni1E96uni1E97uni1E98uni1E99uni1E9Auni1E9Buni1EA0uni1EA1uni1EA2uni1EA3uni1EA4uni1EA5uni1EA6uni1EA7uni1EA8uni1EA9uni1EAAuni1EABuni1EACuni1EADuni1EAEuni1EAFuni1EB0uni1EB1uni1EB2uni1EB3uni1EB4uni1EB5uni1EB6uni1EB7uni1EB8uni1EB9uni1EBAuni1EBBuni1EBCuni1EBDuni1EBEuni1EBFuni1EC0uni1EC1uni1EC2uni1EC3uni1EC4uni1EC5uni1EC6uni1EC7uni1EC8uni1EC9uni1ECAuni1ECBuni1ECCuni1ECDuni1ECEuni1ECFuni1ED0uni1ED1uni1ED2uni1ED3uni1ED4uni1ED5uni1ED6uni1ED7uni1ED8uni1ED9uni1EDAuni1EDBuni1EDCuni1EDDuni1EDEuni1EDFuni1EE0uni1EE1uni1EE2uni1EE3uni1EE4uni1EE5uni1EE6uni1EE7uni1EE8uni1EE9uni1EEAuni1EEBuni1EECuni1EEDuni1EEEuni1EEFuni1EF0uni1EF1Ygraveygraveuni1EF4uni1EF5uni1EF6uni1EF7uni1EF8uni1EF9uni1F00uni1F01uni1F02uni1F03uni1F04uni1F05uni1F06uni1F07uni1F08uni1F09uni1F0Auni1F0Buni1F0Cuni1F0Duni1F0Euni1F0Funi1F10uni1F11uni1F12uni1F13uni1F14uni1F15uni1F18uni1F19uni1F1Auni1F1Buni1F1Cuni1F1Duni1F20uni1F21uni1F22uni1F23uni1F24uni1F25uni1F26uni1F27uni1F28uni1F29uni1F2Auni1F2Buni1F2Cuni1F2Duni1F2Euni1F2Funi1F30uni1F31uni1F32uni1F33uni1F34uni1F35uni1F36uni1F37uni1F38uni1F39uni1F3Auni1F3Buni1F3Cuni1F3Duni1F3Euni1F3Funi1F40uni1F41uni1F42uni1F43uni1F44uni1F45uni1F48uni1F49uni1F4Auni1F4Buni1F4Cuni1F4Duni1F50uni1F51uni1F52uni1F53uni1F54uni1F55uni1F56uni1F57uni1F59uni1F5Buni1F5Duni1F5Funi1F60uni1F61uni1F62uni1F63uni1F64uni1F65uni1F66uni1F67uni1F68uni1F69uni1F6Auni1F6Buni1F6Cuni1F6Duni1F6Euni1F6Funi1F70uni1F71uni1F72uni1F73uni1F74uni1F75uni1F76uni1F77uni1F78uni1F79uni1F7Auni1F7Buni1F7Cuni1F7Duni1F80uni1F81uni1F82uni1F83uni1F84uni1F85uni1F86uni1F87uni1F88uni1F89uni1F8Auni1F8Buni1F8Cuni1F8Duni1F8Euni1F8Funi1F90uni1F91uni1F92uni1F93uni1F94uni1F95uni1F96uni1F97uni1F98uni1F99uni1F9Auni1F9Buni1F9Cuni1F9Duni1F9Euni1F9Funi1FA0uni1FA1uni1FA2uni1FA3uni1FA4uni1FA5uni1FA6uni1FA7uni1FA8uni1FA9uni1FAAuni1FABuni1FACuni1FADuni1FAEuni1FAFuni1FB0uni1FB1uni1FB2uni1FB3uni1FB4uni1FB6uni1FB7uni1FB8uni1FB9uni1FBAuni1FBBuni1FBCuni1FBDuni1FBEuni1FBFuni1FC0uni1FC1uni1FC2uni1FC3uni1FC4uni1FC6uni1FC7uni1FC8uni1FC9uni1FCAuni1FCBuni1FCCuni1FCDuni1FCEuni1FCFuni1FD0uni1FD1uni1FD2uni1FD3uni1FD6uni1FD7uni1FD8uni1FD9uni1FDAuni1FDBuni1FDDuni1FDEuni1FDFuni1FE0uni1FE1uni1FE2uni1FE3uni1FE4uni1FE5uni1FE6uni1FE7uni1FE8uni1FE9uni1FEAuni1FEBuni1FECuni1FEDuni1FEEuni1FEFuni1FF2uni1FF3uni1FF4uni1FF6uni1FF7uni1FF8uni1FF9uni1FFAuni1FFBuni1FFCuni1FFDuni1FFE afii61664afii301uni2010uni2011 figuredash afii00208 underscoredbl quotereverseduni201Funi2023uni2031minuteseconduni2034uni2035uni2036uni2037uni2038uni203B exclamdbluni203Duni203Euni203Funi2040uni2041uni2042uni2043uni2045uni2046uni2047uni2048uni2049uni204Auni204B zerosuperioruni2071 foursuperior fivesuperior sixsuperior sevensuperior eightsuperior ninesuperioruni207Auni207Buni207Cuni207F zeroinferior oneinferior twoinferior threeinferior fourinferior fiveinferior sixinferior seveninferior eightinferior nineinferioruni208Auni208Buni208Cuni20A0 colonmonetaryuni20A2lirauni20A5uni20A6pesetauni20A8uni20A9Eurouni20AFuni20B2uni20DDuni2102uni2103 afii61248uni2109uni210Auni210Buni210Cuni210Duni210Euni210Funi2110Ifrakturuni2112 afii61289uni2115 afii61352uni2117 weierstrassuni2119uni211Auni211BRfrakturuni211D prescriptionuni211Funi2120uni2123uni2124uni2126uni2127uni2128uni212Auni212Buni212Cuni212D estimateduni2130uni2131uni2132uni2133alephuni2136uni2137uni2138uni2139onethird twothirdsuni2155uni2156uni2157uni2158uni2159uni215A oneeighth threeeighths fiveeighths seveneighthsuni215Funi2160uni2161uni2162uni2163uni2164uni2165uni2166uni2167uni2168uni2169uni216Auni216Buni216Cuni216Duni216Euni216Funi2170uni2171uni2172uni2173uni2174uni2175uni2176uni2177uni2178uni2179uni217Auni217Buni217Cuni217Duni217Euni217F arrowleftarrowup arrowright arrowdown arrowboth arrowupdnuni2196uni2197uni2198uni2199uni219Auni219Buni219Cuni219Duni219Euni219Funi21A0uni21A1uni21A2uni21A3uni21A4uni21A5uni21A6uni21A7 arrowupdnbseuni21ABuni21ACuni21ADuni21AEuni21B0uni21B1uni21B2uni21B3uni21B4carriagereturnuni21B6uni21B7uni21BAuni21BBuni21BCuni21BDuni21BEuni21BFuni21C0uni21C1uni21C2uni21C3uni21C4uni21C5uni21C6uni21C7uni21C8uni21C9uni21CAuni21CBuni21CCuni21CDuni21CEuni21CF arrowdblleft arrowdblup arrowdblright arrowdbldown arrowdblbothuni21D5uni21D6uni21D7uni21D8uni21D9uni21DAuni21DBuni21DCuni21DDuni21E0uni21E2 universaluni2201 existentialuni2204emptysetgradientelement notelementuni220Asuchthatuni220Cuni220Duni2210uni2213uni2214uni2215uni2216 asteriskmathuni2218uni2219uni221Buni221C proportional orthogonalangleuni2221uni2222uni2225uni2226 logicaland logicalor intersectionunionuni222Cuni222Duni222Euni222F thereforeuni2235uni2236uni2237uni2238uni2239uni223Auni223Bsimilaruni223Duni2240uni2241uni2242uni2243uni2244 congruentuni2246uni2247uni2249uni224Auni224Buni224Duni224Euni224Funi2250uni2251uni2252uni2253uni2254uni2255uni2256uni2257uni2259uni225Auni225C equivalenceuni2262uni2263uni2266uni2267uni2268uni2269uni226Auni226Buni226Cuni226Duni226Euni226Funi2270uni2271uni2272uni2273uni2274uni2275uni2276uni2277uni2278uni2279uni227Auni227Buni227Cuni227Duni227Euni227Funi2280uni2281 propersubsetpropersuperset notsubsetuni2285 reflexsubsetreflexsupersetuni2288uni2289uni228Auni228Buni228Cuni228Duni228Euni228Funi2290uni2291uni2292uni2293uni2294 circleplusuni2296circlemultiplyuni2298uni2299uni229Auni229Buni229Cuni229Duni229Euni229Funi22A0uni22A1uni22A2uni22A3uni22A4 perpendicularuni22A6uni22A7uni22A9uni22AAuni22ABuni22ACuni22ADuni22AEuni22AFuni22B2uni22B3uni22B4uni22B5uni22B6uni22B7uni22B8uni22BAuni22BBuni22BCuni22BDuni22C0uni22C1uni22C2uni22C3uni22C4dotmathuni22C6uni22C7uni22C8uni22CBuni22CCuni22CDuni22CEuni22CFuni22D0uni22D1uni22D2uni22D3uni22D4uni22D5uni22D6uni22D7uni22D8uni22D9uni22DAuni22DBuni22DCuni22DDuni22DEuni22DFuni22E0uni22E1uni22E2uni22E3uni22E4uni22E5uni22E6uni22E7uni22E8uni22E9uni22EAuni22EBuni22ECuni22EDuni22EEuni22EFuni22F0uni22F1uni2300uni2301uni2308uni2309uni230Auni230B revlogicalnotuni231A integraltp integralbtuni2322uni2323 angleleft anglerightuni2347uni2348uni2350uni2357uni235Euni23AEuni2423uni2460uni2461uni2462uni2463uni2464uni2465uni2466uni2467uni2468uni2469SF100000uni2501SF110000uni2503uni2504uni2505uni2506uni2507uni2508uni2509uni250Auni250BSF010000uni250Duni250Euni250FSF030000uni2511uni2512uni2513SF020000uni2515uni2516uni2517SF040000uni2519uni251Auni251BSF080000uni251Duni251Euni251Funi2520uni2521uni2522uni2523SF090000uni2525uni2526uni2527uni2528uni2529uni252Auni252BSF060000uni252Duni252Euni252Funi2530uni2531uni2532uni2533SF070000uni2535uni2536uni2537uni2538uni2539uni253Auni253BSF050000uni253Duni253Euni253Funi2540uni2541uni2542uni2543uni2544uni2545uni2546uni2547uni2548uni2549uni254Auni254BSF430000SF240000SF510000SF520000SF390000SF220000SF210000SF250000SF500000SF490000SF380000SF280000SF270000SF260000SF360000SF370000SF420000SF190000SF200000SF230000SF470000SF480000SF410000SF450000SF460000SF400000SF540000SF530000SF440000uni256Dupblockuni2581uni2582uni2583dnblockuni2585uni2586uni2587blockuni2589uni258Auni258Blfblockuni258Duni258Euni258Frtblockuni2594uni2595 filledboxH22073triagupuni25B6triagdnuni25C0uni25C6circleuni25CCH18533uni25D0uni25D1uni25D2uni25D3uni25D4uni25D5uni25D6uni25D7uni25E2uni25E3uni25E4uni25E5uni25E7uni25E8uni25E9uni25EAuni2605uni2606uni260Cuni260Duni260Euni2610uni2611uni2612uni2619uni261Auni261Buni261Cuni261Duni261Euni261Funi2620uni2622uni2623uni2626uni2628uni262Auni262Cuni262Euni262Funi2630uni2631uni2632uni2633uni2634uni2635uni2636uni2637uni2638uni2639 smileface invsmilefacesununi263Duni263Euni263Ffemaleuni2641maleuni2643uni2644uni2645uni2646uni2647uni2648uni2649uni264Auni264Buni264Cuni264Duni264Euni264Funi2650uni2651uni2652uni2653uni2654uni2655uni2656uni2657uni2658uni2659uni265Auni265Buni265Cuni265Duni265Euni265Fspadeuni2661uni2662clubheartdiamonduni2669 musicalnotemusicalnotedbluni266Cuni266Duni266Euni266Funi2670uni2671uni2701uni2702uni2703uni2704uni2706uni2707uni2708uni2709uni270Cuni270Duni270Euni270Funi2710uni2711uni2712uni2713uni2714uni2715uni2716uni2717uni2718uni2719uni271Auni271Buni271Cuni271Duni271Euni271Funi2720uni2721uni2722uni2723uni2724uni2725uni2726uni2727uni2729uni272Auni272Buni272Cuni272Duni272Euni272Funi2730uni2731uni2732uni2733uni2734uni2735uni2736uni2737uni2738uni2739uni273Auni273Buni273Cuni273Duni273Euni273Funi2740uni2741uni2742uni2743uni2744uni2745uni2746uni2747uni2748uni2749uni274Auni274Buni274Duni274Funi2750uni2751uni2752uni2756uni2758uni2759uni275Auni275Buni275Cuni275Duni275Euni2761uni2762uni2763uni2764uni2765uni2766uni2767uni2776uni2777uni2778uni2779uni277Auni277Buni277Cuni277Duni277Euni277Funi2780uni2781uni2782uni2783uni2784uni2785uni2786uni2787uni2788uni2789uni278Auni278Buni278Cuni278Duni278Euni278Funi2790uni2791uni2792uni2793uni2794uni2798uni2799uni279Auni279Buni279Cuni279Duni279Euni279Funi27A0uni27A1uni27A2uni27A3uni27A4uni27A5uni27A6uni27A7uni27A8uni27A9uni27AAuni27ABuni27ACuni27ADuni27AEuni27AFuni27B1uni27B2uni27B3uni27B4uni27B5uni27B6uni27B7uni27B8uni27B9uni27BAuni27BBuni27BCuni27BDuni27BEuni3001uni3002uni3003uni3005uni3007uni3008uni3009uni300Auni300Buni300Cuni300Duni300Euni300Funi3010uni3011uni3012uni3014uni3015uni3041uni3042uni3043uni3044uni3045uni3046uni3047uni3048uni3049uni304Auni304Buni304Cuni304Duni304Euni304Funi3050uni3051uni3052uni3053uni3054uni3055uni3056uni3057uni3058uni3059uni305Auni305Buni305Cuni305Duni305Euni305Funi3060uni3061uni3062uni3063uni3064uni3065uni3066uni3067uni3068uni3069uni306Auni306Buni306Cuni306Duni306Euni306Funi3070uni3071uni3072uni3073uni3074uni3075uni3076uni3077uni3078uni3079uni307Auni307Buni307Cuni307Duni307Euni307Funi3080uni3081uni3082uni3083uni3084uni3085uni3086uni3087uni3088uni3089uni308Auni308Buni308Cuni308Duni308Euni308Funi3090uni3091uni3092uni3093uni3094uni3099uni309Buni30A1uni30A2uni30A3uni30A4uni30A5uni30A6uni30A7uni30A8uni30A9uni30AAuni30ABuni30ACuni30ADuni30AEuni30AFuni30B0uni30B1uni30B2uni30B3uni30B4uni30B5uni30B6uni30B7uni30B8uni30B9uni30BAuni30BBuni30BCuni30BDuni30BEuni30BFuni30C0uni30C1uni30C2uni30C3uni30C4uni30C5uni30C6uni30C7uni30C8uni30C9uni30CAuni30CBuni30CCuni30CDuni30CEuni30CFuni30D0uni30D1uni30D2uni30D3uni30D4uni30D5uni30D6uni30D7uni30D8uni30D9uni30DAuni30DBuni30DCuni30DDuni30DEuni30DFuni30E0uni30E1uni30E2uni30E3uni30E4uni30E5uni30E6uni30E7uni30E8uni30E9uni30EAuni30EBuni30ECuni30EDuni30EEuni30EFuni30F0uni30F1uni30F2uni30F3uni30F4uni30F5uni30F6uni30F7uni30F8uni30F9uni30FAuni30FBuni30FCuniF639uniF63AuniF63BuniF63CuniF63DuniF63EuniF63FuniF640uniF641uniF6BE commaaccentcopyrightserif registerseriftrademarkserif onefitted arrowvertex arrowhorizex registersans copyrightsans trademarksans parenlefttp parenleftex parenleftbt bracketlefttp bracketleftex bracketleftbt bracelefttp braceleftmid braceleftbtbraceex integralex parenrighttp parenrightex parenrightbtbracketrighttpbracketrightexbracketrightbt bracerighttp bracerightmid bracerightbtffffiffluniFB06 afii57694 afii57695uniFB2CuniFB2DuniFB2EuniFB2FuniFB30uniFB31uniFB32uniFB33uniFB34 afii57723uniFB36uniFB38uniFB39uniFB3AuniFB3BuniFB3CuniFB3EuniFB40uniFB41uniFB43uniFB44uniFB46uniFB47uniFB48uniFB49uniFB4A afii57700uniFB4CuniFB4DuniFB4EuniFB56uniFB57uniFB58uniFB59uniFB7AuniFB7BuniFB7CuniFB7DuniFB8AuniFB8BuniFB92uniFB93uniFB94uniFB95uniFBFCuniFBFDuniFBFEuniFBFFuniFDF2uniFDFCuniFE70uniFE74uniFE76uniFE78uniFE7AuniFE7CuniFE81uniFE8CuniFE8DuniFE8EuniFE8FuniFE90uniFE91uniFE92uniFE95uniFE96uniFE97uniFE98uniFE99uniFE9AuniFE9BuniFE9CuniFE9DuniFE9EuniFE9FuniFEA0uniFEA1uniFEA2uniFEA3uniFEA4uniFEA5uniFEA6uniFEA7uniFEA8uniFEA9uniFEAAuniFEABuniFEACuniFEADuniFEAEuniFEAFuniFEB0uniFEB1uniFEB2uniFEB3uniFEB4uniFEB5uniFEB6uniFEB7uniFEB8uniFEB9uniFEBAuniFEBBuniFEBCuniFEBDuniFEBEuniFEBFuniFEC0uniFEC1uniFEC5uniFEC9uniFECAuniFECBuniFECCuniFECDuniFECEuniFECFuniFED0uniFED1uniFED2uniFED3uniFED4uniFED5uniFED6uniFED7uniFED8uniFED9uniFEDAuniFEDBuniFEDCuniFEDDuniFEDEuniFEDFuniFEE0uniFEE1uniFEE2uniFEE3uniFEE4uniFEE5uniFEE6uniFEE7uniFEE8uniFEE9uniFEEAuniFEEBuniFEECuniFEEDuniFEEEuniFEFBuniFEFCuniFFFD uni0937091Fr4xxx1y2y2u1y2u2v2 NameMe-195550 NameMe-195551k1xxnhxxn1xxl3xxlhxxr3xxk1u1k1u2k1r1k1r2k1l1k1k1k1k1u1k1k1u2k1k1r1k1k1r3k1k1r3u1k1k1r3u2k1t1k1t1u1k1t1u2k1t1r3k1t1r3u1k1t1r3u2k1t1nhk1nhu1k1nhu2k1th1k1th1u1k1th1u2k1th1r1k1th1r2k1th1r3 k1th1r3u1 k1th1r3u2k1n1k1n1u1k1n1u2k1m1k1m1u1k1m1u2k1r3k1r3u1k1r3u2k1l3k1l3u1k1l3u2k1shk1shu1k1shu2k1shr1k1shnhk1shnhu1k1shnhu2k1shm1k1shm1u1k1shm1u2k1shm1r1k1s1k1s1u1k1s1u2k1s1r1k1rhrhk1rhrhu1k1rhrhu2k2u1k2u2k2r1k3u1k3u2k3r1k3r2k3k3k3k3u1k3k3u2k3k3r1k3k4k3k4u1k3k4u2k3k4r1k3th3k3th3u1k3th3u2k3th3r1k3th3th4 k3th3th4u1 k3th3th4u2 k3th3th4r1 k3th3th4r3 k3th3th4r3u1 k3th3th4r3u2k3n1k3n1u1k3n1u2k3m1k3m1u1k3m1u2k3r3k3r3u1k3r3u2k3l3k3l3u1k3l3u2k4u1k4u2k4r1k4r2k4n1k4n1u1k4n1u2k4r3k4r3u1k4r3u2ngu1ngu2ngk1ngk1u1ngk1u2ngk1r1ngngngngu1ngngu2ch1u1ch1u2ch1ch1ch1ch1u1ch1ch1u2ch1ch2ch1ch2u1ch1ch2u2ch1ch2r1ch1ch2r3 ch1ch2r3u1 ch1ch2r3u2ch2u1ch2u2ch2r1ch2r3ch2r3u1ch2r3u2ch3u1ch3u2ch3r1ch3r2ch3ch3ch3ch3u1ch3ch3u2ch3ch3r1ch3njch3nju1ch3nju2ch3r3ch3r3u1ch3r3u2ch4u1ch4u2ch4r1ch4r2ch4r3ch4r3u1ch4r3u2nju1nju2njch1njch1u1njch1u2njch1r1njch2njch2u1njch2u2njch2r1njch3njch3u1njch3u2njnjnjnju1njnju2t1u1t1u2t1r1t1r2t1t1t1t1u1t1t1u2t1r3t1r3u1t1r3u2t2u1t2u2t3u1t3u2t3r1t3t3t3t3u1t3t3u2t3t4t3t4u1t3t4u2t3m1t3m1u1t3m1u2t3m1r1t3r3t3r3u1t3r3u2t4u1t4u2t4r1t4r3t4r3u1t4r3u2nhu1nhu2nht1nht1u1nht1u2nht1r3nht1r3u1nht1r3u2nht2nht3nht3u1nht3u2nht3r1nht3r3nht3r3u1nht3r3u2nht4nht4u1nht4u2nht4r1nhnhnhnhu1nhnhu2nhm1nhm1u1nhm1u2th1u1th1u2th1r1th1r2th1th1th1th1u1th1th1u2th1th1r1th1th1r2th1th1r3 th1th1r3u1 th1th1r3u2th1th2th1th2u1th1th2u2th1th2r1th1n1th1p4th1p4u1th1p4u2th1p4r1th1m1th1m1u1th1m1u2th1m1r1th1r3th1r3u1th1r3u2th1l3th1l3u1th1l3u2th1s1th1s1u1th1s1u2th1s1r1th1s1r2th1s1th2 th1s1th2u1 th1s1th2u2 th1s1th2r1th1s1n1 th1s1n1u1 th1s1n1u2th1s1m1 th1s1m1u1 th1s1m1u2 th1s1m1r1th1s1r3 th1s1r3u1 th1s1r3u2th2u1th2u2th2n1th2n1u1th2n1u2th2m1th2m1u1th2m1u2th2m1r1th3u1th3u2th3r1th3r2th3th3th3th3u1th3th3u2th3th3r1th3th3r2th3th4th3th4u1th3th4u2th3th4r1th3th4r2th3th4n1 th3th4n1u1 th3th4n1u2th3th4m1 th3th4m1u1 th3th4m1u2 th3th4m1r1th3th4r3 th3th4r3u1 th3th4r3u2th3r3th3r3u1th3r3u2th4u1th4u2th4r1th4r2th4n1th4n1u1th4n1u2th4m1th4m1u1th4m1u2th4m1r1th4r3th4r3u1th4r3u2n1u1n1u2n1r1n1r2n1th1n1th1u1n1th1u2n1th1r1n1th1r2n1th1r3 n1th1r3u1 n1th1r3u2n1th2n1th2u1n1th2u2n1th2r1n1th2r2n1th3n1th3u1n1th3u2n1th3r1n1th3r3 n1th3r3u1 n1th3r3u2n1th4n1th4u1n1th4u2n1th4r1n1th4r3 n1th4r3u1 n1th4r3u2n1n1n1n1u1n1n1u2n1n1r1n1n1r3n1n1r3u1n1n1r3u2n1m1n1m1u1n1m1u2n1m1r1n1m1r3n1m1r3u1n1m1r3u2n1r3n1r3u1n1r3u2n1rhn1rhu1n1rhu2p1u1p1u2p1r1p1r2p1t1p1t1u1p1t1u2p1th1p1th1u1p1th1u2p1th1r1p1th1r2p1n1p1n1u1p1n1u2p1p1p1p1u1p1p1u2p1p1r1p1p2p1p2u1p1p2u2p1r3p1r3u1p1r3u2p1l3p1l3u1p1l3u2p1s1p1s1u1p1s1u2p1s1r1p1s1r3p1s1r3u1p1s1r3u2p2u1p2u2p2k1p2k1u1p2k1u2p2t1p2t1u1p2t1u2p2th1p2th1u1p2th1u2p2th1r1p2n1p2n1u1p2n1u2p2p1p2p1u1p2p1u2p2m1p2m1u1p2m1u2p2r3p2r3u1p2r3u2p2l3p2l3u1p2l3u2p2s1p2s1u1p2s1u2p2s1r1p2rhrhp2rhrhu1p2rhrhu2p3u1p3u2p3r1p3k3p3k3u1p3k3u2p3k3r1p3ch3p3ch3u1p3ch3u2p3ch3r1p3th3p3th3u1p3th3u2p3th3r1p3th4p3th4u1p3th4u2p3th4r1p3th4r2p3n1p3n1u1p3n1u2p3p3p3p3u1p3p3u2p3p4p3r3p3r3u1p3r3u2p3l3p3l3u1p3l3u2p4u1p4u2p4r1p4r2p4r3p4r3u1p4r3u2m1u1m1u2m1r1m1r2m1n1m1n1u1m1n1u2m1p1m1p1u1m1p1u2m1p1r1m1p1r3m1p1r3u1m1p1r3u2m1m1m1m1u1m1m1u2m1m1r1m1r3m1r3u1m1r3u2m1l3m1l3u1m1l3u2y1u1y1u2y1r1y1k1y1k1u1y1k1u2y1k1r1y1k1k1y1k1k1u1y1k1k1u2y1ch1y1ch1u1y1ch1u2y1th1y1th1u1y1th1u2y1th1r1y1th1th1 y1th1th1u1 y1th1th1u2 y1th1th1r1y1n1y1n1u1y1n1u2y1p1y1p1u1y1p1u2y1p1r1y1m1y1m1u1y1m1u2y1m1r1y1y1y1y1u1y1y1u2r3u1r3u2r3r1l3u1l3u2l3r1l3k1l3k1u1l3k1u2l3k1r1l3k1k1l3k1k1u1l3k1k1u2l3k3l3k3u1l3k3u2l3k3r1l3ch1l3ch1u1l3ch1u2l3th1l3th1u1l3th1u2l3th1r1l3th1th1 l3th1th1u1 l3th1th1u2l3p1l3p1u1l3p1u2l3p1r3l3p1r3u1l3p1r3u2l3p2l3p2u1l3p2u2l3p3l3p3u1l3p3u2l3m1l3m1u1l3m1u2l3l3l3l3u1l3l3u2v1u1v1u2v1r1v1r3v1r3u1v1r3u2v1l3v1l3u1v1l3u2v1v1v1v1u1v1v1u2z1u1z1u2z1r1z1ch1z1ch1u1z1ch1u2z1ch1r1z1ch2z1ch2u1z1ch2u2z1ch2r1z1n1z1n1u1z1n1u2z1m1z1m1u1z1m1u2z1m1r1z1r3z1r3u1z1r3u2z1l3z1l3u1z1l3u2z1z1z1z1u1z1z1u2z1z1r1z1z1r3z1z1r3u1z1z1r3u2shu1shu2shr1shk1shk1u1shk1u2shk1r1shk1k1shk1k1u1shk1k1u2shk1k1r1shk1r3shk1r3u1shk1r3u2sht1sht1u1sht1u2sht1r1sht1r2sht1r3sht1r3u1sht1r3u2sht2sht2u1sht2u2shnhshnhu1shnhu2shp1shp1u1shp1u2shp1r1shp1r3shp1r3u1shp1r3u2shp2shp2u1shp2u2shm1shm1u1shm1u2shm1r3shm1r3u1shm1r3u2s1u1s1u2s1r1s1r2s1k1s1k1u1s1k1u2s1k1r1s1k1k1s1k1k1u1s1k1k1u2s1k1k1r1s1k1r3s1k1r3u1s1k1r3u2s1k2s1k2u1s1k2u2s1t1s1t1u1s1t1u2s1t1r3s1t1r3u1s1t1r3u2s1th1s1th1u1s1th1u2s1th1r1s1th1r2s1th1r3 s1th1r3u1 s1th1r3u2s1th2s1th2u1s1th2u2s1th2r1s1n1s1n1u1s1n1u2s1p1s1p1u1s1p1u2s1p1r1s1p1r3s1p1r3u1s1p1r3u2s1p2s1p2u1s1p2u2s1m1s1m1u1s1m1u2s1m1r1s1r3s1r3u1s1r3u2s1l3s1l3u1s1l3u2s1s1s1s1u1s1s1u2s1s1r1s1s1r3s1s1r3u1s1s1r3u2s1rhrhs1rhrhu1s1rhrhu2s1rhrhr3 s1rhrhr3u1 s1rhrhr3u3h1u1h1u2h1r1h1n1h1n1u1h1n1u2h1m1h1m1u1h1m1u2h1m1r1h1r3h1r3u1h1r3u2h1l3h1l3u1h1l3u2lhu1lhu2lhlhlhlhu1lhlhu2zhu1zhu2zhk1zhk1u1zhk1u2zhk1k1zhk1k1u1zhk1k1u2zhch1zhch1u1zhch1u2zhth1zhth1u1zhth1u2zhth1th1 zhth1th1u1 zhth1th1u2zhn1zhn1u1zhn1u2zhn1n1zhn1n1u1zhn1n1u2zhp1zhp1u1zhp1u2zhm1zhm1u1zhm1u2zhv1zhv1u1zhv1u2zhs1zhs1u1zhs1u2rhu1rhu2rhrhrhrhu1rhrhu2 bn_initekaar bn_initaikaarbn_reph bn_baphala bn_raphala bn_half_ka bn_half_kha bn_half_ga bn_half_gha bn_half_nga bn_half_ca bn_half_cha bn_half_ja bn_half_jha bn_half_nya bn_half_tta bn_half_ttha bn_half_dda bn_half_ddha bn_half_nna bn_half_tha bn_half_da bn_half_dha bn_half_na bn_half_pa bn_half_pha bn_half_ba bn_half_bha bn_half_ma bn_half_ya bn_half_ra bn_half_la bn_half_sha bn_half_ssa bn_half_sa bn_half_ha bn_half_rra bn_half_rha bn_half_yyabn_half_asamirabn_half_asamiba bn_yaphalabn_k_rabn_k_ra1bn_kh_rabn_g_rabn_gh_rabn_c_rabn_ch_rabn_j_rabn_tt_ra bn_tth_rabn_dd_ra bn_ddh_rabn_t_rabn_t_ra1bn_th_rabn_d_rabn_dh_rabn_n_rabn_n_ra1bn_p_rabn_ph_rabn_b_rabn_bh_ra bn_bh_ra1bn_m_rabn_y_rabn_sh_rabn_ss_rabn_s_rabn_s_ra1bn_h_ra bn_asamir_ra bn_asamib_ra bn_k_ss_rabn_k_kabn_k_tta bn_k_tt_rabn_k_tabn_k_ta1 bn_k_t_ba bn_k_t_ba1 bn_k_t_ra bn_k_t_ra1 bn_k_t_ra2bn_k_nabn_k_mabn_k_labn_k_ssa bn_k_ss_nna bn_k_ss_mabn_k_sabn_g_gabn_g_dabn_g_dha bn_g_dh_babn_g_nabn_g_mabn_g_labn_gh_nabn_ng_ka bn_ng_k_ra bn_ng_k_ssa bn_ng_k_ss_ra bn_ng_khabn_ng_ga bn_ng_gha bn_ng_gh_rabn_ng_ma bn_ng_ma1bn_c_cabn_c_cha bn_c_ch_ba bn_c_ch_rabn_c_nyabn_c_nabn_j_ja bn_j_j_babn_j_jhabn_j_nyabn_ny_ca bn_ny_chabn_ny_ja bn_ny_jha bn_tt_tta bn_tt_tt_rabn_tt_mabn_dd_ga bn_dd_ddabn_dd_ma bn_nn_tta bn_nn_tt_ra bn_nn_ttha bn_nn_dda bn_nn_dda1 bn_nn_dd_ra bn_nn_dd_ra1 bn_nn_ddha bn_nn_nnabn_nn_mabn_t_ta bn_t_t_babn_t_thabn_t_nabn_t_mabn_t_ma1bn_t_labn_d_gabn_d_ghabn_d_da bn_d_d_ba bn_d_d_rabn_d_dha bn_d_dh_babn_d_nabn_d_bha bn_d_bh_ra bn_d_bh_ra1bn_d_mabn_dh_nabn_dh_mabn_n_tta bn_n_tt_ra bn_n_tthabn_n_dda bn_n_dd_ra bn_n_ddhabn_n_ta bn_n_t_ba bn_n_t_ra bn_n_t_ra1bn_n_thabn_n_da bn_n_d_ba bn_n_d_rabn_n_dha bn_n_dh_ba bn_n_dh_rabn_n_nabn_n_mabn_n_sabn_p_ttabn_p_tabn_p_nabn_p_pabn_p_mabn_p_labn_p_sa bn_ph_ttabn_ph_labn_b_jabn_b_da bn_b_d_rabn_b_dhabn_b_nabn_b_bhabn_b_labn_bh_labn_m_tabn_m_thabn_m_dabn_m_nabn_m_na1bn_m_pa bn_m_p_ra bn_m_p_labn_m_pha bn_m_ph_rabn_m_bha bn_m_bh_ra bn_m_bh_ra1bn_m_mabn_m_labn_m_la1bn_m_sa bn_m_s_rabn_l_kabn_l_gabn_l_tta bn_l_tt_rabn_l_dda bn_l_dd_rabn_l_tabn_l_dabn_l_dhabn_l_pabn_l_pha bn_l_ph_rabn_l_mabn_l_labn_sh_tabn_sh_ca bn_sh_chabn_sh_nabn_sh_mabn_sh_labn_ss_ka bn_ss_k_ra bn_ss_tta bn_ss_tt_ra bn_ss_ttha bn_ss_nnabn_ss_pa bn_ss_p_ra bn_ss_pha bn_ss_ph_rabn_ss_mabn_s_ka bn_s_k_rabn_s_khabn_s_tta bn_s_tt_rabn_s_ta bn_s_t_ba bn_s_t_ra bn_s_t_ra1bn_s_thabn_s_nabn_s_pa bn_s_p_ra bn_s_p_labn_s_pha bn_s_ph_rabn_s_mabn_s_labn_s_la1bn_h_nnabn_h_nabn_h_mabn_h_labn_h_la1bn_rr_gabn_k_babn_g_babn_gh_babn_c_babn_ch_babn_j_babn_tt_babn_dd_babn_nn_babn_t_babn_th_babn_d_babn_dh_babn_n_babn_p_babn_b_babn_bh_babn_m_ba bn_m_b_rabn_l_babn_sh_babn_s_babn_h_babn_h_ba1 bn_kh_r_ukaarbn_kh_r_uukaar bn_g_ukaar bn_g_r_ukaar bn_g_r_uukaar bn_g_l_ukaar bn_g_l_uukaar bn_j_r_ukaar bn_j_r_uukaar bn_t_r_ukaar bn_t_r_uukaar bn_th_r_ukaarbn_th_r_uukaar bn_d_ukaar bn_d_r_ukaar bn_d_r_uukaar bn_dh_r_ukaarbn_dh_r_uukaar bn_n_t_ukaarbn_n_d_r_ukaarbn_n_d_r_uukaar bn_p_r_ukaar bn_p_r_uukaar bn_p_l_ukaar bn_p_l_uukaar bn_b_r_ukaar bn_b_r_uukaar bn_b_l_ukaar bn_b_l_uukaar bn_bh_r_ukaarbn_bh_r_uukaarbn_m_p_r_ukaarbn_m_p_r_uukaar bn_m_r_ukaar bn_m_r_uukaar bn_r_ukaar bn_r_uukaar bn_l_g_ukaar bn_sh_ukaar bn_sh_r_ukaarbn_sh_r_uukaar bn_sh_l_ukaarbn_sh_l_uukaarbn_ss_p_r_ukaarbn_ss_p_r_uukaar bn_s_t_ukaar bn_s_r_ukaar bn_s_r_uukaar bn_s_l_ukaar bn_s_l_uukaarbn_s_p_r_ukaarbn_s_p_r_uukaarbn_s_p_l_ukaarbn_s_p_l_uukaar bn_h_ukaar bn_h_rikaarbn_asamir_ukaarbn_asamir_uukaarbn_asamib_ukaarbn_asamib_uukaarbn_asamib_r_ukaarbn_asamib_r_uukaarbn_d_yabn_n_yabn_sh_yabn_ss_yabn_s_yabn_h_ya bn_k_hasanta bn_kh_hasanta bn_g_hasanta bn_gh_hasanta bn_ng_hasanta bn_c_hasanta bn_ch_hasanta bn_j_hasanta bn_jh_hasanta bn_ny_hasanta bn_tt_hasantabn_tth_hasanta bn_dd_hasantabn_ddh_hasanta bn_nn_hasanta bn_t_hasanta bn_th_hasanta bn_d_hasanta bn_dh_hasanta bn_n_hasanta bn_p_hasanta bn_ph_hasanta bn_b_hasanta bn_bh_hasanta bn_m_hasanta bn_y_hasanta bn_r_hasanta bn_l_hasanta bn_sh_hasanta bn_ss_hasanta bn_s_hasanta bn_h_hasanta bn_rr_hasanta bn_rh_hasanta bn_yy_hasantabn_asamir_hasantabn_asamib_hasanta bn_one_two bn_one_three bn_one_four bn_two_three bn_three_four bn_ukaar1 bn_ukaar2 bn_uukaar1 bn_uukaar2 bn_rikaar1 bn_post_ka bn_below_tabn_below_t_ukaar bn_below_t_ra bn_below_da bn_below_dha bn_above_na bn_below_na1 bn_below_na bn_below_ba1 bn_below_ba bn_post_ba bn_maphala bn_maphala1 bn_raphala1 bn_raphala2 bn_raphala3 bn_below_la bn_below_la1 bn_above_la bn_pre_ssa1 bn_pre_sa1 bn_below_tha bn_glyph571 bn_glyph572 bn_glyph573 bn_glyph574 bn_glyph575 bn_glyph576 bn_yaphala1 bn_glyph578bn_above_na.001 taml_v_i_2 taml_v_ii_2TamlKA_Taml_pul.halfTamlNGA_Taml_pul.halfTamlCA_Taml_pul.halfTamlNYA_Taml_pul.halfTamlTTA_Taml_pul.halfTamlNNA_Taml_pul.halfTamlTA_Taml_pul.halfTamlNA_Taml_pul.halfTamlPA_Taml_pul.halfTamlMA_Taml_pul.halfTamlYA_Taml_pul.halfTamlRA_Taml_pul.halfTamlLA_Taml_pul.halfTamlVA_Taml_pul.halfTamlLLLA_Taml_pul.halfTamlLLA_Taml_pul.halfTamlRRA_Taml_pul.halfTamlNNNA_Taml_pul.halfTamlTTA_Taml_v_I.abvsTamlTTA_Taml_v_II.abvsTamlKA_Taml_v_U.pstsTamlNGA_Taml_v_U.pstsTamlCA_Taml_v_U.pstsTamlNYA_Taml_v_U.pstsTamlTTA_Taml_v_U.pstsTamlNNA_Taml_v_U.pstsTamlTA_Taml_v_U.pstsTamlNA_Taml_v_U.pstsTamlPA_Taml_v_U.pstsTamlMA_Taml_v_U.pstsTamlYA_Taml_v_U.pstsTamlRA_Taml_v_U.pstsTamlLA_Taml_v_U.pstsTamlVA_Taml_v_U.pstsTamlLLLA_Taml_v_U.pstsTamlLLA_Taml_v_U.pstsTamlRRA_Taml_v_U.pstsTamlNNNA_Taml_v_U.pstsTamlKA_Taml_v_UU.pstsTamlNGA_Taml_v_UU.pstsTamlCA_Taml_v_UU.pstsTamlNYA_Taml_v_UU.pstsTamlTTA_Taml_v_UU.pstsTamlNNA_Taml_v_UU.pstsTamlTA_Taml_v_UU.pstsTamlNA_Taml_v_UU.pstsTamlPA_Taml_v_UU.pstsTamlMA_Taml_v_UU.pstsTamlYA_Taml_v_UU.pstsTamlRA_Taml_v_UU.pstsTamlLA_Taml_v_UU.pstsTamlVA_Taml_v_UU.pstsTamlLLLA_Taml_v_UU.pstsTamlLLA_Taml_v_UU.pstsTamlRRA_Taml_v_UU.pstsTamlNNNA_Taml_v_UU.psts*TamlSA_Taml_pul.half_TamlRA_Taml_v_II.pstsTamlCA_TamlSSATamlJA_Taml_pul.halfTamlSSA_Taml_pul.halfTamlSA_Taml_pul.halfTamlHA_Taml_pul.halfTamlCA_TamlSSA.half taml_v_i_3 taml_v_i_4 &YjkNOOP A B B C    2334  !!"'(())**++,-.7889CDDEEFFGJKKL^__``aabijjkrsstuvvwno DFLT&arab4bengBlatnbmlymrtaml    aaltabvsakhnakhnblwfblwsdligfracfrachalfhalfhalnhalnhalninitligaligaligaprespstf pstspstsrlig rphf&vatu,     8@HPX`hpx6:'4'')'+ +0*,-3\79x77>1N>! BVD3N0 $Q0Q;ISQ<!<%%P\0B6rJbt " ^ nT\VPjbH!v% [Y8r &2>JVblv  *4>HRZbjrzQ<Q<IQ<Q<HQBQ9JQBQ9IQBQ9HQBQ/IQBQ/HQ0Q;HQ+Q;IQ+Q;HQ!Q;IQ!Q;HQBQ/Q<Q<Q+Q;QBQ9Q0Q;Q!Q;Q;HQ9IQ9HQ4IQ4HQCIQCHQCJQ0SQ0JQ0IQ0HQ/IQBJQBIQBHQ+IQ+HQ=IQ=HQ;IQ!JQ!IQ!HQ4Q=Q+Q0QCQ/Q9QBQ;Q!JIHJIH#HZl|  *4>HR\dlt|Q2Q3Q;IQ2Q3Q;HQ2Q3Q;Q2Q3JQ2Q3IQ2Q3HQ2Q3Q4H Q=IQ=HQ;IQ;HQ9IQ9HQ4IQ2JQ2IQ2HQ$JQ$IQ$HQ#JQ#IQ#HQ4Q9Q$Q=Q2Q;Q#SJIH  *4>FNTZ`Q;IQ;HQ4IQ4HQ;Q4 S J I H  *4>HPX^Q!QJQ%HQ%IQ!IQ!HQ%Q!IH (6BLV`jt|(Q'Q;I'Q'Q;H&Q'Q;%Q'J$Q'I#Q'H!Q&I Q&H"Q'Q&IH"*06.Q;I-Q;H,Q;+J*I)H(2<FPZdlt|<Q;I;Q;H9Q*I8Q*H6Q(J5Q(I4Q(H7Q*:Q;3Q(2S1J0I/H$,28>CQ;IBQ;HAQ;@S?J>I=H",6@JT^hr|SQ*IRQ*HPQ(IOQ(HMQ'JLQ'IKQ'HIQ&JHQ&IGQ&HNQ(QQ*JQ'FQ&EIDH  *4>FNTZ`]Q;I\Q;HZQ+IYQ+H[Q;XQ+WSVJUITH _I^H",6@JT^hr|oQ;InQ;HlQ9JkQ9IjQ9HhQ.IgQ.HeQ-IdQ-HfQ.mQ;iQ9cQ-bJaI`H"*06uQ;ItQ;HsQ;rJqIpH6DR`nz&.4Q-Q;IQ-Q;H}Q+Q;I|Q+Q;HQ-Q;{Q+Q;Q.HQ9IQ9HQ/IQ-JQ-IQ-HQ/HQ.JQ.IzQ+IyQ+HQ/Q9Q.Q-~Q,xQ+wIvH2ft&2>JT^hr|$,4<DLT\bhnQCQ;IQCQ;HQCQ9JQCQ9IQCQ9HQCQ4IQCQ4HQCQ1JQCQ1IQCQ1HQ0Q;IQ0Q;HQCQ4QCQ1QCQ;QCQ9Q0Q;QCHQ=IQ=HQ;IQ;HQ9JQ9IQ9HQ8JQ8IQ8HQ1JQ1IQ1HQCSQCJQCIQ0SQ0JQ0IQ0HQ;Q8Q4Q9QCQ=Q1Q0SJIH (2<FNV\Q9JQ9IQ9HQ4IQ4HQ9Q4IH8FTbp~"*2:@FLQ3Q;IQ3Q;HQ3Q9JQ3Q9IQ3Q9HQ3Q4IQ3Q4HQ3Q;Q3Q9Q3Q4Q;IQ;HQ3SQ3JQ3IQ3HQ2SQ2JQ2IQ2HQ;Q3Q2SJIH(2<FPZdlt|Q;IQ;HQ9JQ9IQ9HQ4IQ4HQ;Q9Q4SJIH3hv $0:DNXblv  (08@HPX`flr Q9Q;IQ9Q;HQ4Q;IQ4Q;HQ3Q;IQ3Q;H Q2Q;I Q2Q;HQ0Q;IQ0Q;HQ4Q; Q2Q;Q3Q;Q9Q;Q0Q;Q4H#Q;IQ9JQ9IQ3JQ3I Q3HQ9H"Q;H&Q<IQ2JQ2IQ2HQ1SQ1JQ1IQ1H%Q<HQ4JQ4IQ0SQ0JQ0IQ0HQ9Q2Q4$Q<!Q; Q3Q1Q0SJIH#HVdpz$.8@HPX`hpx~IQCQ;IHQCQ;HGQCQ;FQCJEQCIDQCHBQ=IAQ=H?Q;I>Q;H<Q6I;Q6H9Q5J8Q5I7Q5H5Q4I4Q4H2Q0S1Q0J0Q0I/Q0H-Q+I,Q+HCQC@Q=6Q5:Q6.Q0=Q;3Q4+Q+*S)J(I'H"FTbnx",6>FNV^fnv~kQ<Q<IjQ<Q<HiQ<Q<hQCJgQCIfQCHdQ-IcQ-HaQ;I`Q;H^Q9I]Q9H[Q5IZQ5HXQ4IWQ4HUQ0JTQ0ISQ0HQQ+IPQ+HNQ!IMQ!HeQCYQ5RQ0bQ-\Q9OQ+VQ4_Q;LQ!KIJH!DNXblv &.6>FNV^djQ=IQ=HQ;IQ;HQ7IQ7HQ4IQ4HQ3S~Q3J}Q3I|Q3HzQ2JyQ2IxQ2HvQ(JuQ(ItQ(HrQ#JqQ#IpQ#HwQ2Q8Q={Q3sQ(Q4Q;Q7oQ#nJmIlH$,28>Q;IQ;HQ;SJIH2@NZdnx Q5Q;IQ5Q;HQ5Q;Q;HQ9JQ9IQ9HQ=IQ=HQ;IQ5JQ5IQ5HQ4IQ4HQ9Q5Q;Q=Q4SJIH#HVdr (2<FPZbjrzQ0Q0JQ0Q0IQ0Q0HQ!Q!IQ!Q!HQ0Q0Q!Q!Q5HQ4IQ4HQ:IQ:HQ9JQ9IQ0JQ0IQ0HQ&IQ&HQ9HQ5JQ5IQ!JQ!IQ!HQ9Q:Q0Q4Q5Q&Q!JIHJIHQ<HIH*Vdr (2<FPZdnxQ5Q;IQ5Q;HQ0Q0IQ0Q0HQ!Q!IQ!Q!HQ5Q;Q0Q0Q!Q!Q=HQ9IQ5IQ5HQ9HQ7IQ7HQ0JQ0IQ0HQ&IQ&HQ#JQ#IQ#HQ6IQ6HQ=IQ!JQ!IQ!HQ=Q#Q0Q9Q6Q&Q7Q5Q!JIH  (.Q>IQ>HQ>IH#HVdr$.8BLV`hpxQ4Q4IQ4Q4HQ0Q0IQ0Q0HQ!Q!IQ!Q!HQ4Q4Q0Q0Q!Q!QCHQ@IQ4IQ4HQ@HQ9IQ9HQ0IQ0HQ&IQ&HQ5IQ5HQCIQ!IQ!HQ@Q&Q5Q9Q4Q0QCQ!IH $.8BLV^fntzQ@IQ@HQ=IQ=HQ;IQ;HQ@Q=Q;JIH@N\hr|$,4<DLTZ`&QAQ;I%QAQ;H$QAQ;#QAJ"QAI!QAHQ=IQ=HQ;IQ;HQ9JQ9IQ9HQ4IQ4HQ'JQ'IQ'HQ&J Q&I Q&HQ9 QAQ'Q=Q4Q; Q& J IH,Zhv $0:DNXblv "(RQ9Q;IQQ9Q;HIQ5Q;IHQ5Q;H<Q+Q;I;Q+Q;H4Q!Q;I3Q!Q;H1Q!Q!J0Q!Q!I/Q!Q!H2Q!Q;:Q+Q;PQ9Q;GQ5Q;.Q!Q!>Q,HKQ6HOQ9INQ9H9Q+S8Q+J7Q+I6Q+HLQ6IFQ5IEQ5IDQ5HBQ/IAQ/H?Q,I-Q!J,Q!I+Q!H@Q/5Q+CQ5MQ9=Q,JQ6*Q!)J(I'HH (6DR`n|$.8BLV`jt~ &.6>FNV^fnv~Q<Q<Q;IQ<Q<Q;HQ<Q<Q;QCQ;IQCQ;HQ5Q;IQ5Q;HrQ0Q;IqQ0Q;HjQ+Q;IiQ+Q;HaQ!Q;I`Q!Q;H^Q!Q!J]Q!Q!I\Q!Q!HQ<QIhQ+Q;~Q5Q;Q<QH_Q!Q;QCQ;pQ0Q;Q<Q<[Q!Q!|Q5I{Q5HyQ4IxQ4HvQ1JuQ1ItQ1HQ=IQ=HQ;IoQ0SnQ0JmQ0IlQ0HQ;HQ9JQ9IgQ+IfQ+HdQ"IcQ"HQ9HQ6IQ6HQCJQCIQCH}Q5JZQ!JYQ!IXQ!HbQ"Q;kQ0sQ1zQ5Q9QCwQ4eQ+Q=Q6WQ!VSUJTISH",6@JT^hr|Q=IQ=HQ;IQ;HQ9JQ9IQ9HQ4IQ4HQ9Q;Q=Q4JIHYY!DnHR\- "(IOILOLIMW OL,ILV NN;b*  NNN7;b%PZdnx",6@JT^hr|NNNNNNNNNNNNNNNONNNNNNNNNNNNNNNNNNNNNN!@QS bc#2<FPZdnxD ,8l\k[jZm[n\YZ[N:dz"*2:BJ                      "         V>HR\fpz$.8BL      "#!$&(+.0: =@cc11:d,NhBT"T^J|Xz $k<i9h4g1e0  &,28>D4?0</9.4+'0& %+$! &,;<:99473625#<4$*06<E9C$B#A"@#?1>=! L4JH'G&P*O)M( T)S(R'Q&W9V U+Z9Y-X#$*06<d9c/b.` ^-],\ [+$*06<w9ut8q3pn2m$l# y9x4"(.4:@FLRX^djpv|?943210.~ }-|,{ z+"(.4?<9540+ <+ &,<832(< &,28>DJPV\bhnt?<98654210$*06<BHNTZ`fl<965320 - +#! &,<94'&0 $*06<BHNT965/, +!"(.4:@FLRX^djpv|<965410 +"! <94/#3N92N/O1:z  *4FPbl(:L^p"4FXbt F F %G$F 'F8H7F :G9F <G;F GF GF  GF  G F  G F GF GF GF GF GF #G"F )G(F 0G/F >G=F) GFINfor F GF GF GF !G F&F +G*F -G,F .F 4G3F 6G5F 2G1F:!#$&'(+-/02345789;<=?@bc "';HMenq .  :I:H@:Q|,>Pbt(:L^p                  [\\%PZdnx",6@JT^hr|ENFNGNHNINJNKNLNMNNNONPNQNRNSNTNUNVNWNXNYNZN[N\N]N^N_N`NaNbNcNdNeNfNgNhNiN!@QS bc#2<FPZdnx^(2<JTQQQQQ<IQQ!/4;<=> JK rDFLT&arab2beng,V`j       p  > l T Z h ~ "0>LZhv$&*24789}:<DEFGHJRTWXYZ\m $29:< $+.2 $-79:;<$-2DHLMRUX $79:<$&*26DHRX\&26789:<X\ $&*2DHRX $79:;<$-DHR&*2789:<DHRX\ $79:<W-$&*-269:< DFHJLMRUVXYZ\m $PQSU$$&*267 DHJLRUX\m $$&*267DHJLRUX\m &24DHRX\$$&*267 DHJLRSXYmy oY\MYZ\ YZ\KNWYZ[\ DHILMO,RVW   DHOU \ 7MDHJRVXY\SYZ\7SYZ\ 7WYZ[\ W\FX.DFGHIJKLMNOPQRSTUWXYZ[\] W 6D K R  DFHJORVDFHJORVDFHRTDFHJORV &*24789}:<&*24789}:<DEFGHJRTWXYZ\m &*24789}:< &*24789}:<&*24789}:<DEFGJRTWXYZ\m &*24789}:<DEFGHJRTWXYZ\m $79<$79:<79<79<$79:;<$$$PQSU$$EPQSUYZ\YZ\YZ\YZ\YZ\YZ\YZ\YZ\YZ\WWYZ[\$2KN$79WWY\$')*-/13 5= DFHLN\,238=?BDGH"#J??L 0bhntz "(.4:@FLRX^djpv|cc6j|cQ}-c+jj|0$&(,28<DFHLRX\HIJPRYabchqr (346@A*JkZ`flrx~ZX\\\\\\\\\\\\\\\\\\]-Irgl/inst/slowTests/0000755000176200001440000000000014771520323014026 5ustar liggesusersrgl/inst/slowTests/demos.R0000644000176200001440000000054714771520323015266 0ustar liggesuserslibrary(rgl) # regression : this failed for headless tests par3d(userMatrix = diag(4)) if (!rgl.useNULL()) for(demo in demo(package="rgl")$results[,"Item"]) if (!(demo %in% c("rgl", "lsystem", "rglExamples", "shinyDemo", "simpleShinyRgl", "shinyMouse"))) demo(demo, package="rgl", character.only=TRUE) rgl/inst/WORDLIST0000644000176200001440000000442714771520323013220 0ustar liggesusersACM AGL Albrecht Amaya Angerer ansi Asymptote Atte Baranek Baston Bengtsson Bitmapped Bolker Capitan CMD CanvasMatrix Carbonell ChangeLog Christophe Colours Csardi DEV Delaunay Demont Duursma Eddelbuettel Edelsbrunner El Elkner Esswein FC FOV FreeType Frenet FTGL GDI Gebhard Geuzaine Geuzaine's Gitbook GL GLSL GLU GLX Gabor Gebhardt Geuzaine Github Glynn Gouraud Griffiths Hadka Hammerlindl Heiberger Hirst Hornik IGLX ImageMagick Interpolator Javascript Jefferis Jens Jeroen Joue Jüttler Kajan Karline KDE Khemri Kuehnl Lafarge Laszlo Laur LibPNG Ligges Liu Luca MODELVIEW macOS MacPorts McManus Meshlab Millar MinGW ModelView Morey Mucke Mucke's NaNs Nenadic Normals OPENGL OSX Oleg Ooms OpenGL Pandoc Pateiro Pavel PGF Philipp RMarkdown RStudio Remko Rescaling Rolf Rowlingson Rtools STL Samperi Scrucca Senger Settra Soetaert StackOverflow Stříž Strzelecki SunStudio Talbert Tenenbaum Tenkanen TrueType Tuff UI Ulrich Urbanek Uwe WebGL WinBuilder XQuartz XYZ Xie Yihui Yohann Zeeman ZYX Zheng activeSubscene affine al alphashape anaglyph antialias antialiased antialiasing args atmospherical autoconf autoprinting bbox behaviour binormal bitmapped bringtotop browsable bugfix centre centred cex clipplane clipplanes colour colours config cuboctahedron customizable cvs cyclicly de de-emphasize destructor dev dinterp distro dmurdoch downlit dsave embeddings eps et fontname fontsize fpu freetype gcc github gl grayscale gz htmlwidget https ib io ip ignoreExtent interp labelled libGL libGLU libgl libglu libpng luminance lwd magrittr maxClipPlanes meshColor minification minified minify mipmap mipmapped mipmapping modelMatrix modelled modelview mouseMode multisample nd neighbouring neighbours noindent normals onclick opengl orthogonalization orthogonalizes orthogonally pgf pixmap pkgdown playwidget png polyhedra pos pre projMatrix ps rc recoded rescale rescaled rescaling resizable rglControl rwinlib saveable selectable setosa shader shaders skipRedraw specular stereogram stereolithography stylesheet subscene subscene's subscenes subtype svg tcltk tex texcoords texel texels texenvmap texmagfilter texminfilter texmipmap th tickmark tkrgl toolchain trackpad triangulations tripack unselected useFreeType userMatrix userProjection usr vectorized webgl windowRect wireframed xmax xmin xn xy ymax ymin zmax zmin rgl/tools/0000755000176200001440000000000014771520323012202 5ustar liggesusersrgl/tools/winlibs.R0000644000176200001440000000060714771520323013777 0ustar liggesusersVERSION <- commandArgs(TRUE) if(!file.exists(sprintf("../windows/freetype-%s/include/freetype2/ft2build.h", VERSION))){ if(getRversion() < "3.3.0") setInternet2() download.file(sprintf("https://github.com/rwinlib/freetype/archive/v%s.zip", VERSION), "lib.zip", quiet = TRUE) dir.create("../windows", showWarnings = FALSE) unzip("lib.zip", exdir = "../windows") unlink("lib.zip") } rgl/tools/configure.R0000644000176200001440000000032314771520323014304 0ustar liggesusers# Configuration for Windows only lines <- readLines("src/Makevars.win.in") lines <- sub("@HIDE_IF_R42PLUS@", if (getRversion() < '4.2.0') "" else "#", lines, fixed = TRUE) writeLines(lines, "src/Makevars.win") rgl/README.md0000644000176200001440000001612315011677075012331 0ustar liggesusers # RGL - 3D visualization device system for R using OpenGL ![](man/figures/READMEpolyhedra-1.-rgl.png) [![CRAN status](https://www.r-pkg.org/badges/version/rgl)](https://CRAN.R-project.org/package=rgl) [![R-CMD-check](https://github.com/dmurdoch/rgl/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/dmurdoch/rgl/actions/workflows/R-CMD-check.yaml) ## INTRODUCTION The RGL package is a visualization device system for R, using OpenGL or WebGL as the rendering backend. An OpenGL rgl device at its core is a real-time 3D engine written in C++. It provides an interactive viewpoint navigation facility (mouse + wheel support) and an R programming interface. WebGL, on the other hand, is rendered in a web browser; rgl produces the input file, and the browser shows the images. ## WEBSITE A `pkgdown` website is here: The unreleased development version website is here: See [this vignette](https://dmurdoch.github.io/rgl/dev/articles/pkgdown.html) for details on producing your own `pkgdown` website that includes `rgl` graphics. The currently active development site is here: ## INSTALLATION Most users will want to install the latest CRAN release. For Windows, macOS and some Linux platforms, installation can be easy, as CRAN distributes binary versions: # Install latest release from CRAN install.packages("rgl") To install the latest development version from Github, you’ll need to do a source install. Those aren’t easy! Try # Install development version from Github remotes::install_github("dmurdoch/rgl") If that fails, read the instructions below. Currently installs are tested on older R versions back to R 3.5.x, but this version of `rgl` may work back as far as R 3.3.0. ## LICENSE The software is released under the GNU Public License. See [COPYING](./COPYING) for details. ## FEATURES - portable R package using OpenGL (if available) on macOS, Win32 and X11 - can produce 3D graphics in web pages using WebGL - R programming interface - interactive viewpoint navigation - automatic data focus - geometry primitives: points, lines, triangles, quads, texts, point sprites - high-level geometry: surface, spheres - up to 8 light sources - alpha-blending (transparency) - side-dependent fill-mode rendering (dots, wired and filled) - texture-mapping with mipmapping and environment mapping support - environmental effects: fogging, background sphere - bounding box with axis ticks marks - undo operation: shapes and light-sources are managed on type stacks, where the top-most objects can be popped, or any item specified by an identifier can be removed ## PLATFORMS macOS Windows 7/10 Unix-derivatives ## BUILD TOOLS R recommended tools (gcc toolchain) On Windows, Rtools40 (or earlier versions for pre-R-4.0.0) ## REQUIREMENTS **For OpenGL display:** Windowing System (unix/x11 or Windows) OpenGL Library OpenGL Utility Library (GLU) **For WebGL display:** A browser with WebGL enabled. See . ## Installing OpenGL support **Debian and variants including Ubuntu:** aptitude install libgl1-mesa-dev libglu1-mesa-dev **Fedora:** yum install mesa-libGL-devel mesa-libGLU-devel libpng-devel **macOS:** Install XQuartz. `rgl` should work with XQuartz 2.7.11 or newer, but it will probably need rebuilding if the XQuartz version changes. XQuartz normally needs re-installation whenever the macOS version changes. **Windows:** Windows normally includes OpenGL support, but to get the appropriate include files etc., you will need the appropriate version of [Rtools](https://cran.r-project.org/bin/windows/Rtools/) matched to your R version. ## Options The **libpng** library version 1.2.9 or newer is needed for pixmap import/export support. The **freetype** library is needed for resizable anti-aliased fonts. ## BUILDING/INSTALLING Binary builds of `rgl` are available for some platforms on CRAN. For source builds, install the prerequisites as described above, download the tarball and at the command line run R CMD INSTALL rgl_1.3.15.tar.gz (with the appropriate version of the tarball). The build uses an `autoconf` configure script; to see the options, expand the tarball and run `./configure --help`. Alternatively, in R run install.packages("rgl") to install from CRAN, or remotes::install_github("dmurdoch/rgl") to install the development version from Github. ### BUILDING ON MACOS To build on MacOS using one of the ARM64 chips (currently M1, M2 or M3), follow the instructions on to install the tools and libraries into `/opt/R/arm64`. It is important that `/opt/R/arm64/bin` appear in your PATH before `/usr/local/bin` if the latter directory has been used for x86_64 installs. If you don’t do this, or have some other error in setting things up, you’ll get a warning during `rgl` installation saying that some configure test failed, and `rgl` will be installed without OpenGL support. Some versions of RStudio (including 2024.04.2+764) have a bug that modifies your PATH on startup and again after every package installation, putting `/usr/local/bin` at the head of the PATH. If you are building `rgl` in such a system you need to remove files from `/usr/local/bin` if there’s a file with the same name in `/opt/R/arm64/bin`. Hopefully this bug will be fixed soon! ### BUILDING WITHOUT OPENGL As of version 0.104.1, it is possible to build the package without OpenGL support on Unix-alikes (including macOS) with the configure option –disable-opengl For example, R CMD INSTALL --configure-args="--disable-opengl" rgl_1.3.15.tar.gz On Windows, OpenGL support cannot currently be disabled. ## DOCUMENTATION and DEMOS: library(rgl) browseVignettes("rgl") demo(rgl) ## CREDITS Daniel Adler Duncan Murdoch Oleg Nenadic Simon Urbanek Ming Chen Albrecht Gebhardt Ben Bolker Gabor Csardi Adam Strzelecki Alexander Senger The R Core Team for some code from R. Dirk Eddelbuettel The authors of Shiny for their private RNG code. The authors of `knitr` for their graphics inclusion code. Jeroen Ooms for `Rtools40` and `FreeType` help. Yohann Demont for Shiny code, suggestions, and testing. Joshua Ulrich for a lot of help with the Github migration. Xavier Fernandez i Marin for help debugging the build. George Helffrich for draping code. Ivan Krylov for window_group code in X11. Michael Sumner for as.mesh3d.default enhancement. Tomas Kalibera for `winutf8` and other help. David Hugh-Jones for documentation improvements. Trevor Davis for a `snapshot3d` patch. Mike Stein for pointer-handling code. Jonathon Love for the `uname` patch. The Mapbox team for the triangulation code. rgl/build/0000755000176200001440000000000015026603600012133 5ustar liggesusersrgl/build/vignette.rds0000644000176200001440000000057515026603600014501 0ustar liggesusersSO0A1&&^Lz0!#QC zlmXw{vi9yX־{W'zF86pٸ~9A',Ǔ4O,@ΥC\'SrЗ:K5:s`_ `s 0Zv#CmCkYO <"+0zt<њ))`Idu>pw+ f?9um29Lwm7^B=/2*0CDe\\a!ޖՈRlk^]7sXw G昛߄pf6h 4>#U-»,ٷ^Pp/b=}p<QTJyDyBrgl/build/partial.rdb0000644000176200001440000016132615026603560014276 0ustar liggesusers xٖ&HH` @&Ip-VG^z@f̌HxՋZ-ڒVolRwKmem-ɶl˖gG2f<3c[{n7f"{odfǯCd{=w?CL'K~=L/8>}ACWdzOv>/ U& אּߢR2}VܒC4>Z[˩[i%i`薝 U_٧' -_/ o?ӯB!E+z]vZfn̺Ϭx3řRJeյss7̮Yq%E ݰװ{QVwڂa=hZР)z%cX+W^Zd0UbX6 BD}J]@bLǶyB-0$]-ٛnq 5C>Z_* ' OX,5s|*NXoXs+h*`dY/ה] q; 1DžS UfS١؅5_78{[S5;P}A:/+ܵh3ǰE[̋ *_ȱ/C Nx]sW5{ݡ.2Nթ4]B!q^n%L]Zl5/`sL7]Yuʼ+%ȗR {NP*/ 71afcoK>C. F>hL2xkr1ZB{|q t>^K5}:S~(oj)x%'{Ruͮͷ[[oo@~BzRu<]u+ΛEw)v;ݬK+O!O;V&P0*=eZ8;jk ΃:O{$4tf>N ɉe)F3iLNzvkg5 !k=c9YʎdRF^(pl7t  uyQ$q{>>V{qAZ->4@cJ4`Ӻ5h&JM-Kv%#ېokwemeWMv%onĨaaMZሧm5?3hpâRDk#4Q =E3@Ϫ(* X25:oTu tܪժh6lhމ2U07tԲKWб6Mj_A)+< m55gbD$ <\ t\ 'P'Lmϗ5 B֚R↮]VoYf-إҦ;Ga |6dm=.@6_Um*x:n'a'j۷ lM`Ok~i_ khEML4KPheWT{1*3ck^Td2ib,XN%78mX+ nEզOgRm8#*9 器YȳNSsi6׋b/AyWOK>@>W?&gmhO.A)ȧyO qŢ[v*U쒪ji 7UH;*V Oڕ췙3޺[d`r¦:S)8s@y36Iއ55kT CKZcpqGOQ} Z M0fJ:! ʳEi ʵ )ˎU=\)6" x/mSOB$Ygo<pN!u.eڠcn5yN^IeE LQ?]̠xBqO?5o)DgAdG!YH8yX-Cb'~1RM:z|3z9<YoKbQs]t1Nn ; | |1t7cHr)jRaRܬO,Je:{$4/_scߢUr&yK<3_>ǔ\̞Z…!JY;*n8 yXOF`U}6Q _ՌimF-Pڗ ւhhWOYXetDhQ[%iGyKK%.*GB3cJj&ZdǰVF*^/z5URנ#] ?ZLV%%gZX.esM%;_|>9Eb E~,?ydDGQ 뺢OD_G/=oYN5}ѯ|};/{&j6Wm󍢶ZL߄=7cċ]yēKJخB3aƿԞbԾyA]*WѝCѷb&U*]w}:Xew,̼c"K(HMٻDZKЯPi3mw7+v-<.wΘSefI91W <!b<Ӆh|#{w Bi3]DwQty5糩ٜu|Y%sw$ZqW,wna٭2`:g.>siZSbxgl@VGT%//Na]g![6A0=6z\Nv٢O_>^0mmu;$h,LjY25msFC"<1)6ĭ܄™x!-l1^!I S#O1?ΤU=(2QT+TI1zk(W4Fe„b13M#g^ID>?BC-\"8#!Qo vI=C+Hsl.'^-zW\-s>$ 9J|2#{:P+=!L1=D-3iv *GB EvKxΫ77U󴛯Pm< =X(4~{B{QҎ .Y:A(}qW+%иJB.]K6lwV՚/@Wz ~,і//U0O˗gf&w/ ZRq6 ^lW?9?X-%eտtw&IwRl-uKVUJ͖_’c않[S S 7e'\߷?l(dE֦ @&v-JmN- xol O)Do_T-e䷈Vi ضs$5Ě9v.^(+$;3#<7iG1}@/eDgڔ jkKOji-Z@Zd]٨c^ԫ/腘F(P]j~- eK+.X6?6چ[RqEMkm]2OdY^xZ[L\[X*~潕Cik:E[mtKwܘv67<l{ocKOg~(/v#)mSq$oRtt_x/1^>/F+C;/v.9e-^ĩmkgH|D`Ue|\`̯]ji[~Vյ۹ݬ]q| eU\cPxۇzv5v_(b"az<*/<bqE(XJw--ј- uLżX!#< -]JVK6N!6+OΑc^OZ ډ5ӎpRNvRtCһ<_|Ӡ~5:/ j[_Ao sZgvcxEBi;cۀprGcŽ x6Sws-f52;%>L&.V#~V.QCkȍO# +n1~|ԅZ\r䀘54zDKo oLy)طTt[mYaoyoFx=c g<Ɓ\\ " ar1u2ߦGi>],o l m4HX3ܾ_gvLkksg,FDň>i.c[yL#6n mi= mܒ}J+y?a2#.+3Є-mXn—p| 1Ll>u3ヘWC2f]Uߩ>.eğJ{v։b?SD ywO>ܙ^mFcBx06ߺݛ# 5j"Z5[jZl;1S%ēFv'Ӣ^z 1cK/tA)P$ģS:}ЀH'rA#l=}bT*ٛ^-T'Ž fl>8d[Q;2[nG4mx48C%2ͥ!&uէ]1J=Piz8y$5[M cAJ\oȖQ7WXt vK՜(! Lh-gQ B>~!C7V͹Q9oB=Sr耦g"cW|Lq8;@Kbm(t"%b^Ь}[:mJ8 ;|>cy_YkֳR~.ͩג\ _2&~@rOSS˜db<]Y 43}tf$\׬hi?!$jX:-Iޞ1hQ|O C-{>gCBcXBVYUGCB>Dx9c]bkh-oZ1ނ|S!Mv)IZIqyt'SM 3w(e"ޙJω*Uun%&Lsj!2'W _1&7 &p.IЩII5x'J"&ˣuL1kZT|C-S8a<ئtJh0ÜS *lEy[eb,eDd8YvԼ2 /S_=4T՜EIx?QEAD]GWW!_팮k0ɤ@gkl\6_k{HIUe=KUq(O6+w ^VVO.b%/H=D(#azQqHhN pvWFir;:1T "I*+Ee?!_f6-`u"_x ,2Pu8{Sǰ(%Sl)8A`oVPR!@pb}ȑȜ,>8Znv,k@fVή/l;%ў$ 5ɥ$!@,Xn7Qh+J +gQ -}io:cm5ڰP2=`xRR3Sk"K6N7*OB<)ŵ.m{@,5]#jܪm,rŔVK^s~j%Tp g?|Vs\"^q̌|&5+Z tP$f2Tj`= {[B<4q&n%٤)*wuiסU$70әyvpyOFq Pn&&{!Nϵ Z'yi8yXOl6#2 \l>?L':()ҖCAѺ|I |;ӪZH]k5@5sv ςD'{CLOdLN)fWźh4gs~N%P?GWl~boS}H@6oҙ ^~ZJ> QCoeQq灗!_6w²ǟ ;U}K"L&!ȗi!3%rhJ9B4Mq!gWK8g/JeZF]['֟2SX@Iw?*N@T l'7p<8Sd)jb'X;%QtחM.ᓉG!w`@8|ų [AӸeBbxVO߼r~;;R l@QJڬNvm̨ #=th`PB<2V)뽚_襳e#H#y\lmPa7k#7`mĈ#aДmOI#vI.pr+QbwcRk`F-{"($'X-c쳼*|~@K=gYE~/[|,?ydlT$b}ţ->xA6d[UݭhO_(* $MZI,˲λ'roײRf)%lRI-l!WFX7._txТUd/]-rj)2&D2T,~/l4H%ыpԴ2%߅ L6J_^tbS eP:l`Z^ܴgatO䐆@8L Cwe6%W*917r8%~28co AY2(q+ǎp9eOP,il;bu^csrr왖x^UoR#C+f̙X.W׫Eoyc%-'}I(2伓zC3xciH e"pZw.{?c07y7=Nm)Syl~}iL؏7vw6*~st HAV%"()ZD]&Ү riʼn8y<5sO9߅*72izms眇p5xL|ƣKfߴj^& g0{>%\64{J5OtW4H/0 < lǁW _iEz|XKN\ٮy{QGtIWu0U e KLR'݅|%v^tI)Y֗%rqEK$*GBAy"'с Lgt}u6e7-79եb]2ʚ<oC9rVhq U8_btƄS6?$%kz494kL錢 lIY+ƠL쪹t<@ՐZ&3m5 fP!K':+Q8(!CC8I#fh g}~$'~ñV=SYEV>;WgF>] 76$W!km$R+^|-b-w xucQT MZ+j ySx Gn:cvi:?OeLK{$LgfߢUr扅"+S}Ca_j=YU.C,liXij4JSO6p.ZjS5sD9$HGZ5IxmXK;$"ztP=S:tdPB< Cr#6a4B4C;ZCѬ>*r|頮&PP!@V>F Pw*Uw[B%5 ê*KJP.Ǝ2*r*.8!VTF!TRf޷mP4-͠g2tXV`;^5;ʄgAr6cxYzZC}3SU̫AB1+9kL] "EEạ' YJ.IwJn8fd?U~Kx ˜ϲlRm05.jԵT6Q;fMaC\-Bs˜]{-z.-gbݢF 9]}\H }U#lKl~vNUp릻۷CSn"&.ٮi{chchp{Vft,XnLtm%Mmh<WAH="Ko)S2:7@ ѵ FMA#q70d&Yq6rŔlm^ +E*x4h16&2kbK}XRtZ=TQ 񤤞z"<H tJ-T~ hxزӯY+ccm8_l5rPpX[q;% Of}KUB8O4ũTN~8X3|"6g uD-g _2VːNJކ|;ZH$v<[F&2ISaS:/#Z)BmR7EI.A:St n"@8*ub}6Xj"۱kWC`؋BVAK fbWRN>f!M9 1U{Qh?>JSqt3IUウ(ޱc+u"h"<%Cwxз R=h2Cjڦo^ُz{_XfQm˞v ׄUC,KHVLE zS(MK8:Bk!EiuSOu{Bxx.iB!5~p8 y6`b8c7?_Dz$4( D@mOj0ڇ ߗijۆ^+sB)LjP^#(kĤw &+|oJ ԷجtL@h~ ӸޒvxpI:wA>hRQ'Yf4]0Ig/2<YkSH])G!m*xRYID4'D/>ˈ8j@~m(]JltIr-'ʡe=${Mth'`6y~LGlgt^=nL?Msꩋh= =Pq]4fm;탼oT;#>6ITN9Isa?!7(Oytcq)JR&^:*^^cn9Fc1So~doqi"Y#r9|)PG%l9|fMUJO>|n:!*xRP+XJ'XÐS.6GjP8m6y:II'%7T$$VP)P}5"ǭvJ#b\మIoeשj zbe-3Q֊7c2*~Ltd(Rfd]PFb\NoDZZ]v9e7mJ理U T1] BU s+Nz,BkgHv"rdtZ/)\G UtIp XB0/-h Z <0yLrɩOA2^<=@rf:9 ēNK߮UW?욅>u& }J2 XB<)]ذ]xR($B( :IPtZETI tiԀ@<)Yʉ'NH(V{c!ٸ4BNfy^B>yUQ$ģS:T7-k{VeWz|G!&䛩Yӗ{v$;#%NEPG<6֑qC(Lgf-%4fmܘ9J+`Qz6 ,˜Ei+.@6=ڿ239Ccz'co*BFfj}HR$iOU]흊ЬҙDZx kDzyB#F0?=!!K{1kS0p\j  rBK/u}QAj=lP\Ҷ]"{%cNhKP%}G)zyxeB{Ð[JK G  ˮXBHnFKESSU LU5D2k)݄XT\xucm)c*x iXVJĄuY)4s>R6G Յ2&4Ժhr(tV> CKZ+;0. j[, /l5s5 1텟V+rS%za"ع^J SqrcDGf:J<Y%UIW,>)m`Tz=; Q[k۰ܐRJNN5"eckiCokyɻۦ)-SQq#:읶T2QA1c"#[by١cEzcI+S%{)јʊS1WmAn?4"dYySq'yycǨ:w-661ң-7^J]w53F} JX:=w2Z9*-s+*[B ̴c-XRD 6wx>RdjrvLlB&J̱QVvZUiw2Н$W.2VA1j(^|G~{szf$}]kOϩ$LS#CR0Դgady+P7b&Rٝ|O“Z]03UkH8 y"C`:e}@ cM+l+tˎ]jSTAptkNdNT}s!iDz.U8 <YZ!t?Nyu ފ!|HEqb¢Apx Ur+ vgl PgV \䦼zY /hɬ%cS]9J Q87!%kڵIJ1%_EiO2ivʽ#!Nx5 :D ~@CݭhCP"Iiޅc}#C} $qn1I쿨~q+Xb$ۭ5PU!R'!_6&w| ךr ,T6(8ỡ{Uv]BqR|dƴ#ƤFhFB8 y45q^N@H]$ƀG 녲?Pn{(0 9NC؃@1ʻt:-S;U+QO@ل=ۍ ZA^Zǒ9>S1gSw܊:+AzT}'tFBj\*iF;:%CT 2O+/Q~3׾M͏lKSf(+ֺ`C> =ώ7QǦM-apvQSC-|T _rRG旜zME4%cݗUylr|WJE+_;Vd/>סoBi$q~6 >EO@I-O 7L'8LSr%򱱟i#΃<|FDcNB<*ar-1Dڦ-w D zhVoŠQٖ1R+{i@BsejԜd/4jfuj[Z~B( {{7B[Ԓ?}<% pq*l~֚eM+lgf3jVsQ^} Mfګr-s̑_!>clsRXco *䣧LOKZVU tf~*s]}f_uB>}^]8a|>eV+LV%%gZX.esM%;_|>9Eb 垆^ Y8h|RV?z{㪪onޥw^LTh\aT7!g=j]+_U)Vk|Re64ީܤ-h*m/P)3?{uXpKa?THoC6a>X8O)+a}*&4߾&ڋb\BIحy 5fm{fDDj8yDkn]V1~!/oEq{t%*-۫œQ/Ю1pVMUT_ K/p^`)y|gӷA0M5~m$U/cz:v1P%S-|cڬ:&"54wL#:#c1YH~@<\{P@a7eʹ !km5 'ΊL*(k7;>j lJmԨXHf&AV^~Zq,=ƅq)ȧ߃Pq,l{*~RB<]1*Vޝ-nλqK(j zb yi:B2%5 j0TLGقKGRh k9`!k݃WgǷu6߉R-3X1l?&)}}YьȎӻ 3|42vV۠^;2'vchkTѢYK+Q?vןʭPb[]dӬɭNy ނl~fMt^=Miy*# Lo!`SLߥ μ":!k'y ̼HB<4tV~uO ?0D~P!}=oދbO;aO4˰OVvU przֈ j_|plޕmD3_ ӻԩnv e.SSk?/[wm{۫+n)t| gTqD㐄coީ6BIQB_ ދ|{+;{wiә4LuM4F$:`+9 Z{y0s*nx/ӵ(a7?g`фsevqAſ#a:s=+YX϶ '(>ga鄧!kk@'1f{)l6Y3aSw$9ϵնڶC93$d$'Nѭͭށ_59X4]Z"3I+ouGl_myXwֺݵE u,j-֭MM͸i3[Nx/ oC6?lTx`̄^E~?ԂZè}=oLۋbaGPT _zЩ4$Z@}Z#$LJ Z]\u*or8sXX-2=)6 &<Ce?,a:Q՛_BN4 B ~@7k^:e֢ffQ:)Ǫt' ͎ d󛺏x]ww?BV9:y6%). )rވA#WfEiij(D>%">~QpRj ϲ;8N}Č$!8Qqׁ k'jQTc捣_gg&!l t$uf_ fW}5c|fC^| /B:l 3 \w 0ʿ ^wI-R,IzBtC:ĭf M,6k <|ڲK\ކf`m5\E̶;Ihޅ|c*xL}#Asܣ47`WJ.~A8d%RL WqȻN6Yo :BFl]jy;P)<%q &' HvP~I'S=vV,iz72_a6J<B5V.,bb1&УtZsU-oD֙XK]-}9_VIi^iJPq{3a#{`J(d޲߀ހ|Ø5RT Sp*9m}eMGX߅4q{(ZKz.@i 3IaHvp(*0k y] T툸@6_1+Dh6?e# " o @֚ʫ97<Y+{SkyV T,e4XNe;(VD$ǁ%-{K^թGW%.C/pCMaŗ0<'cVk/ H_yaܨ |KcN =<S1Ebg_SU/P>@,?~wb8f97x8/H멾k#L/E5FwިAg9ǽe&'CB`.B„鍔y~9rX8Gva)bC&\lxdnaFz>QL@>g1:!$wMa`=Lu?u!Am =a=hoM! 5Oıg+Q[Y+%s7AaZZGP݊XepPFCUK/'ltS~71Z pV h2OXV B5AHMߌQ_ Zޞ(>"u8YZZGŝ^eqj]w8y܇ %Ue]UAy+̓)) TU tVı}=HohvDh~k*9p͚hڣ]vB['Loyu}vh[2B7ΪFjWb8ԤHحGQ/f}A^{]p /7&X+WF P{W wCWY"[ەzf>6TP?U}8.y~UK믂8qcnפ0VMI: \a ֪ L6}Th/|W hM)xwǜeq..W T kMhOZ ,qS<7' FeU'!kCle՛Xˎַnx2ڪro@0XQ{keoMwd-)$YjtܒvMUy_0 9ۅ!?@لCC#%WB<UߥR-I#86<=Tjt-x5;*5(<4&^wr-Iaܟ*!C/*34FF=B1QC2UueIF`FͲYdPjX WKsK]^M( "d1Vs9 D# ܇ YjeAjH.w-BTwH㯡 zR-PiMP}&9jEywQ_G?Ɓ =X$}gݍ&BފN  Ot'=#.3yZV¡s*nxCT ۳zdgG_P{ NZd'Z ;Ө#!N+wUC[hD#t>zP:&-yEv);v1x1*hAZYmPW mW= :l~Jtp2OhMmuX;{ER*L0#/ 4|VcX#l9l/T-㐏wޥQ@}7PT?e"?%Onq_̞~֭N= NGtǁW!kԆs3l0sD_O's1nYF5_jF7ͮ)4S0aԞo@OuF.fȐ!({ĐinzqE^1 G^|6 Ú_ %-%W/r^#9̈́^k;zPQ(bQ5x@р7<zm,Gr wzTCÑB~P4\CJS/ ]4*\*Z`LczJv3J PN_[3؈Z,B,Ջ;Zq` 4+q6dՒS(X+ ^a m]J;AШ[-uȤ9QFOzarEv4lF^`3U 43w |w`>-fTvnh$w //8)d8eapS-P~`-D[3MFrK h"Z$İBvsp6ׁO"9 eJ / +Ado%jܧ]UpczLc/~E(F=ƛ2i-83Ƥ:r2 L+S!0y0 )QKMXxq=!FdՒ)D Kaf?)q7roz5Wƫ>«<2~^\ٕpgF(\WX=nK~WU#Oxo?M-͏RV;utTSBἩ܂\ECMSy*W!,?=\dZ g/}Hdx!nݫuc**[ΝʿGf^Se} Lɹ<(F̢=#zOvшR---ni[A"L?ͪje#ʺHWe╅fIǀ#9S{8JDJ8*(A8Ë݋wur HN1t SSYgƣ H@^~`6S4&#޺Ӊ$r$qQNLɧ_z'TMT|y8% R#x /i>qvd B{YXb. h,O?,䱁v^E+;y)KbMl*e5]Bgv*;7ժ_lUTycwⰉÇS/k:z`eWʿD=_ ˥lĒ}'h_L!6r%Frr1n BgUuKK|苽-Fhj24UItNO. *%/XƞoƉÝF- URRqsH)#,`]gC3")qF#-HLJo2&>m*:LRl~Hy'd1 ,ǵG^oqmRI81&1SQiI$1 )-H;XRmD(n$g%v|혊_lx4vn4 [nult:i'"0]N9"9b; )\GTMx"9s#"ɜaGNKdN8*~Sm:65zD:ƣ/R =ɚms/饄)(s*el%.X+W. Kk./AbcFr; }wx. @ԉZ.#9S~a&DF3 &q5[ 9FrF FCō'#9)qR\RH+SR#9S]Tpм l>KLCl'FI\F#HN".k&D$uaM|Fޑ)5EQtT㪇t/Fr Q #|:)nZcέ(0hvRStWq(in$ 7G 8؁kT`6Sfo$WyLӻf:B}krMs֫0H3R2]mG[.>Wen(svZ"yP= 4`D,׆@; SĖ:TjeRMƔ=]3*ٖ*خZ[ݭ[[~JmBZXb깔vɵGjH$wm Fr wh[HC=ǀ'#Y/N|EcD,p:;DYM4bQlCިЙ(:[>q<%pR H&4|[[l (Kёegͦ>/W j~Wz5Xk_`pwD7vZb,zTހ/I\Oy*Ы*_ w3==QYfSy]:o9@,/1g'~ZлAD2a}'w4 iEvs.*E _*RNU#vH&4d9$rS"4Oto8J~jSvT|O @yտ@;ZerN 8ɩI(W'删)DI ]GY,oyU{3+^j@8 {Ho+wZ=<̟4 =Iia~m$iy6OCѤnYV.4GD-:`e}A@AR} {j &b4=#DzܤׁJ Mhsa3Zѩkw)ʄ!>maj-M-fؕ7 1J!͈㥜5sSxjm7LC<Bk͠Wu*ZS !Ac>Hيٜ-9A@|VK;v/魔^VA.٥ {38%dL|j\ZJy}\E8 ^Z nn0R͜e֘ 䣓 Sק~^:az7>x(oN9wIuZLG?xPXk`kazjqi--o\|Hd]nCԟӒ }"09B_:1s2Ӱ(SA~?pV_f0jwd蘁j{乮AuP9|'r8y"S'>b'!OؖO*4F|b=f5"& ;O>vR4͸T!ɚLӵNA*x:myH. f. WK;m)m"SG5v3'< f-R"] 8RΈZ%'C!92u*nS:J5w?O/^{yǩ|3I퇖lVv*a܁O~wik7Cc! [ -GN@u)2kZjB:bxE 0+xU/ʀ:>$+K]nW/~7S[l&$jv"82Ƨ]6 2fb8y< صTtB-ŹCxoq.KҡC$$Lgs'X?dW{vhGGJnCVJlkerY# T.siL Fe1 1ѴrPB<2V)뽚_ kNB=#GR3%T[j k#B4C! ^ͥ)'[/gcߚLOw]zἩ B{YHr@&X~>dYV+إJY]N^5׺+LOKZVhSl?Vpb3ȯWe}*ZS/kZf/E,?k?g8xr)k"(d/~_ ?dxJ,;:b""&hx j^|{y3Q{[EGQkL6^ U]KVroײR0]_jO-fJNo88!j,>T6w!5vVu6*{cah@`Vfda){,X#Y/pҔ=ğѬԯTO"bK!.U텼WZ쥪t+ryYWZSf-إҦNu^|E:NoW͟>8xt |I[?x iY-S"/қpc)j-6a'V@<wgF#zT.M7BbgLw²@e;pUw(JvC :#Ƶu=-y:O nEk'u=<✲a"kM /߸O @6P pWB<70m5> `6Yk.J)1"!C^8%Zŏוƃ+Z9jՃ ZP'auMƽ ?Û) vn#HDFDOyRF,7SQϩQI'O th#!bb~\T7 #99XNӠ7|; ,YјY/oI+: m:jiPdiPFgݶDH }p(9`PbI\߁vuRqwO!?m;{6.w;ΩO۹{&^J+qR O֒}q`VǹPįXN8{xxmZUƠy|;T])Jǐ.EK#Aȃ?$aKA÷>7S=POS=OR&MLA 5ex۰C@\;]淦aFٚb-D!x锴A9tx].@Ns!8!ށn&SIabpc&D2{[<4gZ+Wa &yzܩSgot/FU (08jT%\ͪfE㐏k7wRW+t ]V5$wx'S?dHsiY[ܾhwnb͛Fʯ yݽ"aFkтKA8 YkIljE _32ic*]-2*pn.D㘅nFISGYæU"=\uoy:+{E؆Mn$Zd:v4-s)K"JcWWc'/Aq\6*ށl);e*xLTjP7gW2q7t?Q7\G!k]Ɋ-uL"ƵPqP=Ѵֳ t. Ӊw3 و̓oxR h&.`t3iȤ&KP6Bҩ@)"MJ:Y!R;{$4k=tѠxLS̒JYRI*鮍܁]Է#wQ&LD"gPb]{ڶm*$4Gݛi[ٛIw0d7SCYIJQ4 ,?b[&9e6jw5U!G 3WJRtUv?&7es?s?ӈ\1 YV1Sq!n1Sq@qn6f:EX|YBl+;(YTI5wߢ)5Zq,CACB<4Ʃ]Q}7 Fjaf vZ k Z2;72iՄR@6#V.W~OKCg!_&"YIWdGU@wz]Vtޅ?qR̈́^)!{*7Y {>3"ht;!Ci3 UJqm)SyɤU4@^ \\".[dMbDL=ɖPPT@ol nD~/HmvԿ! i6"dʉ-~JiPTJ)^h@`֯fL=q*OeNajC>PlOh;I%Ź߲e)l([g.射x k*  N7"Ero&I$kvF1$ 2'"dj:H|XQ{-Vt39sƔηf,|M`j"_9tVo5]wS4]=oT"EcQ?B> b7jīNBNim$!(D`:#b;ůd?-jn<d6[_e-tlۅvY٨r+Y rbYȳƴbSf,q)@P-ǥH䝏M1|Nʄ+޺a%C>OUaٓOaF3ˇ kQw7a-O$KK xCȺzmuR9AjmqWר/ϪXmN.ϫ猖s#J^?C(KdҰQ$#h6l 64_e/1,a:2bu%cU;R$ [la z^)y3W@aj: & zw I'NBkÁW:| qjqC~3JyJӀ/  rΣ2(oAVg +Iy@Іl@NbXҥ1#!:OE.p?L6yŠ%f,ZQ05e1 G Tcә-ud|&b~vB6_Л(DhfBF%넙^uҹy1s-#´FkU.C_-u`;]m ˂&%6oskN/Bhxy<&yeK/>%XjW[+(-_+`ҞVkS[նl#Ҥ@h>sձ=48Ӑ3o0Xb5xB>{o܁a  < |> k}47-Lg69tEw_'49thIʼn<=FM[t *he'0}VC/5 ҿH|vgArmCT\?dq 2tJtʇQ̛p\꽶Lb!mjk$T@a A^l|,)D0ЂluG}l91h~ↁG!kQ[JaQ+!slyzJ+ ބܝ>Ro'L^ :covJJ Zެ rѱqnˤbr~d?҄"1-\ %$ԛJ4cUcOs Kh~0G|#UA&r2v*E4T_('G 7صT1% +0CQkT|x4ǔ2Zrj,2m2<=?l[ ):,1Ѫza;rjp De]]:8(!ZyX\_ k>zG f"Kv-\ڠ>| hf#;M|N L$_F֯C'f %~/ck3gl%@fW c+U] 襖55 CڄKJdl.Ǝ21.c'(.~V#Y7;tDkE\!֝ienUjۨrj|\BxݖU ePf)X|iʀcee;7S~S9RJ3W'-$< 1+l>,Q}ɧ(kwO@>WٳVvF@bB*GBq[M\vܗORRL69뵳i-XYZZUMuuPe hҰIun3.ޛ|Yl%nZ1@Vm֌ўA`L}vdنh KbUدUjN__)|iJQncҔJNedzUvMʎ+0QIP$<~p<2ޝr ninF'}{!kfRN{jB)HoUhvT%,n|VV~rGؖoW^*I$Lo~pTNš ^4Ȝ4MCd#aFouy (׺֢Az(%y$h.o,HvXsy!JI)jüqm7 hC<'`[^f7Fx5;qXB<ھ՛*2Z+FÕ. Ije"HAݞV6u\ PZlj9q *V<֕iϗZ9w[O i~H*-wW)']YR' UYMl5>AD4)ATQ=9:ԦC\!s Lh%v3&<D톊!:u BCNU5"`+S>jOHح>~0igT@5jzW1qݩk2Pyv98Ko*PŖv)%/-PZ:;$aK *Z9+;3AmQx omxk̪JV BdgiU{ŷŒکF*BHUrYȳƬ'pbԪyT޼rIE|RlO$ܷ{jT]QM%I|‘an~Sje?\޴Jj ͫ窣r"ux ʩ됯+O=-X-ҍLS~E"r6ߘ@F2v[*VB!kY l"Ek8d5u:әFNY]''SOA)9+7`4P ݰ*BUரɬxHsɻ 9v{_ ).&5bU4; CbkxxD՚w8 y xQ]؅tFכ+p-2i *{`LAwQoZЮw gsNTy/+ѢFl<{UCk~&LhAHNwz=/)ܝVOHIJېͻ1e1kjdT{(Z`:^E'/( ou"qCqQqÐOXXG4 ܲ[}63: Pڣa4f^8M- jpad=ިy#ȏG\Xz4)iȗZ4uJokV ;䄋9#.hsi{Jxdf-z.~LoM&!4Z-uH"LfmJL/@`:/VP199^+{Qh[#3 !*,dm=sV^ly=qFp`j&ANJ KF כ*aT%> 4d5kDv+Q79kҞ_t+vEOzɿ"v ɏl*zDf3 A0}|}T ^}}X5̖􏆯]LW7T|f{f:kaX nAX+^~5rfŌ[):otrc}MyZ:_J(uPy;H'߽ľC+ ?{?n[z#Ь-ҡ1̒azRI)l]`ld)3PS`:guEf5B}_O Ivjo|a;\λ0S0OHJD2Lmf$=B2L9pK1JAJH?&QP5 @AyoKG7'fvX6_ :Ԉ؞)dg!/ꤐ̕?Imj.D[b>*V~ L g YrTrS=]q:,s/ ]0@?\Ɩ0e;Sٺ}愥Mъg`L:h}޷Nje'KWN+gݗji!RNe4 znTun䴜FÖếLͺ`١]4E DW@0 9ƁטYƾV MI6s#9fz.(kte~:$q"cafou+M(1|i ݚx9Ump$<ݕn5J'Lۜ&%],2/YnDvq nPn"wd|NDQfY3“OvE^IUӷm鷹Λ&Ig~s&e 뚆o0e!.]6}q6eZw\ ^ؖH(p_h87tu5:o\T涼odh@0,۰\njw-zmT^!9ԴT g!Ϧe͛U4ɝʾa3|Ó+C BkEٽoqɯNiݣ^@Fʼ6p1]SĉtY7ZSMP٬b\B&N&Yr-#!ߒR9^;Et0/~#l:xm|7Da(ĖphX,+at"@ihY(4ڏ^>KK;[?D?-O>ߴN?/~ K vZkg7G44@+oSJC<(':+T9]}j'ԝKvɵTEO&v)PcII+cQZV%|^pD#2-mwJ=TQ hǔN4 ~fL.V,:]c҇TSCe1&tRGZnFl-#MEiJ#1cr"cnwÊ bCfIׂv|X19qE'la!邫S^vEtyјU߮T뫥TjF )JY5y߯kK:a8 i—sv!?ѓ5fIc# |, Ye\W{o]> 9k>l]oWMw<#s|SYZJiF6/s/@h4L 6OwsFHh6p2s5#a.@֯ qo4h JGV:BCEyV&qZ!sH=pO(0N h^|E\[*Deo02lsslX 1kfk_e"rx!!sXW%sN"*GBHTK6|@,hPljh%fhY;ZQcXGiSo?~ 40͂i Vc;j8ƶ[Z 8yvSkr \dƁ' M Q~z~!_Nu56[=9UH; YklȦdh\ޅ|ט M~Fȗgvٺ* 6k/epatZvJކFk~MH^ZlwcS=vcF5δcWJʩA8GgD 2sbpxi؁E~@ lQw8 yXO,cFctFwhVI_jn/s@(%iw̡AR@~󍓊*!7ƹ3:ɤm8 yXYFo)w_58B>k4NB 灷 J%,Paل!N؄.@6_]8j5 C;|dwzT7%q751sz8An8yD.1\~UrRPnamMP}6,mj&cGy̢Խ kww1"Yz6dIgtȩyj*nxVga 36O15^;/|tS%qw<"aPAd-Т/姱m :5x8Yˎc=Z[֒|`Sl[ em2d-Mj1q|H:˧SpuҷeG)OgN{т_VH8TI(Vs⟎E)Td;lAnh>Li!5ï0w+R[N&e˾0YUDz x=c hU΅l\)h]-v5[eXj69vHŊqL$?+!IHJmSn]! փ)ZXcƶM.oCNs()sټsVm*x:nWaWj۽y\[|[EIm5C6 Bp76'T$$iMЪPB{'7oN Xqe,czW֞hpGU-w 3Z}to> Y5M⨸=^.5w̪~'!vwKCzQ"wKT} CKu_SvU@HGQ)(@~ 5@Lg*37$y* BֺAP d-+݃D/͒2bݼSV?%jD:Z/ٕ(*{KYȳƬ0.a9)*{EpYLU>K $g 8jwKes͏5ت-X\ހ|H9xs&<BRqC6EuQ hh})jdȫŞ[]-mi.u˘^܁h+TqUW-d޲FkodaܾI?1œVWgs euKϏѶg 3O6ב.*wYO*PtɗNSv]D?3i,V6;OB[jRkq |E^=' d X[~5K/5 /@Ę0g5wD_ 0Ԛ*u& N!OLv-a39 '5t'JCIlj;$K̎=Q* zͲ$YgX@}-N8&^e!JJ@yUr]@(wWTA~KTtFH:?B}R hDi7pxM7?=XآKQ5Oߪ; |;mA@)9qRRxRU/A6w'DVPu ["xǪ>1“O&&°ܜUffU 3Аӑ C-1٧bgWٴs"w/fZpt}-wxydARqS6Dp6wT4\M vjE!BΦfEǶ߮jX"|a J 5yZYmݴco̹pnTٿQ$dklvŻ *nV[`㳫>jNVVgKFE()2$vCyu}vr Dx4\-c-aS%w@@(}^9֨81$d8qiZwk4t8YRq A8Q9(6dh͋.w3;nZaTR^Z([&Z@~VsfPn,ЂluF3Sz:nCL?)ՂW6Do@0%3;] .Si 3ɈU e6($]v,CF!Z!4hMWҭhsh>H slωla jRU R{ .6ɟFK'kp"Rl~nJj~Z*jЂlT^[Ctݢ 'fBܛ֙С=7(GQkhMk=%{)9yG[xM'o6XlH&"TUP%n߭hN߰Dx:_(n<' KigOU$[& ew,_LĆ Tٷ*=6ͽq"ElTdD\`s&-bm7$E~2V*0 9PJ}c.?EmV@=Z(z2k FǶٮt.B!L^c\MDCNbZҸJ|XC'a-8eSB &lWq; \lPv5H dlY )2PBX[]mB"xB &V4E7|+%',Px*س(!Ksޕ+UKhv^0nz,L8Kеd.k51"eQdmRw-t1%[ɤK)wT|x4͔uxn㰋Mw73qZ3&$;-0TSeBGџA^{>CÐS!q=~ZiAM"7|Oc]a+?Jwus./7ʻbf7przZZ 5혒7Q50GyEH'5(Drяe%"Ð2&qrMhOU`5S n;Z0E\yY?k3+W| M9$,Z"[~R̀ʞⷃ 9ZLE LGOHw኷:<7 -U?gtL)vpv0K@wO=!ٯb'АWt.d%5@:46x#Zf]Bn(NO ?yǨ])5M"k@N5r cP;KMx)j p4ӱTۿ @8|{ޒrppMaqDXA@x޹8Av*P){ٜi-X xVywCW kmǫ)wCW!/7F*kVy`Bt@K,<0Q#Ü3̐ yRKUq@IMg QL|1u\M:#469˱igUq9<4rt!d8pXs)6iz^*μr}fjUixրPͪgBxZ,A1|1}ѬBcxX__Z~GBG"fӐZvQy懚DhWeoD<./Clg| ^UMUn p7AӹOggx4d7vef^p֖U,tC$8Rߑ:Z7j^ F!kyIbwA6tl]Tc l]S30A1G. 5 <@zS,1+VXQiZ:* 3fNCNo8u+Ɲff7 foB6?1CսR$n39w^ٽR Iٽ4[sLS @֊)*(7qzD]w[чjC{D5F8Yvח*iLt4$)cJTЂlOP)}E+#k qqV,p1UBduLCO`3NGA އ|=b ŌwqW*MH&*^f+=Q\ej\=@B<4NN(ݢ|>:H_N^^!Bg3go;T. 3LXpW[eM MSh]R䮲mF\ܐWx(WUp\l~)[Xwp{'6TvR(ΐ>O{sCx§E"EAc"х#eGVKIx/h霸WC\eSㆇ"? Z1Gψi4{@* D~]t?q.YUDB8 y45dƿR>٩d6\wW6g/ hTyc ·S/k.X|~3Y"؟5ڟgs<-SesM%;_|>9Eb a;;KFh# iTn-m7Lţ->xA7ULK1.*3bﶷ5P]x%ǏOx_tޥJO޷kYL7kK){nJ%I-=ϋ1j 63h>4C)v8uG;qrإK"Ri=c0poooSOʣW#`zI\wRG^wCSQ ?zlgR&7,(Sj 独ע2Yu~.8N@07zVR%erC6ջ@)ԴU*z%*wZK d ZPpDxf%F{D^C`:$նΞN2G7&}Ѳ&0 N[|cVs+lx?O 8Iӓy)W2ҿxIBJs%my߼I]'c\dV#p%ܕo<狃+WyٹtklWf]^( QՕ ֛Vj hq%,5Zcjz-㣗/p3@R:ӳOD􈽴?xPkP`k6+HغZY|}, tKs`͍"|mh4`≹gX{# i7 vet+(ԝKvɵHi:)P%ģS:Ѐr}bqX͡MLn1ފkQe=Ƥg6 Kq\,CgbG~ؑ-ҡgXB<EGATr- eD7'jҾܸ ӗ/08YAS( ]`KxYUNtnFv 5s!(D`:NqsyZ̩/J9αk{شk U8_bB0MIVǴ#bѩҊOM'L|=OCWiެ̕i2yf^hܤe >ّȟ5q瓏&±L}Z^ ո}etէwz$4iM錢 cX+=CXsqxW r#:b+l,1 '^ťO0𲖝(2CKf~u`G)&JK<6o{W;7.ӐS(#ϧXlJiAM/B'ҥL3Pcc6NJ^0뤚+HmvQjF(`؎Nc7~㝺1Tje)־S_(N#,q7 5{U{Tu";*x i]ڤ[-n35 ~AzG)m}B3;uRq' wfEUܟ~fKvt?{$Vzp$փ4 @֚'3 *e-R|/^cm؛~y^:aE7\tbހ7{?z -27i$"tMn) $Loz5Tq4d}#kŷ*e81+H͇yI:_I/n%pPs(+Sp+=<*Z6ϤE{SO2+Kv"P#VKSr09$@el<#L=:fEQ\xƛo`QNY 8H&:6>ssQq!k[np|U%y9c&y٪:-"*U$r tMgy,\s%avGZq FUY_Khz/U*3n'qf4BZ_r'q G&aQzGOwLckDXq4X)ŏvz_QE`rz=9Q_}gsLw-!mLӑ[]Z}{$ģihKty["dFPsC{ܻ|*EhARkŃ`AK,!N4ʤєG.Ʒ|pUH:PWYL)Gט̉-59X]o M)Z&e @IDtꮍ܂]4 th{HBfu *2{!N`'TpDǎ LBVCI,"$@6 ǽ(:b%"4[,O++.>|^H@C.KQ+ФF3&$IXƞot#6_5{ hF1v hn{}#4DGױ3Q5-#4PF.S~Ss9+I.x%_|>Dց7渫kR"=_3w(3ئ}ʲA%~!ʟ. TM^@N#&u5[  k~ nSv z1)4 z!k-Qď%Kf 󾆊PIl)Syy~&@Wۿ!B!u:;A4CVgjep U}i ^TK?3]rTP5ʽԛdd-f⮶#Y'ؘ$aeIAo;/ěs43Z`&=g?bG猟b4RtUwWwWWQWĥ(>]vNCl*ǛlaA lT)1A@Tmbhb^1)$E{aqiO1@^ ~:=057-^Mk]'@y1{REUJCap Xvؠ(Q5T[ϕF@\l4I:|ѹL4ӵg+wc<ҠxgkĨGfT\%` BRqSeQ􂀸b{c2P+WzxUq|688VVoaJ+D%6. KSd+fWSڴ-6#ylV\~sK`qCi5Q4hѫ%Uig/5:1O@4U.Z=촃"ĥ)+T_+VMsS-k.':|`L.V *. K(M0Fi-$2yYC$YRt ˖ZHqucS|aIV)` tD΀_?KNGҠ1~:A 8"G8$ɜ`%nOkF@;(Wχy OGoG6߈hZ%vEKSbMM*aV]$/wJƞ ٙ\k9!cS^'e%P t`(06=ܖ*Ҕ'J/`|vR]ߤb&Fn )7OT~ 8:yt#\WKm4=ݸzRgs)&.Å;)6htF#پb6鯨flF>k6[D򑄧!QW3y%oĻDf,p aS0W1azEa,] xqYxvo*<4Uܲ}vzdT]ɸ#f2("\{F8Z錇fG R/y=PG -raE/N{6^;BN ]vh＀-keH'0h|z+9ێzFܥrEUpN-bl 5b8C P&렯kwּ*iQP|nDdba}E83R5,VՊSɎݍrЛ\ӫVj3FmRf c湧xe˶YpGvSmem$m=H)}<\|bzMlRPB8f/^V+9=0KyXڤ8$&IpYBVd$sv_dseBژL䓱jR>=׀@+w2MJm"/ȉmZ))>ΎF A-I*ثI[x0:pQWz7Bx 3Ti95%*Ue*LU !/0YɣM~7t F ֨os{*asfMLY~U_2G8FDg-UrqX:] ]0X7GZUj1]QΨ^cRsVb Y'\v[hҹzDů KsjQ|R٧:Us>(cx O*n8a5RЪhuৠ?]+.+NUC32EqGhFt|p t > seOCѺ)Z<(Ȧ4qZ1vOdۑ tlïz u sT9h~JT$t8 z26 vZ,mz!۠okZK:01 tLJɊhhDr7sj;Kx*hx;E3=-q3rfN^ #+=˖'[.z 9slo. 4&'eZn{=s|c\lO,OiS o-+}}%kK?GN5BIsg3N|j(9Y!@/Pqqҹ PG)jK=mc<4 \-$yG*p &"Pug茂!{YKQ*,pPVhtOz53sζ6×A?i"+KvS ܋c2(hٔG,\Vb48ZiGiӽ~[ds Cu8oV<8+83'PYBܩ{"tT%$;9>/+yˁOSF0}L?|lSrt h>q)v3{3 `F4}5Mb4[l/o6oXe1AeLO >qo^xUf]FwIe}YwYeA]Վ=z?efNą'.,= otqc:OlG)ͪ(WMLCᨵa۶Uah Ez".oSO'0;tl"q4g4}Uyl a=%W` B;|W7(;x6VqA75C26fN oF\NZq|wGb帥I)~F 33L_cJ JI;j<{KZy؛e]kz|~?Nj^dx`#wp 4ߡiDuC$B>TvvAa#sjeJ+F[QFd%+8yH_}  ?d F}}В3JL(d?<gR:\+>>WBM4q˦5>*U'vaVax> VYnN4mxk'S?Û피}ڭV}y>+CTasC QnLE|em אc MW4p*O@e+Pѿ^Pyv7L΄?:o1yhVk[5eZW)5?+e+ywͽŹwy>ٍٗ`e7zY)b.ˆfFL$w0Ϻ b.)-Bxc¯ai~=zpphUDͱx3W F{p!/<6jܺnm-f 6Jޥ٩دZnI_.Urgl/configure0000755000176200001440000052737715026603605012775 0ustar liggesusers#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.71. # # # Copyright (C) 1992-1996, 1998-2017, 2020-2021 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="as_nop=: if test \${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else \$as_nop case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ) then : else \$as_nop exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 blah=\$(echo \$(echo blah)) test x\"\$blah\" = xblah || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" if (eval "$as_required") 2>/dev/null then : as_have_required=yes else $as_nop as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null then : else $as_nop as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && as_run=a "$as_shell" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$as_shell as_have_required=yes if as_run=a "$as_shell" -c "$as_bourne_compatible""$as_suggested" 2>/dev/null then : break 2 fi fi done;; esac as_found=false done IFS=$as_save_IFS if $as_found then : else $as_nop if { test -f "$SHELL" || test -f "$SHELL.exe"; } && as_run=a "$SHELL" -c "$as_bourne_compatible""$as_required" 2>/dev/null then : CONFIG_SHELL=$SHELL as_have_required=yes fi fi if test "x$CONFIG_SHELL" != x then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. printf "%s\n" "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno then : printf "%s\n" "$0: This script requires a shell more modern than all" printf "%s\n" "$0: the shells that I found on your system." if test ${ZSH_VERSION+y} ; then printf "%s\n" "$0: In particular, zsh $ZSH_VERSION has bugs and should" printf "%s\n" "$0: be upgraded to zsh 4.3.4 or later." else printf "%s\n" "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_nop # --------- # Do nothing but, unlike ":", preserve the value of $?. as_fn_nop () { return $? } as_nop=as_fn_nop # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { printf "%s\n" "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='' PACKAGE_TARNAME='' PACKAGE_VERSION='' PACKAGE_STRING='' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_STDIO_H # include #endif #ifdef HAVE_STDLIB_H # include #endif #ifdef HAVE_STRING_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_header_c_list= ac_subst_vars='LTLIBOBJS LIBOBJS HIDE_IF_R42PLUS RGL_NO_OPENGL HIDE_IF_NO_OPENGL NULL_LIBS NULL_CPPFLAGS HAVE_FREETYPE_CONFIG HAVE_PKG_CONFIG XMKMF HAVE_LIBPNG_CONFIG CPP OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_libpng enable_libpng_config enable_libpng_dynamic enable_opengl with_x with_gl_includes with_gl_libs with_gl_libname with_glu_libname enable_ftgl ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP XMKMF' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: \`$ac_useropt'" ac_useropt_orig=$ac_useropt ac_useropt=`printf "%s\n" "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. printf "%s\n" "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && printf "%s\n" "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF X features: --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --disable-libpng compile without PNG image support --disable-libpng-config disable libpng-config test and configuration --disable-libpng-dynamic disable dynamic libpng linkage, force static version linkage (only with --enable-libpng-config) --disable-opengl compile without OpenGL support --disable-ftgl compile without FTGL font support Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-x use the X Window System --with-gl-includes=DIR specify location of OpenGL headers --with-gl-libs=DIR specify location of OpenGL libs --with-gl-libname=NAME specify Library name (defaults to "GL") --with-glu-libname=NAME specify GLU Library name (defaults to "GLU") Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor XMKMF Path to xmkmf, Makefile generator for X Window System Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for configure.gnu first; this name is used for a wrapper for # Metaconfig's "Configure" on case-insensitive file systems. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else printf "%s\n" "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.71 Copyright (C) 2021 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest.beam conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext } then : ac_retval=0 else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 printf %s "checking for $2... " >&6; } if eval test \${$3+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. */ #include #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main (void) { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$3=yes" else $as_nop eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func ac_configure_args_raw= for ac_arg do case $ac_arg in *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append ac_configure_args_raw " '$ac_arg'" done case $ac_configure_args_raw in *$as_nl*) ac_safe_unquote= ;; *) ac_unsafe_z='|&;<>()$`\\"*?[ '' ' # This string ends in space, tab. ac_unsafe_a="$ac_unsafe_z#~" ac_safe_unquote="s/ '\\([^$ac_unsafe_a][^$ac_unsafe_z]*\\)'/ \\1/g" ac_configure_args_raw=` printf "%s\n" "$ac_configure_args_raw" | sed "$ac_safe_unquote"`;; esac cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.71. Invocation command line was $ $0$ac_configure_args_raw _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac printf "%s\n" "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`printf "%s\n" "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Sanitize IFS. IFS=" "" $as_nl" # Save into config.log some information that might help in debugging. { echo printf "%s\n" "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo printf "%s\n" "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then printf "%s\n" "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`printf "%s\n" "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac printf "%s\n" "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then printf "%s\n" "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && printf "%s\n" "$as_me: caught signal $ac_signal" printf "%s\n" "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h printf "%s\n" "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. printf "%s\n" "#define PACKAGE_NAME \"$PACKAGE_NAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_TARNAME \"$PACKAGE_TARNAME\"" >>confdefs.h printf "%s\n" "#define PACKAGE_VERSION \"$PACKAGE_VERSION\"" >>confdefs.h printf "%s\n" "#define PACKAGE_STRING \"$PACKAGE_STRING\"" >>confdefs.h printf "%s\n" "#define PACKAGE_BUGREPORT \"$PACKAGE_BUGREPORT\"" >>confdefs.h printf "%s\n" "#define PACKAGE_URL \"$PACKAGE_URL\"" >>confdefs.h # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. if test -n "$CONFIG_SITE"; then ac_site_files="$CONFIG_SITE" elif test "x$prefix" != xNONE; then ac_site_files="$prefix/share/config.site $prefix/etc/config.site" else ac_site_files="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site" fi for ac_site_file in $ac_site_files do case $ac_site_file in #( */*) : ;; #( *) : ac_site_file=./$ac_site_file ;; esac if test -f "$ac_site_file" && test -r "$ac_site_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 printf "%s\n" "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 printf "%s\n" "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 printf "%s\n" "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Test code for whether the C compiler supports C89 (global declarations) ac_c_conftest_c89_globals=' /* Does the compiler advertise C89 conformance? Do not test the value of __STDC__, because some compilers set it to 0 while being otherwise adequately conformant. */ #if !defined __STDC__ # error "Compiler does not advertise C89 conformance" #endif #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7 src/conf.sh. */ struct buf { int x; }; struct buf * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not \xHH hex character constants. These do not provoke an error unfortunately, instead are silently treated as an "x". The following induces an error, until -std is added to get proper ANSI mode. Curiously \x00 != x always comes out true, for an array size at least. It is necessary to write \x00 == 0 to get something that is true only with -std. */ int osf4_cc_array ['\''\x00'\'' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) '\''x'\'' int xlc6_cc_array[FOO(a) == '\''x'\'' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, int *(*)(struct buf *, struct stat *, int), int, int);' # Test code for whether the C compiler supports C89 (body of main). ac_c_conftest_c89_main=' ok |= (argc == 0 || f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]); ' # Test code for whether the C compiler supports C99 (global declarations) ac_c_conftest_c99_globals=' // Does the compiler advertise C99 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L # error "Compiler does not advertise C99 conformance" #endif #include extern int puts (const char *); extern int printf (const char *, ...); extern int dprintf (int, const char *, ...); extern void *malloc (size_t); // Check varargs macros. These examples are taken from C99 6.10.3.5. // dprintf is used instead of fprintf to avoid needing to declare // FILE and stderr. #define debug(...) dprintf (2, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK #error "your preprocessor is broken" #endif #if BIG_OK #else #error "your preprocessor is broken" #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\''\0'\''; ++i) continue; return 0; } // Check varargs and va_copy. static bool test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str = ""; int number = 0; float fnumber = 0; while (*format) { switch (*format++) { case '\''s'\'': // string str = va_arg (args_copy, const char *); break; case '\''d'\'': // int number = va_arg (args_copy, int); break; case '\''f'\'': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); return *str && number && fnumber; } ' # Test code for whether the C compiler supports C99 (body of main). ac_c_conftest_c99_main=' // Check bool. _Bool success = false; success |= (argc != 0); // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. success &= test_varargs ("s, d'\'' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[0] = argv[0][0]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings ok |= (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == '\''x'\'' || dynamic_array[ni.number - 1] != 543); ' # Test code for whether the C compiler supports C11 (global declarations) ac_c_conftest_c11_globals=' // Does the compiler advertise C11 conformance? #if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112L # error "Compiler does not advertise C11 conformance" #endif // Check _Alignas. char _Alignas (double) aligned_as_double; char _Alignas (0) no_special_alignment; extern char aligned_as_int; char _Alignas (0) _Alignas (int) aligned_as_int; // Check _Alignof. enum { int_alignment = _Alignof (int), int_array_alignment = _Alignof (int[100]), char_alignment = _Alignof (char) }; _Static_assert (0 < -_Alignof (int), "_Alignof is signed"); // Check _Noreturn. int _Noreturn does_not_return (void) { for (;;) continue; } // Check _Static_assert. struct test_static_assert { int x; _Static_assert (sizeof (int) <= sizeof (long int), "_Static_assert does not work in struct"); long int y; }; // Check UTF-8 literals. #define u8 syntax error! char const utf8_literal[] = u8"happens to be ASCII" "another string"; // Check duplicate typedefs. typedef long *long_ptr; typedef long int *long_ptr; typedef long_ptr long_ptr; // Anonymous structures and unions -- taken from C11 6.7.2.1 Example 1. struct anonymous { union { struct { int i; int j; }; struct { int k; long int l; } w; }; int m; } v1; ' # Test code for whether the C compiler supports C11 (body of main). ac_c_conftest_c11_main=' _Static_assert ((offsetof (struct anonymous, i) == offsetof (struct anonymous, w.k)), "Anonymous union alignment botch"); v1.i = 2; v1.w.k = 5; ok |= v1.i != 5; ' # Test code for whether the C compiler supports C11 (complete). ac_c_conftest_c11_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} ${ac_c_conftest_c11_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} ${ac_c_conftest_c11_main} return ok; } " # Test code for whether the C compiler supports C99 (complete). ac_c_conftest_c99_program="${ac_c_conftest_c89_globals} ${ac_c_conftest_c99_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} ${ac_c_conftest_c99_main} return ok; } " # Test code for whether the C compiler supports C89 (complete). ac_c_conftest_c89_program="${ac_c_conftest_c89_globals} int main (int argc, char **argv) { int ok = 0; ${ac_c_conftest_c89_main} return ok; } " as_fn_append ac_header_c_list " stdio.h stdio_h HAVE_STDIO_H" as_fn_append ac_header_c_list " stdlib.h stdlib_h HAVE_STDLIB_H" as_fn_append ac_header_c_list " string.h string_h HAVE_STRING_H" as_fn_append ac_header_c_list " inttypes.h inttypes_h HAVE_INTTYPES_H" as_fn_append ac_header_c_list " stdint.h stdint_h HAVE_STDINT_H" as_fn_append ac_header_c_list " strings.h strings_h HAVE_STRINGS_H" as_fn_append ac_header_c_list " sys/stat.h sys_stat_h HAVE_SYS_STAT_H" as_fn_append ac_header_c_list " sys/types.h sys_types_h HAVE_SYS_TYPES_H" as_fn_append ac_header_c_list " unistd.h unistd_h HAVE_UNISTD_H" # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 printf "%s\n" "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 printf "%s\n" "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 printf "%s\n" "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 printf "%s\n" "$as_me: former value: \`$ac_old_val'" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 printf "%s\n" "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`printf "%s\n" "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 printf "%s\n" "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`${MAKE-make} distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ## pick up compiler as will be used by R CMD INSTALL/SHLIB if test -n "${R_HOME}"; then CC=`${R_HOME}/bin/R CMD config CC` CFLAGS=`${R_HOME}/bin/R CMD config CFLAGS` HIDE_IF_R42PLUS=`${R_HOME}/bin/Rscript -e 'cat(if (getRversion() >= "4.2.0") "#" else "")'` else HIDE_IF_R42PLUS="" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 printf %s "checking whether the C compiler works... " >&6; } ac_link_default=`printf "%s\n" "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test ${ac_cv_exeext+y} && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else $as_nop ac_file='' fi if test -z "$ac_file" then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5 printf "%s\n" "yes" >&6; } fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 printf %s "checking for C compiler default output file name... " >&6; } { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 printf "%s\n" "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 printf %s "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else $as_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 printf "%s\n" "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 printf %s "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 printf "%s\n" "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 printf %s "checking for suffix of object files... " >&6; } if test ${ac_cv_objext+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_nop printf "%s\n" "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 printf "%s\n" "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 printf %s "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test ${ac_cv_prog_CPP+y} then : printf %s "(cached) " >&6 else $as_nop # Double quotes because $CC needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" cpp /lib/cpp do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO" then : # Broken: success on invalid input. continue else $as_nop # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 printf "%s\n" "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO" then : else $as_nop # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO" then : # Broken: success on invalid input. continue else $as_nop # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok then : else $as_nop { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then if test "$as_dir$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}clang", so it can be a program name with args. set dummy ${ac_tool_prefix}clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 printf "%s\n" "$CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "clang", so it can be a program name with args. set dummy clang; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_ac_ct_CC+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="clang" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 printf "%s\n" "$ac_ct_CC" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 printf "%s\n" "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi fi test -z "$CC" && { { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 printf "%s\n" "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion -version; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" printf "%s\n" "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the compiler supports GNU C" >&5 printf %s "checking whether the compiler supports GNU C... " >&6; } if test ${ac_cv_c_compiler_gnu+y} then : printf %s "(cached) " >&6 else $as_nop cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_compiler_gnu=yes else $as_nop ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 printf "%s\n" "$ac_cv_c_compiler_gnu" >&6; } ac_compiler_gnu=$ac_cv_c_compiler_gnu if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+y} ac_save_CFLAGS=$CFLAGS { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 printf %s "checking whether $CC accepts -g... " >&6; } if test ${ac_cv_prog_cc_g+y} then : printf %s "(cached) " >&6 else $as_nop ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes else $as_nop CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : else $as_nop ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main (void) { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 printf "%s\n" "$ac_cv_prog_cc_g" >&6; } if test $ac_test_CFLAGS; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi ac_prog_cc_stdc=no if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C11 features" >&5 printf %s "checking for $CC option to enable C11 features... " >&6; } if test ${ac_cv_prog_cc_c11+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c11=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c11_program _ACEOF for ac_arg in '' -std=gnu11 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c11=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c11" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c11" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c11" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c11" >&5 printf "%s\n" "$ac_cv_prog_cc_c11" >&6; } CC="$CC $ac_cv_prog_cc_c11" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c11 ac_prog_cc_stdc=c11 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C99 features" >&5 printf %s "checking for $CC option to enable C99 features... " >&6; } if test ${ac_cv_prog_cc_c99+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c99_program _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -qlanglvl=extc1x -qlanglvl=extc99 -AC99 -D_STDC_C99= do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c99" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c99" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 printf "%s\n" "$ac_cv_prog_cc_c99" >&6; } CC="$CC $ac_cv_prog_cc_c99" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 ac_prog_cc_stdc=c99 fi fi if test x$ac_prog_cc_stdc = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $CC option to enable C89 features" >&5 printf %s "checking for $CC option to enable C89 features... " >&6; } if test ${ac_cv_prog_cc_c89+y} then : printf %s "(cached) " >&6 else $as_nop ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_c_conftest_c89_program _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO" then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext conftest.beam test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi if test "x$ac_cv_prog_cc_c89" = xno then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 printf "%s\n" "unsupported" >&6; } else $as_nop if test "x$ac_cv_prog_cc_c89" = x then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 printf "%s\n" "none needed" >&6; } else $as_nop { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 printf "%s\n" "$ac_cv_prog_cc_c89" >&6; } CC="$CC $ac_cv_prog_cc_c89" fi ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 ac_prog_cc_stdc=c89 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test `uname` = "Darwin" ; then darwin="yes" else darwin="no" fi ## --- LibPNG ---------------------------------------------------------------- # Check whether --enable-libpng was given. if test ${enable_libpng+y} then : enableval=$enable_libpng; fi # Check whether --enable-libpng-config was given. if test ${enable_libpng_config+y} then : enableval=$enable_libpng_config; fi # Check whether --enable-libpng-dynamic was given. if test ${enable_libpng_dynamic+y} then : enableval=$enable_libpng_dynamic; fi if test "x$enable_libpng" != "xno"; then if test "x$enable_libpng_config" != "xno"; then # Extract the first word of "libpng-config", so it can be a program name with args. set dummy libpng-config; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_HAVE_LIBPNG_CONFIG+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$HAVE_LIBPNG_CONFIG"; then ac_cv_prog_HAVE_LIBPNG_CONFIG="$HAVE_LIBPNG_CONFIG" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_HAVE_LIBPNG_CONFIG="yes" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_HAVE_LIBPNG_CONFIG" && ac_cv_prog_HAVE_LIBPNG_CONFIG="no" fi fi HAVE_LIBPNG_CONFIG=$ac_cv_prog_HAVE_LIBPNG_CONFIG if test -n "$HAVE_LIBPNG_CONFIG"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $HAVE_LIBPNG_CONFIG" >&5 printf "%s\n" "$HAVE_LIBPNG_CONFIG" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi fi if test "x$HAVE_LIBPNG_CONFIG" = "xyes" ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: using libpng-config" >&5 printf "%s\n" "$as_me: using libpng-config" >&6;} CPPFLAGS="${CPPFLAGS} -DHAVE_PNG_H `libpng-config --I_opts`" if test "x$enable_libpng_dynamic" != "xno"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: using libpng dynamic linkage" >&5 printf "%s\n" "$as_me: using libpng dynamic linkage" >&6;} LIBS="${LIBS} `libpng-config --ldflags`" else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: using libpng static linkage" >&5 printf "%s\n" "$as_me: using libpng static linkage" >&6;} LIBS="${LIBS} `libpng-config --static --L_opts`/libpng.a" fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking libpng" >&5 printf %s "checking libpng... " >&6; } save_LIBS="${LIBS}" save_CPPFLAGS="${CPPFLAGS}" ac_header= ac_cache= for ac_item in $ac_header_c_list do if test $ac_cache; then ac_fn_c_check_header_compile "$LINENO" $ac_header ac_cv_header_$ac_cache "$ac_includes_default" if eval test \"x\$ac_cv_header_$ac_cache\" = xyes; then printf "%s\n" "#define $ac_item 1" >> confdefs.h fi ac_header= ac_cache= elif test $ac_header; then ac_cache=$ac_item else ac_header=$ac_item fi done if test $ac_cv_header_stdlib_h = yes && test $ac_cv_header_string_h = yes then : printf "%s\n" "#define STDC_HEADERS 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "png.h" "ac_cv_header_png_h" "$ac_includes_default" if test "x$ac_cv_header_png_h" = xyes then : printf "%s\n" "#define HAVE_PNG_H 1" >>confdefs.h fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for png_read_update_info in -lpng" >&5 printf %s "checking for png_read_update_info in -lpng... " >&6; } if test ${ac_cv_lib_png_png_read_update_info+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-lpng $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char png_read_update_info (); int main (void) { return png_read_update_info (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : ac_cv_lib_png_png_read_update_info=yes else $as_nop ac_cv_lib_png_png_read_update_info=no fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_png_png_read_update_info" >&5 printf "%s\n" "$ac_cv_lib_png_png_read_update_info" >&6; } if test "x$ac_cv_lib_png_png_read_update_info" = xyes then : printf "%s\n" "#define HAVE_LIBPNG 1" >>confdefs.h LIBS="-lpng $LIBS" fi if test "${ac_cv_header_png_h}"; then if test "${ac_cv_lib_png_png_read_update_info}"; then CPPFLAGS="${CPPFLAGS} -DHAVE_PNG_H" LIBS="${LIBS} -lpng" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: libpng header and lib found" >&5 printf "%s\n" "$as_me: libpng header and lib found" >&6;} if test "x$enable_libpng_dynamic" != "xno"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: using libpng dynamic linkage" >&5 printf "%s\n" "$as_me: using libpng dynamic linkage" >&6;} else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: using libpng static linkage" >&5 printf "%s\n" "$as_me: using libpng static linkage" >&6;} fi else LIBS=${save_LIBS} CPPFLAGS=${save_CPPFLAGS} { printf "%s\n" "$as_me:${as_lineno-$LINENO}: libpng header and lib not found" >&5 printf "%s\n" "$as_me: libpng header and lib not found" >&6;} fi fi fi fi # ---[ OpenGL enabled?]--------------------------------------------------------------- # Check whether --enable-opengl was given. if test ${enable_opengl+y} then : enableval=$enable_opengl; fi NULL_CPPFLAGS="${CPPFLAGS} -DRGL_NO_OPENGL" NULL_LIBS="${LIBS}" # ---[ X11 ]------------------------------------------------------------------ if test "x$enable_opengl" != "xno"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for X" >&5 printf %s "checking for X... " >&6; } # Check whether --with-x was given. if test ${with_x+y} then : withval=$with_x; fi # $have_x is `yes', `no', `disabled', or empty when we do not yet know. if test "x$with_x" = xno; then # The user explicitly disabled X. have_x=disabled else case $x_includes,$x_libraries in #( *\'*) as_fn_error $? "cannot use X directory names containing '" "$LINENO" 5;; #( *,NONE | NONE,*) if test ${ac_cv_have_x+y} then : printf %s "(cached) " >&6 else $as_nop # One or both of the vars are not set, and there is no cached value. ac_x_includes=no ac_x_libraries=no # Do we need to do anything special at all? ac_save_LIBS=$LIBS LIBS="-lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { XrmInitialize () ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : # We can compile and link X programs with no special options. ac_x_includes= ac_x_libraries= fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS="$ac_save_LIBS" # If that didn't work, only try xmkmf and file system searches # for native compilation. if test x"$ac_x_includes" = xno && test "$cross_compiling" = no then : rm -f -r conftest.dir if mkdir conftest.dir; then cd conftest.dir cat >Imakefile <<'_ACEOF' incroot: @echo incroot='${INCROOT}' usrlibdir: @echo usrlibdir='${USRLIBDIR}' libdir: @echo libdir='${LIBDIR}' _ACEOF if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. for ac_var in incroot usrlibdir libdir; do eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" done # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. for ac_extension in a so sl dylib la dll; do if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && test -f "$ac_im_libdir/libX11.$ac_extension"; then ac_im_usrlibdir=$ac_im_libdir; break fi done # Screen out bogus values from the imake configuration. They are # bogus both because they are the default anyway, and because # using them would break gcc on systems where it needs fixed includes. case $ac_im_incroot in /usr/include) ac_x_includes= ;; *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; esac case $ac_im_usrlibdir in /usr/lib | /usr/lib64 | /lib | /lib64) ;; *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; esac fi cd .. rm -f -r conftest.dir fi # Standard set of common directories for X headers. # Check X11 before X11Rn because it is often a symlink to the current release. ac_x_header_dirs=' /usr/X11/include /usr/X11R7/include /usr/X11R6/include /usr/X11R5/include /usr/X11R4/include /usr/include/X11 /usr/include/X11R7 /usr/include/X11R6 /usr/include/X11R5 /usr/include/X11R4 /usr/local/X11/include /usr/local/X11R7/include /usr/local/X11R6/include /usr/local/X11R5/include /usr/local/X11R4/include /usr/local/include/X11 /usr/local/include/X11R7 /usr/local/include/X11R6 /usr/local/include/X11R5 /usr/local/include/X11R4 /opt/X11/include /usr/X386/include /usr/x386/include /usr/XFree86/include/X11 /usr/include /usr/local/include /usr/unsupported/include /usr/athena/include /usr/local/x11r5/include /usr/lpp/Xamples/include /usr/openwin/include /usr/openwin/share/include' if test "$ac_x_includes" = no; then # Guess where to find include files, by looking for Xlib.h. # First, try using that file with no special directory specified. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO" then : # We can compile using X headers with no special include directory. ac_x_includes= else $as_nop for ac_dir in $ac_x_header_dirs; do if test -r "$ac_dir/X11/Xlib.h"; then ac_x_includes=$ac_dir break fi done fi rm -f conftest.err conftest.i conftest.$ac_ext fi # $ac_x_includes = no if test "$ac_x_libraries" = no; then # Check for the libraries. # See if we find them without any special options. # Don't add to $LIBS permanently. ac_save_LIBS=$LIBS LIBS="-lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main (void) { XrmInitialize () ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : LIBS=$ac_save_LIBS # We can link X programs with no special library path. ac_x_libraries= else $as_nop LIBS=$ac_save_LIBS for ac_dir in `printf "%s\n" "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` do # Don't even attempt the hair of trying to link an X program! for ac_extension in a so sl dylib la dll; do if test -r "$ac_dir/libX11.$ac_extension"; then ac_x_libraries=$ac_dir break 2 fi done done fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext fi # $ac_x_libraries = no fi # Record the results. case $ac_x_includes,$ac_x_libraries in #( no,* | *,no | *\'*) : # Didn't find X, or a directory has "'" in its name. ac_cv_have_x="have_x=no" ;; #( *) : # Record where we found X for the cache. ac_cv_have_x="have_x=yes\ ac_x_includes='$ac_x_includes'\ ac_x_libraries='$ac_x_libraries'" ;; esac fi ;; #( *) have_x=yes;; esac eval "$ac_cv_have_x" fi # $with_x != no if test "$have_x" != yes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 printf "%s\n" "$have_x" >&6; } no_x=yes else # If each of the values was on the command line, it overrides each guess. test "x$x_includes" = xNONE && x_includes=$ac_x_includes test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries # Update the cache value to reflect the command line values. ac_cv_have_x="have_x=yes\ ac_x_includes='$x_includes'\ ac_x_libraries='$x_libraries'" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 printf "%s\n" "libraries $x_libraries, headers $x_includes" >&6; } fi if test x$no_x = xyes ; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: X11 not found, continuing without OpenGL support." >&5 printf "%s\n" "$as_me: WARNING: X11 not found, continuing without OpenGL support." >&2;} enable_opengl=no else if test -n "${x_includes}"; then CPPFLAGS="${CPPFLAGS} -I${x_includes}" fi if test -n "${x_libraries}"; then LIBS="${LIBS} -L${x_libraries} -lX11" else LIBS="${LIBS} -lX11" fi if test $darwin = yes; then CPPFLAGS="${CPPFLAGS} -DDarwin" if test -e /System/Library/Frameworks/GLKit.framework ; then LIBS="-framework GLKit ${LIBS}" fi # X11 must come *after* the OpenGL stuff CPPFLAGS="${CPPFLAGS} -I/opt/X11/include" fi ac_fn_c_check_func "$LINENO" "XAllocClassHint" "ac_cv_func_XAllocClassHint" if test "x$ac_cv_func_XAllocClassHint" = xyes then : else $as_nop enable_opengl=no fi fi fi if test "x$enable_opengl" != "xno"; then ## --- OpenGL ---------------------------------------------------------------- # Check whether --with-gl-includes was given. if test ${with_gl_includes+y} then : withval=$with_gl_includes; CPPFLAGS="${CPPFLAGS} -I${withval}" fi if test $darwin != yes; then ac_fn_c_check_header_compile "$LINENO" "GL/gl.h" "ac_cv_header_GL_gl_h" "$ac_includes_default" if test "x$ac_cv_header_GL_gl_h" = xyes then : printf "%s\n" "#define HAVE_GL_GL_H 1" >>confdefs.h fi ac_fn_c_check_header_compile "$LINENO" "GL/glu.h" "ac_cv_header_GL_glu_h" "$ac_includes_default" if test "x$ac_cv_header_GL_glu_h" = xyes then : printf "%s\n" "#define HAVE_GL_GLU_H 1" >>confdefs.h fi if test "x$ac_cv_header_GL_gl_h" = xno; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: missing required header GL/gl.h" >&5 printf "%s\n" "$as_me: WARNING: missing required header GL/gl.h" >&2;} enable_opengl=no fi if test "x$ac_cv_header_GL_glu_h" = xno; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: missing required header GL/glu.h" >&5 printf "%s\n" "$as_me: WARNING: missing required header GL/glu.h" >&2;} enable_opengl=no fi fi fi if test "x$enable_opengl" != "xno"; then # Check whether --with-gl-libs was given. if test ${with_gl_libs+y} then : withval=$with_gl_libs; LDFLAGS="${LDFLAGS} -L${withval}" L_LIB="-L${withval}" fi # Check whether --with-gl-libname was given. if test ${with_gl_libname+y} then : withval=$with_gl_libname; lGL=${withval} else $as_nop lGL=GL fi as_ac_Lib=`printf "%s\n" "ac_cv_lib_$lGL""_glEnd" | $as_tr_sh` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for glEnd in -l$lGL" >&5 printf %s "checking for glEnd in -l$lGL... " >&6; } if eval test \${$as_ac_Lib+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-l$lGL $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char glEnd (); int main (void) { return glEnd (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$as_ac_Lib=yes" else $as_nop eval "$as_ac_Lib=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi eval ac_res=\$$as_ac_Lib { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } if eval test \"x\$"$as_ac_Lib"\" = x"yes" then : cat >>confdefs.h <<_ACEOF #define `printf "%s\n" "HAVE_LIB$lGL" | $as_tr_cpp` 1 _ACEOF LIBS="-l$lGL $LIBS" fi this=`eval echo '${'$as_ac_Lib'}'` if test "x$this" != xyes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: missing required library ${lGL}" >&5 printf "%s\n" "$as_me: WARNING: missing required library ${lGL}" >&2;} enable_opengl=no else ac_fn_c_check_func "$LINENO" "glEnd" "ac_cv_func_glEnd" if test "x$ac_cv_func_glEnd" = xyes then : else $as_nop enable_opengl=no fi fi fi if test "x$enable_opengl" != "xno"; then # Check whether --with-glu-libname was given. if test ${with_glu_libname+y} then : withval=$with_glu_libname; lGLU=${withval} else $as_nop lGLU=GLU fi as_ac_Lib=`printf "%s\n" "ac_cv_lib_$lGLU""_gluErrorString" | $as_tr_sh` { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for gluErrorString in -l$lGLU" >&5 printf %s "checking for gluErrorString in -l$lGLU... " >&6; } if eval test \${$as_ac_Lib+y} then : printf %s "(cached) " >&6 else $as_nop ac_check_lib_save_LIBS=$LIBS LIBS="-l$lGLU $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ char gluErrorString (); int main (void) { return gluErrorString (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO" then : eval "$as_ac_Lib=yes" else $as_nop eval "$as_ac_Lib=no" fi rm -f core conftest.err conftest.$ac_objext conftest.beam \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi eval ac_res=\$$as_ac_Lib { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 printf "%s\n" "$ac_res" >&6; } if eval test \"x\$"$as_ac_Lib"\" = x"yes" then : cat >>confdefs.h <<_ACEOF #define `printf "%s\n" "HAVE_LIB$lGLU" | $as_tr_cpp` 1 _ACEOF LIBS="-l$lGLU $LIBS" fi this=`eval echo '${'$as_ac_Lib'}'` if test "x$this" != xyes; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: missing required library ${lGLU}" >&5 printf "%s\n" "$as_me: WARNING: missing required library ${lGLU}" >&2;} enable_opengl=no else ac_fn_c_check_func "$LINENO" "gluErrorString" "ac_cv_func_gluErrorString" if test "x$ac_cv_func_gluErrorString" = xyes then : else $as_nop enable_opengl=no fi fi fi if test "x$enable_opengl" != "xno"; then if test x$L_LIB != x; then LIBS="${L_LIB} ${LIBS}" fi ## --- FTGL ------------------------------------------------------------------ # Check whether --enable-ftgl was given. if test ${enable_ftgl+y} then : enableval=$enable_ftgl; fi if test "x$enable_ftgl" != "xno"; then if test "x$darwin" = "xyes"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Darwin, so ensuring /opt/X11/bin is at the head of the PATH..." >&5 printf "%s\n" "$as_me: Darwin, so ensuring /opt/X11/bin is at the head of the PATH..." >&6;} PATH=/opt/X11/bin:${PATH} fi ## new pkg-config bit # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_HAVE_PKG_CONFIG+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$HAVE_PKG_CONFIG"; then ac_cv_prog_HAVE_PKG_CONFIG="$HAVE_PKG_CONFIG" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_HAVE_PKG_CONFIG="yes" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_HAVE_PKG_CONFIG" && ac_cv_prog_HAVE_PKG_CONFIG="no" fi fi HAVE_PKG_CONFIG=$ac_cv_prog_HAVE_PKG_CONFIG if test -n "$HAVE_PKG_CONFIG"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $HAVE_PKG_CONFIG" >&5 printf "%s\n" "$HAVE_PKG_CONFIG" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$HAVE_PKG_CONFIG" = "xyes" && test "x`pkg-config freetype2 --cflags`" != "x"; then CPPFLAGS="${CPPFLAGS} -DHAVE_FREETYPE -Iext/ftgl `pkg-config freetype2 --cflags`" LIBS="${LIBS} `pkg-config freetype2 --static --libs`" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: using Freetype and FTGL" >&5 printf "%s\n" "$as_me: using Freetype and FTGL" >&6;} else # Extract the first word of "freetype-config", so it can be a program name with args. set dummy freetype-config; ac_word=$2 { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 printf %s "checking for $ac_word... " >&6; } if test ${ac_cv_prog_HAVE_FREETYPE_CONFIG+y} then : printf %s "(cached) " >&6 else $as_nop if test -n "$HAVE_FREETYPE_CONFIG"; then ac_cv_prog_HAVE_FREETYPE_CONFIG="$HAVE_FREETYPE_CONFIG" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir$ac_word$ac_exec_ext"; then ac_cv_prog_HAVE_FREETYPE_CONFIG="yes" printf "%s\n" "$as_me:${as_lineno-$LINENO}: found $as_dir$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS test -z "$ac_cv_prog_HAVE_FREETYPE_CONFIG" && ac_cv_prog_HAVE_FREETYPE_CONFIG="no" fi fi HAVE_FREETYPE_CONFIG=$ac_cv_prog_HAVE_FREETYPE_CONFIG if test -n "$HAVE_FREETYPE_CONFIG"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $HAVE_FREETYPE_CONFIG" >&5 printf "%s\n" "$HAVE_FREETYPE_CONFIG" >&6; } else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5 printf "%s\n" "no" >&6; } fi if test "x$HAVE_FREETYPE_CONFIG" = "xyes"; then CPPFLAGS="${CPPFLAGS} -DHAVE_FREETYPE -Iext/ftgl `freetype-config --cflags`" LIBS="${LIBS} `freetype-config --static --libs`" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: using Freetype and FTGL" >&5 printf "%s\n" "$as_me: using Freetype and FTGL" >&6;} else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: compiling without FTGL support" >&5 printf "%s\n" "$as_me: compiling without FTGL support" >&6;} fi fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: compiling without FTGL support" >&5 printf "%s\n" "$as_me: compiling without FTGL support" >&6;} fi fi if test "x$enable_opengl" = "xno"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: compiling without OpenGL support" >&5 printf "%s\n" "$as_me: compiling without OpenGL support" >&6;} HIDE_IF_NO_OPENGL="#" RGL_NO_OPENGL=TRUE else HIDE_IF_NO_OPENGL="" RGL_NO_OPENGL=FALSE fi ## --- Output ---------------------------------------------------------------- ac_config_files="$ac_config_files R/noOpenGL.R src/useNULL/Makevars" ac_config_files="$ac_config_files src/Makevars" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 printf "%s\n" "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test ${\1+y} || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 printf "%s\n" "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { printf "%s\n" "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 printf "%s\n" "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`printf "%s\n" "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 printf "%s\n" "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh as_nop=: if test ${ZSH_VERSION+y} && (emulate sh) >/dev/null 2>&1 then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else $as_nop case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi # Reset variables that may have inherited troublesome values from # the environment. # IFS needs to be set, to space, tab, and newline, in precisely that order. # (If _AS_PATH_WALK were called with IFS unset, it would have the # side effect of setting IFS to empty, thus disabling word splitting.) # Quoting is to prevent editors from complaining about space-tab. as_nl=' ' export as_nl IFS=" "" $as_nl" PS1='$ ' PS2='> ' PS4='+ ' # Ensure predictable behavior from utilities with locale-dependent output. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # We cannot yet rely on "unset" to work, but we need these variables # to be unset--not just set to an empty or harmless value--now, to # avoid bugs in old shells (e.g. pre-3.0 UWIN ksh). This construct # also avoids known problems related to "unset" and subshell syntax # in other old shells (e.g. bash 2.01 and pdksh 5.2.14). for as_var in BASH_ENV ENV MAIL MAILPATH CDPATH do eval test \${$as_var+y} \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done # Ensure that fds 0, 1, and 2 are open. if (exec 3>&0) 2>/dev/null; then :; else exec 0&1) 2>/dev/null; then :; else exec 1>/dev/null; fi if (exec 3>&2) ; then :; else exec 2>/dev/null; fi # The user is always right. if ${PATH_SEPARATOR+false} :; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS case $as_dir in #((( '') as_dir=./ ;; */) ;; *) as_dir=$as_dir/ ;; esac test -r "$as_dir$0" && as_myself=$as_dir$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then printf "%s\n" "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi printf "%s\n" "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null then : eval 'as_fn_append () { eval $1+=\$2 }' else $as_nop as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null then : eval 'as_fn_arith () { as_val=$(( $* )) }' else $as_nop as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits # Determine whether it's possible to make 'echo' print without a newline. # These variables are no longer used directly by Autoconf, but are AC_SUBSTed # for compatibility with existing Makefiles. ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac # For backward compatibility with old third-party macros, we provide # the shell variables $as_echo and $as_echo_n. New code should use # AS_ECHO(["message"]) and AS_ECHO_N(["message"]), respectively. as_echo='printf %s\n' as_echo_n='printf %s' rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`printf "%s\n" "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.71. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to the package provider." _ACEOF ac_cs_config=`printf "%s\n" "$ac_configure_args" | sed "$ac_safe_unquote"` ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\''/g"` cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.71, with options \\"\$ac_cs_config\\" Copyright (C) 2021 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) printf "%s\n" "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) printf "%s\n" "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`printf "%s\n" "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) printf "%s\n" "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \printf "%s\n" "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX printf "%s\n" "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "R/noOpenGL.R") CONFIG_FILES="$CONFIG_FILES R/noOpenGL.R" ;; "src/useNULL/Makevars") CONFIG_FILES="$CONFIG_FILES src/useNULL/Makevars" ;; "src/Makevars") CONFIG_FILES="$CONFIG_FILES src/Makevars" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test ${CONFIG_FILES+y} || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`printf "%s\n" "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` printf "%s\n" "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { printf "%s\n" "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 printf "%s\n" "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`printf "%s\n" "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || printf "%s\n" X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`printf "%s\n" "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`printf "%s\n" "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 printf "%s\n" "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 printf "%s\n" "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { printf "%s\n" "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 printf "%s\n" "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi rgl/man/0000755000176200001440000000000015026603601011610 5ustar liggesusersrgl/man/spheres.Rd0000644000176200001440000000461714771520323013565 0ustar liggesusers\name{spheres3d} \alias{spheres3d} \title{Add spheres} \description{ Adds a sphere set shape node to the scene } \usage{ spheres3d(x, y = NULL, z = NULL, radius = 1, fastTransparency = TRUE, ...) } \arguments{ \item{x, y, z}{Numeric vector of point coordinates corresponding to the center of each sphere. Any reasonable way of defining the coordinates is acceptable. See the function \code{\link[grDevices]{xyz.coords}} for details.} \item{radius}{Vector or single value defining the sphere radius/radii} \item{fastTransparency}{logical value indicating whether fast sorting should be used for transparency. See the Details.} \item{ ... }{Material properties. See \code{\link{material3d}} for details.} } \details{ If a non-isometric aspect ratio is chosen, these functions will still draw objects that appear to the viewer to be spheres. Use \code{\link{ellipse3d}} to draw shapes that are spherical in the data scale. When the scale is not isometric, the radius is measured in an average scale. In this case the bounding box calculation is iterative, since rescaling the plot changes the shape of the spheres in user-coordinates, which changes the bounding box. Versions of \pkg{rgl} prior to 0.92.802 did not do this iterative adjustment. If any coordinate or radius is \code{NA}, the sphere is not plotted. If a texture is used, its bitmap is wrapped around the sphere, with the top edge at the maximum y coordinate, and the left-right edges joined at the maximum in the z coordinate, centred in x. If the \code{alpha} material value of the spheres is less than the default \code{1}, they need to be drawn in order from back to front. When \code{fastTransparency} is \code{TRUE}, this is approximated by sorting the centers and drawing complete spheres in that order. This produces acceptable results in most cases, but artifacts may be visible, especially if the \code{radius} values vary, or they intersect other transparent objects. Setting \code{fastTransparency = FALSE} will cause the sorting to apply to each of the 480 facets of individual spheres. This is much slower, but may produce better output. } \value{ A shape ID of the spheres object is returned. } \examples{ open3d() spheres3d(rnorm(10), rnorm(10), rnorm(10), radius = runif(10), color = rainbow(10)) } \seealso{ \code{\link{material3d}}, \code{\link{aspect3d}} for setting non-isometric scales } \keyword{dynamic} rgl/man/setUserShaders.Rd0000644000176200001440000001207314771520323015053 0ustar liggesusers\name{setUserShaders} \alias{setUserShaders} \alias{getShaders} \title{ Set user-defined shaders for RGL objects, or get shaders. } \description{ \code{setUserShaders} sets user-defined shaders (programs written in GLSL) for customized display of RGL objects. Currently only supported in WebGL displays, as the regular displays do not support GLSL. \code{getShaders} gets the user defined shader, or if it is not present, the automatically generated one. } \usage{ setUserShaders(ids, vertexShader = NULL, fragmentShader = NULL, attributes = NULL, uniforms = NULL, textures = NULL, scene = scene3d(minimal), minimal = TRUE) getShaders(id, scene = scene3d(minimal), minimal = TRUE) } \arguments{ \item{ids, id}{ Which objects should receive the shaders, or which object should be queried? } \item{vertexShader, fragmentShader}{ The vertex and fragment shader source code. If \code{NULL}, the automatically generated shader will be used instead. } \item{attributes}{ A named list of \dQuote{attributes} to attach to each vertex. } \item{uniforms}{ A named list of \dQuote{uniforms}. } \item{textures}{ A named list of textures. } \item{scene}{ A \code{\link{scene3d}} object to work with. } \item{minimal}{ See \code{\link{scene3d}}. } } \details{ Modern versions of OpenGL work with \dQuote{shaders}, programs written to run on the graphics processor. The vertex shader does the calculations to move vertices and set their intrinsic colours. The fragment shader computes how each pixel in the display will be shown, taking into account lighting, material properties, etc. (More precisely, it does the computation for each \dQuote{fragment}; a fragment is a pixel within an object to display. There may be many objects at a particular location, and each will result in a fragment calculation unless culled by z-buffering or being discarded in some other way.) Normally the WebGL Javascript code uses the default shaders stored in \code{system.file("htmlwidgets/lib/rglClass/shaders", package = "rgl")}. This function allows them to be written by hand, for testing new features, hand optimization, etc. The defines used by the default shaders will also be prepended to user shaders, which can use them for customization on an object-by-object basis. The names used for the \code{attributes}, \code{uniforms} and \code{textures} should match names in the shaders for corresponding variables. (The texture names should be names of \code{uniform sampler2D} variables.) } \note{ The \code{getShaders} function requires the \pkg{V8} package to extract auto-generated shaders, since the defines are generated by Javascript code. } \value{ A modified version of the \code{scene}. } \author{ Duncan Murdoch } \seealso{ \code{\link{rglwidget}} for display of the scene in WebGL. } \examples{ open3d() id <- shade3d(octahedron3d(), col = "red") # For each triangle, set weights on the 3 vertices. # This will be replicated to the appropriate size in Javascript. wts <- diag(3) # This leaves out the centres of each face vs <- " attribute vec3 aPos; attribute vec4 aCol; uniform mat4 mvMatrix; uniform mat4 prMatrix; varying vec4 vCol; varying vec4 vPosition; attribute vec3 aNorm; uniform mat4 normMatrix; varying vec3 vNormal; attribute vec3 wts; varying vec3 vwts; void main(void) { vPosition = mvMatrix * vec4(aPos, 1.); gl_Position = prMatrix * vPosition; vCol = aCol; vNormal = normalize((normMatrix * vec4(aNorm, 1.)).xyz); vwts = wts; } " fs <- " #ifdef GL_ES precision highp float; #endif varying vec4 vCol; // carries alpha varying vec4 vPosition; varying vec3 vNormal; uniform mat4 mvMatrix; uniform vec3 emission; uniform float shininess; uniform vec3 ambient[NLIGHTS]; uniform vec3 specular[NLIGHTS]; // light*material uniform vec3 diffuse[NLIGHTS]; uniform vec3 lightDir[NLIGHTS]; uniform bool viewpoint[NLIGHTS]; uniform bool finite[NLIGHTS]; varying vec3 vwts; uniform vec2 wtrange; void main(void) { float minwt = min(vwts.x, min(vwts.y, vwts.z)); if (minwt < wtrange.x || minwt > wtrange.y) discard; vec3 eye = normalize(-vPosition.xyz); vec3 lightdir; vec4 colDiff; vec3 halfVec; vec4 lighteffect = vec4(emission, 0.); vec3 col; float nDotL; vec3 n = normalize(vNormal); n = -faceforward(n, n, eye); colDiff = vec4(vCol.rgb * diffuse[0], vCol.a); lightdir = lightDir[0]; if (!viewpoint[0]) lightdir = (mvMatrix * vec4(lightdir, 1.)).xyz; if (!finite[0]) { halfVec = normalize(lightdir + eye); } else { lightdir = normalize(lightdir - vPosition.xyz); halfVec = normalize(lightdir + eye); } col = ambient[0]; nDotL = dot(n, lightdir); col = col + max(nDotL, 0.) * colDiff.rgb; col = col + pow(max(dot(halfVec, n), 0.), shininess) * specular[0]; lighteffect = lighteffect + vec4(col, colDiff.a); gl_FragColor = lighteffect; } " x <- setUserShaders(id, vs, fs, attributes = list(wts=wts), uniforms = list(wtrange = c(-0.01, 0.15))) if (interactive() || in_pkgdown_example()) rglwidget(x) } rgl/man/par3dinterp.Rd0000644000176200001440000000605014771520323014340 0ustar liggesusers\name{par3dinterp} \alias{par3dinterp} \title{Interpolator for par3d parameters} \description{ Returns a function which interpolates \code{par3d} parameter values, suitable for use in animations. } \usage{ par3dinterp(times = NULL, userMatrix, scale, zoom, FOV, method = c("spline", "linear"), extrapolate = c("oscillate", "cycle", "constant", "natural"), dev = cur3d(), subscene = par3d("listeners", dev = dev)) } \arguments{ \item{times}{ Times at which values are recorded or a list; see below } \item{userMatrix}{ Values of \code{par3d("userMatrix")} } \item{scale}{ Values of \code{par3d("scale")} } \item{zoom}{ Values of \code{par3d("zoom")} } \item{FOV}{ Values of \code{par3d("FOV")} } \item{method}{ Method of interpolation } \item{extrapolate}{ How to extrapolate outside the time range } \item{dev}{ Which RGL device to use } \item{subscene}{ Which subscene to use } } \details{ This function is intended to be used in constructing animations. It produces a function that returns a list suitable to pass to \code{\link{par3d}}, to set the viewpoint at a given point in time. All of the parameters are optional. Only those \code{par3d} parameters that are specified will be returned. The input values other than \code{times} may each be specified as lists, giving the parameter value settings at a fixed time, or as matrices or arrays. If not lists, the following formats should be used: \code{userMatrix} can be a \code{4 x 4 x n} array, or a \code{4 x 4n} matrix; \code{scale} should be an \code{n x 3} matrix; \code{zoom} and \code{FOV} should be length \code{n} vectors. An alternative form of input is to put all of the above arguments into a list (i.e. a list of lists, or a list of arrays/matrices/vectors), and pass it as the first argument. This is the most convenient way to use this function with the function \code{\link{tkpar3dsave}}. Interpolation is by cubic spline or linear interpolation in an appropriate coordinate-wise fashion. Extrapolation may oscillate (repeat the sequence forward, backward, forward, etc.), cycle (repeat it forward), be constant (no repetition outside the specified time range), or be natural (linear on an appropriate scale). In the case of cycling, the first and last specified values should be equal, or the last one will be dropped. Natural extrapolation is only supported with spline interpolation. } \value{ A function is returned. The function takes one argument, and returns a list of \code{par3d} settings interpolated to that time. } \note{ Prior to \pkg{rgl} version 0.95.1476, the \code{subscene} argument defaulted to the current subscene, and any additional entries would be ignored by \code{\link{play3d}}. The current default value of \code{par3d("listeners", dev = dev)} means that all subscenes that share mouse responses will also share modifications by this function. } \author{Duncan Murdoch } \seealso{ \code{\link{play3d}} to play the animation. } \examples{ f <- par3dinterp( zoom = c(1, 2, 3, 1) ) f(0) f(1) f(0.5) \dontrun{ play3d(f) } } \keyword{ dplot } rgl/man/propertyControl.Rd0000644000176200001440000000503515012460301015320 0ustar liggesusers\name{propertyControl} \alias{subsetControl} \alias{propertyControl} \title{ Controls to use with playwidget() } \description{ These are setter functions to produce actions in a Shiny app, or in an animation. } \usage{ subsetControl(value = 1, subsets, subscenes = NULL, fullset = Reduce(union, subsets), accumulate = FALSE) propertyControl(value = 0, entries, properties, objids = tagged3d(tags), tags, values = NULL, param = seq_len(NROW(values)) - 1, interp = TRUE) } \arguments{ \item{value}{The value to use for input (typically \code{input$value} in a Shiny app.)} \item{subsets}{A list of vectors of object identifiers; the value will choose among them.} \item{fullset}{Objects in the subscene which are not in \code{fullset} will not be touched.} \item{subscenes}{The subscenes to be controlled. If \code{NULL}, the root subscene.} \item{accumulate}{If \code{TRUE}, the subsets will accumulate (by union) as the value increases.} \item{entries, properties, objids}{Which properties to set.} \item{tags}{ Select objects with matching tags. Ignored if \code{objids} is specified. } \item{values}{Values to set.} \item{param}{Parameter values corresponding to the rows of \code{value}} \item{interp}{Whether to use linear interpolation between \code{param} values} } \details{ \code{subsetControl} produces data for \code{\link{playwidget}} to display subsets of the object in one or more subscenes. This code will not touch objects in the subscenes if they are not in \code{fullset}. \code{fullset} defaults to the union of all the object ids mentioned in \code{subsets}, so by default if an id is not mentioned in one of the subsets, it will not be controlled by the slider. If \code{value} is specified in R code, it will be a 1-based index into the \code{subsets} list; when specified internally in Javascript, 0-based indexing into the corresponding array will be used. \code{propertyControl} sets individual properties. Here the row of \code{values} is determined by the position of \code{value} in \code{param}. } \value{ These functions return controller data in a list of class \code{"rglControl"}. } \author{ Duncan Murdoch } \seealso{ \code{\link{subsetSetter}} for a way to embed a pure Javascript control, and \code{\link{playwidget}} for a way to use these in animations (including Shiny), \code{\link{rglShared}} for linking using the \pkg{crosstalk} package. The \HTMLVignette{WebGL}{}{User Interaction in WebGL} vignette gives more details. } rgl/man/scene.Rd0000644000176200001440000000546214771520323013210 0ustar liggesusers\name{scene} \alias{clear3d} \alias{pop3d} \alias{ids3d} \title{Scene management} \description{ Clear shapes, lights, bbox } \usage{ clear3d( type = c("shapes", "bboxdeco", "material"), defaults, subscene = 0 ) pop3d( type = "shapes", id = 0, tag = NULL) ids3d( type = "shapes", subscene = NA, tags = FALSE ) } \arguments{ \item{type}{Select subtype(s): \describe{ \item{"shapes"}{shape stack} \item{"lights"}{light stack} \item{"bboxdeco"}{bounding box} \item{"userviewpoint"}{user viewpoint} \item{"modelviewpoint"}{model viewpoint} \item{"material"}{material properties} \item{"background"}{scene background} \item{"subscene"}{subscene list} \item{"all"}{all of the above} } } \item{defaults}{default values to use after clearing} \item{subscene}{which subscene to work with. \code{NA} means the current one, \code{0} means the whole scene} \item{id}{vector of ID numbers of items to remove} \item{tag}{override \code{id} with objects matching these \code{tag} material properties} \item{tags}{logical; whether to return \code{tag} column.} } \details{ RGL holds several lists of objects in each scene. There are lists for shapes, lights, bounding box decorations, subscenes, etc. \code{clear3d} clears the specified stack, or restores the defaults for the bounding box (not visible) or viewpoint. With \code{id = 0} \code{pop3d} removes the last added node on the list (except for subscenes: there it removes the active subscene). The \code{id} argument may be used to specify arbitrary item(s) to remove; if \code{id != 0}, the \code{type} argument is ignored. \code{clear3d} may also be used to clear material properties back to their defaults. \code{clear3d} has an optional \code{defaults} argument, which defaults to \code{\link{r3dDefaults}}. Only the \code{materials} component of this argument is currently used by \code{clear3d}. \code{ids3d} returns a dataframe containing the IDs in the currently active subscene by default, or a specified subscene, or if \code{subscene = 0}, in the whole rgl window along with an indicator of their type and if \code{tags = TRUE}, the \code{tag} value for each. Note that clearing the light stack leaves the scene in darkness; it should normally be followed by a call to \code{\link{light3d}}. } \seealso{ \code{\link{rgl}}, \code{\link{bbox3d}}, \code{\link{light3d}}, \code{\link{open3d}} to open a new window. } \examples{ x <- rnorm(100) y <- rnorm(100) z <- rnorm(100) p <- plot3d(x, y, z, type = 's', tag = "plot") ids3d() lines3d(x, y, z) ids3d(tags = TRUE) if (interactive() && !rgl.useNULL() && !in_pkgdown_example()) { readline("Hit enter to change spheres") pop3d(id = p["data"]) spheres3d(x, y, z, col = "red", radius = 1/5) box3d() } } \keyword{dynamic} rgl/man/tkspinControl.Rd0000644000176200001440000000266014771520323014761 0ustar liggesusers\name{tkspinControl} \alias{tkspinControl} \title{Create a spin control in a TCL/TK window} \description{ This function may be used to embed a spin control in a TCL/TK window. } \usage{ tkspinControl(base, dev = cur3d(), continue=FALSE, speed=30, scale=100, ... ) } \arguments{ \item{base}{The TCL/TK frame in which to insert this control. } \item{dev}{A vector of one or more RGL device numbers to control. } \item{continue}{Initial setting for continuous rotation checkbox. } \item{speed}{Initial setting for speed slider. } \item{scale}{Initial setting for scale slider. } \item{...}{Additional parameters to pass to \code{\link[tcltk:TkWidgets]{tkframe}}} } \author{ Ming Chen and Duncan Murdoch } \seealso{\code{\link{spin3d}}} \examples{ if (interactive() && !in_pkgdown_example()) { library(tcltk) open3d() win1 <- cur3d() plot3d(rexp(100), rexp(100), rexp(100), size=3, col='green') open3d() win2 <- cur3d() plot3d(rt(100,2), rt(100,2), rt(100, 2), size=3, col='yellow') open3d() win3 <- cur3d() plot3d(rexp(100), rexp(100), rexp(100), size=3, col='red') open3d() win4 <- cur3d() plot3d(rbinom(100,10,0.5), rbinom(100,10,0.5), rbinom(100,10,0.5), size=3, col='cyan') base <- tktoplevel() tkwm.title(base, "Spinners") con1 <- tkspinControl(base, dev=c(win1,win2)) con2 <- tkspinControl(base, dev=c(win3,win4)) tkpack(con1, con2) } } rgl/man/shinyGetPar3d.Rd0000644000176200001440000000730114771520323014571 0ustar liggesusers\name{shinyGetPar3d} \alias{shinyGetPar3d} \alias{shinySetPar3d} \alias{shinyResetBrush} \title{ Communicate RGL parameters between R and Javascript in Shiny } \description{ These functions allow Shiny apps to read and write the \code{par3d} settings that may have been modified by user interaction in the browser. } \usage{ shinyGetPar3d(parameters, session, subscene = currentSubscene3d(cur3d()), tag = "") shinySetPar3d(..., session, subscene = currentSubscene3d(cur3d())) shinyResetBrush(session, brush) } \arguments{ \item{parameters}{ A character vector naming the parameters to get. } \item{session}{ The Shiny session object. } \item{subscene}{ The subscene to which the parameters apply. Defaults to the currently active subscene in the R session. } \item{tag}{ An arbitrary string or value which will be sent as part of the response. } \item{...}{ A number of \code{name = value} pairs to be modified, or a single named list of parameters. Entries named \code{tag} or \code{subscene} will be ignored. } \item{brush}{The name of a Shiny input element corresponding to the \code{shinyBrush} argument to \code{\link{rglwidget}}.} } \details{ Requesting information from the browser is a complicated process. The \code{shinyGetPar3d} function doesn't return the requested value, it just submits a request for the value to be returned later in \code{input$par3d}, a reactive input. No action will result except when a reactive observer depends on \code{input$par3d}. See the example code below. The \code{shinySetPar3d} function sends a message to the browser asking it to change a particular parameter. The change will be made immediately, without sending the full scene to the browser, so should be reasonably fast. } \value{ These functions are called for their side effects, and don't return useful values. The side effect of \code{shinyGetPar3d} is to cause \code{input$par3d} to be updated sometime later. Besides the requested parameter values, \code{input$par3d} will contain a copy of the \code{subscene} and \code{tag} arguments. The side effect of \code{shinySetPar3d} is to send a message to the browser to update its copy of the \code{par3d} parameters immediately. } \note{ R and the browser don't maintain a perfect match between the way parameters are stored internally. The browser version of parameters will be returned by \code{shinyGetPar3d} and should be supplied to \code{shinySetPar3d}. } \references{ \url{https://shiny.rstudio.com/articles/communicating-with-js.html} describes the underlying mechanisms used by these two functions. } \seealso{The \code{\link{rglwidget}} argument \code{shinySelectionInput} allows information about mouse selections to be returned to R.} \author{ Duncan Murdoch } \examples{ if (interactive() && !in_pkgdown_example() && requireNamespace("shiny")) { save <- options(rgl.useNULL = TRUE) xyz <- matrix(rnorm(300), ncol = 3) app = shiny::shinyApp( ui = shiny::bootstrapPage( shiny::actionButton("redraw", "Redraw"), rglwidgetOutput("rglPlot") ), server = function(input, output, session) { # This waits until the user to click on the "redraw" # button, then sends a request for the current userMatrix shiny::observeEvent(input$redraw, { shinyGetPar3d("userMatrix", session) }) # This draws the plot whenever input$par3d changes, # i.e. whenever a response to the request above is # received. output$rglPlot <- renderRglwidget({ if (length(rgl.dev.list())) close3d() col <- sample(colors(), 1) plot3d(xyz, col = col, type = "s", main = col) par3d(userMatrix = input$par3d$userMatrix) rglwidget() }) }) shiny::runApp(app) options(save) } } rgl/man/clipMesh3d.Rd0000644000176200001440000001707215011677075014113 0ustar liggesusers\name{clipMesh3d} \alias{clipMesh3d} \alias{clipObj3d} \title{ Clip mesh or RGL object to general region } \description{ Modifies a mesh3d object so that values of a function are bounded. } \usage{ clipMesh3d(mesh, fn, bound = 0, greater = TRUE, minVertices = 0, plot = FALSE, keepValues = FALSE, keepTags = FALSE) clipObj3d(ids = tagged3d(tags), fn, bound = 0, greater = TRUE, minVertices = 0, replace = TRUE, tags) } \arguments{ \item{mesh}{ A \code{\link{mesh3d}} object. } \item{fn}{ A function used to determine clipping, or a vector of values from such a function, with one value per vertex. } \item{bound}{ The value(s) of \code{fn} on the clipping boundary. } \item{greater}{ Logical; whether to keep \code{fn >= bound} or not. } \item{minVertices}{ See Details below. } \item{plot}{Logical; whether or not to plot the mesh.} \item{keepValues}{Logical; whether to save the function values at each vertex when \code{plot = FALSE}.} \item{keepTags}{Whether to keep the \code{"tags"} component of the result; see details below.} \item{ids}{ The RGL id value(s) of objects to clip. } \item{tags}{ Object tags; an alternate way to specify \code{ids}. Ignored if \code{ids} is given. } \item{replace}{ Should the \code{ids} objects be deleted after the clipped ones are drawn? } } \details{ These functions transform a mesh3d object or other RGL objects by removing parts where \code{fn} violates the bound. For \code{clipMesh3d} the \code{fn} argument can be any of the following: \itemize{ \item{a character vector naming a function (with special names \code{"x"}, \code{"y"}, and \code{"z"} corresponding to functions returning those coordinates)} \item{a function} \item{a numeric vector with one value per vertex} \item{\code{NULL}, indicating that the numeric values are saved in \code{mesh$values}} } For \code{clipObj3d} any of the above except \code{NULL} may be used. If \code{fn} is a numeric vector, with one value per vertex, those values will be used in the test. If it is a function with formal arguments \code{x}, \code{y} and \code{z}, it will receive the coordinates of vertices in those arguments, otherwise it will receive the coordinates in a single n x 3 matrix. The function should be vectorized and return one value per vertex, to check against the bound. These operations are performed on the mesh: First, all quads are converted to triangles. Next, each vertex is checked against the condition. Modifications to triangles depend on how many of the vertices satisfy the condition (\code{fn >= bound} or \code{fn <= bound}, depending on \code{greater}) for inclusion. \itemize{ \item If no vertices in a triangle satisfy the condition, the triangle is omitted. \item If one vertex satisfies the condition, the other two vertices in that triangle are shrunk towards it by assuming \code{fn} is locally linear. \item If two vertices satisfy the condition, the third vertex is shrunk along each edge towards each other vertex, forming a quadrilateral made of two new triangles. \item If all vertices satisfy the condition, they are included with no modifications. } Modifications to line segments are similar: the segment will be shortened if it crosses the boundary, or omitted if it is entirely out of bounds. Points, spheres, text and sprites will just be kept or rejected. The \code{minVertices} argument is used to improve the approximation to the boundary when \code{fn} is a non-linear function. In that case, the interpolation described above can be inaccurate. If \code{minVertices} is set to a positive number (e.g. \code{10000}), then each object is modified by subdivision to have at least that number of vertices, so that pieces are smaller and the linear interpolation is more accurate. In the \code{clipObj3d} function, \code{minVertices} can be a vector, with entries corresponding to each of the entries in \code{ids}. } \section{The \code{keepTags} argument}{ If \code{keepTags = TRUE}, a \code{"tags"} element will be added to the result. It will be a vector with one entry per point, segment, triangle and quad in the output mesh. (These tags are not related to the tags used to identify \pkg{rgl} objects.) The mesh tags may be used to show the correspondence between the parts of the input mesh and output mesh. By default, the tags are constructed as a numerical sequence over points, segments, triangles and quads in the input mesh, in that order, starting from one. This is the same order used for colours when shading with \code{meshColor == "faces"}. For example, start with a mesh with one point, two segments, three triangles and four quads, but no \code{tags} member. It would implicitly tag the parts from one to ten as \verb{ c(1, # the point 2:3, # the two segments 4:6, # the three triangles 7:10) # the four quads } If clipping deleted the segments and the first triangle, the output would contain the seven element result \verb{ mesh$tags <- c(1, # the point remains # no segments now 5:6, # the two remaining triangles # were previously items 5 and 6 7:10) # the four quads } The \code{tags} output may contain repetitions. For example, when a triangle is partially clipped and replaced by several smaller triangles, entries for all of them will contain the value corresponding to the original triangle. The \code{mesh$tags} component may be supplied as part of the input mesh as any type of vector; the output will propagate values to the new mesh. The input length must match the total number of points, segments, triangles and quads in the input mesh or an error will be raised. } \value{ If \code{plot = FALSE}, \code{clipMesh3d} returns new mesh3d object in which all vertices (approximately) satisfy the clipping condition. Note that the order of vertices will likely differ from the original order, and new vertices will be added near the boundary (and if \code{minVertices > 0}, in the interior). If in addition \code{keepValues = TRUE}, a component named \code{"values"} will be added to the mesh containing the values for each vertex. If \code{keepTags = TRUE}, the \code{tags} component described below will be added to the output mesh. If \code{plot = TRUE}, the result will be plotted with \code{\link{shade3d}} and its result returned. \code{clipObj3d} is called for the side effect of modifying the scene. It returns a list of new RGL id values corresponding to the \code{ids} passed as arguments. } \author{ Duncan Murdoch } \references{ See \url{https://stackoverflow.com/q/56242470/2554330} and \url{https://laustep.github.io/stlahblog/posts/MeshClipping.html} for a motivating example. } \seealso{ See \code{\link{contourLines3d}} and \code{\link{filledContour3d}} for ways to display function values without clipping. } \examples{ # Show the problem that minVertices solves: cube <- cube3d(col = rainbow(6), meshColor = "faces") # This function only has one argument, so it will # be passed x, y and z in columns of a matrix vecnorm <- function(vals) apply(vals, 1, function(row) sqrt(sum(row^2))) open3d() mfrow3d(2, 2, sharedMouse = TRUE) id1 <- shade3d(cube) # All vertices have norm sqrt(3), so this clips nothing: clipObj3d(id1, fn = vecnorm, bound = sqrt(2)) next3d() id2 <- wire3d(cube, lit = FALSE) clipObj3d(id2, fn = vecnorm, bound = sqrt(2)) # This subdivides the cube, and does proper clipping: next3d() id3 <- shade3d(cube) clipObj3d(id3, fn = vecnorm, bound = sqrt(2), minVertices = 200) next3d() id4 <- wire3d(cube, lit = FALSE) clipObj3d(id4, fn = vecnorm, bound = sqrt(2), minVertices = 200) } rgl/man/merge.mesh3d.Rd0000644000176200001440000000243314771520323014367 0ustar liggesusers\name{merge.mesh3d} \alias{merge.mesh3d} \title{ Merge RGL mesh objects } \description{ Attempts to merge \code{"mesh3d"} objects. Objects need to be similar enough; see Details. } \usage{ \method{merge}{mesh3d}(x, y, ..., attributesMustMatch = FALSE) } \arguments{ \item{x, y}{ \code{"mesh3d"} objects to merge. } \item{\dots}{ Optional additional objects. } \item{attributesMustMatch}{ See Details.} } \details{ To allow objects to be merged, they need to be similar enough in terms of having the same list of material properties, normals, texture coordinates, etc. If \code{attributesMustMatch} is \code{TRUE}, it is an error to have attributes in one mesh but not in another, and those attributes that only specify a single value must have equal values in all meshes. If \code{attributesMustMatch} is \code{FALSE}, any non-matching attributes will be dropped from the final result. } \value{ A single \code{"mesh3d"} object merging the contents of the arguments. } \author{ Duncan Murdoch } \examples{ open3d() # Notice that the alpha setting for the cube is dropped, because # the other shapes don't specify alpha. shade3d(merge(cube3d(col="red", alpha = 0.5), translate3d(tetrahedron3d(col="green"), 2, 0, 0), translate3d(octahedron3d(col="blue"), 4, 0, 0))) } rgl/man/decorate3d.Rd0000644000176200001440000000215714771520323014126 0ustar liggesusers\name{decorate3d} \alias{decorate3d} \title{ Add decorations to a 3D plot } \description{ \code{decorate3d} adds the usual decorations to a plot: labels, axes, etc. } \usage{ decorate3d(xlim = NULL, ylim = NULL, zlim = NULL, xlab = "x", ylab = "y", zlab = "z", box = TRUE, axes = TRUE, main = NULL, sub = NULL, top = TRUE, aspect = FALSE, expand = 1.03, tag = material3d("tag"), ...) } \arguments{ \item{xlim, ylim, zlim}{These are used for the labels.} \item{xlab, ylab, zlab}{labels for the coordinates.} \item{box, axes}{whether to draw a box and axes.} \item{main, sub}{main title and subtitle.} \item{top}{whether to bring the window to the top when done.} \item{aspect}{either a logical indicating whether to adjust the aspect ratio, or a new ratio.} \item{expand}{how much to expand the box around the data, if it is drawn.} \item{tag}{optional label for objects being produced.} \item{...}{ignored.} } \value{ The RGL id values for those items. } \examples{ open3d() shade3d(tetrahedron3d(), col = "red") decorate3d(main = "A Tetrahedron") } rgl/man/tkpar3dsave.Rd0000644000176200001440000000325114771520323014334 0ustar liggesusers\name{tkpar3dsave} \alias{tkpar3dsave} \alias{par3dsave} \title{ Modal dialog for saving par3d settings } \description{ This function opens a TCL/TK modal dialog to allow particular views of an RGL scene to be saved. } \usage{ tkpar3dsave(params = c("userMatrix", "scale", "zoom", "FOV"), times = FALSE, dev = cur3d(), ...) } \arguments{ \item{params}{ Which parameters to save } \item{times}{ Should times be saved as well? } \item{dev}{ Which RGL device to work with } \item{...}{ Additional parameters to pass to \code{\link[tcltk:TkWidgets]{tktoplevel}}} } \details{ This opens a TCL/TK modal dialog box with \code{Record} and \code{Quit} buttons. Each time \code{Record} is clicked, a snapshot is taken of current \code{\link[rgl]{par3d}} settings. When \code{Quit} is clicked, the dialog closes and the values are returned in a list. If \code{times == TRUE}, then the times at which the views are recorded will also be saved, so that the \code{\link[rgl]{play3d}} function will play back with the same timing. } \value{ A list of the requested components. Each one will consist of a list of values that were current when the \code{Record} button was clicked. These are suitable to be passed directly to the \code{\link[rgl]{par3dinterp}} function. } \author{ Duncan Murdoch } \seealso{ \code{\link{par3d}}, \code{\link{par3dinterp}}} \examples{ if (interactive() && !in_pkgdown_example()) { # Record a series of positions, and then play them back immediately # at evenly spaced times, in an oscillating loop example(plot3d) play3d( par3dinterp( tkpar3dsave() ) ) # As above, but preserve the click timings # play3d( par3dinterp( tkpar3dsave(times=TRUE) ) ) } } rgl/man/play3d.Rd0000644000176200001440000001205314771520323013301 0ustar liggesusers\name{play3d} \alias{play3d} \alias{movie3d} \title{ Play animation of RGL scene } \description{ \code{play3d} calls a function repeatedly, passing it the elapsed time in seconds, and using the result of the function to reset the viewpoint. \code{movie3d} does the same, but records each frame to a file to make a movie. } \usage{ play3d(f, duration = Inf, dev = cur3d(), ..., startTime = 0) movie3d(f, duration, dev = cur3d(), ..., fps = 10, movie = "movie", frames = movie, dir = tempdir(), convert = NULL, clean = TRUE, verbose = TRUE, top = !rgl.useNULL(), type = "gif", startTime = 0, webshot = TRUE) } \arguments{ \item{f}{ A function returning a list that may be passed to \code{\link{par3d}} } \item{duration}{ The duration of the animation } \item{dev}{ Which RGL device to select } \item{\dots}{ Additional parameters to pass to \code{f}. } \item{startTime}{ Initial time at which to start the animation } \item{fps}{ Number of frames per second } \item{movie}{ The base of the output filename, not including .gif } \item{frames}{ The base of the name for each frame } \item{dir}{ A directory in which to create temporary files for each frame of the movie } \item{convert}{ How to convert to a GIF movie; see Details } \item{clean}{ If \code{convert} is \code{NULL} or \code{TRUE}, whether to delete the individual frames } \item{verbose}{ Whether to report the \code{convert} command and the output filename } \item{top}{ Whether to call \code{\link{rgl.bringtotop}} before each frame } \item{type}{ What type of movie to create. See Details. } \item{webshot}{ Whether to use the \pkg{webshot2} package for snapshots of frames. See \code{\link{snapshot3d}}.} } \details{ The function \code{f} will be called in a loop with the first argument being the \code{startTime} plus the time in seconds since the start (where the start is measured after all arguments have been evaluated). \code{play3d} is likely to place a high load on the CPU; if this is a problem, calls to \code{\link{Sys.sleep}} should be made within the function to release time to other processes. \code{play3d} will run for the specified \code{duration} (in seconds), but can be interrupted by pressing \code{ESC} while the RGL window has the focus. \code{movie3d} saves each frame to disk in a filename of the form \file{framesXXX.png}, where XXX is the frame number, starting from 0. If \code{convert} is \code{NULL} (the default) and the \pkg{\link[magick]{magick}} package is installed, it will be used to convert the frames to a GIF movie (or other format if supported). If \pkg{\link[magick]{magick}} is not installed or \code{convert} is \code{TRUE}, \code{movie3d} will attempt to use the external \command{ImageMagick} program to convert the frames to a movie. The newer \command{magick} executable is tried first, then \command{convert} if that fails. The \code{type} argument will be passed to \command{ImageMagick} to use as a file extension to choose the file type. Finally, \code{convert} can be a template for a command to execute in the standard shell (wildcards are allowed). The template is converted to a command using \cr \code{\link{sprintf}(convert, fps, frames, movie, type, duration, dir)} \cr For example, \code{convert = TRUE} uses the template \code{"magick -delay 1x\%d \%s*.png \%s.\%s"}. All work is done in the directory \code{dir}, so paths should not be needed in the command. (Note that \code{\link{sprintf}} does not require all arguments to be used, and supports formats that use them in an arbitrary order.) The \code{top = TRUE} default is designed to work around an OpenGL limitation: in some implementations, \code{\link{rgl.snapshot}} will fail if the window is not topmost. As of \pkg{rgl} version 0.94, the \code{dev} argument is not needed: the function \code{f} can specify its device, as \code{\link{spin3d}} does, for example. However, if \code{dev} is specified, it will be selected as the current device as each update is played. As of \pkg{rgl} version 0.95.1476, \code{f} can include multiple values in a \code{"subscene"} component, and \code{par3d()} will be called for each of them. } \value{ \code{play3d} is called for the side effect of its repeated calls to \code{f}. It returns \code{NULL} invisibly. \code{movie3d} is also normally called for the side effect of producing the output movie. It invisibly returns } \author{ Duncan Murdoch, based on code by Michael Friendly } \seealso{ \code{\link{spin3d}} and \code{\link{par3dinterp}} return functions suitable to use as \code{f}. See \code{demo(flag)} for an example that modifies the scene in \code{f}.} \examples{ open3d() plot3d( cube3d(col = "green") ) M <- par3d("userMatrix") if (!rgl.useNULL() && interactive()) play3d( par3dinterp(times = (0:2)*0.5, userMatrix = list(M, rotate3d(M, pi/2, 1, 0, 0), rotate3d(M, pi/2, 0, 1, 0) ) ), duration = 2 ) \dontrun{ movie3d( spin3d(), duration = 5 ) } } \keyword{ dplot } rgl/man/cube3d.Rd0000644000176200001440000000265014771520323013254 0ustar liggesusers\name{cube3d} \alias{cube3d} \alias{oh3d} \alias{tetrahedron3d} \alias{octahedron3d} \alias{icosahedron3d} \alias{dodecahedron3d} \alias{cuboctahedron3d} \title{Sample 3D mesh objects} \description{ A collection of sample mesh objects. } \usage{ cube3d(trans = identityMatrix(), ...) tetrahedron3d(trans = identityMatrix(), ...) octahedron3d(trans = identityMatrix(), ...) icosahedron3d(trans = identityMatrix(), ...) dodecahedron3d(trans = identityMatrix(), ...) cuboctahedron3d(trans = identityMatrix(), ...) oh3d(trans = identityMatrix(), ...) # an 'o' object } \arguments{ \item{trans}{transformation to apply to objects} \item{...}{additional parameters to pass to \code{\link{mesh3d}}} } \details{ These sample objects optionally take a 4x4 matrix transformation \code{trans} as an argument. This transformation is applied to all vertices of the default shape. The default is an identity transformation. } \value{ Objects of class \code{c("mesh3d", "shape3d")}. } \examples{ # render all of the Platonic solids open3d() shade3d( translate3d( tetrahedron3d(col = "red"), 0, 0, 0) ) shade3d( translate3d( cube3d(col = "green"), 3, 0, 0) ) shade3d( translate3d( octahedron3d(col = "blue"), 6, 0, 0) ) shade3d( translate3d( dodecahedron3d(col = "cyan"), 9, 0, 0) ) shade3d( translate3d( icosahedron3d(col = "magenta"), 12, 0, 0) ) } \seealso{ \code{\link{mesh3d}} } \keyword{dynamic} rgl/man/rglToLattice.Rd0000644000176200001440000000353414771520323014506 0ustar liggesusers\name{rglToLattice} \alias{rglToLattice} \alias{rglToBase} \title{ Convert RGL userMatrix to lattice or base angles } \description{ These functions take a user orientation matrix from an RGL scene and approximate the parameters to either \pkg{lattice} or base graphics functions. } \usage{ rglToLattice(rotm = par3d("userMatrix")) rglToBase(rotm = par3d("userMatrix")) } \arguments{ \item{rotm}{ A matrix in homogeneous coordinates to convert. } } \details{ The \pkg{lattice} package can use Euler angles in the ZYX scheme to describe the rotation of a scene in its \code{\link[lattice:cloud]{wireframe}} or \code{\link[lattice]{cloud}} functions. The \code{rglToLattice} function computes these angles based on \code{rotm}, which defaults to the current user matrix. This allows RGL to be used to interactively find a decent viewpoint and then reproduce it in \pkg{lattice}. The base graphics \code{\link{persp}} function does not use full Euler angles; it uses a viewpoint angle, and assume the z axis remains vertical. The \code{rglToBase} function computes the viewpoint angle accurately if the RGL scene is displayed with a vertical z axis, and does an approximation otherwise. } \value{ \code{rglToLattice} returns a list suitable to be used as the \code{screen} argument to \code{\link[lattice:cloud]{wireframe}}. \code{rglToBase} returns a list containing \code{theta} and \code{phi} components which can be used as corresponding arguments in \code{\link{persp}}. } \author{ Duncan Murdoch } \examples{ persp3d(volcano, col = "green") if ((hasorientlib <- requireNamespace("orientlib", quietly = TRUE)) && requireNamespace("lattice", quietly = TRUE)) lattice::wireframe(volcano, screen = rglToLattice()) if (hasorientlib) { angles <- rglToBase() persp(volcano, col = "green", border = NA, shade = 0.5, theta = angles$theta, phi = angles$phi) } } rgl/man/shade3d.Rd0000644000176200001440000001170614771520323013424 0ustar liggesusers\name{shade3d} \alias{dot3d} \alias{dot3d.mesh3d} \alias{wire3d} \alias{wire3d.mesh3d} \alias{shade3d} \alias{shade3d.mesh3d} \title{Draw 3D mesh objects} \description{ Draws 3D mesh objects in full, or just the edges, or just the vertices. } \usage{ dot3d(x, ...) # draw dots at the vertices of an object \method{dot3d}{mesh3d}(x, ..., front = "points", back = "points") wire3d(x, ...) # draw a wireframe object \method{wire3d}{mesh3d}(x, ..., front = "lines", back = "lines") shade3d(x, ...) # draw a shaded object \method{shade3d}{mesh3d}(x, override = TRUE, meshColor = c("vertices", "edges", "faces", "legacy"), texcoords = NULL, ..., front = "filled", back = "filled") } \arguments{ \item{x}{a \code{mesh3d} object.} \item{...}{additional rendering parameters, or for \code{dots3d} and \code{wire3d}, parameters to pass to \code{shade3d}} \item{override}{should the parameters specified here override those stored in the object?} \item{meshColor}{how should colours be interpreted? See details below} \item{texcoords}{texture coordinates at each vertex.} \item{front, back}{Material properties for rendering.} } \details{ The \code{meshColor} argument controls how material colours and textures are interpreted. This parameter was added in \pkg{rgl} version 0.100.1 (0.100.27 for \code{dot3d}). Possible values are: \describe{ \item{\code{"vertices"}}{Colours and texture coordinates are applied by vertex, in the order they appear in the \code{x$vb} matrix.} \item{\code{"edges"}}{Colours are applied to each edge: first to the segments in the \code{x$is} matrix, then the 3 edges of each triangle in the \code{x$it} matrix, then the 4 edges of each quad in the \code{x$ib} matrix. This mode is only supported if both front and back materials are \code{"lines"}, and the mesh contains no points.} \item{\code{"faces"}}{Colours are applied to each object in the mesh: first to the points, then the segments, triangles and finally quads. The entire whole face (or point or segment) receives one colour from the specified colours.} \item{\code{"legacy"}}{Colours and textures are applied in the same way as in \pkg{rgl} versions earlier than 0.100.1.} } Unique partial matches of these values will be recognized. If colours are specified but \code{meshColor} is not and \code{options(rgl.meshColorWarning = TRUE)}, a warning will be given that their interpretation may have changed. In versions 0.100.1 to 0.100.26 of \pkg{rgl}, the default was to give the warning; now the default is for no warning. Note that since version 0.102.10, \code{meshColor = "edges"} is only allowed when drawing lines (the \code{wire3d} default), and it may draw edges more than once. In general, if any rendering draws twice at the same location, which copy is visible depends on the order of drawing and the \code{\link{material3d}("depth_test")} setting. Whether points, lines or solid faces are drawn is determined in 3 steps: \enumerate{ \item{If arguments \code{"front"} or \code{"back"} are specified in the call, those are used.} \item{If one or both of those arguments are not specified, but the material properties are present in the object, those are used.} \item{If values are not specified in either of those places, \code{shade3d} draws filled surfaces, \code{wire3d} draws lines, and \code{dot3d} draws points. } } Note: For some versions of rgl up to version 0.107.15, rule 2 above was not respected. } \value{ \code{dot3d}, \code{wire3d}, and \code{shade3d} are called for their side effect of drawing an object into the scene; they return an object ID (or vector of IDs) invisibly. See \link{primitives} for a discussion of texture coordinates. } \examples{ # generate a quad mesh object vertices <- c( -1.0, -1.0, 0, 1.0, -1.0, 0, 1.0, 1.0, 0, -1.0, 1.0, 0 ) indices <- c( 1, 2, 3, 4 ) open3d() wire3d( mesh3d(vertices = vertices, quads = indices) ) # render 4 meshes vertically in the current view open3d() bg3d("gray") l0 <- oh3d(tran = par3d("userMatrix"), color = "green" ) shade3d( translate3d( l0, -6, 0, 0 )) l1 <- subdivision3d( l0 ) shade3d( translate3d( l1 , -2, 0, 0 ), color = "red", override = FALSE ) l2 <- subdivision3d( l1 ) shade3d( translate3d( l2 , 2, 0, 0 ), color = "red", override = TRUE ) l3 <- subdivision3d( l2 ) shade3d( translate3d( l3 , 6, 0, 0 ), color = "red" ) # render all of the Platonic solids open3d() shade3d( translate3d( tetrahedron3d(col = "red"), 0, 0, 0) ) shade3d( translate3d( cube3d(col = "green"), 3, 0, 0) ) shade3d( translate3d( octahedron3d(col = "blue"), 6, 0, 0) ) shade3d( translate3d( dodecahedron3d(col = "cyan"), 9, 0, 0) ) shade3d( translate3d( icosahedron3d(col = "magenta"), 12, 0, 0) ) } \seealso{ \code{\link{mesh3d}}, \code{\link{par3d}}, \code{\link{shapelist3d}} for multiple shapes } \keyword{dynamic} rgl/man/ageControl.Rd0000644000176200001440000000534615012460301014175 0ustar liggesusers\name{ageControl} \alias{ageControl} \title{ Set attributes of vertices based on their age } \description{ This is a function to produce actions in response to a \code{\link{playwidget}} or Shiny input control. The mental model is that each of the vertices of some object has a certain birth time; a control sets the current time, so that vertices have ages depending on the control setting. Attributes of those vertices can then be changed. } \usage{ ageControl(births, ages, objids = tagged3d(tags), tags, value = 0, colors = NULL, alpha = NULL, radii = NULL, vertices = NULL, normals = NULL, origins = NULL, texcoords = NULL, x = NULL, y = NULL, z = NULL, red = NULL, green = NULL, blue = NULL) } \arguments{ \item{births}{Numeric birth times of vertices.} \item{ages}{Chosen ages at which the following attributes will apply.} \item{objids}{Object ids to which the changes apply.} \item{tags}{ Alternate way to specify \code{objids}. Ignored if \code{objids} is given. } \item{value}{Initial value; typically overridden by input.} \item{colors, alpha, radii, vertices, normals, origins, texcoords}{ Attributes of the vertices that can be changed. There should be one entry or row for each entry in \code{ages}.} \item{x, y, z, red, green, blue}{These one-dimensional components of vertices and colors are provided for convenience.} } \details{ All attributes must have the same number of entries (rows for the matrices) as the ages vector. The births vector must have the same number of entries as the number of vertices in the object. Not all objects contain all attributes; if one is chosen that is not a property of the corresponding object, a Javascript \code{alert()} will be generated. (This restriction may be removed in the future by attempting to add the attribute when it makes sense.) If a \code{births} entry is \code{NA}, no change will be made to that vertex. } \value{ A list of class \code{"rglControl"} of cleaned up parameter values, to be used in an RGL widget. } \author{ Duncan Murdoch } \seealso{ The \HTMLVignette{WebGL}{}{User Interaction in WebGL} vignette gives more details. } \examples{ saveopts <- options(rgl.useNULL = TRUE) theta <- seq(0, 4*pi, length.out = 100) xyz <- cbind(sin(theta), cos(theta), sin(theta/2)) lineid <- plot3d(xyz, type="l", alpha = 0, lwd = 5, col = "blue")["data"] widget <- rglwidget() \%>\% playwidget(ageControl(births = theta, ages = c(-4*pi, -4*pi, 1-4*pi, 0, 0, 1), objids = lineid, alpha = c(0, 1, 0, 0, 1, 0)), start = 0, stop = 4*pi, step = 0.1, rate = 4) if (interactive() || in_pkgdown_example()) widget options(saveopts) } rgl/man/setGraphicsDelay.Rd0000644000176200001440000000237214771520323015343 0ustar liggesusers\name{setGraphicsDelay} \alias{setGraphicsDelay} \alias{RGL_SLOW_DEV} \title{ Set a one-time slowdown on opening standard graphics } \description{ This function is mainly for internal use, to work around a bug in macOS Catalina: if base plotting happens too quickly after opening RGL and the first call to quartz, R crashes. This inserts a delay after the first call to open the graphics device. The default is no delay, unless on Catalina with no graphics device currently open but the \code{\link{quartz}} device set as the default, when a 1 second delay will be added. Use environment variable "RGL_SLOW_DEV = value" to set a different default delay. It works by changing the value of \code{\link{options}("device")}, so explicit calls to the device will not be affected. It is called automatically when the \pkg{rgl} package is loaded. } \usage{ setGraphicsDelay(delay = Sys.getenv("RGL_SLOW_DEV", 0), unixos = "none") } \arguments{ \item{delay}{ Number of seconds for the delay. } \item{unixos}{ The name of the Unix OS. If set to \code{"Darwin"}, and the version is 19.0.0 or greater, the default delay is changed to 1 second. } } \value{ Called for the side effect of adding the delay to the first opening of the graphics device. } rgl/man/arc3d.Rd0000644000176200001440000000656114771520323013110 0ustar liggesusers\name{arc3d} \alias{arc3d} \title{ Draw arcs } \description{ Given starting and ending points on a sphere and the center of the sphere, draw the great circle arc between the starting and ending points. If the starting and ending points have different radii, a segment of a logarithmic spiral will join them, unless they are in the same direction, in which case a straight line will join them. } \usage{ arc3d(from, to, center, radius, n, circle = 50, base = 0, plot = TRUE, ...) } \arguments{ \item{from}{ One or more points from which to start arcs. } \item{to}{ One or more destination points. } \item{center}{ One or more center points. } \item{radius}{ If not missing, a vector of length \code{n} giving the radii at each point between \code{from} and \code{to}. If missing, the starting and ending points will be joined by a logarithmic spiral. } \item{n}{ If not missing, how many segments to use between the first and last point. If missing, a value will be calculated based on the angle between starting and ending points as seen from the center. } \item{circle}{ How many segments would be used if the arc went completely around a circle. } \item{base}{ See Details below. } \item{plot}{ Should the arcs be plotted, or returned as a matrix? } \item{\dots}{ Additional parameters to pass to \code{\link{points3d}}. } } \details{ If any of \code{from}, \code{to} or \code{center} is an n by 3 matrix with n > 1, multiple arcs will be drawn by recycling each of these parameters to the number of rows of the longest one. If the vector lengths of \code{from - center} and \code{to - center} differ, then instead of a spherical arc, the function will draw a segment of a logarithmic spiral joining the two points. By default, the arc is drawn along the shortest great circle path from \code{from} to \code{to}, but the \code{base} parameter can be used to modify this. If \code{base = 1} is used, the longer arc will be followed. Larger positive integer values will result in \code{base - 1} loops in that direction completely around the sphere. Negative values will draw the curve in the same direction as the shortest arc, but with \code{abs(base)} full loops. It doesn't make much sense to ask for such loops unless the radii of \code{from} and \code{to} differ, because spherical arcs would overlap. Normally the \code{base} parameter is left at its default value of \code{0}. When \code{base} is non-zero, the curve will be constructed in multiple pieces, between \code{from}, \code{to}, \code{-from} and \code{-to}, for as many steps as necessary. If \code{n} is specified, it will apply to each of these pieces. } \value{ If \code{plot = TRUE}, called mainly for the side effect of drawing arcs. Invisibly returns the object ID of the collection of arcs. If \code{plot = FALSE}, returns a 3 column matrix containing the points that would be drawn as the arcs. } \author{ Duncan Murdoch } \examples{ normalize <- function(v) v/sqrt(sum(v^2)) # These vectors all have the same length from <- t(apply(matrix(rnorm(9), ncol = 3), 1, normalize)) to <- normalize(rnorm(3)) center <- c(0, 0, 0) open3d() spheres3d(center, radius = 1, col = "white", alpha = 0.2) arc3d(from, to, center, col = "red") arc3d(from, 2*to, center, col = "blue") text3d(rbind(from, to, center, 2*to), texts = c(paste0("from", 1:3), "to", "center", "2*to"), depth_mask = FALSE, depth_test = "always") } rgl/man/selectpoints3d.Rd0000644000176200001440000000622214771520323015051 0ustar liggesusers\name{selectpoints3d} \alias{selectpoints3d} \title{ Select points from a scene } \description{ This function uses the \code{\link{select3d}} function to allow the user to choose a point or region in the scene, then reports on all the vertices in or near that selection. } \usage{ selectpoints3d(objects = ids3d()$id, value = TRUE, closest = TRUE, % $ multiple = FALSE, ...) } \arguments{ \item{objects}{ A vector of object id values to use for the search. } \item{value}{ If \code{TRUE}, return the coordinates of the points; otherwise, return their indices. } \item{closest}{ If \code{TRUE}, return the points closest to the selection of no points are exactly within it. } \item{multiple}{ If \code{TRUE} or a function, do multiple selections. See the Details below. } \item{\dots}{ Other parameters to pass to \code{\link{select3d}}. } } \details{ The \code{multiple} argument may be a logical value or a function. If logical, it controls whether multiple selections will be performed. If \code{multiple} is \code{FALSE}, a single selection will be performed; it might contain multiple points. If \code{TRUE}, multiple selections will occur and the results will be combined into a single matrix. If \code{multiple} is a function, it should take a single argument. This function will be called with the argument set to a matrix containing newly added rows to the value, i.e. it will contain coordinates of the newly selected points (if \code{value = TRUE}), or the indices of the points (if \code{value = FALSE}). It should return a logical value, \code{TRUE} to indicate that selection should continue, \code{FALSE} to indicate that it should stop. In either case, if multiple selections are being performed, the \code{ESC} key will stop the process. } \value{ If \code{value} is \code{TRUE}, a 3-column matrix giving the coordinates of the selected points. All rows in the matrix will be unique even if multiple vertices have the same coordinates. If \code{value} is \code{FALSE}, a 2-column matrix containing columns: \item{id}{The object id containing the point.} \item{index}{The index of the point within \code{\link{rgl.attrib}(id, "vertices")}. If multiple points have the same coordinates, all indices will be returned.} } \note{This function selects points, not areas. For example, if the selection region is in the interior of the triangle, that will count as a miss for all of the triangle's vertices.} \author{ Duncan Murdoch } \seealso{ \code{\link{select3d}} to return a selection function. } \examples{ xyz <- cbind(rnorm(20), rnorm(20), rnorm(20)) ids <- plot3d( xyz ) if (interactive() && !in_pkgdown_example()) { # Click near a point to select it and put a sphere there. # Press ESC to quit... # This version returns coordinates selectpoints3d(ids["data"], multiple = function(x) { spheres3d(x, color = "red", alpha = 0.3, radius = 0.2) TRUE }) # This one returns indices selectpoints3d(ids["data"], value = FALSE, multiple = function(ids) { spheres3d(xyz[ids[, "index"], , drop = FALSE], color = "blue", alpha = 0.3, radius = 0.2) TRUE }) } } \keyword{ graphics } rgl/man/rgl.Sweave.Rd0000644000176200001440000000631514771520323014126 0ustar liggesusers\name{rgl.Sweave} \alias{rgl.Sweave} \alias{rgl.Sweave.off} \alias{Sweave.snapshot} \title{ Integrating RGL with Sweave } \description{ As of \R 2.13.0, it is possible to include RGL graphics into a \link{Sweave} document. These functions support that integration. } \usage{ Sweave.snapshot() rgl.Sweave(name, width, height, options, ...) rgl.Sweave.off() } \arguments{ \item{name, width, height, options, ...}{ These arguments are passed by \code{\link{Sweave}} to \code{rgl.Sweave} when it opens the device. } } \details{ The \code{rgl.Sweave} function is not normally called by the user. The user specifies it as the graphics driver when opening the code chunk, e.g. by using \preformatted{<>=} When the RGL device is closed at the end of the code chunk, \code{rgl.Sweave.off()} will be called automatically. It will save a snapshot of the last image (by default in \file{.png} format) for inclusion in the Sweave document and (by default) close the device. Alternatively, the \code{Sweave.snapshot()} function can be called to save the image before the end of the chunk. Only one snapshot will be taken per chunk. Several chunk options are used by the \code{rgl.Sweave} device: \describe{ \item{stayopen}{(default \code{FALSE}). If \code{TRUE} then the RGL device will \emph{not} be closed at the end of the chunk, instead a call to \code{Sweave.snapshot()} will be used if it has not been called explicitly. Subsequent chunks can add to the scene.} \item{outputtype}{(default \code{png}). The output may be specified as \code{outputtype = pdf} or \code{outputtype = eps} instead, in which case the \code{\link{rgl.postscript}} function will be used to write output in the specified format. Note that \code{\link{rgl.postscript}} has limitations and does not always render scenes correctly.} \item{delay}{(default 0.1). After creating the display window, \code{\link{Sys.sleep}} will be called to delay this many seconds, to allow the display system to initialize. This is needed in X11 systems which open the display asynchronously. If the default time is too short, \code{rgl.Sweave} may falsely report that the window is too large to open.} } } \note{ We recommend turning off all other graphics drivers in a chunk that uses \code{grdevice = rgl.Sweave}. The RGL functions do not write to a standard graphics device. } \note{ The \pkg{rgl} package relies on your graphics hardware to render OpenGL scenes, and the default \file{.png} output copies a bitmap from the hardware device. All such devices have limitations on the size of the bitmap, but they do not always signal these limitations in a way that RGL will detect. If you find that images are not being produced properly, try reducing the size using the \code{resolution}, \code{width} or \code{height} chunk options. } \value{ These functions are called for their side effects. } \author{ Duncan Murdoch } \seealso{ \code{\link{RweaveLatex}} for a description of alternate graphics drivers in Sweave, and standard options that can be used in code chunks. \code{\link{hook_rgl}} and \code{\link{hook_webgl}} allow fixed or interactive RGL scenes to be embedded in \pkg{knitr} documents. } \keyword{ utilities } rgl/man/abclines.Rd0000644000176200001440000000221114771520323013660 0ustar liggesusers\name{abclines3d} \alias{abclines3d} \title{ Lines intersecting the bounding box } \description{ This adds mathematical lines to a scene. Their intersection with the current bounding box will be drawn. } \usage{ abclines3d(x, y = NULL, z = NULL, a, b = NULL, c = NULL, ...) } \arguments{ \item{x, y, z}{ Coordinates of points through which each line passes. } \item{a, b, c}{ Coordinates of the direction vectors for the lines. } \item{...}{ Material properties. } } \details{ Draws the segment of a line that intersects the current bounding box of the scene using the parametrization \eqn{ (x, y, z) + (a, b, c) * s } where \eqn{s} is a real number. Any reasonable way of defining the coordinates \code{x, y, z} and \code{a, b, c} is acceptable. See the function \code{\link[grDevices]{xyz.coords}} for details. } \value{ A shape ID of the object is returned invisibly. } \seealso{ \code{\link{planes3d}} for mathematical planes. \code{\link{segments3d}} draws sections of lines that do not adapt to the bounding box. } \examples{ plot3d(rnorm(100), rnorm(100), rnorm(100)) abclines3d(0, 0, 0, a = diag(3), col = "gray") } \keyword{ dynamic } rgl/man/bg.Rd0000644000176200001440000000723715011677075012512 0ustar liggesusers\name{bg3d} \alias{bg3d} \title{Set up background} \description{ Set up the background of the scene. } \usage{ bg3d(color, sphere=FALSE, back="lines", fogtype="none", fogScale = 1, col, ...) } \arguments{ \item{color, col}{ See Details below. } \item{sphere}{ logical: if \code{TRUE}, an environmental sphere geometry is used for the background decoration. } \item{back}{ Specifies the fill style of the sphere geometry. See \code{\link{material3d}} for details. } \item{fogtype}{fog type: \describe{ \item{"none"}{no fog} \item{"linear"}{linear fog function} \item{"exp"}{exponential fog function} \item{"exp2"}{squared exponential fog function} } Fog only applies to objects with \code{\link{material3d}} property \code{fog} set to \code{TRUE}. } \item{fogScale}{ Scaling for fog. See Details. } \item{ ... }{Additional material properties. See \code{\link{material3d}} for details.} } \details{ The background color is taken from \code{color} or \code{col} if \code{color} is missing. The first entry is used for background clearing and as the fog color. The second (if present) is used for background sphere geometry. If \code{color} and \code{col} are both missing, the default is found in the \code{\link{r3dDefaults}$bg} list, or \code{"white"} is used if nothing is specified there. If \code{sphere} is set to \code{TRUE}, an environmental sphere enclosing the whole scene is drawn. If not, but the material properties include a bitmap as a texture, the bitmap is drawn in the background of the scene. (The bitmap colors modify the general color setting.) If neither a sphere nor a bitmap background is drawn, the background is filled with a solid color. The \code{fogScale} parameter should be a positive value to change the density of the fog in the plot. For \code{fogtype = "linear"} it multiplies the density of the fog; for the exponential fog types it multiplies the density parameter used in the display. See \href{https://registry.khronos.org/OpenGL-Refpages/gl2.1/xhtml/glFog.xml}{the OpenGL 2.1 reference} for the formulas used in the fog calculations within \R (though the \code{"exp2"} formula appears to be wrong, at least on my system). In WebGL displays, the following rules are used. They appear to match the rules used in \R on my system. \itemize{ \item{For \code{"linear"} fog, the near clipping plane is taken as \eqn{c=0}, and the far clipping plane is taken as \eqn{c=1}. The amount of fog is \eqn{s * c} clamped to a 0 to 1 range, where \eqn{s = fogScale}.} \item{For \code{"exp"} and \code{"exp2"} fog, the observer location is negative at a distance depending on the field of view. The formula for the distance is \deqn{c = [1-sin(theta)]/[1 + sin(theta)]} where \eqn{theta = FOV/2}. We calculate \deqn{c' = d(1-c) + c} so \eqn{c'} runs from 0 at the observer to 1 at the far clipping plane.} \item{For \code{"exp"} fog, the amount of fog is \eqn{1 - exp(-s * c')}.} \item{For \code{"exp2"} fog, the amount of fog is \eqn{1 - exp[-(s * c')^2]}.} } } \examples{ open3d() # a simple white background bg3d("white") # the holo-globe (inspired by star trek): bg3d(sphere = TRUE, color = c("black", "green"), lit = FALSE, back = "lines" ) # an environmental sphere with a nice texture. bg3d(sphere = TRUE, texture = system.file("textures/sunsleep.png", package = "rgl"), back = "filled" ) # The same texture as a fixed background open3d() bg3d(texture = system.file("textures/sunsleep.png", package = "rgl"), col = "white") } \seealso{ \code{\link{material3d}}, \code{\link{bgplot3d}} to add a 2D plot as background. } \keyword{dynamic} rgl/man/asRow.Rd0000644000176200001440000000473315012460301013172 0ustar liggesusers\name{asRow} \alias{asRow} \alias{getWidgetId} \title{ Convenience functions for RGL HTML layouts } \description{ The \code{asRow} function arranges objects in a row in the display; the \code{getWidgetId} function extracts the HTML element ID from an HTML widget. } \usage{ asRow(..., last = NA, height = NULL, colsize = 1) getWidgetId(widget) } \arguments{ \item{\dots}{ Either a single \code{"combineWidgets"} object produced by \code{asRow} or a \code{\%>\%} pipe of RGL objects, or several objects intended for rearrangement. } \item{last}{ If not \code{NA}, the number of objects from \code{...} that are to be arranged in a row. Earlier ones will remain in a column. } \item{height}{ An optional height for the resulting row. This is normally specified in pixels, but will be rescaled as necessary to fit the display. } \item{colsize}{ A vector of relative widths for the columns in the row. } \item{widget}{ A single HTML widget from which to extract the HTML element ID. } } \details{ Using \code{asRow} requires that the \pkg{manipulateWidget} package is installed. \code{asRow} produces a \code{"combineWidgets"} object which is a single column whose last element is another \code{"combineWidgets"} object which is a single row. If \code{n} objects are given as input and \code{last} is given a value less than \code{n}, the first \code{n - last} objects will be displayed in a column above the row containing the \code{last} objects. } \value{ \code{asRow} returns a single \code{"combineWidgets"} object suitable for display or nesting within a more complicated display. \code{getWidgetId} returns a character string containing the HTML element ID of the widget. } \author{ Duncan Murdoch } \seealso{ \link{pipe} for the \code{\%>\%} operator. The \HTMLVignette{WebGL}{}{User Interaction in WebGL} vignette gives more details. } \examples{ if (requireNamespace("manipulateWidget", quietly = TRUE) && require("crosstalk", quietly = TRUE)) { sd <- SharedData$new(mtcars) ids <- plot3d(sd$origData(), col = mtcars$cyl, type = "s") # Copy the key and group from existing shared data rglsd <- rglShared(ids["data"], key = sd$key(), group = sd$groupName()) w <- rglwidget(shared = rglsd) \%>\% asRow("Mouse mode: ", rglMouse(getWidgetId(.)), "Subset: ", filter_checkbox("cylinderselector", "Cylinders", sd, ~ cyl, inline = TRUE), last = 4, colsize = c(1,2,1,2), height = 60) if (interactive() || in_pkgdown_example()) w } } rgl/man/pch3d.Rd0000644000176200001440000000513415011677075013115 0ustar liggesusers\name{pch3d} \alias{pch3d} \title{ Plot symbols similar to base graphics } \description{ This function plots symbols similarly to what the base graphics function \code{\link{points}} does when \code{pch} is specified. } \usage{ pch3d(x, y = NULL, z = NULL, pch = 1, bg = material3d("color")[1], cex = 1, radius, color = "black", lit = FALSE, ...) } \arguments{ \item{x, y, z}{ The locations at which to plot in a form suitable for use in \code{\link{xyz.coords}}. } \item{pch}{ A vector of integers or single characters describing the symbols to plot. } \item{bg}{ The fill color(s) to use for \code{pch} from 21 to 25. } \item{cex}{ A relative size of the symbol to plot. } \item{radius}{ An absolute size of the symbol to plot in user coordinates. } \item{color}{ The color(s) to use for symbols. } \item{lit}{ Whether the object responds to lighting or just shows the displayed color directly. } \item{\dots}{ Other material properties. } } \details{ The list of symbols encoded by numerical \code{pch} values is given in the \code{\link{points}} help page. } \note{ This function is not a perfect match to how the \code{\link{points}} function works due to limitations in RGL and OpenGL. In particular: Symbols with numbers from 1 to 25 are drawn as 3D sprites (see \code{\link{sprites3d}}), so they will resize as the window is zoomed. Letters and numbers from 32 to 255 (which are mapped to letters) are drawn using \code{\link{text3d}}, so they maintain a fixed size. A calculation somewhat like the one in \code{\link{plot3d}} that sets the size of spheres is used to choose the size of sprites based on \code{cex} and the current scaling. This will likely need manual tweaking. Use the \code{radius} argument for a fixed size. No special handling is done for the case of \code{pch = "."}. Use \code{points3d} for small dots. As of \pkg{rgl} version 0.100.10, background and foreground colors can vary from symbol to symbol. } \value{ A vector of object id values is returned invisibly. Separate objects will be drawn for each different combination of \code{pch} value from 0 to 25, \code{color} and \code{bg}, and another holding all the character symbols. } \author{ Duncan Murdoch } \seealso{ \code{\link{points3d}}, \code{\link{text3d}} and \code{\link{sprites3d}} for other ways to label points, \code{\link{points}} for the base graphics symbol definitions. } \examples{ open3d() i <- 0:25; x <- i \%\% 5; y <- rep(0, 26); z <- i \%/\% 5 pch3d(x, y, z, pch = i, bg = "gray", color = rainbow(26)) text3d(x, y, z + 0.3, i) pch3d(x + 5, y, z, pch = i+65) text3d(x + 5, y, z + 0.3, i+65) } rgl/man/tagged3d.Rd0000644000176200001440000000251014771520323013564 0ustar liggesusers\name{tagged3d} \alias{tagged3d} \title{ Find tags on rgl objects. } \description{ Objects with material properties may have an arbitrary string set as a tag. This function retrieves the id values associated with a given tag, or the tags set on given ids. } \usage{ tagged3d(tags = NULL, ids = NULL, full = FALSE, subscene = 0) } \arguments{ \item{tags}{ A vector of tags to use for selection. } \item{ids}{ A vector of ids to report the tags on. } \item{full}{logical; whether to return a dataframe containing \code{id}, \code{type}, \code{tag}, or a vector of ids or tags.} \item{subscene}{ Where to look: by default, the whole scene is searched. \code{NA} restricts the search to the current subscene, or a subscene id can be given. } } \details{ Exactly one of \code{tags} and \code{ids} must be specified. } \value{ A dataframe is constructed with columns \item{id}{item id} \item{type}{item type} \item{tag}{item tag} matching the specified \code{tags} or \code{ids} value. If \code{full = TRUE}, the full dataframe is returned, otherwise just the requested ids or tags. If \code{ids} is specified, the return value will be in the same order as \code{ids}). } \author{ Duncan Murdoch } \examples{ open3d() ids <- plot3d(rnorm(10), rnorm(10), rnorm(10), tag = "plot") unclass(ids) tagged3d("plot") tagged3d(ids = ids, full = TRUE) } rgl/man/tkspin3d.Rd0000644000176200001440000000137014771520323013644 0ustar liggesusers\name{tkspin3d} \alias{tkspin3d} \title{Create TCL/TK controller for RGL window} \description{ This function creates a TCL/TK window containing buttons to spin and resize one or more RGL windows. } \usage{ tkspin3d(dev = cur3d(), ...) } \arguments{ \item{dev}{A vector of one or more RGL device numbers to control } \item{...}{Named parameters in that match named formal arguments to \code{\link{tkspinControl}} are passed there, while others are passed to \code{\link[tcltk:TkWidgets]{tktoplevel}}}} \author{ Ming Chen and Duncan Murdoch } \seealso{ \code{\link{tkspinControl}}} \examples{ if (interactive() && !in_pkgdown_example()) { open3d() points3d(rnorm(100), rnorm(100), rnorm(100), size=3) axes3d() box3d() tkspin3d() } } rgl/man/par3d.Rd0000644000176200001440000003244614771520323013126 0ustar liggesusers\name{par3d} \alias{par3d} \alias{rgl.par3d.names} \alias{rgl.par3d.readonly} \concept{activeSubscene} \concept{antialias} \concept{bbox} \concept{cex} \concept{family} \concept{font} \concept{fontname} \concept{FOV} \concept{ignoreExtent} \concept{maxClipPlanes} \concept{modelMatrix} \concept{listeners} \concept{mouseMode} \concept{projMatrix} \concept{scale} \concept{skipRedraw} \concept{useFreeType} \concept{userMatrix} \concept{userProjection} \concept{viewport} \concept{windowRect} \concept{zoom} \title{Set or query RGL parameters} \description{ \code{par3d} can be used to set or query graphical parameters in RGL. Parameters can be set by specifying them as arguments to \code{par3d} in \code{name = value} form, or by passing them as a list of named values. } \usage{ par3d(\dots, no.readonly = FALSE, dev = cur3d(), subscene = currentSubscene3d(dev)) rgl.par3d.names rgl.par3d.readonly } \arguments{ \item{\dots}{arguments in \code{name = value} form, or a list of tagged values. The names must come from the graphical parameters described below.} \item{no.readonly}{logical; if \code{TRUE} and there are no other arguments, only those parameters which can be set by a subsequent \code{par3d()} call are returned.} \item{dev}{integer; the RGL device.} \item{subscene}{integer; the subscene.} } \details{ Parameters are queried by giving one or more character vectors to \code{par3d}. \code{par3d()} (no arguments) or \code{par3d(no.readonly = TRUE)} is used to get \emph{all} the graphical parameters (as a named list). By default, queries and modifications apply to the current subscene on the current device; specify \code{dev} and/or \code{subscene} to change this. Some parameters apply to the device as a whole; these are marked in the list below. } \value{ When parameters are set, their former values are returned in an invisible named list. Such a list can be passed as an argument to \code{par3d} to restore the parameter values. Use \code{par3d(no.readonly = TRUE)} for the full list of parameters that can be restored. When just one parameter is queried, its value is returned directly. When two or more parameters are queried, the result is a list of values, with the list names giving the parameters. Note the inconsistency: setting one parameter returns a list, but querying one parameter returns an object. } \section{Parameters}{ The \code{rgl.par3d.names} variable contains the full list of names of \code{par3d} properties. \code{rgl.par3d.readonly} contains the list of read-only properties. In the list below, \emph{\bold{R.O.}} indicates the read-only arguments: These may only be used in queries, they do not set anything. \describe{ \item{\code{activeSubscene}}{\emph{\bold{R.O.}} integer. Used with \code{\link{rgl.setMouseCallbacks}}: during a callback, indicates the id of the subscene that was clicked.} \item{\code{antialias}}{\emph{\bold{R.O.}} in \code{par3d}, may be set in \code{open3d}. The (requested) number of hardware antialiasing planes to use (with multisample antialiasing). The OpenGL driver may not support the requested number, in which case \code{par3d("antialias")} will report what was actually set. Applies to the whole device.} \item{\code{cex}}{real. The default size for text.} \item{\code{family}}{character. The default device independent family name; see \code{\link{text3d}}. Applies to the whole device.} \item{\code{font}}{integer. The default font number (from 1 to 4; see \code{\link{text3d}}). Applies to the whole device.} \item{\code{useFreeType}}{logical. Should FreeType fonts be used? Applies to the whole device.} \item{\code{fontname}}{\emph{\bold{R.O.}}; the system-dependent name of the current font. Applies to the whole device.} \item{\code{FOV}}{real. The field of view, from 0 to 179 degrees. This controls the degree of parallax in the perspective view. Isometric perspective corresponds to \code{FOV = 0}.} \item{\code{ignoreExtent}}{logical. Set to \code{TRUE} so that subsequently plotted objects will be ignored in calculating the bounding box of the scene. Applies to the whole device.} \item{\code{maxClipPlanes}}{\emph{\bold{R.O.}}; an integer giving the maximum number of clip planes that can be defined in the current system. Applies to the whole device.} \item{\code{modelMatrix}}{\emph{\bold{R.O.}}; a 4 by 4 matrix describing the position of the user data. See the Note below.} \item{\code{listeners}}{integer. A vector of subscene id values. If a subscene receives a mouse event (see \code{mouseMode} just below), the same action will be carried out on all subscenes in this list. (The subscene itself is normally listed as a listener. If it is not listed, it will not respond to its own mouse events.)} \item{\code{mouseMode}}{character. A vector of 5 strings describing mouse actions. The 5 entries are named \code{c("none", "left", "right", "middle", "wheel")}, corresponding to actions for no button, the left, right or middle button, and the mouse wheel. Partial matching to action names is used. Possible values for the actions are: \describe{ \item{\code{"none"}}{No action for this button.} \item{\code{"trackball"}}{Mouse acts as a virtual trackball, rotating the scene.} \item{\code{"xAxis"}}{Similar to \code{"trackball"}, but restricted to X axis rotation.} \item{\code{"yAxis"}}{Y axis rotation.} \item{\code{"zAxis"}}{Z axis rotation.} \item{\code{"polar"}}{Mouse rotates the scene by moving in polar coordinates.} \item{\code{"selecting"}}{Mouse is used for selection. This is not normally set by the user, but is used internally by the \code{\link{select3d}} function.} \item{\code{"zoom"}}{Mouse is used to zoom the display.} \item{\code{"fov"}}{Mouse changes the field of view of the display.} \item{\code{"user"}}{Used when a user handler is set by \code{\link{rgl.setMouseCallbacks}}.} } Possible values for the last entry corresponding to the mouse wheel also include \describe{ \item{\code{"pull"}}{Pulling on the mouse wheel increases magnification, i.e. \dQuote{pulls the scene closer}.} \item{\code{"push"}}{Pulling on the mouse wheel decreases magnification, i.e. \dQuote{pushes the scene away}.} \item{\code{"user2"}}{Used when a user handler is set by \code{\link{rgl.setWheelCallback}}.} } A common default on Mac OSX is to convert a two finger drag on a trackpad to a mouse wheel rotation. The first entry is for actions to take when no mouse button is pressed. Legal values are the same as for the mouse buttons. The first entry was added after \pkg{rgl} version 0.106.8. For back compatibility, if the vector of actions is less than 5 entries, \code{"none"} will be added at the start of it. } \item{\code{observer}}{\emph{\bold{R.O.}}; the position of the observer relative to the model. Set by \code{\link{observer3d}}. See the Note below.} \item{\code{projMatrix}}{\emph{\bold{R.O.}}; a 4 by 4 matrix describing the current projection of the scene.} \item{\code{scale}}{real. A vector of 3 values indicating the amount by which to rescale each axis before display. Set by \code{\link{aspect3d}}.} \item{\code{skipRedraw}}{whether to update the display. Set to \code{TRUE} to suspend updating while making multiple changes to the scene. See \code{demo(hist3d)} for an example. Applies to the whole device.} \item{\code{userMatrix}}{a 4 by 4 matrix describing user actions to display the scene.} \item{\code{userProjection}}{a 4 by 4 matrix describing changes to the projection.} \item{\code{viewport}}{real. A vector giving the dimensions of the window in pixels. The entries are taken to be \code{c(x, y, width, height)} where \code{c(x, y)} are the coordinates in pixels of the lower left corner within the window.} \item{\code{zoom}}{real. A positive value indicating the current magnification of the scene.} \item{\code{bbox}}{\emph{\bold{R.O.}}; real. A vector of six values indicating the current values of the bounding box of the scene (xmin, xmax, ymin, ymax, zmin, zmax)} \item{\code{windowRect}}{integer. A vector of four values indicating the left, top, right and bottom of the displayed window (in pixels). Applies to the whole device.} } } \note{ The \code{"xAxis"}, \code{"yAxis"} and \code{"zAxis"} mouse modes rotate relative to the coordinate system of the data, regardless of the current orientation of the scene. When multiple parameters are set, they are set in the order given. In some cases this may lead to warnings and ignored values; for example, some font families only support \code{cex = 1}, so changing both \code{cex} and \code{family} needs to be done in the right order. For example, when using the \code{"bitmap"} family on Windows, \code{par3d(family = "sans", cex = 2)} will work, but \code{par3d(cex = 2, family = "sans")} will leave \code{cex} at 1 (with a warning that the \code{"bitmap"} family only supports that size). Although \code{par3d("viewport")} names the entries of the reported vector, names are ignored when setting the viewport and entries must be specified in the standard order. In \pkg{rgl} versions 0.94.x the \code{modelMatrix} entry had a changed meaning; before and after that it contains a copy of the OpenGL MODELVIEW matrix. As of version 0.100.32, when changing the \code{"windowRect"} parameter, the \code{"viewport"} for the root (or specified) subscene is changed immediately. This fixes a bug where in earlier versions it would only be changed when the window was redrawn, potentially after another command making use of the value. Default values are not described here, as several of them are changed by the \code{\link{r3dDefaults}} variable when the window is opened by \code{\link{open3d}}. } \section{Rendering}{ The parameters returned by \code{par3d} are sufficient to determine where RGL would render a point on the screen. Given a column vector \code{(x, y, z)} in a subscene \code{s}, it performs the equivalent of the following operations: \enumerate{ \item It converts the point to homogeneous coordinates by appending \code{w = 1}, giving the vector \code{v = (x, y, z, 1)}. \item It calculates the \code{M = par3d("modelMatrix")} as a product from right to left of several matrices: \itemize{ \item A matrix to translate the centre of the bounding box to the origin. \item A matrix to rescale according to \code{par3d("scale")}. \item The \code{par3d("userMatrix")} as set by the user. \item A matrix which may be set by mouse movements. \item The description above applies to the usual case where there is just one subscene, or where the subscene's \code{"model"} is set to \code{"replace"}. If it is set to \code{"modify"}, the first step is skipped, and at the end the procedure is followed for the parent subscene. If it is set to \code{"inherit"} only the parent settings are used. } \item It multiplies the point by \code{M} giving \code{u = M \%*\% v}. \item It multiplies that point by a matrix based on the observer position to translate the origin to the centre of the viewing region. \item Using this location and information on the normals (which have been similarly transformed), it performs lighting calculations. \item It obtains the projection matrix \code{P = par3d("projMatrix")} based on the bounding box and field of view or observer location, multiplies that by the \code{userProjection} matrix to give \code{P}. It multiplies the point by it giving \code{P \%*\% u = (x2, y2, z2, w2)}. \item It converts back to Euclidean coordinates by dividing the first 3 coordinates by \code{w2}. \item The new value \code{z2/w2} represents the depth into the scene of the point. Depending on what has already been plotted, this depth might be obscured, in which case nothing more is plotted. \item If the point is not culled due to depth, the \code{x2} and \code{y2} values are used to determine the point in the image. The \code{par3d("viewport")} values are used to translate from the range \code{(-1, 1)} to pixel locations, and the point is plotted. \item If hardware antialiasing is enabled, then the whole process is repeated multiple times (at least conceptually) with different locations in each pixel sampled to determine what is plotted there, and then the images are combined into what is displayed. } See ?\link{matrices} for more information on homogeneous and Euclidean coordinates. Note that many of these calculations are done on the graphics card using single precision; you will likely see signs of rounding error if your scene requires more than 4 or 5 digit precision to distinguish values in any coordinate. } \seealso{ \code{\link{view3d}} to set \code{FOV} and \code{zoom}. \code{\link{open3d}} for how to open a new window with default settings for these parameters. } \references{ OpenGL Architecture Review Board (1997). OpenGL Programming Guide. Addison-Wesley. } \examples{ open3d() shade3d(cube3d(color = rainbow(6), meshColor = "faces")) save <- par3d(userMatrix = rotationMatrix(90*pi/180, 1, 0, 0)) highlevel() # To trigger display save par3d("userMatrix") par3d(save) highlevel() par3d("userMatrix") } \keyword{dynamic} rgl/man/facing3d.Rd0000644000176200001440000000422714771520323013567 0ustar liggesusers\name{facing3d} \alias{facing3d} \alias{projectDown} \title{ Subset an object to parts facing in a particular direction } \description{ \code{facing3d} subsets an object by converting it to a triangle mesh, then subsetting to those triangles that are counterclockwise (for \code{front = TRUE}) when projected into a plane. \code{projectDown} computes a projection that \dQuote{looks down} the specified direction. } \usage{ facing3d(obj, up = c(0, 0, 1), P = projectDown(up), front = TRUE, strict = TRUE) projectDown(up) } \arguments{ \item{obj}{ An object that can be converted to a triangular mesh object. } \item{up}{ The direction that is to be considered \dQuote{up}. It may be either a 3 vector in Euclidean coordinates or a 4 vector in homogeneous coordinates. } \item{P}{ The projection to use for draping, a 4x4 matrix. See \code{\link{drape3d}} for details on how \code{P} is used. } \item{front}{ If \code{front = TRUE}, retains triangles that are counterclockwise after projection by \code{P}, otherwise retains those that are clockwise. } \item{strict}{If \code{TRUE}, drops indeterminate triangles (those that are annihilated by \code{P}).} } \details{ By default the returned subset will be those triangles whose upper side matches \code{front}. Change \code{up} or use an arbitrary projection for different subsets. \code{\link{drape3d}} and \code{\link{shadow3d}} project objects onto meshes; these functions can be used to project only onto the top or front. } \value{ \code{facing3d} returns a mesh object made of those triangles which face in the desired direction. \code{projectDown} computes a 4x4 matrix. The first two coordinates of \code{asEuclidean(x \%*\% projectDown(up))} give a projection of \code{x} from above into a plane, where \code{up} determines which direction is taken to be \dQuote{up}. } \seealso{\code{\link{drape3d}}, \code{\link{shadow3d}}} \examples{ open3d() d <- rnorm(3) d <- d/sqrt(sum(d^2)) shade3d( facing3d( icosahedron3d(), up = d, strict = FALSE), col = "yellow") wire3d( facing3d( icosahedron3d(), up = d, front = FALSE), col = "black") # Show the direction: arrow3d(-2*d , -d) } rgl/man/material.Rd0000644000176200001440000003114515012460301013672 0ustar liggesusers\name{material3d} \alias{material3d} \alias{rgl.material.names} \alias{rgl.material.readonly} \concept{color} \concept{lit} \concept{ambient} \concept{specular} \concept{emission} \concept{shininess} \concept{alpha} \concept{smooth} \concept{texture} \concept{textype} \concept{texmode} \concept{texmipmap} \concept{texmagfilter} \concept{texminfilter} \concept{texenvmap} \concept{front} \concept{back} \concept{size} \concept{lwd} \concept{fog} \concept{point_antialias} \concept{line_antialias} \concept{depth_mask} \concept{depth_test} \concept{polygon_offset} \concept{margin} \concept{floating} \concept{tag} \concept{blend} \concept{isTransparent} \concept{rgl.warnBlackTexture} \title{Get or set material properties} \description{ Get or set material properties for geometry appearance. } \usage{ material3d(..., id = NULL) rgl.material.names rgl.material.readonly } \arguments{ \item{...}{Material properties to set or query.} \item{id}{ the \pkg{rgl} id of an object to query, or \code{NULL} to query or set the defaults. } } \details{ In an \pkg{rgl} scene, each object has \dQuote{material properties} that control how it is rendered and (in the case of \code{tag}) that can be used to store a label or other information. \code{material3d} sets defaults for these properties and queries the defaults or specific values for an individual object. To set values, use \code{name = value} settings, e.g. \code{material3d(color = "red")}. To query values, specify the property or properties in a character vector, e.g. \code{material3d("color")}. Only one side at a time can be culled. The \code{material} member of the \code{\link{r3dDefaults}} list may be used to set default values for material properties. } \section{Material Properties}{ The \code{rgl.material.names} variable contains the full list of material names. The following read-write material properties control the appearance of objects in an \pkg{rgl} scene. \describe{ \item{color}{ vector of R color characters. Represents the diffuse component in case of lighting calculation (lit = TRUE), otherwise it describes the solid color characteristics. } \item{lit}{ logical, specifying if lighting calculation should take place on geometry } \item{ambient, specular, emission, shininess}{ properties for lighting calculation. ambient, specular, emission are R color character string values; shininess represents a numerical. } \item{alpha}{ vector of alpha values between 0.0 (fully transparent) and 1.0 (opaque). See \HTMLVignette{transparency}{}{A Note on Transparency} for a discussion of some issues with transparency. } \item{smooth}{ logical, specifying whether smooth shading or flat shading should be used. For smooth shading, Gouraud shading is used in \pkg{rgl} windows, while Phong shading is used in WebGL. } \item{texture}{ path to a texture image file. See the Textures section below for details. } \item{textype}{ specifies what is defined with the pixmap \describe{ \item{"alpha"}{alpha values} \item{"luminance"}{luminance} \item{"luminance.alpha"}{luminance and alpha} \item{"rgb"}{color} \item{"rgba"}{color and alpha texture} } Note that support for these modes is slightly different in the display within R versus the WebGL display using \code{rglwidget()}. In particular, in WebGL \code{textype = "alpha"} will always take the alpha value from the luminance (i.e. the average of the R, G and B channels) of the texture, whereas the R display bases the choice on the internal format of the texture file. } \item{texmode}{ specifies how the texture interacts with the existing color \describe{ \item{"replace"}{texture value replaces existing value} \item{"modulate"}{default; texture value multiplies existing value} \item{"decal"}{for \code{textype = "rgba"}, texture is mixed with existing value} \item{"blend"}{uses the texture to blend the existing value with black} \item{"add"}{adds the texture value to the existing. May not be available in the R display with very old OpenGL drivers.} } } \item{texmipmap}{ Logical, specifies if the texture should be mipmapped. } \item{texmagfilter}{ specifies the magnification filtering type (sorted by ascending quality): \describe{ \item{"nearest"}{texel nearest to the center of the pixel} \item{"linear"}{weighted linear average of a 2x2 array of texels} } } \item{texminfilter}{ specifies the minification filtering type (sorted by ascending quality): \describe{ \item{"nearest"}{texel nearest to the center of the pixel} \item{"linear"}{weighted linear average of a 2x2 array of texels} \item{"nearest.mipmap.nearest"}{low quality mipmapping} \item{"nearest.mipmap.linear"}{medium quality mipmapping} \item{"linear.mipmap.nearest"}{medium quality mipmapping} \item{"linear.mipmap.linear"}{high quality mipmapping} } } \item{texenvmap}{ logical, specifies if auto-generated texture coordinates for environment-mapping should be performed on geometry. } \item{front, back}{ Determines the polygon mode for the specified side: \describe{ \item{"filled"}{filled polygon} \item{"lines"}{wireframed polygon} \item{"points"}{point polygon} \item{"culled"}{culled (hidden) polygon} } } \item{size}{ numeric, specifying the size of points in pixels } \item{lwd}{ numeric, specifying the line width in pixels } \item{fog}{logical, specifying if fog effect should be applied on the corresponding shape. Fog type is set in \code{\link{bg3d}}.} \item{point_antialias, line_antialias}{logical, specifying if points should be round and lines should be antialiased, but see Note below.} \item{depth_mask}{logical, specifying whether the object's depth should be stored.} \item{depth_test}{Determines which depth test is used to see if this object is visible, depending on its apparent depth in the scene compared to the stored depth. Possible values are \code{"never"}, \code{"less"} (the default), \code{"equal"}, \code{"lequal"} (less than or equal), \code{"greater"}, \code{"notequal"}, \code{"gequal"} (greater than or equal), \code{"always"}.} \item{polygon_offset}{A one or two element vector giving the \samp{factor} and \samp{units} values to use in a \code{glPolygonOffset()} call in OpenGL. If only one value is given, it is used for both elements. The \samp{units} value is added to the depth of all pixels in a filled polygon, and the \samp{factor} value is multiplied by an estimate of the slope of the polygon and then added to the depth. Positive values \dQuote{push} polygons back slightly for the purpose of depth testing, to allow points, lines or other polygons to be drawn on the surface without being obscured due to rounding error. Negative values pull the object forward. A typical value to use is \code{1} (which is automatically expanded to \code{c(1,1)}). If values are too large, objects which should be behind the polygon will show through, and if values are too small, the objects on the surface will be partially obscured. Experimentation may be needed to get it right. The first example in \code{?\link{persp3d}} uses this property to add grid lines to a surface.} \item{margin, floating}{Used mainly for text to draw annotations in the margins, but supported by most kinds of objects: see \code{\link{mtext3d}}.} \item{tag}{A length 1 string value. These may be used to identify objects, or encode other meta data about the object.} \item{blend}{Two string values from the list below describing how transparent objects are blended with colors behind them. The first determines the coefficient applied to the color of the current object (the source); the second determines the coefficient applied to the existing color (the destination). The resulting color will be the sum of the two resulting colors. The allowed strings correspond to OpenGL constants: \describe{ \item{"zero"}{Zero; color has no effect.} \item{"one"}{One; color is added to the other term.} \item{"src_color", "one_minus_src_color"}{Multiply by source color or its opposite.} \item{"dst_color", "one_minus_dst_color"}{Multiply by destination color or its opposite.} \item{"src_alpha", "one_minus_src_alpha"}{Multiply by source alpha or its opposite. Default values.} \item{"dst_alpha", "one_minus_dst_alpha"}{Multiply by destination alpha or its opposite.} \item{"constant_color", "one_minus_constant_color", "constant_alpha", "one_minus_constant_alpha", "src_alpha_saturate"}{These are allowed, but to be useful they require other settings which \pkg{rgl} doesn't support.} } } \item{col}{An allowed abbreviation of \code{color}.} } The \code{rgl.material.readonly} variable contains the subset of material properties that are read-only so they can be queried but not set. Currently there is only one: \describe{ \item{isTransparent}{Is the current color transparent?} } } \value{ \code{material3d()} returns values similarly to \code{\link{par3d}}: When setting properties, it returns the previous values invisibly in a named list. When querying multiple values, a named list is returned. When a single value is queried it is returned directly. } \section{Textures}{ The \code{texture} material property may be \code{NULL} or the name of a bitmap file to be displayed on the surface being rendered. Currently only PNG format files are supported. By default, the colors in the bitmap will modify the color of the object being plotted. If the color is black (a common default), you won't see anything, so a warning may be issued. You can suppress the warning by specifying the color explicitly, or calling \code{options{rgl.warnBlackTexture = FALSE}}. Other aspects of texture display are controlled by the material properties \code{textype, texmode, texmipmap, texmagfilter, texminfilter} and \code{texenvmap} described above. For an extensive discussion of textures, see the \HTMLVignette{rgl}{textures}{Textures} section of the \HTMLVignette{rgl}{}{rgl Overview} vignette. } \section{Display of objects}{ Object display colors are determined as follows: \itemize{ \item{If \code{lit = FALSE}, an element of the \code{color} vector property is displayed without modification. See documentation for individual objects for information on which element is chosen.} \item{If \code{lit = TRUE}, the color is determined as follows.} \enumerate{ \item{The color is set to the \code{emission} property of the object. } \item{For each defined light, the following are added: \itemize{ \item{the product of the \code{ambient} color of the light and the \code{ambient} color of the object is added.} \item{the \code{color} of the object is multiplied by the \code{diffuse} color of the light and by a constant depending on the angle between the surface and the direction to the light, and added.} \item{the \code{specular} color of the object is multiplied by the \code{specular} color of the light and a constant depending on the \code{shininess} of the object and the direction to the light, and added. The \code{shininess} property mainly determines the size of the shiny highlight; adjust one or both of the \code{specular} colors to change its brightness.} } } } } If \code{point_antialias} is \code{TRUE}, points will be drawn as circles in WebGL; otherwise, they will be drawn as squares. Within R, the behaviour depends on your graphics hardware: for example, I see circles for both settings on my laptop. Within R, lines tend to appear heavier with \code{line_antialias == TRUE}. There's no difference at all in WebGL. } \seealso{ \code{\link{bbox3d}}, \code{\link{bg3d}}, \code{\link{light3d}} } \examples{ save <- material3d("color") material3d(color = "red") material3d("color") material3d(color = save) # this illustrates the effect of depth_test x <- c(1:3); xmid <- mean(x) y <- c(2, 1, 3); ymid <- mean(y) z <- 1 open3d() tests <- c("never", "less", "equal", "lequal", "greater", "notequal", "gequal", "always") for (i in 1:8) { triangles3d(x, y, z + i, col = heat.colors(8)[i]) texts3d(xmid, ymid, z + i, paste(i, tests[i], sep = ". "), depth_test = tests[i]) } highlevel() # To trigger display # this illustrates additive blending open3d() bg3d("darkgray") quad <- cbind(c(-1, 1, 1, -1), 1, c(-1, -1, 1, 1)) quads3d(rbind(translate3d(quad, -0.5, 0, -0.5), translate3d(quad, 0.5, 0.5, -0.5), translate3d(quad, 0, 1, 0.5)), col = rep(c("red", "green", "blue"), each = 4), alpha = 0.5, blend = c("src_alpha", "one")) } \keyword{dynamic} rgl/man/snapshot.Rd0000644000176200001440000000774615011677075013766 0ustar liggesusers\name{snapshot3d} \alias{rgl.snapshot} \alias{snapshot3d} \alias{RGL_USE_WEBSHOT} \title{Export screenshot} \description{ Saves the screenshot to a file. } \usage{ rgl.snapshot( filename, fmt = "png", top = TRUE ) snapshot3d( filename = tempfile(fileext = ".png"), fmt = "png", top = TRUE, ..., scene, width = NULL, height = NULL, webshot = as.logical(Sys.getenv("RGL_USE_WEBSHOT", "TRUE")) ) } \arguments{ \item{filename}{path to file to save.} \item{fmt}{image export format, currently supported: png. Ignored if \code{webshot = TRUE}. } \item{top}{whether to call \code{\link{rgl.bringtotop}}. Ignored if \code{webshot = TRUE}.} \item{...}{arguments to pass to \code{webshot2::webshot} } \item{scene}{an optional result of \code{\link{scene3d}} or \code{\link{rglwidget}} to plot} \item{width, height}{optional specifications of output size in pixels} \item{webshot}{Use the \pkg{webshot2} package to take the snapshot} } \details{ \code{rgl.snapshot()} is a low-level function that copies the current RGL window from the screen. Users should usually use \code{snapshot3d()} instead; it is more flexible, and (if \pkg{webshot2} is installed) can take images even if no window is showing, and they can be larger than the physical screen. On some systems \pkg{webshot2} doesn't work reliably; if you find \code{snapshot3d()} failing or taking a very long time I'd recommend using \code{snapshot3d(..., webshot = FALSE)}. See the note below about \code{RGL_USE_WEBSHOT} to make this the default. Animations can be created in a loop modifying the scene and saving each screenshot to a file. Various graphics programs (e.g. ImageMagick) can put these together into a single animation. (See \code{\link{movie3d}} or the example below.) } \value{ These functions are mainly called for the side effects. The filename of the saved file is returned invisibly. } \note{ When \code{rgl.useNULL()} is \code{TRUE}, only \code{webshot = TRUE} will produce a snapshot. It requires the \pkg{webshot2} package and a Chrome browser. If no suitable browser is found, \code{snapshot3d()} will revert to \code{rgl.snapshot()}. To override the automatic search, set environment variable \env{CHROMOTE_CHROME} to the path to a suitable browser. \code{rgl.snapshot} works by taking an image from the displayed window on-screen. On some systems, the snapshot will include content from other windows if they cover the active RGL window. Setting \code{top = TRUE} (the default) will use \code{\link{rgl.bringtotop}} before the snapshot to avoid this. There are likely limits to how large \code{width} and \code{height} can be set based on the display hardware; if these are exceeded the results are undefined. A typical result is that the snapshot will still be made but at a smaller size. There are slight differences between the displays with \code{webshot = TRUE} and \code{webshot = FALSE}, as the former are rendered using WebGL while the latter are rendered using OpenGL. Often the \code{webshot = TRUE} displays have better quality, but they are usually slower to produce, sometimes drastically so. Set the environment variable \env{RGL_USE_WEBSHOT} to \code{"FALSE"} if you want \code{rgl.snapshot} to be used by default. } \seealso{\code{\link{movie3d}}, \code{\link{view3d}}} \examples{ if (interactive() && !in_pkgdown_example()) { saveopts <- options(rgl.useNULL = TRUE) plot3d(matrix(rnorm(300), ncol = 3, dimnames = list(NULL, c("x", "y", "z"))), col = "red") options(saveopts) browseURL(snapshot3d()) } \dontrun{ # # create animation # shade3d(oh3d(), color = "red") rgl.bringtotop() view3d(0, 20) olddir <- setwd(tempdir()) for (i in 1:45) { view3d(i, 20) filename <- paste("pic", formatC(i, digits = 1, flag = "0"), ".png", sep = "") snapshot3d(filename) } ## Now run ImageMagick in tempdir(). Use 'convert' instead of 'magick' ## if you have an older version of ImageMagick: ## magick -delay 10 *.png -loop 0 pic.gif setwd(olddir) } } \keyword{dynamic} rgl/man/drape3d.Rd0000644000176200001440000000565514771520323013441 0ustar liggesusers\name{drape3d} \alias{drape3d} \alias{drape3d.default} \alias{drape3d.mesh3d} \title{ Drape lines over a scene. } \description{ Project a line onto the surface in a scene so that it appears to drape itself onto the surface. } \usage{ drape3d(obj, ...) \method{drape3d}{mesh3d}(obj, x, y = NULL, z = NULL, plot = TRUE, up = c(0, 0, 1), P = projectDown(up), ...) \method{drape3d}{default}(obj, ...) } \arguments{ \item{obj}{ The object(s) upon which to drape lines. } \item{x,y,z}{Coordinates of the line segments to be draped. Any reasonable way of defining the coordinates is acceptable. See the function \code{\link[grDevices]{xyz.coords}} for details. } \item{plot}{ Should the result be plotted, or returned as a data frame? } \item{up}{ The direction to consider as \dQuote{up}. } \item{P}{ The projection to use for draping, a 4x4 matrix. } \item{\dots}{ For the \code{"mesh3d"} method, additional parameters to pass to \code{\link{segments3d}} when drawing the draped lines. For the \code{"default"} method, additional parameters to pass to the \code{"mesh3d"} method. } } \details{ The default method converts \code{obj} to a mesh using \code{\link{as.mesh3d}}, then uses the \code{"mesh3d"} method. The current implementation constructs the segments to drape across the surface using the same method as \code{\link{lines3d}} uses: each successive point is joined to the previous one. Use \code{NA} coordinates to indicate breaks in the line. The \code{P} matrix is used to project points to a plane as follows: They are transformed by \code{P} in homogeneous coordinates, then only first two (Euclidean) coordinates are kept. } \value{ If \code{plot = TRUE}, plots the result and invisibly returns the object ID of the collection of segments. If \code{plot = FALSE}, returns a matrix containing "x", "y" and "z" values for the line(s) (for use with \code{\link{segments3d}}), } \author{ George Helffrich and Duncan Murdoch } \seealso{\code{\link{shadow3d}}, \code{\link{facing3d}}} \examples{ # # volcano example taken from "persp" # z <- 2 * volcano # Exaggerate the relief x <- 10 * (1:nrow(z)) # 10 meter spacing (S to N) y <- 10 * (1:ncol(z)) # 10 meter spacing (E to W) zlim <- range(z) zlen <- zlim[2] - zlim[1] + 1 colorlut <- terrain.colors(zlen) # height color lookup table col <- colorlut[ z - zlim[1] + 1 ] # assign colors to heights for each point open3d() id <- surface3d(x, y, z, color = col, polygon_offset = 1) segs <- data.frame(x = range(x) + c(100, -100), y = range(y) + c(150, -100), z = 325) drape3d(id, segs, col = 'yellow', lwd = 3) lines3d(segs, col='red', lwd=3) p <- c(350, 205) # (x,y) of strike & dip reading off <- 20*c(-1, +1) # X-marks-the-spot offset segs <- data.frame( x = c(p[1] + off, NA, p[1] + off), y = c(p[2] + off, NA, p[2] - off), z = rep(350, 5) ) drape3d(id, segs, col = "yellow", lwd = 3) } rgl/man/as.triangles3d.Rd0000644000176200001440000000247614771520323014736 0ustar liggesusers\name{as.triangles3d} \alias{as.triangles3d} \alias{as.triangles3d.rglId} \title{ Convert an object to triangles } \description{ This generic and its methods extract or creates a matrix of coordinates of triangles from an object, suitable for passing to \code{\link{triangles3d}}. } \usage{ as.triangles3d(obj, ...) \method{as.triangles3d}{rglId}(obj, attribute = c("vertices", "normals", "texcoords", "colors"), subscene = NA, ...) } \arguments{ \item{obj}{ The object to convert. } \item{attribute}{Which attribute of an RGL object to extract?} \item{subscene}{Which subscene is this object in?} \item{\dots}{ Additional arguments used by the methods. } } \details{ The method for \code{"rglId"} objects can extract several different attributes, organizing them as it would organize the vertices for the triangles. } \value{ An \code{n x 3} matrix containing the vertices of triangles making up the object. Each successive 3 rows of the matrix corresponds to a triangle. If the attribute doesn't exist, \code{NULL} will be returned. } \author{ Duncan Murdoch } \seealso{ \code{\link{as.mesh3d}} to also capture material properties. } \examples{ open3d() x <- surface3d(x = 1:10, y = 1:10, z = rnorm(100), col = "red") tri <- as.triangles3d(x) open3d() triangles3d(tri, col = "blue") } rgl/man/rgl.attrib.info.Rd0000644000176200001440000000256614771520323015117 0ustar liggesusers\name{rgl.attrib.info} \alias{rgl.attrib.info} \alias{rgl.attrib.count} \title{ Get information about attributes of objects } \description{ These functions give information about the attributes of RGL objects. \code{rgl.attrib.info} is the more \dQuote{user-friendly} function; \code{rgl.attrib.count} is a lower-level function more likely to be used in programming. } \usage{ rgl.attrib.info(id = ids3d("all", 0)$id, attribs = NULL, showAll = FALSE) rgl.attrib.count(id, attrib) } %- maybe also 'usage' for other objects documented here. \arguments{ \item{id}{ One or more RGL object ids. } \item{attribs}{ A character vector of one or more attribute names. } \item{showAll}{ Should attributes with zero entries be shown? } \item{attrib}{ A single attribute name. } } \details{ See the first example below to get the full list of attribute names. } \value{ A dataframe containing the following columns: \item{id}{The id of the object.} \item{attrib}{The full name of the attribute.} \item{nrow, ncol}{The size of matrix that would be returned by \code{\link{rgl.attrib}} for this attribute.} } \author{ Duncan Murdoch } \seealso{ \code{\link{rgl.attrib}} to obtain the attribute values. } \examples{ open3d() id <- points3d(rnorm(100), rnorm(100), rnorm(100), col = "green") rgl.attrib.info(id, showAll = TRUE) rgl.attrib.count(id, "vertices") merge(rgl.attrib.info(), ids3d("all")) } rgl/man/hover3d.Rd0000644000176200001440000000751114771520323013462 0ustar liggesusers\name{hover3d} \alias{hover3d} \title{ Display hover info in plot. } \description{ This adds text to identify points within a plot when the mouse is near them. } \usage{ hover3d(x, y = NULL, z = NULL, labeller = NULL, tolerance = 20, persist = c("no", "one", "yes"), labels = seq_along(x), adj = c(-0.2, 0.5), scene = scene3d(minimal = FALSE), applyToScene = TRUE, ...) } \arguments{ \item{x, y, z}{ Coordinates of point to identify. Any reasonable way of defining the coordinates is acceptable. See the function \code{\link[grDevices]{xyz.coords}} for details. Alternatively, \code{x} may be the id of a single existing object, and its vertices will be used. } \item{labeller}{ A function to display information about identified points. \code{NULL} indicates the default function, described in Details. } \item{tolerance}{ How close (in pixels) the mouse should be to a point to display the information. } \item{persist}{ Should the label persist? If \code{"no"} (the default), it will be removed when the mouse moves away. If \code{"one"}, it will be removed when another point is closer to the mouse. If \code{"yes"}, it will not be removed. } \item{labels}{ If the default \code{labeller} is used, these labels will be displayed. } \item{adj}{ If the default \code{labeller} is used, this adjustment will be passed to \code{\link{text3d}} to display the labels. } \item{scene, applyToScene}{ Arguments to pass to \code{\link{setUserCallbacks}}. The \code{applyToDev} argument to that function is always \code{TRUE}. } \item{\dots}{ Additional arguments that will be passed to the labeller. } } \details{ If specified, the \code{labeller} argument should specify a function with arguments compatible with \code{function(index, ...)}. It will be called with \code{index} being the index of the point that was selected. It should plot the label, and return the \pkg{rgl} ids of the objects that were plotted. When \code{applyToScene} is \code{TRUE}, all labels or labelling objects will be created and attached to the scene. You may want to delete them (using the ids returned in \code{idverts} and \code{idtexts}) once \code{\link{rglwidget}} has been called, as they serve no purpose in the current device. Only one hover handler is supported per scene or device. } \value{ A \code{\link{lowlevel}} vector of ids is returned invisibly. If \code{applyToScene} is \code{TRUE}, it will contain the ids of the temporary objects created for Javascript. It will also have these attributes: \item{oldPar}{Values of \code{\link{par3d}} parameters that were changed. Currently only \code{"mouseMode"}.} \item{oldDev}{The value of \code{cur3d()} at the time of calling, so that \code{oldPar} can be restored to the right device.} } \author{ Duncan Murdoch } \seealso{ \code{\link{identify3d}} and \code{\link{selectpoints3d}} work in the \pkg{rgl} device and return information about the selections. \code{\link{setUserCallbacks}} is the underlying function used by \code{hover3d}. } \examples{ # Create a labeller to show the coordinates of the selected point. labelLocation <- function(x, y = NULL, z = NULL) { xyz <- xyz.coords(x, y, z) function(sel, ...) { p <- with(xyz, matrix(c(x[sel], y[sel], z[sel]), ncol = 3)) c(text3d(p, texts = sprintf("x:\%.2f", p[1]), adj = c(-0.2, -0.6), ...), text3d(p, texts = sprintf("y:\%.2f", p[2]), adj = c(-0.2, 0.5), ...), text3d(p, texts = sprintf("z:\%.2f", p[3]), adj = c(-0.2, 1.6), ...)) } } xyz <- matrix(rnorm(30), ncol = 3) open3d() ids <- plot3d(xyz) hover3d(xyz, labeller = labelLocation(xyz), col = "red", cex = 0.8) # The same thing using the data id: # hover3d(ids["data"], # labeller = labelLocation(rgl.attrib(ids["data"], "vertices")), # col = "red", cex = 0.8) } rgl/man/polygon3d.Rd0000644000176200001440000000435115011677075014032 0ustar liggesusers\name{polygon3d} \alias{polygon3d} \title{ Draw a polygon in three dimensions } \description{ This function takes a description of a flat polygon in x, y and z coordinates, and draws it in three dimensions. } \usage{ polygon3d(x, y = NULL, z = NULL, fill = TRUE, plot = TRUE, coords, random = TRUE, ...) } \arguments{ \item{x, y, z}{ Vertices of the polygon in a form accepted by \code{\link{xyz.coords}}. } \item{fill}{ logical; should the polygon be filled? } \item{plot}{ logical; should the polygon be displayed? } \item{coords}{ Which two coordinates (\code{x = 1}, \code{y = 2}, \code{z = 3}) describe the polygon. If missing, \code{\link{triangulate}} makes an automatic choice. } \item{random}{ Currently ignored. The triangulation is deterministic. } \item{\dots}{ Other parameters to pass to \code{\link{lines3d}} or \code{\link{shade3d}} if \code{plot = TRUE}. } } \details{ The function triangulates the two dimensional polygon described by \code{coords}, then applies the triangulation to all three coordinates. No check is made that the polygon is actually all in one plane, but the results may be somewhat unpredictable (especially if \code{random = TRUE}) if it is not. Polygons need not be simple; use \code{NA} to indicate separate closed pieces. For \code{fill = FALSE} there are no other restrictions on the pieces, but for \code{fill = TRUE} the resulting two-dimensional polygon needs to be one that \code{\link{triangulate}} can handle. } \value{ If \code{plot = TRUE}, the id number of the lines (for \code{fill = FALSE}) or triangles (for \code{fill = TRUE}) that have been plotted. If \code{plot = FALSE}, then for \code{fill = FALSE}, a vector of indices into the XYZ matrix that could be used to draw the polygon. For \code{fill = TRUE}, a triangular mesh object representing the triangulation. } \author{ Duncan Murdoch } \seealso{ \code{\link{extrude3d}} for a solid extrusion of a polygon, \code{\link{triangulate}} for the triangulation. } \examples{ theta <- seq(0, 4*pi, length.out = 50) r <- theta + 1 r <- c(r[-50], rev(theta*0.8) + 1) theta <- c(theta[-50], rev(theta)) x <- r*cos(theta) y <- r*sin(theta) open3d() plot(x, y, type = "n") polygon(x, y) polygon3d(x, y, x + y, col = "blue") } \keyword{ graphics } rgl/man/identify3d.Rd0000644000176200001440000000317414771520323014153 0ustar liggesusers\name{identify3d} \alias{identify3d} \title{ Identify points in plot } \description{ Identify points in a plot, similarly to the \code{\link{identify}} function in base graphics. } \usage{ identify3d(x, y = NULL, z = NULL, labels = seq_along(x), n = length(x), plot = TRUE, adj = c(-0.1, 0.5), tolerance = 20, buttons = c("right", "middle")) } \arguments{ \item{x, y, z}{coordinates of points in a scatter plot. Alternatively, any object which defines coordinates (see \code{\link{xyz.coords}}) can be given as \code{x}, and \code{y} and \code{z} left missing.} \item{labels}{an optional character vector giving labels for the points. Will be coerced using \code{\link{as.character}}, and recycled if necessary to the length of \code{x}.} \item{n}{the maximum number of points to be identified.} \item{plot}{logical: if \code{plot} is \code{TRUE}, the labels are printed near the points and if \code{FALSE} they are omitted.} \item{adj}{numeric vector to use as \code{adj} parameter to \code{\link{text3d}} when plotting the labels.} \item{tolerance}{the maximal distance (in pixels) for the pointer to be \sQuote{close enough} to a point.} \item{buttons}{a length 1 or 2 character vector giving the buttons to use for selection and quitting.} } \details{ If \code{buttons} is length 1, the user can quit by reaching \code{n} selections, or by hitting the escape key, but the result will be lost if escape is used. } \value{ A vector of selected indices. } \author{ Duncan Murdoch } \seealso{ \code{\link{identify}} for base graphics, \code{\link{select3d}} for selecting regions. } \keyword{ graphics } rgl/man/aspect3d.Rd0000644000176200001440000000237114265301464013616 0ustar liggesusers\name{aspect3d} \alias{aspect3d} \title{Set the aspect ratios of the current plot} \description{ This function sets the apparent ratios of the x, y, and z axes of the current bounding box. } \usage{ aspect3d(x, y = NULL, z = NULL) } \arguments{ \item{x}{The ratio for the x axis, or all three ratios, or \code{"iso"} } \item{y}{The ratio for the y axis } \item{z}{The ratio for the z axis } } \details{ If the ratios are all 1, the bounding box will be displayed as a cube approximately filling the display. Values may be set larger or smaller as desired. Aspect \code{"iso"} signifies that the coordinates should all be displayed at the same scale, i.e. the bounding box should not be rescaled. (This corresponds to the default display before \code{aspect3d} has been called.) Partial matches to \code{"iso"} are allowed. \code{aspect3d} works by modifying \code{par3d("scale")}. } \value{ The previous value of the scale is returned invisibly. } \author{Duncan Murdoch} \seealso{\code{\link{plot3d}}, \code{\link{par3d}}} \examples{ x <- rnorm(100) y <- rnorm(100)*2 z <- rnorm(100)*3 open3d() plot3d(x, y, z) aspect3d(1, 1, 0.5) highlevel() # To trigger display open3d() plot3d(x, y, z) aspect3d("iso") highlevel() } \keyword{dynamic} rgl/man/primitives.Rd0000644000176200001440000001002614771520323014276 0ustar liggesusers\name{primitives} \alias{primitives} \alias{points3d} \alias{lines3d} \alias{segments3d} \alias{triangles3d} \alias{quads3d} \alias{3dobjects} \title{Add primitive shape} \description{ Adds a shape node to the current scene. } \usage{ points3d(x, y = NULL, z = NULL, ...) lines3d(x, y = NULL, z = NULL, ...) segments3d(x, y = NULL, z = NULL, ...) triangles3d(x, y = NULL, z = NULL, ...) quads3d(x, y = NULL, z = NULL, ...) } \arguments{ \item{x, y, z}{coordinates. Any reasonable way of defining the coordinates is acceptable. See the function \code{\link[grDevices]{xyz.coords}} for details.} \item{ ... }{Material properties (see \code{\link{material3d}}), \code{normals}, \code{texcoords} or \code{indices}; see details below.} } \details{ The functions \code{points3d}, \code{lines3d}, \code{segments3d}, \code{triangles3d} and \code{quads3d} add points, joined lines, line segments, filled triangles or quadrilaterals to the plots. They correspond to the OpenGL types \code{GL_POINTS, GL_LINE_STRIP, GL_LINES, GL_TRIANGLES} and \code{GL_QUADS} respectively. Points are taken in pairs by \code{segments3d}, triplets as the vertices of the triangles, and quadruplets for the quadrilaterals. Colors are applied vertex by vertex; if different at each end of a line segment, or each vertex of a polygon, the colors are blended over the extent of the object. Polygons must be non-degenerate and quadrilaterals must be entirely in one plane and convex, or the results are undefined. The appearance of the new objects are defined by the material properties. See \code{\link{material3d}} for details. For triangles and quads, the normals at each vertex may be specified using \code{normals}. These may be given in any way that would be acceptable as a single argument to \code{\link[grDevices]{xyz.coords}}. These need not match the actual normals to the polygon: curved surfaces can be simulated by using other choices of normals. Texture coordinates may also be specified. These may be given in any way that would be acceptable as a single argument to \code{\link[grDevices]{xy.coords}}, and are interpreted in terms of the bitmap specified as the material texture, with \code{(0, 0)} at the lower left, \code{(1, 1)} at the upper right. The texture is used to modulate the color of the polygon. All of these functions support an argument called \code{indices}, which allows vertices (and other attributes) to be re-used, as they are in objects created by \code{\link{mesh3d}} and related functions. This is intended to be used on smooth surfaces, where each shared vertex has just one value for normals, colors and texture coordinates. For shapes with flat-looking faces (e.g. polyhedra like \code{\link{cube3d}}), the vertices \bold{must} be duplicated to be rendered properly. } \value{ Each function returns the integer object ID of the shape that was added to the scene. These can be passed to \code{\link{pop3d}} to remove the object from the scene. } \author{ Ming Chen and Duncan Murdoch } \examples{ # Show 12 random vertices in various ways. M <- matrix(rnorm(36), 3, 12, dimnames = list(c('x', 'y', 'z'), rep(LETTERS[1:4], 3))) # Force 4-tuples to be convex in planes so that quads3d works. for (i in c(1, 5, 9)) { quad <- as.data.frame(M[, i + 0:3]) coeffs <- runif(2, 0, 3) if (mean(coeffs) < 1) coeffs <- coeffs + 1 - mean(coeffs) quad$C <- with(quad, coeffs[1]*(B - A) + coeffs[2]*(D - A) + A) M[, i + 0:3] <- as.matrix(quad) } open3d() # Rows of M are x, y, z coords; transpose to plot M <- t(M) shift <- matrix(c(-3, 3, 0), 12, 3, byrow = TRUE) points3d(M) lines3d(M + shift) segments3d(M + 2*shift) triangles3d(M + 3*shift, col = 'red') quads3d(M + 4*shift, col = 'green') text3d(M + 5*shift, texts = 1:12) # Add labels shift <- outer(0:5, shift[1, ]) shift[, 1] <- shift[, 1] + 3 text3d(shift, texts = c('points3d', 'lines3d', 'segments3d', 'triangles3d', 'quads3d', 'text3d'), adj = 0) rgl.bringtotop() } \keyword{dynamic} rgl/man/figWidth.Rd0000644000176200001440000000124214771520323013650 0ustar liggesusers\name{figWidth} \alias{figWidth} \alias{figHeight} \title{ Get R Markdown figure dimensions in pixels } \description{ In an R Markdown document, figure dimensions are normally specified in inches; these are translated into pixel dimensions when HTML output is requested and \code{\link{rglwidget}} is used. These functions reproduce that translation. } \usage{ figWidth() figHeight() } \value{ When used in an R Markdown document, these functions return the requested current dimensions of figures in pixels. Outside such a document, \code{NULL} is returned. } \author{ Duncan Murdoch } \examples{ # No useful return value outside of R Markdown: figWidth() figHeight() } rgl/man/cylinder3d.Rd0000644000176200001440000001133414771520323014146 0ustar liggesusers\name{cylinder3d} \alias{cylinder3d} \encoding{UTF-8} \title{ Create cylindrical or "tube" plots } \description{ This function converts a description of a space curve into a \code{\link[=mesh3d]{"mesh3d"}} object forming a cylindrical tube around the curve. } \usage{ cylinder3d(center, radius = 1, twist = 0, e1 = NULL, e2 = NULL, e3 = NULL, sides = 8, section = NULL, closed = 0, rotationMinimizing = is.null(e2) && is.null(e3), debug = FALSE, keepVars = FALSE, ...) } \arguments{ \item{center}{An n by 3 matrix whose columns are the x, y and z coordinates of the space curve.} \item{radius}{The radius of the cross-section of the tube at each point in the center.} \item{twist}{The amount by which the polygon forming the tube is twisted at each point.} \item{e1, e2, e3}{The local coordinates to use at each point on the space curve. These default to a rotation minimizing frame or Frenet coordinates.} \item{sides}{The number of sides in the polygon cross section.} \item{section}{The polygon cross section as a two-column matrix, or \code{NULL}.} \item{closed}{Whether to treat the first and last points of the space curve as identical, and close the curve, or put caps on the ends. See the Details.} \item{rotationMinimizing}{Use a rotation minimizing local frame if \code{TRUE}, or a Frenet or user-specified frame if \code{FALSE}.} \item{debug}{If \code{TRUE}, plot the local Frenet coordinates at each point.} \item{keepVars}{If \code{TRUE}, return the local variables in attribute \code{"vars"}.} \item{...}{Additional arguments to set as material properties.} } \details{ The number of points in the space curve is determined by the vector lengths in \code{center}, after using \code{\link{xyz.coords}} to convert it to a list. The other arguments \code{radius}, \code{twist}, \code{e1}, \code{e2}, and \code{e3} are extended to the same length. The \code{closed} argument controls how the ends of the cylinder are handled. If \code{closed > 0}, it represents the number of points of overlap in the coordinates. \code{closed == TRUE} is the same as \code{closed = 1}. If \code{closed > 0} but the ends don't actually match, a warning will be given and results will be somewhat unpredictable. Negative values of \code{closed} indicate that caps should be put on the ends of the cylinder. If \code{closed == -1}, a cap will be put on the end corresponding to \code{center[1, ]}. If \code{closed == -2}, caps will be put on both ends. If \code{section} is \code{NULL} (the default), a regular \code{sides}-sided polygon is used, and \code{radius} measures the distance from the center of the cylinder to each vertex. If not \code{NULL}, \code{sides} is ignored (and set internally to \code{nrow(section)}), and \code{radius} is used as a multiplier to the vertex coordinates. \code{twist} specifies the rotation of the polygon. Both \code{radius} and \code{twist} may be vectors, with values recycled to the number of rows in \code{center}, while \code{sides} and \code{section} are the same at every point along the curve. The three optional arguments \code{e1}, \code{e2}, and \code{e3} determine the local coordinate system used to create the vertices at each point in \code{center}. If missing, they are computed by simple numerical approximations. \code{e1} should be the tangent coordinate, giving the direction of the curve at the point. The cross-section of the polygon will be orthogonal to \code{e1}. When \code{rotationMinimizing} is \code{TRUE}, \code{e2} and \code{e3} are chosen to give a rotation minimizing frame (see Wang et al., 2008). When it is \code{FALSE}, \code{e2} defaults to an approximation to the normal or curvature vector; it is used as the image of the \code{y} axis of the polygon cross-section. \code{e3} defaults to an approximation to the binormal vector, to which the \code{x} axis of the polygon maps. The vectors are orthogonalized and normalized at each point. } \value{ A \code{\link[=mesh3d]{"mesh3d"}} object holding the cylinder, possibly with attribute \code{"vars"} containing the local environment of the function. } \author{ Duncan Murdoch } \references{ Wang, W., Jüttler, B., Zheng, D. and Liu, Y. (2008). Computation of rotation minimizing frames. ACM Transactions on Graphics, Vol. 27, No. 1, Article 2. } \examples{ # A trefoil knot open3d() theta <- seq(0, 2*pi, length.out = 25) knot <- cylinder3d( center = cbind( sin(theta) + 2*sin(2*theta), 2*sin(3*theta), cos(theta) - 2*cos(2*theta)), e1 = cbind( cos(theta) + 4*cos(2*theta), 6*cos(3*theta), sin(theta) + 4*sin(2*theta)), radius = 0.8, closed = TRUE, color = "green") shade3d(addNormals(subdivision3d(knot, depth = 2))) } \keyword{ dynamic } rgl/man/rglExtrafonts.Rd0000644000176200001440000000475314771520323014757 0ustar liggesusers\name{rglExtrafonts} \alias{rglExtrafonts} \title{ Register extra fonts } \description{ This function uses the \href{https://github.com/wch/extrafont}{\pkg{extrafont}} package to help register system fonts for use with FreeType in \pkg{rgl}. } \usage{ rglExtrafonts(..., quiet = TRUE) } \arguments{ \item{\dots}{ Vectors of fonts to try. See the Details. } \item{quiet}{ Whether to print information on progress. } } \details{ The \pkg{extrafont} package collects information on installed fonts from the system. When you first install \pkg{extrafont}, or after new fonts have been installed on your system, run \code{extrafont::font_import()} to build its database of system fonts. Fonts can be installed in \pkg{rgl} using \code{rglExtrafonts(rglname = familyname)} or \code{rglExtrafonts(familyname)}. In this call \code{familyname} is a vector of family names to look for in the \pkg{extrafont} database using \code{extrafont::choose_font(familyname)}; the first one found will be registered with \pkg{rgl}. The optional name \code{rglname} will also be usable to refer to the font family. If none of the given family names is found, no change will be made to the registered fonts in \pkg{rgl}. During startup, \pkg{rgl} detects whether \pkg{extrafont} is installed, and if so runs \verb{ rglExtrafonts(sans = c("Helvetica", "Arial"), serif = c("Times", "Times New Roman"), mono = c("Courier", "Courier New")) } to attempt to set up the default fonts. Fonts found by \pkg{extrafont} can also be used in some other graphics devices besides \pkg{rgl}; see \href{https://github.com/wch/extrafont}{the \pkg{extrafont} documentation} for details. } \note{ Each font in a display needs a unique \pkg{rgl} name; if the associated font for a given name is changed, all previously plotted text will also change. Currently \code{\link{rglwidget}} displays will not respect the new definitions. } \value{ Invisibly returns a vector giving the \pkg{rgl} name and the family name for the newly installed font. } \author{ Duncan Murdoch } \seealso{ \code{\link{text3d}}, \code{\link{rglFonts}} } \examples{ if (requireNamespace("extrafont") && !in_pkgdown_example()) { open3d() text3d(1,1,1, "Default", family = "sans", cex = 2) # Attempt to register new sans-serif font: newfamily <- rglExtrafonts(newsans = c("Comic Sans MS", "Impact", "Verdana", "Tahoma")) text3d(2,2,2, newfamily, family = "newsans", cex = 2) } } rgl/man/tkrgl.Rd0000644000176200001440000000222214771520323013225 0ustar liggesusers\name{tkrgl} \alias{tkrgl} \title{ The former tkrgl package } \description{ Functions from the former \pkg{tkrgl} package. } \details{ The \pkg{tkrgl} package contained functions to use TCL/TK to control an RGL scene on screen. These functions have now been merged into the \pkg{rgl} package, and the \pkg{tkrgl} package has been archived. To avoid conflicts with RGL names and to indicate the TCL/TK nature of these functions, they have all been prefixed with \code{tk}: \describe{ \item{\code{\link{tkpar3dsave}}}{Formerly \code{tkrgl::par3dsave}, allows interactive saving of scene parameters.} \item{\code{\link{tkspin3d}, \link{tkspinControl}}}{Formerly \code{tkrgl::spin3d} and \code{tkrgl::spinControl}, create buttons to spin the scene.} } History: \tabular{ll}{ 0.2-2 \tab First public release \cr 0.3 \tab Added possibility to control multiple windows \cr 0.4 \tab Compatibility with 2.0.0 tcltk package \cr 0.5 \tab Added continuous rotation \cr 0.6 \tab Added par3dsave \cr 0.7 \tab Added parameters to \code{\link{tkspinControl}}, fixed startup \cr 0.8 \tab Minor fixes to pass checks \cr 0.9 \tab Merge functions into \pkg{rgl} \cr } } rgl/man/writePLY.Rd0000644000176200001440000000565615011677075013644 0ustar liggesusers\name{writePLY} \alias{writePLY} \title{ Write Stanford PLY format files } \description{ This function writes PLY files. This is a simple file format that is commonly used in 3D printing. It does not represent text, only edges and polygons. The \code{writePLY} function does the necessary conversions. } \usage{ writePLY(con, format = c("little_endian", "big_endian", "ascii"), pointRadius = 0.005, pointShape = icosahedron3d(), lineRadius = pointRadius, lineSides = 20, pointsAsEdges = FALSE, linesAsEdges = pointsAsEdges, withColors = TRUE, withNormals = !(pointsAsEdges || linesAsEdges), ids = tagged3d(tags), tags = NULL) } \arguments{ \item{con}{ A connection or filename. } \item{format}{ Which output format. Defaults to little-endian binary. } \item{pointRadius, lineRadius}{ The radius of points and lines relative to the overall scale of the figure, if they are converted to polyhedra. } \item{pointShape}{ A mesh shape to use for points if they are converted. It is scaled by the \code{pointRadius}. } \item{lineSides}{ Lines are rendered as cylinders with this many sides. } \item{pointsAsEdges, linesAsEdges}{ Whether to convert points and lines to \dQuote{Edge} records in the PLY output. } \item{withColors}{ Whether to output vertex color information. } \item{withNormals}{ Whether to output vertex normals for smooth shading. } \item{ids}{ The identifiers (from \code{\link{ids3d}}) of the objects to write. If \code{NULL}, try to write everything. } \item{tags}{ Select objects with matching tags. Ignored if \code{ids} is specified. } } \details{ The current implementation only outputs triangles, quads, planes, spheres, points, line segments, line strips and surfaces. The defaults for \code{pointsAsEdges} and \code{linesAsEdges} have been chosen because Blender (\url{https://www.blender.org}) does not import lines, only polygons. If you are exporting to other software you may want to change them. Since the PLY format only allows one object per file, all RGL objects are combined into a single object when output. The output file is readable by Blender and Meshlab; the latter can write in a number of other formats, including U3D, suitable for import into a PDF document. } \value{ Invisibly returns the name of the connection to which the data was written. } \references{ The file format was found on \code{www.mathworks.com} on November 10, 2012 at a URL that no longer exists; currently the format is described at \code{www.mathworks.com/help/vision/ug/the-ply-format.html}. } \author{ Duncan Murdoch } \seealso{ \code{\link{scene3d}} saves a copy of a scene to an R variable; \code{\link{rglwidget}}, \code{\link{writeASY}}, \code{\link{writeOBJ}} and \code{\link{writeSTL}} write the scene to a file in various other formats. } \examples{ filename <- tempfile(fileext = ".ply") open3d() shade3d( icosahedron3d(col = "magenta") ) writePLY(filename) } \keyword{ graphics } rgl/man/ellipse3d.Rd0000644000176200001440000000633214771520323013774 0ustar liggesusers\name{ellipse3d} \alias{ellipse3d} \alias{ellipse3d.default} \alias{ellipse3d.lm} \alias{ellipse3d.glm} \alias{ellipse3d.nls} \title{ Make an ellipsoid } \description{ A generic function and several methods returning an ellipsoid or other outline of a confidence region for three parameters. } \usage{ ellipse3d(x, \dots) \method{ellipse3d}{default}(x, scale = c(1, 1, 1), centre = c(0, 0, 0), level = 0.95, t = sqrt(qchisq(level, 3)), which = 1:3, subdivide = 3, smooth = TRUE, ...) \method{ellipse3d}{lm}(x, which = 1:3, level = 0.95, t = sqrt(3 * qf(level, 3, x$df.residual)), ...) \method{ellipse3d}{glm}(x, which = 1:3, level = 0.95, t, dispersion, ...) \method{ellipse3d}{nls}(x, which = 1:3, level = 0.95, t = sqrt(3 * qf(level, 3, s$df[2])), ...) } \arguments{ \item{x}{ An object. In the default method the parameter \code{x} should be a square positive definite matrix at least 3x3 in size. It will be treated as the correlation or covariance of a multivariate normal distribution. } \item{\dots}{ Additional parameters to pass to the default method or to \code{\link{qmesh3d}}. } \item{scale}{ If \code{x} is a correlation matrix, then the standard deviations of each parameter can be given in the scale parameter. This defaults to \code{c(1, 1, 1)}, so no rescaling will be done. } \item{centre}{ The centre of the ellipse will be at this position. } \item{level}{ The confidence level of a simultaneous confidence region. The default is 0.95, for a 95\% region. This is used to control the size of the ellipsoid. } \item{t}{ The size of the ellipse may also be controlled by specifying the value of a t-statistic on its boundary. This defaults to the appropriate value for the confidence region. } \item{which}{ This parameter selects which variables from the object will be plotted. The default is the first 3. } \item{subdivide}{ This controls the number of subdivisions (see \code{\link{subdivision3d}}) used in constructing the ellipsoid. Higher numbers give a smoother shape. } \item{smooth}{ If \code{TRUE}, smooth interpolation of normals is used; if \code{FALSE}, a faceted ellipsoid will be displayed. } \item{dispersion}{ The value of dispersion to use. If specified, it is treated as fixed, and chi-square limits for \code{t} are used. If missing, it is taken from \code{summary(x)}. } } \value{ A \code{\link{mesh3d}} object representing the ellipsoid. } \examples{ # Plot a random sample and an ellipsoid of concentration corresponding to a 95\% # probability region for a # trivariate normal distribution with mean 0, unit variances and # correlation 0.8. if (requireNamespace("MASS", quietly = TRUE)) { Sigma <- matrix(c(10, 3, 0, 3, 2, 0, 0, 0, 1), 3, 3) Mean <- 1:3 x <- MASS::mvrnorm(1000, Mean, Sigma) open3d() plot3d(x, box = FALSE) plot3d( ellipse3d(Sigma, centre = Mean), col = "green", alpha = 0.5, add = TRUE) } # Plot the estimate and joint 90\% confidence region for the displacement and cylinder # count linear coefficients in the mtcars dataset data(mtcars) fit <- lm(mpg ~ disp + cyl , mtcars) open3d() plot3d(ellipse3d(fit, level = 0.90), col = "blue", alpha = 0.5, aspect = TRUE) } \keyword{dplot} rgl/man/light.Rd0000644000176200001440000000507514771520323013222 0ustar liggesusers\name{light} \alias{light3d} \title{Add light source} \description{ add a light source to the scene. } \usage{ light3d(theta=0, phi=15, x=NULL, y = NULL, z = NULL, viewpoint.rel = TRUE, ambient = "#FFFFFF", diffuse = "#FFFFFF", specular = "#FFFFFF") } \arguments{ \item{theta, phi}{direction to infinitely distant light} \item{x, y, z}{position of finitely distant light} \item{viewpoint.rel}{logical, if TRUE light is a viewpoint light that is positioned relative to the current viewpoint} \item{ambient, diffuse, specular }{ light color values used for lighting calculation } } \details{ Up to 8 light sources are supported. They are positioned either in world space or relative to the camera. By providing polar coordinates to \code{theta} and \code{phi} a directional light source is used. If numerical values are given to x, y and z, a point-like light source with finite distance to the objects in the scene is set up. If \code{x} is non-null, \code{\link{xyz.coords}} will be used to form the location values, so all three coordinates can be specified in \code{x}. If no lights have been added to a subscene, lights from the parent subscene will be used. See \code{\link{material3d}} for a discussion of how the components of the light affect the display of objects. } \value{ This function is called for the side effect of adding a light. A light ID is returned to allow \code{\link{pop3d}} to remove it. } \seealso{ \code{\link{clear3d}} \code{\link{pop3d}} } \examples{ # # a lightsource moving through the scene # data(volcano) z <- 2 * volcano # Exaggerate the relief x <- 10 * (1:nrow(z)) # 10 meter spacing (S to N) y <- 10 * (1:ncol(z)) # 10 meter spacing (E to W) zlim <- range(z) zlen <- zlim[2] - zlim[1] + 1 colorlut <- terrain.colors(zlen) # height color lookup table col <- colorlut[ z - zlim[1] + 1 ] # assign colors to heights for each point open3d() bg3d("gray50") surface3d(x, y, z, color = col, back = "lines") r <- max(y) - mean(y) lightid <- spheres3d(1, 1, 1, alpha = 0) frame <- function(time) { a <- pi*(time - 1) save <- par3d(skipRedraw = TRUE) clear3d(type = "lights") pop3d(id = lightid) xyz <- matrix(c(r*sin(a) + mean(x), r*cos(a) + mean(y), max(z)), ncol = 3) light3d(x = xyz, diffuse = "gray75", specular = "gray75", viewpoint.rel = FALSE) light3d(diffuse = "gray10", specular = "gray25") lightid <<- spheres3d(xyz, emission = "white", radius = 4) par3d(save) Sys.sleep(0.02) NULL } play3d(frame, duration = 2) } \keyword{dynamic} rgl/man/setAxisCallbacks.Rd0000644000176200001440000000730015011677075015331 0ustar liggesusers\name{setAxisCallbacks} \alias{setAxisCallbacks} \title{ User-defined axis labelling callbacks. } \description{ This function sets user callbacks to construct axes in R or \code{\link{rglwidget}} displays. } \usage{ setAxisCallbacks(axes, fns, javascript = NULL, subscene = scene$rootSubscene$id, scene = scene3d(minimal = FALSE), applyToScene = TRUE, applyToDev = missing(scene)) } \arguments{ \item{axes}{ Which axes? Specify as number in \code{1:3} or letter in \code{c("x", "y", "z")}. } \item{fns}{ Function or list of functions or character vector giving names of functions. } \item{javascript}{ Optional block of Javascript code to be included (at the global level). } \item{subscene}{ Which subscene do these callbacks apply to? } \item{scene}{ Which scene? } \item{applyToScene}{ Should these changes apply to the scene object? } \item{applyToDev}{ Should these changes apply to the current device? } } \details{ If \code{applyToScene} is \code{TRUE}, this function adds Javascript callbacks to the \code{scene} object. If \code{applyToDev} is \code{TRUE}, it adds R callbacks to the current RGL device. For Javascript, the callbacks are specified as strings; these will be evaluated within the browser in the global context to define the functions, which will then be called with the Javascript \code{this} object set to the current \code{rglwidgetClass} object. For R, they may be strings or R functions. Both options may be \code{TRUE}, in which case the callbacks must be specified as strings which are both valid Javascript and valid R. The usual way to do this is to give just a function name, with the function defined elsewhere, as in the Example below. The functions should have a header of the form \code{function(margin)}. The \code{margin} argument will be a string like \code{"x++"} indicating which margin would be chosen by R. If RGL would not choose to draw any axis annotations (which happens with \code{\link{rglwidget}}, though not currently in R itself), only the letter will be passed, e.g. \code{"x"}. } \value{ Invisibly returns an \code{rglScene} object. This object will record the changes if \code{applyToScene} is \code{TRUE}. If \code{applyToDev} is \code{TRUE}, it will also have the side effect of attempting to install the callbacks. } \seealso{ \code{\link{setUserCallbacks}} for mouse callbacks. } \author{ Duncan Murdoch } \examples{ # Draw arrows instead of tick marks on axes arrowAxis <- local({ ids <- c(NA, NA, NA) bbox <- c(NA, NA, NA, NA, NA, NA) function(margin) { dim <- if (grepl("x", margin)) 1 else if (grepl("y", margin)) 2 else 3 inds <- 2*dim + (-1):0 range <- par3d("bbox")[inds] if (!identical(bbox[inds], range)) { if (!is.na(ids[dim])) pop3d(id = ids[dim]) bbox[inds] <<- range center <- mean(range) from <- mean(c(range[1], center)) to <- mean(c(center, range[2])) # margin should agree with suggestion, so use "x++" etc. margin <- gsub("-", "+", margin) ids[dim] <<- arrow3d(p0 = c(from, 1, 1), p1 = c(to, 1, 1), n = 4, type = "lines", margin = margin, floating = TRUE) } } }) # Define the Javascript function with the same name to use in WebGL # Since Javascript won't change the bounding box, this function # doesn't need to do anything. js <- " window.arrowAxis = function(margin) {} ; " xyz <- matrix(rnorm(60), ncol = 3) plot3d(xyz, xlab = "x", ylab = "y", zlab = "z") setAxisCallbacks(1:3, "arrowAxis", javascript = js) rglwidget() } rgl/man/rgl.user2window.Rd0000644000176200001440000000403414771520323015160 0ustar liggesusers\name{rgl.user2window} \alias{rgl.user2window} \alias{rgl.window2user} \alias{rgl.projection} \title{ Convert between RGL user and window coordinates } \description{ This function converts from 3-dimensional user coordinates to 3-dimensional window coordinates. } \usage{ rgl.user2window(x, y = NULL, z = NULL, projection = rgl.projection()) rgl.window2user(x, y = NULL, z = 0, projection = rgl.projection()) rgl.projection(dev = cur3d(), subscene = currentSubscene3d(dev)) } \arguments{ \item{x, y, z}{Input coordinates. Any reasonable way of defining the coordinates is acceptable. See the function \code{\link[grDevices]{xyz.coords}} for details.} \item{projection}{The RGL projection to use } \item{dev, subscene}{The RGL device and subscene to work with } } \details{ These functions convert between user coordinates and window coordinates. Window coordinates run from 0 to 1 in X, Y, and Z. X runs from 0 on the left to 1 on the right; Y runs from 0 at the bottom to 1 at the top; Z runs from 0 foremost to 1 in the background. RGL does not currently display vertices plotted outside of this range, but in normal circumstances will automatically resize the display to show them. In the example below this has been suppressed. } \value{ The coordinate conversion functions produce a matrix with columns corresponding to the X, Y, and Z coordinates. \code{rgl.projection()} returns a list containing the following components: \item{model}{the modelview matrix} \item{projection}{the projection matrix} \item{viewport}{the viewport vector} See \code{\link{par3d}} for more details. } \author{ Ming Chen / Duncan Murdoch} \seealso{\code{\link{select3d}} } \examples{ open3d() points3d(rnorm(100), rnorm(100), rnorm(100)) if (interactive() || !.Platform$OS == "unix") { # Calculate a square in the middle of the display and plot it square <- rgl.window2user(c(0.25, 0.25, 0.75, 0.75, 0.25), c(0.25, 0.75, 0.75, 0.25, 0.25), 0.5) par3d(ignoreExtent = TRUE) lines3d(square) par3d(ignoreExtent = FALSE) } } \keyword{ dynamic } rgl/man/as.mesh3d.ashape3d.Rd0000644000176200001440000000671314771520323015367 0ustar liggesusers\name{as.mesh3d.ashape3d} \alias{as.mesh3d.ashape3d} \title{ Convert alpha-shape surface of a cloud of points to RGL mesh object } \description{ The \code{\link[alphashape3d:ashape3d]{alphashape3d::ashape3d}} function computes the 3D \eqn{\alpha}-shape of a cloud of points. This is an approximation to the visual outline of the cloud. It may include isolated points, line segments, and triangular faces: this function converts the triangular faces to an RGL \code{\link{tmesh3d}} object. } \usage{ \method{as.mesh3d}{ashape3d}(x, alpha = x$alpha[1], tri_to_keep = 2L, col = "gray", smooth = FALSE, normals = NULL, texcoords = NULL, ...) } \arguments{ \item{x}{ An object of class \code{"ashape3d"}. } \item{alpha}{ Which \code{alpha} value stored in \code{x} should be converted? } \item{tri_to_keep}{ Which triangles to keep. Expert use only: see \code{triang} entry in \bold{Value} section of \link[alphashape3d]{ashape3d} for details. } \item{col}{ The surface colour. } \item{smooth}{ Whether to attempt to add normals to make the surface look smooth. See the Details below. } \item{normals, texcoords}{ Normals and texture coordinates at each vertex can be specified. } \item{\dots}{ Additional arguments to pass to use as \code{\link{material3d}} properties on the resulting mesh. } } \details{ Edelsbrunner and Mucke's (1994) \eqn{\alpha}-shape algorithm is intended to compute a surface of a general cloud of points. Unlike the convex hull, the cloud may have voids, isolated points, and other oddities. This function is designed to work in the case where the surface is made up of simple polygons. If \code{smooth = TRUE}, this method attempts to orient all of the triangles in the surface consistently and add normals at each vertex by averaging the triangle normals. However, for some point clouds, the \eqn{\alpha}-shape will contain sheets of polygons with a few solid polyhedra embedded. This does not allow a consistent definition of "inside" and outside. If this is detected, a warning is issued and the resulting mesh will likely contain boundaries where the assumed orientation of triangles changes, resulting in ugly dark lines through the shape. Larger values of \code{alpha} in the call to \code{\link[alphashape3d:ashape3d]{alphashape3d::ashape3d}} may help. Methods for \code{\link{plot3d}} and \code{\link{persp3d}} are also defined: they call the \code{\link{as.mesh3d}} method and then plot the result. } \value{ A \code{"mesh3d"} object, suitable for plotting. } \references{ Edelsbrunner, H., Mucke, E. P. (1994). Three-Dimensional Alpha Shapes. ACM Transactions on Graphics, 13(1), pp.43-72. Lafarge, T. and Pateiro-Lopez, B. (2017). alphashape3d: Implementation of the 3D Alpha-Shape for the Reconstruction of 3D Sets from a Point Cloud. R package version 1.3. } \author{ Duncan Murdoch } \examples{ if (requireNamespace("alphashape3d", quietly = TRUE)) { set.seed(123) n <- 400 # 1000 gives a nicer result, but takes longer xyz <- rbind(cbind(runif(n), runif(n), runif(n)), cbind(runif(n/8, 1, 1.5), runif(n/8, 0.25, 0.75), runif(n/8, 0.25, 0.75))) ash <- suppressMessages(alphashape3d::ashape3d(xyz, alpha = 0.2)) m <- as.mesh3d(ash, smooth = TRUE) open3d() mfrow3d(1, 2, sharedMouse = TRUE) plot3d(xyz, size = 1) plot3d(m, col = "red", alpha = 0.5) points3d(xyz, size = 1) } }rgl/man/bbox.Rd0000644000176200001440000000503614771520323013042 0ustar liggesusers\name{bbox3d} \alias{bbox3d} \title{Set up bounding box decoration} \description{ Set up the bounding box decoration. } \usage{ bbox3d(xat = NULL, yat = NULL, zat = NULL, xunit = "pretty", yunit = "pretty", zunit = "pretty", expand = 1.03, draw_front = FALSE, xlab=NULL, ylab=NULL, zlab=NULL, xlen=5, ylen=5, zlen=5, marklen=15.0, marklen.rel=TRUE, ...) } \arguments{ \item{xat, yat, zat}{vector specifying the tickmark positions} \item{xlab, ylab, zlab}{character vector specifying the tickmark labeling} \item{xunit, yunit, zunit}{value specifying the tick mark base for uniform tick mark layout} \item{xlen, ylen, zlen}{value specifying the number of tickmarks} \item{marklen}{value specifying the length of the tickmarks} \item{marklen.rel}{logical, if TRUE tick mark length is calculated using 1/\code{marklen} * axis length, otherwise tick mark length is \code{marklen} in coordinate space} \item{expand}{value specifying how much to expand the bounding box around the data} \item{draw_front}{draw the front faces of the bounding box} \item{ ... }{Material properties (or other \code{rgl.bbox} parameters in the case of \code{bbox3d}). See \code{\link{material3d}} for details.} } \details{ Four different types of tick mark layouts are possible. This description applies to the X axis; other axes are similar: If \code{xat} is not \code{NULL}, the ticks are set up at custom positions. If \code{xunit} is numeric but not zero, it defines the tick mark base. If it is \code{"pretty"} (the default in \code{bbox3d}), ticks are set at \code{\link{pretty}} locations. If \code{xlen} is not zero, it specifies the number of ticks (a suggestion if \code{xunit} is \code{"pretty"}). The first color specifies the bounding box, while the second one specifies the tick mark and font color. \code{bbox3d} defaults to \code{\link{pretty}} locations for the axis labels and a slightly larger box, whereas \code{rgl.bbox} covers the exact range. \code{\link{axes3d}} offers more flexibility in the specification of the axes, but they are static, unlike those drawn by \code{\link{bbox3d}}. } \value{ This function is called for the side effect of setting the bounding box decoration. A shape ID is returned to allow \code{\link{pop3d}} to delete it. } \examples{ open3d() points3d(rnorm(100), rnorm(100), rnorm(100)) bbox3d(color = c("#333377", "black"), emission = "#333377", specular = "#3333FF", shininess = 5, alpha = 0.8) } \seealso{ \code{\link{material3d}}, \code{\link{axes3d}} } \keyword{dynamic} rgl/man/makeDependency.Rd0000644000176200001440000000713115011677075015027 0ustar liggesusers\name{makeDependency} \alias{makeDependency} \alias{RGL_DEBUGGING} \title{ Process Javascript for HTML dependency } \description{ A utility function to help in development of internal Javascript code, this function processes the Javascript to minify it and report on errors and bad style. } \usage{ makeDependency(name, src, script = NULL, package, version = packageVersion(package), minifile = paste0(basename(src), ".min.js"), debugging = FALSE, ...) } \arguments{ \item{name, src, script, package, version, ...}{ Arguments to pass to \code{htmltools::\link[htmltools]{htmlDependency}.} } \item{minifile}{Basename of minified file.} \item{debugging}{ See details below. } } \details{ This is a utility function used by RGL to process its Javascript code used when displaying \code{\link{rglwidget}} values. It may be helpful in other packages to use in their own installation. If the \pkg{js} package version 1.2 or greater is installed, the Javascript code will be minified and stored in the file named by \code{minifile} in the \code{src} directory. Syntax errors in the code will stop the process; unused variables will be reported. If \code{debugging} is \code{TRUE}, the locations of Javascript syntax errors will be reported, along with hints about improvements, and the original files will be used in the dependency object that is created. If \code{debugging} is \code{FALSE} (the default), the minified file will be used in the dependency object, hints won't be given, and syntax errors will lead to an uninformative failure to minify. } \note{ The usual way to use \code{makeDependency} is to call it in a \file{.R} file in a package, saving the result in a variable that will be used when an HTML widget is created. This way it is only run during package installation, when it is safe to write to the R library holding the package. Do not call it to write to the R library from code the user can run, as that is not allowed in general. If your package uses Roxygen, you may have problems because by default Roxygen will run the code, and it is likely to fail. The current workaround is to specify Roxygen option \code{load = "installed"} which prevents it from running your \file{.R} code. } \value{ An object that can be included in a list of dependencies passed to \code{htmltools::\link[htmltools:htmlDependencies]{attachDependencies}}. } \author{ Duncan Murdoch } \examples{ \dontrun{ # This is a slightly simplified version of the code used to # produce one of the dependencies for rglwidget(). # It writes to the system library copy of rgl so # has been marked not to run in the example code. makeDependency("rglwidgetClass", src = "htmlwidgets/lib/rglClass", script = c("rglClass.src.js", "utils.src.js", "buffer.src.js", "subscenes.src.js", "shaders.src.js", "textures.src.js", "projection.src.js", "mouse.src.js", "init.src.js", "pieces.src.js", "draw.src.js", "controls.src.js", "selection.src.js", "rglTimer.src.js", "pretty.src.js", "axes.src.js", "animation.src.js"), stylesheet = "rgl.css", package = "rgl", debugging = isTRUE(as.logical(Sys.getenv("RGL_DEBUGGING", "FALSE")))) } } rgl/man/shapelist3d.Rd0000644000176200001440000000346714771520323014341 0ustar liggesusers\name{shapelist3d} \alias{shapelist3d} \title{ Create and plot a list of shapes } \description{ These functions create and plot a list of shapes. } \usage{ shapelist3d(shapes, x = 0, y = NULL, z = NULL, size = 1, matrix = NULL, override = TRUE, ..., plot = TRUE) } \arguments{ \item{shapes}{ A single \code{shape3d} object, or a list of them. } \item{x, y, z}{ Translation(s) to apply } \item{size}{ Scaling(s) to apply } \item{matrix}{ A single matrix transformation, or a list of them. } \item{override}{ Whether the material properties should override the ones in the shapes. } \item{\dots}{ Material properties to apply. } \item{plot}{ Whether to plot the result. } } \details{ \code{shapelist3d} is a quick way to create a complex object made up of simpler ones. Each of the arguments \code{shapes} through \code{override} may be a vector of values (a list in the case of \code{shapes} or \code{matrix}). All values will be recycled to produce a list of shapes as long as the longest of them. The \code{\link{xyz.coords}} function will be used to process the \code{x}, \code{y} and \code{z} arguments, so a matrix may be used as \code{x} to specify all three. If a vector is used for \code{x} but \code{y} or \code{z} is missing, default values of \code{0} will be used. The \code{"shapelist3d"} class is simply a list of \code{"shape3d"} objects. Methods for \code{\link{dot3d}}, \code{\link{wire3d}}, \code{\link{shade3d}}, \code{\link{translate3d}}, \code{\link{scale3d}}, and \code{\link{rotate3d}} are defined for these objects. } \value{ An object of class \code{c("shapelist3d", "shape3d")}. } \author{ Duncan Murdoch } \seealso{ \code{\link{mesh3d}} } \examples{ open3d() shapelist3d(icosahedron3d(), x = rnorm(10), y = rnorm(10), z = rnorm(10), col = 1:5, size = 0.3) } \keyword{ dynamic } rgl/man/as.tmesh3d.Rd0000644000176200001440000000313514771520323014057 0ustar liggesusers\name{as.tmesh3d} \alias{as.tmesh3d} \alias{as.tmesh3d.default} \alias{as.tmesh3d.mesh3d} \title{ Convert object to a triangular mesh } \description{ Converts the quads in a mesh version of an object to triangles by splitting them up. Optionally drops any point or segment components. } \usage{ as.tmesh3d(x, ...) \method{as.tmesh3d}{default}(x, drop = FALSE, ...) \method{as.tmesh3d}{mesh3d}(x, drop = FALSE, keepTags = FALSE, ...) } %- maybe also 'usage' for other objects documented here. \arguments{ \item{x}{ An object from which to create a triangular mesh object. } \item{drop}{ If \code{TRUE}, drop any point or segment components. } \item{keepTags}{ Whether to include the \code{"tags"} component in the output. } \item{\dots}{ Ignored in the \code{mesh3d} method, passed to \code{as.mesh3d} in the default method. } } \details{ The default method simply calls \code{\link{as.mesh3d}(x, ...)} and passes the result to the \code{"mesh3d"} method. } \note{ Older versions of \pkg{rgl} had a \code{"tmesh3d"} class for meshes of triangles. That class is no longer used: \code{as.tmesh3d} and \code{\link{tmesh3d}} both produce \code{"mesh3d"} objects. } \value{ A \code{"mesh3d"} object containing no quads. If \code{drop = TRUE}, it will only contain triangles. If \code{keepTags = TRUE}, a \code{"tags"} element will be added to the result. For details, see the \code{\link{clipMesh3d}} help page. } \author{ Duncan Murdoch } \seealso{ \code{as.triangles3d} to get just the coordinates. } \examples{ x <- cuboctahedron3d() x # has quads and triangles as.tmesh3d(x) # has only triangles }rgl/man/getBoundary3d.Rd0000644000176200001440000000220114771520323014611 0ustar liggesusers\name{getBoundary3d} \alias{getBoundary3d} \title{ Extract the boundary of a mesh } \description{ Constructs a mesh of line segments corresponding to non-shared (i.e. boundary) edges of triangles or quads in the original mesh. } \usage{ getBoundary3d(mesh, sorted = FALSE, simplify = TRUE, ...) } \arguments{ \item{mesh}{ A mesh object. } \item{sorted}{ Whether the result should have the segments sorted in sequential order. } \item{simplify}{ Whether to simplify the resulting mesh, dropping all unused vertices. If \code{FALSE}, the vertices of the result will be identical to the vertices of \code{mesh}; if \code{TRUE}, they will likely be different, even if no vertices were dropped. } \item{...}{ Material properties to apply to the mesh. } } \value{ A \code{"mesh3d"} object containing 0 or more segments. } \author{ Duncan Murdoch } \seealso{ \code{\link{mesh3d}} } \examples{ x <- cube3d(col = "blue") x$ib <- x$ib[,-(1:2)] b <- getBoundary3d(x, sorted = TRUE, col = "black") open3d() shade3d(x, alpha=0.2) shade3d(b) # Show edge vertices in sequence: text3d(t(b$vb), texts = 1:ncol(b$vb), adj = 0) c(b$is[1,1], b$is[2,]) } rgl/man/as.mesh3d.rglId.Rd0000644000176200001440000000355414771520323014740 0ustar liggesusers\name{as.mesh3d.rglId} \alias{as.mesh3d.rglId} \title{ Convert object in plot to RGL mesh object } \description{ This method attempts to read the attributes of objects in the rgl display and construct a mesh3d object to approximate them. } \usage{ \method{as.mesh3d}{rglId}(x, type = NA, subscene = NA, ...) } \arguments{ \item{x}{ A vector of RGL identifiers of objects in the specified subscene. } \item{type}{ A vector of names of types of shapes to convert. Other shapes will be ignored. } \item{subscene}{ Which subscene to look in; the default \code{NA} specifies the current subscene. } \item{\dots}{ Ignored. } } \details{ This function attempts to construct a triangle mesh to approximate one or more objects from the current display. It can handle objects of types from \code{c("points", "lines", "linestrip", "triangles", "quads", "planes", "surface")}. Since this method only produces meshes containing points, segments and triangles, they won't necessarily be an exact match to the original object. If the generic \code{\link{as.mesh3d}} is called with no \code{x} argument, this method will be called with \code{x} set to the ids in the current scene. } \value{ A mesh object. } \author{ Duncan Murdoch } \seealso{ \code{\link{as.triangles3d.rglId}} for extracting the triangles, \code{\link{clipMesh3d}} to apply complex clipping to a mesh object. } \examples{ # volcano example taken from "persp" # data(volcano) z <- 2 * volcano # Exaggerate the relief x <- 10 * (1:nrow(z)) # 10 meter spacing (S to N) y <- 10 * (1:ncol(z)) # 10 meter spacing (E to W) zlim <- range(y) zlen <- zlim[2] - zlim[1] + 1 colorlut <- terrain.colors(zlen) # height color lookup table col <- colorlut[ z - zlim[1] + 1 ] # assign colors to heights for each point open3d(useNULL = TRUE) surface3d(x, y, z, color = col) m <- as.mesh3d() close3d() open3d() shade3d(m) } rgl/man/r3d.Rd0000644000176200001440000000747614771520323012612 0ustar liggesusers\name{r3d} \alias{r3d} \title{Generic 3D interface} \description{Generic 3D interface for 3D rendering and computational geometry.} \details{ R3d is a design for an interface for 3d rendering and computation without dependency on a specific rendering implementation. R3d includes a collection of 3D objects and geometry algorithms. All r3d interface functions are named \code{*3d}. They represent generic functions that delegate to implementation functions. The interface can be grouped into 8 categories: Scene Management, Primitive Shapes, High-level Shapes, Geometry Objects, Visualization, Interaction, Transformation, Subdivision. The rendering interface gives an abstraction to the underlying rendering model. It can be grouped into four categories: \describe{ \item{Scene Management:}{A 3D scene consists of shapes, lights and background environment.} \item{Primitive Shapes:}{Generic primitive 3D graphics shapes such as points, lines, triangles, quadrangles and texts.} \item{High-level Shapes:}{Generic high-level 3D graphics shapes such as spheres, sprites and terrain.} \item{Interaction:}{Generic interface to select points in 3D space using the pointer device.} } In this package we include an implementation of r3d using the underlying \code{rgl.*} functions. 3D computation is supported through the use of object structures that live entirely in R. \describe{ \item{Geometry Objects:}{Geometry and mesh objects allow to define high-level geometry for computational purpose such as triangle or quadrangle meshes (see \code{\link{mesh3d}}).} \item{Transformation:}{Generic interface to transform 3d objects.} \item{Visualization:}{Generic rendering of 3d objects such as dotted, wired or shaded.} \item{Computation:}{Generic subdivision of 3d objects.} } At present, the main practical differences between the r3d functions and the \code{rgl.*} functions are as follows. The r3d functions call \code{\link{open3d}} if there is no device open, and the \code{rgl.*} functions call \code{\link{rgl.open}}. By default \code{\link{open3d}} sets the initial orientation of the coordinate system in 'world coordinates', i.e. a right-handed coordinate system in which the x-axis increases from left to right, the y-axis increases with depth into the scene, and the z-axis increases from bottom to top of the screen. \code{rgl.*} functions, on the other hand, use a right-handed coordinate system similar to that used in OpenGL. The x-axis matches that of r3d, but the y-axis increases from bottom to top, and the z-axis decreases with depth into the scene. Since the user can manipulate the scene, either system can be rotated into the other one. The r3d functions also preserve the \code{rgl.material} setting across calls (except for texture elements, in the current implementation), whereas the deprecated \code{rgl.*} functions leave it as set by the last call. The example code below illustrates the two coordinate systems. } \seealso{ \code{\link{points3d}}, \code{\link{lines3d}}, \code{\link{segments3d}}, \code{\link{triangles3d}}, \code{\link{quads3d}}, \code{\link{text3d}}, \code{\link{spheres3d}}, \code{\link{sprites3d}}, \code{\link{terrain3d}}, \code{\link{select3d}}, \code{\link{dot3d}}, \code{\link{wire3d}}, \code{\link{shade3d}}, \code{\link{transform3d}}, \code{\link{rotate3d}}, \code{\link{subdivision3d}}, \code{\link{mesh3d}}, \code{\link{cube3d}}, \code{\link{rgl}} } \examples{ x <- c(0, 1, 0, 0) y <- c(0, 0, 1, 0) z <- c(0, 0, 0, 1) labels <- c("Origin", "X", "Y", "Z") i <- c(1, 2, 1, 3, 1, 4) # *3d interface open3d() text3d(x, y, z, labels) text3d(1, 1, 1, "*3d coordinates") segments3d(x[i], y[i], z[i]) } \keyword{dynamic} rgl/man/attributes.Rd0000644000176200001440000000523014555455305014301 0ustar liggesusers\name{rgl.attrib} \alias{rgl.attrib} \title{ Get information about shapes } \description{ Retrieves information about the shapes in a scene. } \usage{ rgl.attrib(id, attrib, first = 1, last = rgl.attrib.count(id, attrib)) } \arguments{ \item{id}{ A shape identifier, as returned by \code{\link{ids3d}}. } \item{attrib}{ An attribute of a shape. Currently supported: one of \cr \code{"vertices"}, \code{"normals"}, \code{"colors"}, \code{"texcoords"}, \code{"dim"}, \code{"texts"}, \code{"cex"}, \code{"adj"}, \code{"radii"}, \code{"centers"}, \code{"ids"}, \code{"usermatrix"}, \code{"types"}, \code{"flags"}, \code{"offsets"}, \code{"family"}, \code{"font"}, \code{"pos"}\cr or unique prefixes to one of those. } \item{first, last}{ Specify these to retrieve only those rows of the result. } } \details{ If the identifier is not found or is not a shape that has the given attribute, zero will be returned by \code{rgl.attrib.count}, and an empty matrix will be returned by \code{rgl.attrib}. The first four \code{attrib} names correspond to the usual OpenGL properties; \code{"dim"} is used just for surfaces, defining the rows and columns in the rectangular grid; \code{"cex"}, \code{"adj"}, \code{"family"}, \code{"font"} and \code{"pos"} apply only to text objects. } \value{ \code{rgl.attrib} returns the values of the attribute. Attributes are mostly real-valued, with the following sizes: \tabular{lll}{ \code{"vertices"} \tab 3 values \tab x, y, z \cr \code{"normals"} \tab 3 values \tab x, y, z \cr \code{"centers"} \tab 3 values \tab x, y, z \cr \code{"colors"} \tab 4 values \tab r, g, b, a \cr \code{"texcoords"} \tab 2 values \tab s, t \cr \code{"dim"} \tab 2 values \tab r, c \cr \code{"cex"} \tab 1 value \tab cex \cr \code{"adj"} \tab 2 values \tab x, y \cr \code{"radii"} \tab 1 value \tab r \cr \code{"ids"} \tab 1 value \tab id \cr \code{"usermatrix"} \tab 4 values \tab x, y, z, w \cr \code{"texts"} \tab 1 value \tab text \cr \code{"types"} \tab 1 value \tab type \cr \code{"flags"} \tab 1 value \tab flag \cr \code{"family"} \tab 1 value \tab family \cr \code{"font"} \tab 1 value \tab font \cr \code{"pos"} \tab 1 value \tab pos \cr } The \code{"texts"}, \code{"types"} and \code{"family"} attributes are character-valued; the \code{"flags"} attribute is logical valued, with named rows. These are returned as matrices with the row count equal to the count for the attribute, and the columns as listed above. } \author{ Duncan Murdoch } \seealso{ \code{\link{ids3d}}, \code{\link{rgl.attrib.info}} } \examples{ p <- plot3d(rnorm(100), rnorm(100), rnorm(100), type = "s", col = "red") rgl.attrib(p["data"], "vertices", last = 10) } \keyword{ graphics } rgl/man/show2d.Rd0000644000176200001440000001137414771520323013320 0ustar liggesusers\name{show2d} \alias{show2d} \title{ Draw a 2D plot on a rectangle in a 3D scene } \description{ This function uses a bitmap of a standard 2D graphics plot as a texture on a quadrilateral. Default arguments are set up so that it will appear on the face of the bounding box of the current 3D plot, but optional arguments allow it to be placed anywhere in the scene. } \usage{ show2d(expression, face = "z-", line = 0, reverse = FALSE, rotate = 0, x = NULL, y = NULL, z = NULL, width = 480, height = 480, filename = NULL, ignoreExtent = TRUE, color = "white", specular = "black", lit = FALSE, texmipmap = TRUE, texminfilter = "linear.mipmap.linear", expand = 1.03, texcoords = matrix(c(0, 1, 1, 0, 0, 0, 1, 1), ncol = 2), ...) } %- maybe also 'usage' for other objects documented here. \arguments{ \item{expression}{ Any plotting commands to produce a plot in standard graphics. Ignored if \code{filename} is not \code{NULL}. } \item{face}{ A character string defining which face of the bounding box to use. See Details below. } \item{line}{ How far out from the bounding box should the quadrilateral be placed? Uses same convention as \code{\link{mtext3d}}: not lines of text, but fraction of the bounding box size. } \item{reverse, rotate}{ Should the image be reversed or rotated? See Details below. } \item{x, y, z}{ Specific values to use to override \code{face}. } \item{width,height}{ Parameters to pass to \code{\link{png}} when creating the bitmap. See Details below. } \item{filename}{ A \file{.png} file image to use as the texture. } \item{ignoreExtent}{ Whether the quadrilateral should be ignored when computing the bounding box of the scene. } \item{color, specular, lit, texmipmap, texminfilter, \dots}{ Material properties to use for the quadrilateral. } \item{expand}{Amount by which the quadrilateral is expanded outside the bounding box of the data. } \item{texcoords}{Coordinates on the image. Lower left of the bitmap is \code{c(0,0)}, upper right is \code{c(1,1)}.} } \details{ The default arguments are chosen to make it easy to place a 2D image on the face of the bounding box. If \code{x}, \code{y} and \code{z} are \code{NULL} (the defaults), \code{face} will be used as a code for one of the six faces of the bounding box. The first letter should be \code{"x"}, \code{"y"} or \code{"z"}; this defines the axis perpendicular to the desired face. If the second letter is \code{"-"} or is missing, the face will be chosen to be the face with the lower value on that axis. Any other letter will use the opposite face. If any of \code{x}, \code{y} or \code{z} is given, the specified value will be used to replace the value calculated above. Usually four values should be given, corresponding to the coordinates of the lower left, lower right, upper right and upper left of the destination for the image before \code{reverse} and \code{rotate} are used. Fewer values can be used for one or two coordinates; \code{\link{cbind}} will be used to put together all 3 coordinates into a 4 by 3 matrix (which will be returned as an attribute of the result). The bitmap plot will by default be oriented so that it is properly oriented when viewed from the direction of the higher values of the perpendicular coordinate, and its lower left corner is at the lower value of the two remaining coordinates. The argument \code{reverse} causes the orientation to be mirrored, and \code{rotate} causes it to be rotated by multiples of 90 degrees. \code{rotate} should be an integer, with \code{0} for no rotation, \code{1} for a 90 degree counter-clockwise rotation, etc. The \code{width} and \code{height} arguments control the shape and resolution of the bitmap. The defaults give a square bitmap, which is appropriate with the usual \code{c(1,1,1)} aspect ratios (see \code{aspect3d}). Some tuning may be needed to choose the resolution. The plot will look best when displayed at its original size; shrinking it smaller tends to make it look faded, while expanding it bigger will make it look blurry. If \code{filename} is given, the width and height will be taken from the file, and \code{width} and \code{height} arguments will be ignored. } \value{ Invisibly returns the id value of the quadrilateral, with the following attributes: \item{value}{The value returned by \code{expression}.} \item{xyz}{A 4 by 3 matrix giving the coordinates of the corners as used in plotting.} \item{texcoords}{A 4 by 2 matrix giving the texture coordinates of the image.} \item{filename}{The filename for the temporary file holding the bitmap image.} } \author{ Duncan Murdoch } \seealso{ \code{\link{bgplot3d}} uses a plot as the background for the window. } \examples{ example(plot3d, ask = FALSE) show2d({ par(mar=c(0,0,0,0)) plot(x, y, col = rainbow(1000), axes=FALSE) }) }rgl/man/gltfTypes.Rd0000644000176200001440000000122714771520323014067 0ustar liggesusers\name{gltfTypes} \alias{gltfTypes} \docType{data} \title{ Names of glTF types. } \description{ The glTF specification packs data into buffers, labelling the type of each part with an integer. The first six values in \code{gltfTypes} are the integers used there, with \code{"int"} and \code{"double"} added for completeness; those values are taken from OpenGL header files. } \usage{gltfTypes} \format{ \code{gltfTypes} is simply a named vector containing integer values. } \details{ These are used in the \code{\link{Buffer}} object. } \references{ \url{https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#_accessor_componenttype} } \examples{ gltfTypes } rgl/man/plot3d.formula.Rd0000644000176200001440000000314614771520323014761 0ustar liggesusers\name{plot3d.formula} \alias{plot3d.formula} \alias{persp3d.formula} \title{ Methods for formulas } \description{ These functions provide a simple formula-based interface to \code{\link{plot3d}} and \code{\link{persp3d}}. } \usage{ \method{plot3d}{formula}(x, data = NULL, xlab, ylab, zlab, ...) \method{persp3d}{formula}(x, data = NULL, xlab, ylab, zlab, ...) } \arguments{ \item{x}{ A formula like \code{z ~ x + y}. } \item{data}{ An optional dataframe or list in which to find the components of the formula. } \item{xlab, ylab, zlab}{ Optional axis labels to override the ones automatically obtained from the formula. } \item{\dots}{ Additional arguments to pass to the default \code{plot3d} method, or the \code{persp3d} method for \code{"deldir"} objects. } } \details{ Only simple formulas (the ones handled by the \code{\link{xyz.coords}} function) are supported: a single variable on the left hand side (which will be plotted on the Z axis), and a sum of two variables on the right hand side (which will be the X and Y axis variables in the plot.) } \note{ The \code{persp3d} method requires that the suggested package \pkg{deldir} is installed. } \value{ These functions are called for the side effect of drawing the plots. The \code{plot3d} method draws a scatterplot. The \code{persp3d} method draws a surface plot. Return values are as given by the \code{\link{plot3d.default}} method or the \code{\link{persp3d.deldir}} methods. } \author{ Duncan Murdoch } \examples{ open3d() mfrow3d(1, 2, sharedMouse = TRUE) plot3d(mpg ~ wt + qsec, data = mtcars) if (checkDeldir()) persp3d(mpg ~ wt + qsec, data = mtcars) } rgl/man/postscript.Rd0000644000176200001440000000361315011677075014326 0ustar liggesusers\name{rgl.postscript} \alias{rgl.postscript} \title{Export vector graphics} \description{ Saves the screenshot to a file in PostScript or other vector graphics format. } \usage{ rgl.postscript( filename, fmt = "eps", drawText = TRUE ) } \arguments{ \item{filename}{full path to filename.} \item{fmt}{export format, currently supported: ps, eps, tex, pdf, svg, pgf } \item{drawText}{logical, whether to draw text} } \details{ Animations can be created in a loop modifying the scene and saving a screenshot to a file. (See example below) This function is a wrapper for the GL2PS library by Christophe Geuzaine, and has the same limitations as that library: not all OpenGL features are supported, and some are only supported in some formats. See the reference for full details. } \references{ GL2PS: an OpenGL to PostScript printing library by Christophe Geuzaine, \url{https://www.geuz.org/gl2ps/}, version 1.4.2. } \author{ Christophe Geuzaine / Albrecht Gebhardt } \examples{ # Create new files in tempdir savedir <- setwd(tempdir()) x <- y <- seq(-10, 10, length.out = 20) z <- outer(x, y, function(x, y) x^2 + y^2) persp3d(x, y, z, col = 'lightblue') title3d("Using LaTeX text", col = 'red', line = 3) rgl.postscript("persp3da.ps", "ps", drawText = FALSE) rgl.postscript("persp3da.pdf", "pdf", drawText = FALSE) rgl.postscript("persp3da.tex", "tex") pop3d() title3d("Using ps/pdf text", col = 'red', line = 3) rgl.postscript("persp3db.ps", "ps") rgl.postscript("persp3db.pdf", "pdf") rgl.postscript("persp3db.tex", "tex", drawText = FALSE) setwd(savedir) \dontrun{ # # create a series of frames for an animation # open3d() shade3d(oh3d(), color = "red") view3d(0, 20) for (i in 1:45) { view3d(i, 20) filename <- paste("pic", formatC(i, digits = 1, flag = "0"), ".eps", sep = "") rgl.postscript(filename, fmt = "eps") } } } \seealso{ \code{\link{view3d}}, \code{\link{snapshot3d}} } \keyword{dynamic} rgl/man/setUserCallbacks.Rd0000644000176200001440000002055314771520323015343 0ustar liggesusers\name{setUserCallbacks} \alias{setUserCallbacks} \title{ Set mouse callbacks in R or Javascript code } \description{ This function sets user mouse callbacks in R or \code{\link{rglwidget}} displays. } \usage{ setUserCallbacks(button, begin = NULL, update = NULL, end = NULL, rotate = NULL, javascript = NULL, subscene = scene$rootSubscene$id, scene = scene3d(minimal = FALSE), applyToScene = TRUE, applyToDev = missing(scene)) } \arguments{ \item{button}{ Which button should this callback apply to? Can be numeric from \code{0:4}, or character from \code{"none", "left", "right", "center", "wheel"}. } \item{begin, update, end, rotate}{ Functions to call when events occur. See Details. } \item{javascript}{ Optional block of Javascript code to be included (at the global level). } \item{subscene}{ Which subscene do these callbacks apply to? } \item{scene}{ Which scene? } \item{applyToScene}{ Should these changes apply to the scene object? } \item{applyToDev}{ Should these changes apply to the current device? } } \details{ If \code{applyToScene} is \code{TRUE}, this function adds Javascript callbacks to the \code{scene} object. If \code{applyToDev} is \code{TRUE}, it adds R callbacks to the current RGL device. For Javascript, the callbacks are specified as strings; these will be evaluated within the browser in the global context to define the functions, which will then be called with the Javascript \code{this} object set to the current \code{rglwidgetClass} object. For R, they may be strings or R functions. Both options may be \code{TRUE}, in which case the callbacks must be specified as strings which are both valid Javascript and valid R. The usual way to do this is to give just a function name, with the function defined elsewhere, as in the Example below. The \code{begin} and \code{update} functions should be of the form \code{function(x, y) { ... }}. The \code{end} function will be called with no arguments. The \code{rotate} callback can only be set on the mouse wheel. It is called when the mouse wheel is rotated. It should be of the form \code{function(away)}, where \code{away} will be 1 while rotating the wheel \dQuote{away} from you, and 2 while rotating it towards you. If \code{rotate} is not set but other callbacks are set on the wheel \dQuote{button}, then each click of the mouse wheel will trigger all \code{start}, \code{update}, then \code{end} calls in sequence. The \code{javascript} argument is an optional block of code which will be evaluated once during the initialization of the widget. It can define functions and assign them as members of the \code{window} object, and then the names of those functions can be given in the callback arguments; this allows the callbacks to share information. } \value{ Invisibly returns an \code{rglScene} object. This object will record the changes if \code{applyToScene} is \code{TRUE}. If \code{applyToDev} is \code{TRUE}, it will also have the side effect of attempting to install the callbacks using \code{\link{rgl.setMouseCallbacks}} and \code{\link{rgl.setWheelCallback}}. } \seealso{ \code{\link{setAxisCallbacks}} for user defined axes. } \author{ Duncan Murdoch } \examples{ # This example identifies points in both the rgl window and # in WebGL verts <- cbind(rnorm(11), rnorm(11), rnorm(11)) idverts <- plot3d(verts, type = "s", col = "blue")["data"] # Plot some invisible text; the Javascript will move it idtext <- text3d(verts[1,,drop = FALSE], texts = 1, adj = c(0.5, -1.5), alpha = 0) # Define the R functions to use within R fns <- local({ idverts <- idverts idtext <- idtext closest <- -1 update <- function(x, y) { save <- par3d(skipRedraw = TRUE) on.exit(par3d(save)) rect <- par3d("windowRect") size <- rect[3:4] - rect[1:2] x <- x / size[1]; y <- 1 - y / size[2]; verts <- rgl.attrib(idverts, "vertices") # Put in window coordinates vw <- rgl.user2window(verts) dists <- sqrt((x - vw[,1])^2 + (y - vw[,2])^2) newclosest <- which.min(dists) if (newclosest != closest) { if (idtext > 0) pop3d(id = idtext) closest <<- newclosest idtext <<- text3d(verts[closest,,drop = FALSE], texts = closest, adj = c(0.5, -1.5)) } } end <- function() { if (idtext > 0) pop3d(id = idtext) closest <<- -1 idtext <<- -1 } list(rglupdate = update, rglend = end) }) rglupdate <- fns$rglupdate rglend <- fns$rglend # Define the Javascript functions with the same names to use in WebGL js <- ' var idverts = \%id\%, idtext = \%idtext\%, closest = -1, subid = \%subid\%; window.rglupdate = function(x, y) { var obj = this.getObj(idverts), i, newdist, dist = Infinity, pt, newclosest; x = x/this.canvas.width; y = y/this.canvas.height; for (i = 0; i < obj.vertices.length; i++) { pt = obj.vertices[i].concat(1); pt = this.user2window(pt, subid); pt[0] = x - pt[0]; pt[1] = y - pt[1]; pt[2] = 0; newdist = rglwidgetClass.vlen(pt); if (newdist < dist) { dist = newdist; newclosest = i; } } if (newclosest !== closest) { closest = newclosest var text = this.getObj(idtext); text.vertices[0] = obj.vertices[closest]; text.colors[0][3] = 1; // alpha is here! text.texts[0] = (closest + 1).toString(); text.initialized = false; this.drawScene(); } }; window.rglend = function() { var text = this.getObj(idtext); closest = -1; text.colors[0][3] = 0; text.initialized = false; this.drawScene(); }' js <- sub("\%id\%", idverts, js) js <- sub("\%subid\%", subsceneInfo()$id, js) js <- sub("\%idtext\%", idtext, js) # Install both setUserCallbacks("left", begin = "rglupdate", update = "rglupdate", end = "rglend", javascript = js) rglwidget() # This example doesn't affect the rgl window, it only modifies # the scene object to implement panning # Define the Javascript functions to use in WebGL js <- ' window.subid = \%subid\%; window.panbegin = function(x, y) { var activeSub = this.getObj(subid), viewport = activeSub.par3d.viewport, activeModel = this.getObj(this.useid(activeSub.id, "model")), l = activeModel.par3d.listeners, i; this.userSave = {x:x, y:y, viewport:viewport, cursor:this.canvas.style.cursor}; for (i = 0; i < l.length; i++) { activeSub = this.getObj(l[i]); activeSub.userSaveMat = new CanvasMatrix4(activeSub.par3d.userMatrix); } this.canvas.style.cursor = "grabbing"; }; window.panupdate = function(x, y) { var objects = this.scene.objects, activeSub = this.getObj(subid), activeModel = this.getObj(this.useid(activeSub.id, "model")), l = activeModel.par3d.listeners, viewport = this.userSave.viewport, par3d, i, zoom; if (x === this.userSave.x && y === this.userSave.y) return; x = (x - this.userSave.x)/this.canvas.width; y = (y - this.userSave.y)/this.canvas.height; for (i = 0; i < l.length; i++) { activeSub = this.getObj(l[i]); par3d = activeSub.par3d; /* NB: The right amount of zoom depends on the scaling of the data and the position of the observer. This might need tweaking. */ zoom = rglwidgetClass.vlen(par3d.observer)*par3d.zoom; activeSub.par3d.userMatrix.load(objects[l[i]].userSaveMat); activeSub.par3d.userMatrix.translate(zoom*x, zoom*y, 0); } this.drawScene(); }; window.panend = function() { this.canvas.style.cursor = this.userSave.cursor; }; ' js <- sub("\%subid\%", subsceneInfo()$id, js) scene <- setUserCallbacks("left", begin = "panbegin", update = "panupdate", end = "panend", applyToDev = FALSE, javascript = js) rglwidget(scene) } rgl/man/turn3d.Rd0000644000176200001440000000153114771520323013323 0ustar liggesusers\name{turn3d} \alias{turn3d} \title{ Create a solid of rotation from a two-dimensional curve } \description{ This function \dQuote{turns} the curve (as on a lathe) to form a solid of rotation along the x axis. } \usage{ turn3d(x, y = NULL, n = 12, smooth = FALSE, ...) } \arguments{ \item{x, y}{ Points on the curve, in a form suitable for \code{\link{xy.coords}}. The \code{y} values must be non-negative. } \item{n}{ How many steps in the rotation? } \item{smooth}{ logical; whether to add normals for a smooth appearance. } \item{...}{ Additional parameters to pass to \code{\link{tmesh3d}}. } } \value{ A mesh object containing triangles and/or quadrilaterals. } \author{ Fang He and Duncan Murdoch } \seealso{ \code{\link{extrude3d}} } \examples{ x <- 1:10 y <- rnorm(10)^2 open3d() shade3d(turn3d(x, y), col = "green") } \keyword{ graphics } rgl/man/rglMouse.Rd0000644000176200001440000000555115012460301013673 0ustar liggesusers\name{rglMouse} \alias{rglMouse} \title{ Generate HTML code to select mouse mode } \description{ This generates an HTML \code{select} element to choose among the mouse modes supported by \code{\link{rglwidget}}. } \usage{ rglMouse(sceneId, choices = c("trackball", "selecting", "xAxis", "yAxis", "zAxis", "polar", "zoom", "fov", "none"), labels = choices, button = 1, dev = cur3d(), subscene = currentSubscene3d(dev), default = par3d("mouseMode", dev = dev, subscene = subscene)[button + 1], stayActive = FALSE, height = 40, ...) } \arguments{ \item{sceneId}{ Either an \code{\link{rglwidget}} or the \code{elementId} from one of them. } \item{choices}{ Which mouse modes to support? } \item{labels}{ How to label each mouse mode. } \item{button}{ Which mouse button is being controlled. } \item{dev}{ The RGL device used for defaults. } \item{subscene}{ Which subscene is being modified. } \item{default}{ What is the default entry to show in the control. } \item{stayActive}{ Whether a selection brush should stay active if the mouse mode is changed. } \item{height}{ The (relative) height of the item in the output display. } \item{...}{ Additional arguments to pass to \code{htmltools::tags$select()}, e.g. \code{id} or \code{class}. } } \details{ A result of an \code{\link{rglwidget}} call can be passed as the \code{sceneId} argument. This allows the widget to be \dQuote{piped} into the \code{rglMouse} call. The widget will appear first, the selector next in a \code{\link[htmltools:tag]{tagList}}. If the \code{sceneId} is a character string, it should be the \code{elementId} of a separately constructed \code{\link{rglwidget}} result. Finally, the \code{sceneId} can be omitted. In this case the \code{rglMouse} result needs to be passed into an \code{\link{rglwidget}} call as part of the \code{controllers} argument. This will place the selector before the widget on the resulting display. If the mouse mode is changed while brushing the scene, by default the brush will be removed (and so the selection will be cleared too). If this is not desired, set \code{stayActive = TRUE}. } \value{ A browsable value to put in a web page. } \author{ Duncan Murdoch } \seealso{ The \HTMLVignette{WebGL}{}{User Interaction in WebGL} vignette gives more details. } \examples{ if (interactive() || in_pkgdown_example()) { open3d() xyz <- matrix(rnorm(300), ncol = 3) id <- plot3d(xyz, col = "red", type = "s")["data"] par3d(mouseMode = "selecting") share <- rglShared(id) # This puts the selector below the widget. rglwidget(shared = share, width = 300, height = 300) \%>\% rglMouse() # This puts the selector above the widget. rglMouse() \%>\% rglwidget(shared = share, width = 300, height = 300, controllers = .) } } rgl/man/all.equal.mesh3d.Rd0000644000176200001440000000343414771520323015150 0ustar liggesusers\name{all.equal.mesh3d} \alias{all.equal.mesh3d} \alias{compare_proxy.mesh3d} \title{ Compare mesh3d objects in a meaningful way. } \description{ These functions allow comparison of mesh3d objects, ignoring irrelevant differences. \code{compare_proxy.mesh3d} can function as a \code{compare_proxy} method for the \pkg{waldo} package, by stripping out \code{NULL} components and ordering other components alphabetically by name. \code{all.equal.mesh3d} compares mesh3d objects by using \code{compare_proxy.mesh3d} to standardize them, then using the regular \code{\link{all.equal}} function to compare them. } \usage{ \method{all.equal}{mesh3d}(target, current, ...) compare_proxy.mesh3d(x, path = "x") } %- maybe also 'usage' for other objects documented here. \arguments{ \item{target, current}{ Two mesh3d objects to compare. } \item{x}{ A single mesh3d object to standardize. } \item{path}{ The string to use in a \pkg{waldo} display of this object. } \item{\dots}{ Additional parameters to pass to \code{\link{all.equal}}. } } \value{ \code{all.equal.mesh3d} returns \code{TRUE}, or a character vector describing (some of) the differences. \code{compare_proxy.mesh3d} returns a list containing two components: \describe{ \item{object}{a copy of \code{x} with relevant components in alphabetical order.} \item{path}{a modification of the path label for \code{x}} } } \note{ \pkg{waldo} is not an installation requirement for \pkg{rgl} and \pkg{rgl} will never cause it to be loaded. The \code{compare_proxy.mesh3d} function will only be registered as a method for \code{waldo::compare_proxy} if you load \pkg{waldo} before \pkg{rgl}, as would normally happen during testing using \pkg{testthat}, or if you load it before calling \code{\link{mesh3d}}, as might happen if you are doing manual tests. } rgl/man/readSTL.Rd0000644000176200001440000000600415011677075013407 0ustar liggesusers\name{readSTL} \alias{readSTL} \alias{writeSTL} \title{ Read and write STL (stereolithography) format files } \description{ These functions read and write STL files. This is a simple file format that is commonly used in 3D printing. It does not represent text, only triangles. The \code{writeSTL} function converts some RGL object types to triangles. } \usage{ readSTL(con, ascii = NA, plot = TRUE, ...) writeSTL(con, ascii = FALSE, pointRadius = 0.005, pointShape = icosahedron3d(), lineRadius = pointRadius, lineSides = 20, ids = tagged3d(tags), tags = NULL) } \arguments{ \item{con}{ A connection or filename. } \item{ascii}{ Whether to use the ASCII format or the binary format. The default \code{NA} setting for \code{readSTL()} causes it to detect the format. This only works for files, not other connections, which default to binary. } \item{plot}{ On reading, should the object be plotted? } \item{\dots}{ If plotting, other parameters to pass to \code{\link{triangles3d}} } \item{pointRadius, lineRadius}{ The radius of points and lines relative to the overall scale of the figure. } \item{pointShape}{ A mesh shape to use for points. It is scaled by the \code{pointRadius}. } \item{lineSides}{ Lines are rendered as cylinders with this many sides. } \item{ids}{ The identifiers (from \code{\link{ids3d}}) of the objects to write. If \code{NULL}, try to write everything. } \item{tags}{ Alternate way to specify \code{ids}. Ignored if \code{ids} is given. } } \details{ The current implementation is limited. For reading, it ignores normals and color information. For writing, it only outputs triangles, quads, planes, spheres, points, line segments, line strips and surfaces, and does not write color information. Lines and points are rendered in an isometric scale: if your data scales vary, they will look strange. Since the STL format only allows one object per file, all RGL objects are combined into a single object when output. The output file is readable by Blender and Meshlab; the latter can write in a number of other formats, including U3D, suitable for import into a PDF document. } \value{ \code{readSTL} invisibly returns the object id if \code{plot = TRUE}, or (visibly) a matrix of vertices of the triangles if not. \code{writeSTL} invisibly returns the name of the connection to which the data was written. } \references{ The file format was found on Wikipedia on October 25, 2012. I learned about the STL file format from David Smith's blog reporting on Ian Walker's \code{r2stl} function. } \author{ Duncan Murdoch } \seealso{ \code{\link{scene3d}} saves a copy of a scene to an R variable; \code{\link{rglwidget}}, \code{\link{writeASY}}, \code{\link{writePLY}}, \code{\link{writeOBJ}} and \code{\link{writeSTL}} write the scene to a file in various other formats. } \examples{ filename <- tempfile(fileext = ".stl") open3d() shade3d( icosahedron3d(col = "magenta") ) writeSTL(filename) open3d() readSTL(filename, col = "red") } \keyword{ graphics } rgl/man/rgl.incrementID.Rd0000644000176200001440000000071215011677075015075 0ustar liggesusers\name{rgl.incrementID} \alias{rgl.incrementID} \title{ Increment ID } \description{ This function is mainly for internal use. It simply increments the internal object ID number and returns the new value. Negative values have no effect. } \usage{ rgl.incrementID(n = 1L) } \arguments{ \item{n}{ An integer increment to use. } } \value{ The resulting ID value. } \examples{ # Get the current ID value rgl.incrementID(0) # Increment it rgl.incrementID() }rgl/man/callbacks.Rd0000644000176200001440000000756714771520323014042 0ustar liggesusers\name{callbacks} \alias{rgl.setMouseCallbacks} \alias{rgl.getMouseCallbacks} \alias{rgl.setWheelCallback} \alias{rgl.getWheelCallback} \title{ User callbacks on mouse events } \description{ Set and get user callbacks on mouse events. } \usage{ rgl.setMouseCallbacks(button, begin = NULL, update = NULL, end = NULL, dev = cur3d(), subscene = currentSubscene3d(dev)) rgl.getMouseCallbacks(button, dev = cur3d(), subscene = currentSubscene3d(dev)) rgl.setWheelCallback(rotate, dev = cur3d(), subscene = currentSubscene3d(dev)) rgl.getWheelCallback(dev = cur3d(), subscene = currentSubscene3d(dev)) } \arguments{ \item{button}{ Which button? Use 1 for left, 2 for right, 3 for middle, 4 for wheel. Use 0 to set an action when no button is pressed. } \item{begin}{ Called when mouse down event occurs } \item{update}{ Called when mouse moves } \item{end}{ Called when mouse is released } \item{rotate}{ Called when mouse wheel is rotated } \item{dev, subscene}{The RGL device and subscene to work with } } \details{ The set functions set event handlers on mouse events that occur within the current RGL window. The \code{begin} and \code{update} events should be functions taking two arguments; these will be the mouse coordinates when the event occurs. The \code{end} event handler takes no arguments. The \code{rotate} event takes a single argument, which will be equal to \code{1} if the user pushes the wheel away by one click, and \code{2} if the user pulls the wheel by one click. Alternatively, the handlers may be set to \code{NULL}, the default value, in which case no action will occur. If a subscene has multiple listeners, the user action will still only be called for the subscene that received the mouse event. It should consult \code{\link{par3d}("listeners")} if it makes sense to take action on the whole group of subscenes. The get function retrieves the callbacks that are currently set. The \dQuote{no button} mouse handler may be set by specifying \code{button = 0}. The \code{begin} function will be called the first time the mouse moves within the subscene, and the \code{update} function will be called repeatedly as it moves. The \code{end} function will never be called. } \value{ The set functions are called for the side effect of setting the mouse event handlers. The \code{rgl.getMouseCallbacks} function returns a list containing the callback functions or \code{NULL} if no user callback is set. The \code{rgl.getWheelCallback} returns the callback function or \code{NULL}. } \author{ Duncan Murdoch } \seealso{ \code{\link{par3d}} to set built-in handlers, \code{\link{setUserCallbacks}} to work with \code{\link{rglwidget}}.} \examples{ pan3d <- function(button, dev = cur3d(), subscene = currentSubscene3d(dev)) { start <- list() begin <- function(x, y) { activeSubscene <- par3d("activeSubscene", dev = dev) start$listeners <<- par3d("listeners", dev = dev, subscene = activeSubscene) for (sub in start$listeners) { init <- par3d(c("userProjection","viewport"), dev = dev, subscene = sub) init$pos <- c(x/init$viewport[3], 1 - y/init$viewport[4], 0.5) start[[as.character(sub)]] <<- init } } update <- function(x, y) { for (sub in start$listeners) { init <- start[[as.character(sub)]] xlat <- 2*(c(x/init$viewport[3], 1 - y/init$viewport[4], 0.5) - init$pos) mouseMatrix <- translationMatrix(xlat[1], xlat[2], xlat[3]) par3d(userProjection = mouseMatrix \%*\% init$userProjection, dev = dev, subscene = sub ) } } rgl.setMouseCallbacks(button, begin, update, dev = dev, subscene = subscene) cat("Callbacks set on button", button, "of RGL device", dev, "in subscene", subscene, "\n") } open3d() shade3d(icosahedron3d(), col = "yellow") # This only works in the internal display... pan3d(1) } \keyword{ dynamic } rgl/man/rglwidget.Rd0000644000176200001440000002040615012460301014062 0ustar liggesusers\name{rglwidget} \alias{rglwidget} \alias{rgl.printRglwidget} \title{ An htmlwidget to hold an RGL scene } \description{ The \pkg{htmlwidgets} package provides a framework for embedding graphical displays in HTML documents of various types. This function provides the necessities to embed an RGL scene in one. } \usage{ rglwidget(x = scene3d(minimal), width = figWidth(), height = figHeight(), controllers = NULL, elementId = NULL, reuse = FALSE, webGLoptions = list(preserveDrawingBuffer = TRUE), shared = NULL, minimal = TRUE, webgl, snapshot, shinyBrush = NULL, altText = "3D plot", ..., oldConvertBBox = FALSE, fastTransparency = getOption("rgl.fastTransparency", TRUE)) } \arguments{ \item{x}{ An RGL scene produced by the \code{\link[rgl]{scene3d}} function. } \item{width, height}{ The width and height of the display in pixels. } \item{controllers}{Names of \code{\link{playwidget}} objects associated with this scene, or objects (typically piped in). See Details below. } \item{snapshot,webgl}{Control of mode of display of scene. See Details below. } \item{elementId}{The id to use on the HTML \code{div} component that will hold the scene. } \item{reuse}{Ignored. See Details below. } \item{webGLoptions}{A list of options to pass to WebGL when the drawing context is created. See the Details below.} \item{shared}{An object produced by \code{\link{rglShared}}, or a list of such objects.} \item{minimal}{Should attributes be skipped if they currently have no effect? See \code{\link{scene3d}}.} \item{shinyBrush}{The name of a Shiny \code{input} element to receive information about mouse selections.} \item{altText}{Text to include for screen-readers or browsers that don't handle WebGL. See Details below.} \item{oldConvertBBox, fastTransparency}{See Details below.} \item{...}{Additional arguments to pass to \code{htmlwidgets::\link[htmlwidgets]{createWidget}}.} } \details{ This produces a WebGL version of an RGL scene using the \pkg{htmlwidgets} framework. This allows display of the scene in the RStudio IDE, a browser, an \pkg{rmarkdown} document or in a \pkg{shiny} app. \code{options(rgl.printRglwidget = TRUE)} will cause \code{rglwidget()} to be called and displayed when the result of an RGL call that changes the scene is printed. In RMarkdown or in standalone code, you can use a \pkg{magrittr}-style \dQuote{pipe} command to join an \code{rglwidget} with a \code{\link{playwidget}} or \code{\link{toggleWidget}}. If the control widget comes first, it should be piped into the \code{controllers} argument. If the \code{rglwidget} comes first, it can be piped into the first argument of \code{playwidget} or \code{toggleWidget}. In earlier versions, the \code{reuse} argument let one output scene share data from earlier ones. This is no longer supported. If \code{elementId} is \code{NULL} and we are not in a Shiny app, \code{elementId} is set to a random value to facilitate re-use of information. To save the display to a file, use \code{htmlwidgets::\link[htmlwidgets]{saveWidget}}. This requires \command{pandoc} to be installed. For a snapshot, you can use \code{htmltools::save_html(img(src=rglwidget(snapshot=TRUE)), file = ...)}. The \code{webGLoptions} argument is a list which will be passed when the WebGL context is created. See the WebGL 1.0 specification on \url{https://registry.khronos.org/webgl/} for possible settings. The default in \code{rglwidget} differs from the WebGL default by setting \code{preserveDrawingBuffer = TRUE} in order to allow other tools to read the image, but please note that some implementations of WebGL contain bugs with this setting. We have attempted to work around them, but may change our default in the future if this proves unsatisfactory. The \code{webgl} argument controls whether a dynamic plot is displayed in HTML. In LaTeX and some other formats dynamic plots can't be displayed, so if the \code{snapshot} argument is \code{TRUE}, \code{webgl} must be \code{FALSE}. (In previous versions of the \pkg{rgl} package, both \code{webgl} and \code{snapshot} could be \code{TRUE}; that hasn't worked for a while and is no longer allowed as of version 0.105.6.) The \code{snapshot} argument controls whether a snapshot is displayed: it must be \code{!webgl} if both are specified. Prior to \pkg{rgl} 0.106.21, \code{rglwidget} converted bounding box decorations into separate objects: a box, text for the labels, segments for the ticks. By default it now generates these in Javascript, allowing axis labels to move as they do in the display in \R. If you prefer the old conversion, set \code{oldConvertBBox = TRUE}. In version 1.3.4, the handling of transparent objects was changed to match the \pkg{rgl} device more closely. The new method of rendering is quite a bit faster, though sometimes less accurate. To get the older drawing method set \code{fastTransparency = FALSE}. } \section{R Markdown specifics}{ In an R Markdown document, you would normally call \code{\link{setupKnitr}(autoprint = TRUE)} and would not make explicit calls to \code{rglwidget()}. If you do make such calls, the graphics will be inserted into the document. In \pkg{knitr} versions greater than 1.42.5, the \code{altText} argument will be ignored and the alternate text will be set from chunk option \code{fig.alt} or \code{fig.cap} as with other graphics. } \section{Shiny specifics}{ This widget is designed to work with Shiny for interactive displays linked to a server running R. In a Shiny app, there will often be one or more \code{\link{playwidget}} objects in the app, taking input from the user. In order to be sure that the initial value of the user control is reflected in the scene, you should list all players in the \code{controllers} argument. See the sample application in \code{system.file("shinyDemo", package = "rglwidget")} for an example. In Shiny, it is possible to find out information about mouse selections by specifying the name of an \code{input} item in the \code{shinyBrush} argument. For example, with \code{shinyBrush = "brush3d"}, each change to the mouse selection will send data to \code{input$brush3d} in an object of class \code{"rglMouseSelection"} with the following components: \describe{ \item{subscene}{The ID of the subscene where the mouse is selecting.} \item{state}{Either \code{"changing"} or \code{"inactive"}.} \item{region}{The coordinates of the corners of the selected region in the window, in order \code{c(x1, y1, x2, y2)}.} \item{model, proj, view}{The model matrix, projection matrix and viewport in effect at that location.} } This object can be used as the first argument to \code{\link{selectionFunction3d}} to produce a test function for whether a particular location is in the selected region. If the brush becomes inactive, an object containing only the \code{state} field will be sent, with value \code{"inactive"}. } \value{ An object of class \code{"htmlwidget"} (or \code{"shiny.tag.list"} if pipes are used) that will intelligently print itself into HTML in a variety of contexts including the R console, within R Markdown documents, and within Shiny output bindings. If objects are passed in the \code{shared} argument, then the widget will respond to selection and filtering applied to those as shared datasets. See \code{\link{rglShared}} for more details and an example. } \section{Appearance}{ The appearance of the display is set by the stylesheet in \code{system.file("htmlwidgets/lib/rglClass/rgl.css")}. The widget is of class \code{rglWebGL}, with id set according to \code{elementId}. (As of this writing, no special settings are given for class \code{rglWebGL}, but you can add your own.) } \author{ Duncan Murdoch } \seealso{ \code{\link{hook_webgl}} for an earlier approach to this problem. \code{\link{rglwidgetOutput}} for Shiny details. The \HTMLVignette{WebGL}{}{User Interaction in WebGL} vignette gives more details. } \examples{ save <- options(rgl.useNULL=TRUE) example("plot3d", "rgl") widget <- rglwidget() if (interactive() || in_pkgdown_example()) widget \donttest{ if (interactive() && !in_pkgdown_example()) { # Save it to a file. This requires pandoc filename <- tempfile(fileext = ".html") htmlwidgets::saveWidget(rglwidget(), filename) browseURL(filename) } } options(save) } rgl/man/rgl.select.Rd0000644000176200001440000000143414771520323014150 0ustar liggesusers\name{rgl.select} \alias{rgl.select} \title{ Switch to select mode, and return the mouse position selected } \description{ Mostly for internal use, this function temporarily installs a handler on a button of the mouse that will return the mouse coordinates of one click and drag rectangle. } \usage{ rgl.select(button = c("left", "middle", "right"), dev = cur3d(), subscene = currentSubscene3d(dev)) } \arguments{ \item{button}{ Which button to use? } \item{dev, subscene}{ The RGL device and subscene to work with } } \value{ A vector of four coordinates: the X and Y coordinates of the start and end of the dragged rectangle. } \author{ Duncan Murdoch } \seealso{ \code{\link{select3d}}, a version that allows the selection region to be used to select points in the scene. } rgl/man/plotmath3d.Rd0000644000176200001440000000447114771520323014171 0ustar liggesusers\name{plotmath3d} \alias{plotmath3d} \title{ Draw text using base graphics math plotting } \description{ To plot mathematical text, this function uses base graphics functions to plot it to a \file{.png} file, then uses that file as a texture in a sprite. } \usage{ plotmath3d(x, y = NULL, z = NULL, text, cex = par("cex"), adj = 0.5, pos = NULL, offset = 0.5, fixedSize = TRUE, startsize = 480, initCex = 5, margin = "", floating = FALSE, tag = "", ...) } \arguments{ \item{x, y, z}{coordinates. Any reasonable way of defining the coordinates is acceptable. See the function \code{\link[grDevices]{xyz.coords}} for details.} \item{text}{ A character vector or expression. See \code{\link[grDevices]{plotmath}} for how expressions are interpreted. } \item{cex}{ Character size expansion. } \item{adj}{ one value specifying the horizontal adjustment, or two, specifying horizontal and vertical adjustment respectively, or three, for depth as well. } \item{pos, offset}{ alternate way to specify \code{adj}; see \code{\link{text3d}}} \item{fixedSize}{ Should the resulting sprite behave like the default ones, and resize with the scene, or like text, and stay at a fixed size? } \item{startsize, initCex}{ These parameters are unlikely to be needed by users. \code{startsize} is an over-estimate of the size (in pixels) of the largest expression. Increase this if large expressions are cut off. \code{initCex} is the size of text used to form the bitmap. Increase this if letters look too blurry at the desired size. } \item{margin, floating, tag}{ \code{\link{material3d}} properties. } \item{\dots}{ Additional arguments to pass to \code{\link[graphics]{text}} when drawing the text. } } \note{ The \code{\link{text3d}} function passes calls to this function if its \code{usePlotmath} argument is \code{TRUE}. This is the default value if its \code{texts} argument looks like an expression. } \value{ Called for the side effect of displaying the sprites. The shape ID of the displayed object is returned. } \author{ Duncan Murdoch } \seealso{ \code{\link{text3d}} } \examples{ open3d() plotmath3d(1:3, 1:3, 1:3, expression(x[1] == 1, x[2] == 2, x[3] == 3)) # This lets the text resize with the plot text3d(4, 4, 4, "resizeable text", usePlotmath = TRUE, fixedSize = FALSE) }rgl/man/macros/0000755000176200001440000000000015026471106013077 5ustar liggesusersrgl/man/macros/macros.Rd0000644000176200001440000000250015026471106014647 0ustar liggesusers% Macro to create link to an HTML vignette from a help page. In % this version the vignette must be in the same package as the help % page % arg 1 is the name of the vignette (without .html) % arg 2 is an optional anchor within the vignette (without the leading #) % arg 3 is the text to show on the link. % Use the RdVignettePath environment variable if vignettes aren't stored % in ../doc/, e.g. pkgdown puts them in ../articles/. \newcommand{\HTMLVignette}{\Sexpr[stage=build,results=rd]{ local({anchor <- "#2" if (nchar(anchor)) anchor <- paste0("#", anchor) vigpath <- Sys.getenv("RdVignettePath", unset = "../doc/") paste0("\\\\\\\\href{", vigpath, "#1.html", anchor, "}{#3}") })}} % Macro to create link to an HTML vignette in another package on CRAN % from a help page. % arg 1 is the package name % arg 2 is the name of the vignette (without .html) % arg 3 is an optional anchor within the vignette (without the leading #) % arg 4 is the text to show on the link. \newcommand{\HTMLVignetteCRAN}{\Sexpr[stage=build,results=rd]{ local({anchor <- "#3" if (nchar(anchor)) anchor <- paste0("#", anchor) paste0("\\\\\\\\href{https://cran.r-project.org/package=#1/vignettes/#2.html", anchor, "}{#4}") })}} rgl/man/rglIds.Rd0000644000176200001440000000344714771520323013340 0ustar liggesusers\name{rglIds} \alias{lowlevel} \alias{highlevel} \alias{rglId} \alias{rglLowlevel} \alias{rglHighlevel} \alias{print.rglId} \title{ RGL id values } \description{ All objects in an RGL scene have a numerical id. These ids are normally stored in vectors of class \code{c("rglIds", "numeric")}, which will also have class \code{"rglHighlevel"} or \code{"rglLowlevel"} depending on whether a high level function like \code{\link{plot3d}} or \code{\link{persp3d}}, or a low level function created the objects. } \usage{ rglId(ids = integer()) lowlevel(ids = integer()) highlevel(ids = integer()) \method{print}{rglId}(x, rglwidget = getOption("rgl.printRglwidget", FALSE), ...) } \arguments{ \item{ids}{ A vector of object ids. } \item{x}{ An \code{"rglId"} object to print. } \item{rglwidget}{ Whether to create and print an RGL widget. If false, nothing is printed. } \item{...}{ Other arguments which will be passed to \code{\link{rglwidget}} if it is used. } } \details{ These functions and classes are intended to allow RGL scenes to be automatically displayed in R Markdown documents. See \code{\link{setupKnitr}} for details on enabling auto-printing. Note that \emph{all} objects in the current scene will be printed by default, not just the ids in \code{x}. (One reason for this is that lights are also objects; printing objects without lights would rarely make sense.) } \value{ Objects of class \code{"rglId"}, \code{c("rglHighlevel", "rglId", "numeric")} or \code{c("rglLowlevel", "rglId", "numeric")} for \code{rglId}, \code{lowlevel} or \code{highlevel} respectively. } \author{ Duncan Murdoch } \examples{ x <- matrix(rnorm(30), ncol = 3, dimnames = list(NULL, c("x", "y", "z"))) p <- plot3d(x, type = "s") str(p) if (interactive() || in_pkgdown_example()) print(p, rglwidget = TRUE) } rgl/man/rglShared.Rd0000644000176200001440000000710615012460301014007 0ustar liggesusers\name{rglShared} \alias{rglShared} \title{ Create shared data from an RGL object } \description{ The \pkg{crosstalk} package provides a way for different parts of an interactive display to communicate about datasets, using \dQuote{shared data} objects. When selection or filtering is performed in one view, the result is mirrored in all other views. This function allows vertices of RGL objects to be treated as shared data. } \usage{ rglShared(id, key = NULL, group = NULL, deselectedFade = 0.1, deselectedColor = NULL, selectedColor = NULL, selectedIgnoreNone = TRUE, filteredFade = 0, filteredColor = NULL) } \arguments{ \item{id}{ An existing RGL id. } \item{key}{ Optional unique labels to apply to each vertex. If missing, numerical keys will be used. } \item{group}{ Optional name of the shared group to which this data belongs. If missing, a random name will be generated. } \item{deselectedFade, deselectedColor}{ Appearance of points that are not selected. See Details. } \item{selectedColor}{ Appearance of points that are selected. } \item{selectedIgnoreNone}{ If no points are selected, should the points be shown in their original colors (\code{TRUE}), or in the deselected colors (\code{FALSE})? } \item{filteredFade, filteredColor}{ Appearance of points that have been filtered out. } } \details{ Some functions which normally work on dataframe-like datasets will accept shared data objects in their place. If a selection is in progress, the alpha value for unselected points is multiplied by \code{deselectedFade}. If \code{deselectedColor} is \code{NULL}, the color is left as originally specified; if not, the point is changed to the color given by \code{deselectedColor}. If no points have been selected, then by default points are shown in their original colors. However, if \code{selectedIgnoreNone = FALSE}, all points are displayed as if unselected. The \code{selectedColor} argument is similarly used to change the color (or not) of selected points, and \code{filteredFade} and \code{filteredColor} are used for points that have been filtered out of the display. } \value{ An object of class \code{"SharedData"} (from the optional \pkg{crosstalk} package) which contains the x, y and z coordinates of the RGL object with the given \code{id}. } \references{ \url{https://rstudio.github.io/crosstalk/index.html} } \author{ Duncan Murdoch } \seealso{ The \HTMLVignette{WebGL}{}{User Interaction in WebGL} vignette gives more details. } \examples{ save <- options(rgl.useNULL = TRUE) # rglShared requires the crosstalk package, # and the slider and rglMouse require manipulateWidget if (requireNamespace("crosstalk", quietly = TRUE) && requireNamespace("manipulateWidget", quietly = TRUE)) { open3d() x <- sort(rnorm(100)) y <- rnorm(100) z <- rnorm(100) + atan2(x, y) ids <- plot3d(x, y, z, col = rainbow(100)) # The data will be selected and filtered, not the axes. sharedData <- rglShared(ids["data"]) # Also add some labels that are only displayed # when points are selected sharedLabel <- rglShared(text3d(x, y, z, text = 1:100, adj = -0.5), group = sharedData$groupName(), deselectedFade = 0, selectedIgnoreNone = FALSE) if (interactive() || in_pkgdown_example()) crosstalk::filter_slider("x", "x", sharedData, ~x) \%>\% rglwidget(shared = list(sharedData, sharedLabel), controller = .) \%>\% rglMouse() } options(save) } rgl/man/rglFonts.Rd0000644000176200001440000000530314771520323013703 0ustar liggesusers\name{rglFonts} \alias{rglFonts} \title{ Specify FreeType fonts } \description{ Specify FreeType fonts for use in \pkg{rgl} graphics. } \usage{ rglFonts(...) } \arguments{ \item{ ... }{Device dependent font definitions for use with FreeType.} } \details{ FreeType fonts are specified using the \code{rglFonts} function. This function takes a vector of four filenames of TrueType font files which will be used for the four styles regular, bold, italic and bold italic. The vector is passed with a name to be used as the family name, e.g. \code{rglFonts(sans = c("/path/to/FreeSans.ttf", ...))}. In order to limit the file size, the \pkg{rgl} package ships with just 3 font files, for regular versions of the \code{serif}, \code{sans} and \code{mono} families. Additional free font files were available in the past from the Amaya project, though currently the \code{\link{rglExtrafonts}} function provides an easier way to register new fonts. On Windows the system fonts are acceptable and are used when \code{useFreeType = FALSE} (the current default in \code{\link{r3dDefaults}}). Mappings to \code{family} names are controlled by the \code{grDevices::windowsFonts()} function. Full pathnames should normally be used to specify font files. If relative paths are used, they are interpreted differently by platform. Currently Windows fonts are looked for in the Windows fonts folder, while other platforms use the current working directory. If FreeType fonts are not used, then bitmapped fonts will be used instead. On Windows these will be based on the fonts specified using the #ifdef windows \code{\link{windowsFonts}} #endif #ifndef windows \code{windowsFonts} #endif function, and are resizable. Other platforms will use the default bitmapped font which is not resizable. Bitmapped fonts have a limited number of characters supported; if any unsupported characters are used, an error will be thrown. } \value{ the current set of font definitions. } \seealso{\code{\link{text3d}}} \examples{ \dontrun{ # These FreeType fonts are available from the Amaya project, and are not shipped # with rgl. You would normally install them to the rgl/fonts directory # and use fully qualified pathnames, e.g. # system.file("fonts/FreeSerif.ttf", package = "rgl") rglFonts(serif = c("FreeSerif.ttf", "FreeSerifBold.ttf", "FreeSerifItalic.ttf", "FreeSerifBoldItalic.ttf"), sans = c("FreeSans.ttf", "FreeSansBold.ttf", "FreeSansOblique.ttf", "FreeSansBoldOblique.ttf"), mono = c("FreeMono.ttf", "FreeMonoBold.ttf", "FreeMonoOblique.ttf", "FreeMonoBoldOblique.ttf"), symbol= c("ESSTIX10.TTF", "ESSTIX12.TTF", "ESSTIX9_.TTF", "ESSTIX11.TTF")) } } rgl/man/rgl.bringtotop.Rd0000644000176200001440000000162014771520323015055 0ustar liggesusers\name{rgl.bringtotop} \alias{rgl.bringtotop} \title{Assign focus to an RGL window } \description{ 'rgl.bringtotop' brings the current RGL window to the front of the window stack (and gives it focus).} \usage{ rgl.bringtotop(stay = FALSE) } \arguments{ \item{stay}{whether to make the window stay on top.} } \details{ If \code{stay} is \code{TRUE}, then the window will stay on top of normal windows. } \author{ Ming Chen/Duncan Murdoch } \note{not completely implemented for X11 graphics (stay not implemented; window managers such as KDE may block this action (set "Focus stealing prevention level" to None in Control Center/Window Behavior/Advanced)). Not currently implemented under OS/X.} #ifdef windows \seealso{\code{\link[grDevices]{bringToTop}}} #endif \examples{ open3d() points3d(rnorm(1000), rnorm(1000), rnorm(1000), color = heat.colors(1000)) rgl.bringtotop(stay = TRUE) } \keyword{ dynamic } rgl/man/rgl.pixels.Rd0000644000176200001440000000275314265301465014204 0ustar liggesusers\name{rgl.pixels} \alias{rgl.pixels} \title{ Extract pixel information from window } \description{ This function extracts single components of the pixel information from the topmost window. } \usage{ rgl.pixels(component = c("red", "green", "blue"), viewport = par3d("viewport"), top = TRUE) } \arguments{ \item{component}{ Which component(s)? } \item{viewport}{ Lower left corner and size of desired region. } \item{top}{ Whether to bring window to top before reading. } } \details{ The possible components are \code{"red"}, \code{"green"}, \code{"blue"}, \code{"alpha"}, \code{"depth"}, and \code{"luminance"} (the sum of the three colors). All are scaled from 0 to 1. Note that the luminance is kept below 1 by truncating the sum; this is the definition used for the \code{GL_LUMINANCE} component in OpenGL. } \value{ A vector, matrix or array containing the desired components. If one component is requested, a vector or matrix will be returned depending on the size of block requested (length 1 dimensions are dropped); if more, an array, whose last dimension is the list of components. } \author{ Duncan Murdoch } \seealso{ \code{\link{rgl.snapshot}} to write a copy to a file, \code{demo("stereo")} for functions that make use of this to draw a random dot stereogram and an anaglyph. } \examples{ example(surface3d) depth <- rgl.pixels(component = "depth") if (length(depth) && is.matrix(depth)) # Protect against empty or single pixel windows contour(depth) } \keyword{ dynamic } rgl/man/elementId2Prefix.Rd0000644000176200001440000000150314771520323015251 0ustar liggesusers\name{elementId2Prefix} \alias{elementId2Prefix} \title{ Use widget with old-style controls } \description{ The \code{\link{rglwidget}} control is designed to work in the \pkg{htmlwidgets} framework. Older RGL web pages that used the deprecated \code{\link{writeWebGL}} or \pkg{knitr} used a different method of linking the controls to the scene. This is a partial bridge between the two systems. You should adopt the new system, not use this function. } \usage{ elementId2Prefix(elementId, prefix = elementId) } \arguments{ \item{elementId}{ An element identifier from a \code{\link{rglwidget}} call. } \item{prefix}{ The prefix to use in the old-style control. } } \value{ This function generates Javascript code, so it should be used in an \code{results = "asis"} block in a \pkg{knitr} document. } \author{ Duncan Murdoch } rgl/man/GramSchmidt.Rd0000644000176200001440000000245414265301464014314 0ustar liggesusers\name{GramSchmidt} \alias{GramSchmidt} \title{ The Gram-Schmidt algorithm } \description{ Generate a 3x3 orthogonal matrix using the Gram-Schmidt algorithm. } \usage{ GramSchmidt(v1, v2, v3, order = 1:3) } \arguments{ \item{v1, v2, v3}{ Three length 3 vectors (taken as row vectors). } \item{order}{ The precedence order for the vectors; see Details. } } \details{ This function orthogonalizes the matrix \code{rbind(v1, v2, v3)} using the Gram-Schmidt algorithm. It can handle rank 2 matrices (returning a rank 3 matrix). If the original is rank 1, it is likely to fail. The \code{order} vector determines the precedence of the original vectors. For example, if it is \code{c(i, j, k)}, then row \code{i} will be unchanged (other than normalization); row \code{j} will normally be transformed within the span of rows \code{i} and \code{j}. Row \code{k} will be transformed orthogonally to the span of the others. } \value{ A 3x3 matrix whose rows are the orthogonalization of the original row vectors. } \author{ Duncan Murdoch } \examples{ # Proceed through the rows in order print(A <- matrix(rnorm(9), 3, 3)) GramSchmidt(A[1, ], A[2, ], A[3, ]) # Keep the middle row unchanged print(A <- matrix(c(rnorm(2), 0, 1, 0, 0, rnorm(3)), 3, 3, byrow = TRUE)) GramSchmidt(A[1, ], A[2, ], A[3, ], order = c(2, 1, 3)) } rgl/man/extrude3d.Rd0000644000176200001440000000263714265301464014024 0ustar liggesusers\name{extrude3d} \alias{extrude3d} \title{ Generate extrusion mesh } \description{ Given a two-dimensional polygon, this generates a three-dimensional extrusion of the shape by triangulating the polygon and creating a cylinder with that shape as the end faces. } \usage{ extrude3d(x, y = NULL, thickness = 1, smooth = FALSE, ...) } \arguments{ \item{x, y}{ A polygon description in one of the forms supported by \code{\link{triangulate}}. } \item{thickness}{ The extrusion will have this thickness. } \item{smooth}{ logical; should normals be added so that the edges of the extrusion appear smooth? } \item{\dots}{ Other parameters to pass to \code{\link{tmesh3d}} when constructing the mesh. } } \details{ The extrusion is always constructed with the polygon in the xy plane at \code{z = 0} and another copy at \code{z = thickness}. Use the transformation functions (e.g. \code{\link{rotate3d}}) to obtain other orientations and placements. } \value{ A mesh object containing a triangulation of the polygon for each face, and quadrilaterals for the sides. } \author{ Duncan Murdoch } \seealso{ \code{\link{polygon3d}} for a simple polygon, \code{\link{triangulate}} for the triangulation, \code{\link{turn3d}} for a solid of rotation. } \examples{ x <- c(1:10, 10:1) y <- rev(c(rep(c(0, 2), 5), rep(c(1.5, -0.5), 5))) plot(x, y, type = "n") polygon(x, y) open3d() shade3d( extrude3d(x, y), col = "red" ) } \keyword{ graphics } rgl/man/rgl-duplicated.Rd0000644000176200001440000000146714771520323015014 0ustar liggesusers\name{rgl-duplicated} \alias{rgl.pop} \alias{rgl.cur} \alias{rgl.ids} \alias{terrain3d} \title{ Duplicated functions in \pkg{rgl} } \description{ These functions are provided for compatibility with older versions of \pkg{rgl}. See the functions in the comments for the full documentation. } \usage{ rgl.cur() # cur3d rgl.ids(type = "shapes", subscene = NA, tags = FALSE) # ids3d rgl.pop(type = "shapes", id = 0, tag = NULL) # pop3d terrain3d(x, y = NULL, z = NULL, ..., normal_x = NULL, normal_y = NULL, normal_z = NULL, texture_s = NULL, texture_t=NULL, flip = FALSE) # surface3d } \seealso{\code{\link{cur3d}}, \code{\link{ids3d}}, \code{\link{pop3d}}, \code{\link{surface3d}}} \keyword{internal} \keyword{misc}rgl/man/textureSource.Rd0000644000176200001440000000317014771520323014766 0ustar liggesusers\name{textureSource} \alias{textureSource} \title{ Retrieve source code used to produce texture file. } \description{ Internally, \pkg{rgl} works with PNG files for textures. If a texture is requested using a different format, a temporary PNG file of the image will be saved. This function allows you to retrieve the original expression used to produce the texture. } \usage{ textureSource(texture) } \arguments{ \item{texture}{ The filename of a texture file. If missing, the directory where texture files are stored will be returned. } } \details{ \pkg{rgl} creates a new file in the temporary directory whenever a non-PNG texture is used. It will delete them when it knows there are no references and at the end of the session, but conceivably there will be situations where you need to delete them earlier. Calling \code{textureSource()} with no arguments will give you the directory holding the textures so that they can be deleted sooner. } \value{ If \code{texture} is specified and it is the name of a temporary PNG texture file produced by \pkg{rgl}, the expression used to specify the texture will be returned. If it is the name of some other file, \code{texture} will be returned. If no argument is given, the session-specific directory holding the temporary texture files will be returned. } \seealso{ \code{\link{material3d}} } \examples{ xyz <- cbind(c(0,1,1,0), c(0,0,1,1), c(0,0,0,0)) st <- xyz[,1:2] open3d() id <- quads3d(xyz, texcoords = st, texture = as.raster(matrix(colors()[1:120], ncol = 10)), col="white") material3d(id = id, "texture") textureSource(material3d(id = id, "texture")) }rgl/man/rgl-defunct.Rd0000644000176200001440000000375114771520323014324 0ustar liggesusers\name{rgl-defunct} \alias{rgl-defunct} \alias{subsetSlider} \alias{subsetSetter} \alias{clipplaneSlider} \alias{toggleButton} \alias{propertySlider} \alias{propertySetter} \alias{par3dinterpSetter} \alias{matrixSetter} \alias{vertexSetter} \title{ Defunct functions in \pkg{rgl} } \description{ These functions have been removed from \pkg{rgl}. } \usage{ # Removed in version 1.0.0: subsetSlider(subsets, labels = names(subsets), fullset = Reduce(union, subsets), subscenes = currentSubscene3d(), prefixes = "", accumulate = FALSE, ...) subsetSetter(subsets, subscenes = currentSubscene3d(), prefixes = "", fullset = Reduce(union, subsets), accumulate = FALSE) clipplaneSlider(a=NULL, b=NULL, c=NULL, d=NULL, plane = 1, clipplaneids, prefixes = "", labels = signif(values[,1],3), ...) toggleButton(subset, subscenes = currentSubscene3d(), prefixes = "", label = deparse(substitute(subset)), id = paste0(basename(tempfile("input"))), name = id) propertySlider(setter = propertySetter, minS = NULL, maxS = NULL, step = 1, init = NULL, labels, id = basename(tempfile("input")), name = id, outputid = paste0(id, "text"), index = NULL, ...) propertySetter(values = NULL, entries, properties, objids, prefixes = "", param = seq_len(NROW(values)), interp = TRUE, digits = 7) par3dinterpSetter(fn, from, to, steps, subscene, omitConstant = TRUE, rename = character(), ...) matrixSetter(fns, from, to, steps, subscene = currentSubscene3d(), matrix = "userMatrix", omitConstant = TRUE, prefix = "", ...) vertexSetter(values, vertices = 1, attributes, objid, prefix = "", param = seq_len(NROW(values)), interp = TRUE, digits = 7) } \seealso{ \code{\link{Defunct}} } \keyword{internal} \keyword{misc}rgl/man/scene3d.Rd0000644000176200001440000001070714771520323013435 0ustar liggesusers\name{scene3d} \alias{scene3d} \alias{rglscene-class} \alias{rglobject-class} \alias{plot3d.rglscene} \alias{plot3d.rglobject} \alias{print.rglscene} \alias{print.rglobject} \title{ Saves the current scene to a variable, and displays such variables } \description{ This function saves a large part of the RGL state associated with the current window to a variable. } \usage{ scene3d(minimal = TRUE) \S3method{plot3d}{rglscene}(x, add = FALSE, open3dParams = getr3dDefaults(), ...) \S3method{plot3d}{rglobject}(x, ...) \S3method{print}{rglscene}(x, ...) \S3method{print}{rglobject}(x, ...) } \arguments{ \item{minimal}{Should attributes be skipped if they currently have no effect? See Details.} \item{x}{An object of class \code{"rglscene"}} \item{add}{Whether to open a new window, or add to the existing one.} \item{open3dParams}{Default parameters for \code{open3d}} \item{...}{Additional parameters passed to \code{open3d} by \code{plot3d(..., add = FALSE)}. These override \code{open3dParams}. } } \details{ The components saved are: the \code{\link{par3d}} settings, the \code{\link{material3d}} settings, the \code{\link{bg3d}} settings, the lights and the objects in the scene. In most cases, calling \code{\link{plot3d}} on that variable will duplicate the scene. (There are likely to be small differences, mostly internal, but some aspects of the scene are not currently available.) If textures are used, the name of the texture will be saved, rather than the contents of the texture file. Other than saving the code to recreate a scene, saving the result of \code{scene3d} to a file will allow it to be reproduced later most accurately. In roughly decreasing order of fidelity, \code{\link{writeWebGL}} (now deprecated), \code{\link{writePLY}}, \code{\link{writeOBJ}} and \code{\link{writeSTL}} write the scene to a file in formats readable by other software. If \code{minimal = TRUE} (the default), then attributes of objects will not be saved if they currently have no effect on the display, thereby reducing the file size. Set \code{minimal = FALSE} if the scene is intended to be used in a context where the appearance could be changed. Currently this only affects the inclusion of normals; with \code{minimal = TRUE} they are omitted for objects when the material is not lit. } \value{ The \code{scene3d} function returns an object of class \code{"rglscene"}. This is a list with some or all of the components: \item{material}{The results returned from a \code{\link{material3d}} call.} \item{rootSubscene}{A list containing information about the main ("root") subscene. This may include: \describe{ \item{id}{The scene id.} \item{type}{"subscene"} \item{par3d}{The \code{\link{par3d}} settings for the subscene.} \item{embeddings}{The \code{\link{subsceneInfo}()$embeddings} for the main subscene.} \item{objects}{The ids for objects in the subscene.} \item{subscenes}{A recursive list of child subscenes.}}} \item{objects}{A list containing the RGL lights, background and objects in the scene.} The objects in the \code{objects} component are of class \code{"rglobject"}. They are lists containing some or all of the components \item{id}{The RGL identifier of the object in the original scene.} \item{type}{A character variable identifying the type of object.} \item{material}{Components of the material that differ from the scene material.} \item{vertices, normals, etc.}{Any of the attributes of the object retrievable by \code{\link{rgl.attrib}}.} \item{ignoreExtent}{A logical value indicating whether this object contributes to the bounding box. Currently this may differ from the object in the original scene.} \item{objects}{Sprites may contain other objects; they will be stored here as a list of \code{"rglobject"}s.} Lights in the scene are stored similarly, mixed into the \code{objects} list. The \code{plot3d} methods invisibly return a vector of RGL object ids that were plotted. The \code{print} methods invisibly return the object that was printed. } \author{ Duncan Murdoch } \seealso{ \code{\link{rglwidget}}, \code{\link{writePLY}}, \code{\link{writeOBJ}} and \code{\link{writeSTL}} write the scene to a file in various formats. } \examples{ open3d() z <- 2 * volcano # Exaggerate the relief x <- 10 * (1:nrow(z)) # 10 meter spacing (S to N) y <- 10 * (1:ncol(z)) # 10 meter spacing (E to W) persp3d(x, y, z, col = "green3", aspect = "iso") s <- scene3d() # Make it bigger s$par3d$windowRect <- 1.5*s$par3d$windowRect # and draw it again plot3d(s) } \keyword{ graphics } rgl/man/grid3d.Rd0000644000176200001440000000456614265301464013274 0ustar liggesusers\name{grid3d} \alias{grid3d} \title{Add a grid to a 3D plot } \description{ This function adds a reference grid to an RGL plot. } \usage{ grid3d(side, at = NULL, col = "gray", lwd = 1, lty = 1, n = 5) } \arguments{ \item{side}{ Where to put the grid; see the Details section. } \item{at}{ How to draw the grid; see the Details section. } \item{col}{ The color of the grid lines. } \item{lwd}{ The line width of the grid lines. (Currently only \code{lty = 1} is supported.)} \item{lty}{ The line type of the grid lines. } \item{n}{ Suggested number of grid lines; see the Details section. } } \details{ This function is similar to \code{\link{grid}} in classic graphics, except that it draws a 3D grid in the plot. The grid is drawn in a plane perpendicular to the coordinate axes. The first letter of the \code{side} argument specifies the direction of the plane: \code{"x"}, \code{"y"} or \code{"z"} (or uppercase versions) to specify the coordinate which is constant on the plane. If \code{at = NULL} (the default), the grid is drawn at the limit of the box around the data. If the second letter of the \code{side} argument is \code{"-"} or is not present, it is the lower limit; if \code{"+"} then at the upper limit. The grid lines are drawn at values chosen by \code{\link{pretty}} with \code{n} suggested locations. The default locations should match those chosen by \code{\link{axis3d}} with \code{nticks = n}. If \code{at} is a numeric vector, the grid lines are drawn at those values. If \code{at} is a list, then the \code{"x"} component is used to specify the x location, the \code{"y"} component specifies the y location, and the \code{"z"} component specifies the z location. Missing components are handled using the default as for \code{at = NULL}. Multiple grids may be drawn by specifying multiple values for \code{side} or for the component of \code{at} that specifies the grid location. } \note{ If the scene is resized, the grid will not be resized; use \code{\link{abclines3d}} to draw grid lines that will automatically resize. } \value{ A vector or matrix of object ids is returned invisibly. } \author{ Ben Bolker and Duncan Murdoch } \seealso{ \code{\link{axis3d}} } \examples{ x <- 1:10 y <- 1:10 z <- matrix(outer(x - 5, y - 5) + rnorm(100), 10, 10) open3d() persp3d(x, y, z, col = "red", alpha = 0.7, aspect = c(1, 1, 0.5)) grid3d(c("x", "y+", "z")) } \keyword{ dynamic } rgl/man/arrow3d.Rd0000644000176200001440000000665014771520323013474 0ustar liggesusers\name{arrow3d} \alias{arrow3d} \title{ Draw an arrow } \description{ Draws various types of arrows in a scene. } \usage{ arrow3d(p0 = c(1, 1, 1), p1 = c(0, 0, 0), barblen, s = 1/3, theta = pi/12, type = c("extrusion", "lines", "flat", "rotation"), n = 3, width = 1/3, thickness = 0.618 * width, spriteOrigin = NULL, plot = TRUE, ...) } \arguments{ \item{p0}{ The base of the arrow. } \item{p1}{ The head of the arrow. } \item{barblen}{ The length of the barbs (in display coordinates). Default given by \code{s}. } \item{s}{ The length of the barbs as a fraction of line length. Ignored if \code{barblen} is present. } \item{theta}{ Opening angle of barbs } \item{type}{ Type of arrow to draw. Choose one from the list of defaults. Can be abbreviated. See below. } \item{n}{ Number of barbs. } \item{width}{ Width of shaft as fraction of barb width. } \item{thickness}{ Thickness of shaft as fraction of barb width. } \item{spriteOrigin}{ If arrow is to be replicated as sprites, the origins relative to which the sprites are drawn. } \item{plot}{ If \code{TRUE} (the default), plot the object; otherwise return the computed data that would be used to plot it. } \item{\dots}{ Material properties passed to \code{\link{polygon3d}}, \code{\link{shade3d}} or \code{\link{segments3d}}. } } \details{ Four types of arrows can be drawn. The shapes of all of them are affected by \code{p0}, \code{p1}, \code{barblen}, \code{s}, \code{theta}, material properties in \code{...}, and \code{spriteOrigin}. Other parameters only affect some of the types, as shown. \describe{ \item{\code{"extrusion"}}{(default) A 3-dimensional flat arrow, drawn with \code{\link{shade3d}}. Affected by \code{width}, \code{thickness} and \code{smooth}.} \item{\code{"lines"}}{Drawn with lines, similar to \code{\link{arrows}}, drawn with \code{\link{segments3d}}. Affected by \code{n}.} \item{\code{"flat"}}{A flat arrow, drawn with \code{\link{polygon3d}}. Affected by \code{width} and \code{smooth}.} \item{\code{"rotation"}}{A solid of rotation, drawn with \code{\link{shade3d}}. Affected by \code{n} and \code{width}.} } Normally this function draws just one arrow from \code{p0} to \code{p1}, but if \code{spriteOrigin} is given (in any form that \code{\link{xyz.coords}(spriteOrigin)} can handle), arrows will be drawn for each point specified, with \code{p0} and \code{p1} interpreted relative to those origins. The arrows will be drawn as 3D sprites which will maintain their orientation as the scene is rotated, so this is a good way to indicate particular locations of interest in the scene. } \value{ If \code{plot = TRUE} (the default), this is called mainly for the side effect of drawing the arrow; invisibly returns the id(s) of the objects drawn. If \code{plot = FALSE}, the data that would be used in the plot (not including material properties) is returned. } \author{ Design based on \code{heplots::arrow3d}, which contains modifications by Michael Friendly to a function posted by Barry Rowlingson to R-help on 1/10/2010. Additions by Duncan Murdoch. } \examples{ xyz <- matrix(rnorm(300), ncol = 3) plot3d(xyz) arrow3d(xyz[1,], xyz[2,], type = "extrusion", col = "red") arrow3d(xyz[3,], xyz[4,], type = "flat", col = "blue") arrow3d(xyz[5,], xyz[6,], type = "rotation", col = "green") arrow3d(xyz[7,], xyz[8,], type = "lines", col = "black") arrow3d(spriteOrigin = xyz[9:12,], col = "purple") }rgl/man/checkDeldir.Rd0000644000176200001440000000066514771520323014314 0ustar liggesusers\name{checkDeldir} \alias{checkDeldir} \title{ Check for a compatible version of \pkg{deldir} } \description{ Version 1.0-2 of \pkg{deldir} is not compatible with \pkg{rgl}. This allows code to avoid trying to call it. } \usage{ checkDeldir(error = FALSE) } \arguments{ \item{error}{ If \code{TRUE}, stop with an error. } } \value{ Returns \code{TRUE} if \pkg{deldir} is available in a compatible version. } \examples{ checkDeldir() } rgl/man/rgl.getAxisCallback.Rd0000644000176200001440000000105414771520323015710 0ustar liggesusers\name{rgl.getAxisCallback} \alias{rgl.getAxisCallback} \title{ Get user-defined axis labelling callbacks. } \description{ This function gets a user-defined axis labelling callback in R. } \usage{ rgl.getAxisCallback(axis, dev = cur3d(), subscene = currentSubscene3d(dev)) } \arguments{ \item{axis}{ Which axis? Can be value from \code{1:3}. } \item{dev, subscene}{ The RGL device and subscene to work with. } } \value{ The callback function. } \seealso{\code{\link{setAxisCallbacks}} to work with \code{\link{rglwidget}}. } \author{ Duncan Murdoch } rgl/man/subsceneInfo.Rd0000644000176200001440000000274014771520323014532 0ustar liggesusers\name{subsceneInfo} \alias{subsceneInfo} \title{ Get information on subscenes } \description{ This function retrieves information about the tree of subscenes shown in the active window. } \usage{ subsceneInfo(id = NA, embeddings, recursive = FALSE) } \arguments{ \item{id}{ Which subscene to report on; \code{NA} is the current subscene. Set to \code{"root"} for the root. } \item{embeddings}{ Optional new setting for the embeddings for this subscene. } \item{recursive}{ Whether to report on children recursively. } } \details{ In RGL, each window contains a tree of \dQuote{subscenes}, each containing views of a subset of the objects defined in the window. Rendering in each subscene depends on the viewport, the projection, and the model transformation. Each of these characteristics may be inherited from the parent (\code{embedding[i] = "inherit"}), may modify the parent (\code{embedding[i] = "modify"}), or may replace the parent (\code{embedding[i] == "replace"}). All three must be specified if \code{embeddings} is used. } \value{ \item{id}{The object id of the subscene} \item{parent}{The object id of the parent subscene, if any} \item{children}{If \code{recursive}, a list of the information for the children, otherwise just their object ids.} \item{embedding}{A vector of 3 components describing how this subscene is embedded in its parent. } } \author{ Duncan Murdoch } \seealso{ \code{\link{newSubscene3d}} } \examples{ example(plot3d) subsceneInfo() } \keyword{ graphics } rgl/man/mesh3d.Rd0000644000176200001440000000626514771520323013300 0ustar liggesusers\name{mesh3d} \alias{shape3d} \alias{mesh3d} \alias{qmesh3d} \alias{tmesh3d} \title{Construct 3D mesh objects} \description{ Creates meshes containing points, segments, triangles and quads. } \usage{ mesh3d( x, y = NULL, z = NULL, vertices, material = NULL, normals = NULL, texcoords = NULL, points = NULL, segments = NULL, triangles = NULL, quads = NULL, meshColor = c("vertices", "edges", "faces", "legacy")) qmesh3d(vertices, indices, homogeneous = TRUE, material = NULL, normals = NULL, texcoords = NULL, meshColor = c("vertices", "edges", "faces", "legacy")) tmesh3d(vertices, indices, homogeneous = TRUE, material = NULL, normals = NULL, texcoords = NULL, meshColor = c("vertices", "edges", "faces", "legacy")) } \arguments{ \item{x, y, z}{coordinates. Any reasonable way of defining the coordinates is acceptable. See the function \code{\link[grDevices]{xyz.coords}} for details.} \item{vertices}{A 4 row matrix of homogeneous coordinates; takes precedence over \code{x, y, z}.} \item{material}{material properties for later rendering} \item{normals}{normals at each vertex} \item{texcoords}{texture coordinates at each vertex} \item{points}{vector of indices of vertices to draw as points} \item{segments}{2 x n matrix of indices of vertices to draw as segments} \item{triangles}{3 x n matrix of indices of vertices to draw as triangles} \item{quads}{4 x n matrix of indices of vertices to draw as quads} \item{indices}{(obsolete) 3 or 4 x n matrix of vertex indices} \item{homogeneous}{(obsolete) should \code{tmesh3d} and \code{qmesh3d} vertices be assumed to be homogeneous?} \item{meshColor}{how should colours be interpreted? See details in \code{\link{shade3d}}.} } \details{ These functions create \code{mesh3d} objects, which consist of a matrix of vertex coordinates together with a matrices of indices indicating how the vertices should be displayed, and material properties. The \code{"shape3d"} class is a general class for shapes that can be plotted by \code{dot3d}, \code{wire3d} or \code{shade3d}. The \code{"mesh3d"} class is a class of objects that form meshes: the vertices are in member \code{vb}, as a 4 by \code{n} matrix using homogeneous coordinates. Indices of these vertices are contained in optional components \code{ip} for points, \code{is} for line segments, \code{it} for triangles, and \code{ib} for quads. Individual meshes may have any combination of these. The functions \code{tmesh3d} and \code{qmesh3d} are included for back-compatibility; they produce meshes of triangles and quads respectively. } \value{ Objects of class \code{c("mesh3d", "shape3d")}. See \code{\link{points3d}} for a discussion of texture coordinates. } \examples{ # generate a quad mesh object vertices <- c( -1.0, -1.0, 0, 1.0, -1.0, 0, 1.0, 1.0, 0, -1.0, 1.0, 0 ) indices <- c( 1, 2, 3, 4 ) open3d() wire3d( mesh3d(vertices = vertices, quads = indices) ) } \seealso{ \code{\link{shade3d}}, \code{\link{shapelist3d}} for multiple shapes } \keyword{dynamic} rgl/man/addNormals.Rd0000644000176200001440000000305414771520323014172 0ustar liggesusers\name{addNormals} \alias{addNormals} \alias{addNormals.mesh3d} \alias{addNormals.shapelist3d} \title{ Add normal vectors to objects so they render more smoothly } \description{ This generic function adds normals at each of the vertices of a polyhedron by averaging the normals of each incident face. This has the effect of making the surface of the object appear smooth rather than faceted when rendered. } \usage{ addNormals(x, ...) \method{addNormals}{mesh3d}(x, angleWeighted = TRUE, ...) } \arguments{ \item{x}{An object to which to add normals.} \item{\dots}{Additional parameters which will be passed to the methods.} \item{angleWeighted}{See Details below.} } \details{ Currently methods are supplied for \code{\link[=mesh3d]{"mesh3d"}} and \code{\link[=shapelist3d]{"shapelist3d"}} classes. These methods work by averaging the normals on the faces incident at each vertex. By default these are weighted according to the angle in the polygon at that vertex. If \code{angleWeighted = FALSE}, a slightly faster but less accurate weighting by the triangle area is used. Prior to \pkg{rgl} version 0.104.12 an incorrect weighting was used; it can be partially reproduced by using \code{angleWeighted = NA}, but not all the bugs in that scheme will be kept. } \value{ A new object of the same class as \code{x}, with normals added. } \author{ Duncan Murdoch } \examples{ open3d() y <- subdivision3d(tetrahedron3d(col = "red"), depth = 3) shade3d(y) # No normals y <- addNormals(y) shade3d(translate3d(y, x = 1, y = 0, z = 0)) # With normals } \keyword{dynamic} rgl/man/toggleWidget.Rd0000644000176200001440000000404015012460301014513 0ustar liggesusers\name{toggleWidget} \alias{toggleWidget} \title{ An HTML widget to toggle display of elements of a scene } \description{ This function produces a button in an HTML scene that will toggle the display of items in the scene. } \usage{ toggleWidget(sceneId, ids = tagged3d(tags), tags = NULL, hidden = integer(), subscenes = NULL, label, ...) } \arguments{ \item{sceneId}{ The HTML id of the RGL scene being controlled, or an object as in \code{\link{playwidget}}. } \item{ids, hidden}{ The RGL id numbers of the objects to toggle. Those in \code{ids} are initially shown; those in \code{hidden} are initially hidden. } \item{tags}{ Alternate way to specify \code{ids}. Ignored if \code{ids} is given. } \item{subscenes}{ The subscenes in which to toggle the objects. } \item{label}{ The label to put on the button. The default is set from the expression passed to \code{ids} or the value of \code{tags}. } \item{\dots}{ Additional arguments to pass to \code{\link{playwidget}}. } } \details{ Like \code{\link{playwidget}}, this function is designed to work within the \pkg{htmlwidgets} framework. If the value is printed, the button will be inserted into the output. It is also designed to work with \pkg{magrittr}-style pipes: the result of \code{\link{rglwidget}} or other widgets can be piped into it to add it to a display. It can also appear first in the pipeline, if \code{sceneId} is set to \code{NA}. } \value{ A widget suitable for use in an \pkg{Rmarkdown}-generated web page, or elsewhere. } \author{ Duncan Murdoch } \seealso{ \code{\link{toggleButton}} for the older style of HTML control. The \HTMLVignette{WebGL}{}{User Interaction in WebGL} vignette gives more details. } \examples{ theplot <- plot3d(rnorm(100), rnorm(100), rnorm(100), col = "red") widget <- rglwidget(height = 300, width = 300) \%>\% toggleWidget(theplot["data"], hidden = theplot[c("xlab", "ylab", "zlab")], label = "Points") if (interactive() || in_pkgdown_example()) widget } rgl/man/figures/0000755000176200001440000000000015011677075013266 5ustar liggesusersrgl/man/figures/READMEpolyhedra-1.-rgl.png0000644000176200001440000002433415011677075017645 0ustar liggesusersPNG  IHDRAsRGB IDATx{U՝翷GI/FQ3XF*{t5;c!]cukI'j#QtN!IL3 ДFc:FA(P9ǭsy}>úp=4M@!BHL$=B!R,(B!$V(B!$V(B!$V(B!$V(B!$V(B!$V(B!$V(B!$V(B!$V(B!$V(B!$V(B!$V(B!$V(B!$V(B!$V(B!$V(B!$V(B!$V(B!$V(B!$V(B!$V(B!$V(B!$V(B!$V(B!$VNHzBHj5,FOH%Oܳ J%io~ xc,;*?3)厒iZғ B{n{'=T6SxzFjXfqgb1k΢6(ґT!7+NH5_ܭΥIO#T?PՇ,]D%Ի:= ۛ4GU@EPJ(Z E{q@ τⅉ2{/ehp /R;P7B-6}>GG]|;*|!$\wx󣷓F(z*> Qt)-zO+baO+QB }7~fqU?1M<TAJ҅\ʹHv0ʧ%4z"wv[IOz,5ϕ-V(٣Qs/ݿCi|ޥ/"ԡ 3|&YPi\hi"~'{8_zco1NC "fֿC[F$>xXX(碈vg]8kT>u߁m?}jPVԡFoEUgTDRRI K<`,`,;G~ 0 RDke;6rhۿ`_|NV/C ޣ( 84ST ԡY'xȯJpU2> 霁!swnm7iXWKLIz FGi*TU< O@[ k?U˝NԸ-"~ qũ‰n}GzT.FL#0So.wT&fIl^ AOaDzj2D ,?fY(tzwOq..~i똁Q4gQ7PV=OBu! tcm6QDG>ϙyΙyŒF>/i_[^-/(E;%4}D!礄CųTZ5Z4],-G.ez%ٞ8&NMʣX?1]?"qӭ`(,V[P"?=/fԳ8x:hho΄ETiP,Z{>c 锞w8' i~&_Dy"hnÙftOqlPxH"N,F[\>1O;Q miQe߆K/+?qU7JӈCMC3ؿys^z]o8`$4SN[Y"HhulǙĆOGt'[w<͔|#%]ַ'c >xf^_s_] ]H*NP:zē|~C]>CO'yUE_AOE67"'.4Hw{G#Αg7?Ga(@+u#K["֝VLcxhc/W = V_SZ%X`4QP'ekvPuy7ųMĔ +p)_< ~m^z^F?L 0M(riRH( :5# O85T`XP(XtTq#q_D۬h5?Z,þ% r#Q^I>'߀ GKK ZJ%c$ƣyRKx\K ޼oPnAm{ERSݼ}k$v,RV@׍LjǘYe>xk;& {'ĥԅ?SP @]Z6PbN^*'t|:?'.-*Qr$ǘ3VΟu#Nt)n|045Oئ)OFBiZ3oQ:E;U"ւ#]Z䚂涯\.&"nךcĥϫ-ms]?Ox;? ཥu2QтCѰuT>i*n|{6>z iȧ%TrwT:BZ-ogD\_y=hG?TYGDK#ax~Z`k^ޟph4tφg{PJh4M>u(jh'WeMǛFطdbi}5 օ&2 CBqig;$Y]~*mt ?^ zsb8Tb$:uK%|6EyuT: i 4DZSԻImHJmMN#XEE2cբjZR$"w "$t`$B$ٶ ߯{#m565u#&S^T,6* ,HHT_}0n?.uz^$iO&ɩT* ~A HPd#8X yӹ` '',6gNID@ĞR^ |^w5^ 'cNo>NI_q?ɤM.e2*Wҥp7 @:i>ォig?Ɯ^O8=cYOJQTIp  Զ_jcled+%ciQ=Ե%ۿk qVK*ޚolxϏGP۸_B`PdM>uc\"L;1oCDеbT9TN246LVTPo`1\K>!fψE@~oȟ><gwac$-kAhwmt__`ӷK%.+@LV>?dW>u(4Di* FBaGҦٞxl+g!%ExkM՞ΟH  4|,sOw]l#w? -t5n]*Y SԼS>/][# tqo,LL8n(1!I PהkJy̸(<˧;P#|؞{P:F9oI*EgN5B1uX *[0/~?0N^SjG$eS4V.B!%zBlR)KMJxO${v`j^sgƪ-S~9wg=nIRhyM!gH[5C{vޝBɛ|0_VZs/M[~nEyxÖk]s Az^>ZLm0Nn#mg4#nO>6 Z{vn8*jdI;dRx[/IR֨5*ZJWa$I8v9c$ivq$T U~ϧ!I.+~@ FB{tN#4 =@ԬsxxZSrtjɤz(uvLw)&ȣdMXX wI_ATeitq*cn#0aZ+!m6{9.H>յs|;t ;YZ?:=;OOH$HX<>u`ώť(Sd ܶ&Jk:i>P(=E@FBք^Y4lj[N; U$O?w %k@5Cݒ2W^I_ z\y-Opzj~e6FL@K(=H(|zM}X3>ӬoѲmݾT|#B=QfxLCWFOHIbJk%hW}=xA)Jr$Ǔ7,~2 BQSD]2~{ @/is,$I'5an|dԺOu9C\ wjË1E.J.o]5l[~}St5U^wJuPN)wH3)N34CBloHH@E=-(Dh%um7!UxHi,i]iUƵ-\7'(f$rY(X2i.*UW[tfy7[.cHyvphGI=͞a?ȥSvĭIpz#h rEPdcC3zkz*xڣo|ߵLCS$ "g8QO/YC1">Aʦ@PIQ AH(i,*;^r {p~s)xQ]r/ 2ߎSpG$NۖY(IBuzF){U>S5^2uJûK@53B+H,ϠE5o mxZQ/Hֻ9]z;Ζ2^/m~󺌒:u|i7^bE) iB$5|?/^/j>{^xh$ O)+_XjWܷF^%53*OFhhh'vW<p;4"HNNfRDJ=#k9gsJ_R)|N>+)x'TKFT^=\S5 ϻ4 ER*sCCzlZiA hhT. m˿2gNE]F*v7]5^̙S^D>~q{%t|8KS8"a߁SЌ Ȣl S*ǸeR2n&h3z8R I}ݧ|_K~[H70K($کS3| %-$2JbQ oRȫHjBH&#!Hc{vPQDg(hKK=XBEMg%0d=oT,jTT4R] ݍSS(nlDKFHEѧ3;"$a zqY)ڎL]-fߣ+mcg^Ekk/~畈 z ׋. idIn|0~84Uhz?Hmj'~jWO C4kOTF@L3 ߣdzVz;Hۓ{z"I[TT!iztA /\TU(9V zE@?l) !j']$uDukML)NhC>Ukco=^iz#踺ݱ܄1ݔ*гЀG_\)!B=F@ajg'aRx2*}]_IDECvǧ*oZ4A E] /OhBI3M'(zVzI{av-zf݅m7vW~OG>GTo az?ȢaD; P>UD2!Xu]W ENsniGO ;4MK_yIcJ0""T3 ׎ )]b[q"k*'^.\TA {n˧or"ӷvWhJ`s7i[glOĻGY(g(LIz BsӿM^y% bazb P':i,{;%k/O K/z ׆ C콵 (9nfק&$E>H)M[Gp!ly aİvE13TIc#,BKQdMS P>)nzK;'/O7N=1I)P'1{g|齳G>@Ic}Z| z q2HR>sh xBepO?R"aIe_Y iO ЎJ|a IS*E P9EF((S;?:7ʧ?.kT wI^z5?Y4&;)+%p yV 22UP3z*Oy;'3 Z {TOް>$3fɴjIPh 0)iϹ'b֜^'hg-& *:%>GyW*>OQP#pz?|8G RwJ]%R]?|Ν5~HX@.ĺ5͊OXT]Ž#i~xdrd?pz]kh??π\TTU&3IDATv d~ WEC!%}_wxIEHvk*d|BvS>xOs#L'Gh %|xPtaё ˉ+=Ny]%": κ0I$:jQu!Q<QJg! .{H*KP>&X.Ccޏ]>bC.zw1tԇ.Dg~z4ꭕ:*z^Y~4;/?3OQ>In))|9)+-R7M3a0Q}mSJkCjϤnIzR>OܙzO?zzU\ML1}Sz ϸ{xAIӴLXۄgwbgGz2] @d`*OAJz&Dwmx~ 7֤KwwBd_]sQ J&"F:qEBUk= 9i,Séa=R\Ϥ{xATgqB_>j uk4Qi5L@c&^MKz:9~CxbmX s8U=*LK0\ ^IJx\l17:h6 =8joJz*T{6-L^=ᦗe7m =jb%UN%)`[Y'bN#P}mh$y'ԑ6AIO?ǣ2vɍmty:CF0oW`1tV:Ѓ؇ pq(גytRiSI(镳K]haɫQR."R |fRr#:{.>_hQhmSѷj-jZ]@$$/zT\JC?1^?X>":P Tۄ]uXzܯQlTV682z)u1T,Yye2qk͹bY6}VHPJj1F4ݒw9b3?gt0u `kd/~KI"}, \ κLPuZ{}2_(k{KVgLMz 14qA*¤ٝ(hQb!Z/ : !O1&FdԳ׋B).^3ﭔ;!A..-IѢBv-^IENDB`rgl/man/as.rglscene.Rd0000644000176200001440000000071014771520323014306 0ustar liggesusers\name{as.rglscene} \alias{as.rglscene} \title{ Convert an object to an \code{rglscene} object. } \description{ This is a placeholder generic function, to allow other packages to create \code{"rglscene"} objects compatible with the objects produced by \code{\link{scene3d}}. No methods are currently defined in \pkg{rgl}. } \usage{ as.rglscene(x, ...) } \arguments{ \item{x}{ Object to convert. } \item{\dots}{ Other parameters to pass to methods. } } rgl/man/rgl.fns.Rd0000644000176200001440000000251515011677075013465 0ustar liggesusers\name{rgl.fns} \alias{rgl.abclines} \alias{rgl.planes} \alias{rgl.clipplanes} \alias{rgl.sprites} \alias{rgl.spheres} \title{ Low level functions that should not be called by users. } \description{ These functions provide the implementation for various \code{*3d} functions designed for users to call. } \usage{ rgl.abclines(x, y = NULL, z = NULL, a, b = NULL, c = NULL, ...) rgl.planes(a, b = NULL, c = NULL, d = 0, ...) rgl.clipplanes(a, b = NULL, c = NULL, d = 0) rgl.sprites(x, y = NULL, z = NULL, radius = 1, shapes = NULL, userMatrix, fixedSize = FALSE, adj = 0.5, pos = NULL, offset = 0.25, rotating = FALSE, ...) rgl.spheres(x, y = NULL, z = NULL, radius, fastTransparency = TRUE, ...) } \arguments{ \item{x, y, z}{ Coordinates of points } \item{a, b, c}{ Coordinates of the direction vectors for the lines, or normals for the planes. } \item{d}{Plane offset.} \item{radius}{Size of sprites or spheres.} \item{fixedSize, rotating}{Fixed size, changing orientation.} \item{fastTransparency}{Sphere drawing strategy.} \item{adj, pos, offset}{Positioning.} \item{...}{ Material properties. } } \details{ See the corresponding \code{*3d} function: \code{\link{abclines3d}}, \code{\link{planes3d}}, \code{\link{clipplanes3d}}, \code{\link{sprites3d}}, \code{\link{spheres3d}}. } \keyword{internal} rgl/man/writeOBJ.Rd0000644000176200001440000001113314771520323013570 0ustar liggesusers\name{writeOBJ} \alias{writeOBJ} \alias{readOBJ} \title{ Read and write Wavefront OBJ format files } \description{ \code{writeOBJ} writes OBJ files. This is a file format that is commonly used in 3D graphics applications. It does not represent text, but does represent points, lines, polygons (and many other types that RGL doesn't support). \code{readOBJ} reads only some parts of OBJ files. } \usage{ writeOBJ(con, pointRadius = 0.005, pointShape = icosahedron3d(), lineRadius = pointRadius, lineSides = 20, pointsAsPoints = FALSE, linesAsLines = FALSE, withNormals = TRUE, withTextures = TRUE, separateObjects = TRUE, ids = tagged3d(tags), tags = NULL) readOBJ(con, ...) } \arguments{ \item{con}{ A connection or filename. } \item{pointRadius, lineRadius}{ The radius of points and lines relative to the overall scale of the figure, if they are converted to polyhedra. } \item{pointShape}{ A mesh shape to use for points if they are converted. It is scaled by the \code{pointRadius}. } \item{lineSides}{ Lines are rendered as cylinders with this many sides. } \item{pointsAsPoints, linesAsLines}{ Whether to convert points and lines to \dQuote{point} and \dQuote{line} records in the OBJ output. } \item{withNormals}{ Whether to output vertex normals for smooth shading. } \item{separateObjects}{ Whether to mark each RGL object as a separate object in the file. } \item{withTextures}{ Whether to output texture coordinates. } \item{ids}{ The identifiers (from \code{\link{ids3d}}) of the objects to write. If \code{NULL}, try to write everything. } \item{tags}{ Alternate way to specify \code{ids}. Ignored if \code{ids} is given. } \item{...}{ Additional arguments (typically just \code{material}) to pass to \code{\link{tmesh3d}}. } } \details{ The current \code{writeOBJ} implementation only outputs triangles, quads, planes, spheres, points, line segments, line strips and surfaces. It does not output material properties such as colors, since the OBJ format does not support the per-vertex colors that RGL uses. The \code{readOBJ} implementation can read faces, normals, and textures coordinates, but ignores material properties (including the specification of the texture file to use). To read a file that uses a single texture, specify it in the \code{material} argument, e.g. \code{readOBJ("model.OBJ", material = list(color = "white", texture = "texture.png"))}. There is no support for files that use multiple textures. The defaults for \code{pointsAsPoints} and \code{linesAsLines} have been chosen because Blender (\url{https://www.blender.org}) does not import points or lines, only polygons. If you are exporting to other software you may want to change them. If present, texture coordinates are output by default, but the textures themselves are not. Individual RGL objects are output as separate objects in the file when \code{separateObjects = TRUE}, the default. The output file should be readable by Blender and Meshlab; the latter can write in a number of other formats, including U3D, suitable for import into a PDF document. } \value{ \code{writeObj} invisibly returns the name of the connection to which the data was written. \code{readObj} returns a mesh object constructed from the input file. } \references{ The file format was found at \url{http://www.martinreddy.net/gfx/3d/OBJ.spec} on November 11, 2012. } \author{ Duncan Murdoch } \seealso{ \code{\link{scene3d}} saves a copy of a scene to an R variable; \code{\link{rglwidget}}, \code{\link{writeASY}}, \code{\link{writePLY}} and \code{\link{writeSTL}} write the scene to a file in various other formats. } \examples{ filename <- tempfile(fileext = ".obj") open3d() shade3d( icosahedron3d() ) writeOBJ(filename) # The motivation for writing readObj() was to read a shape # file of Comet 67P/Churyumov-Gerasimenko, from the ESA. # The file no longer appears to be online, but may still be # available on archive.org. Here was the original URL: # cometurl <- "http://sci.esa.int/science-e/www/object/doc.cfm?fobjectid=54726" # This code would read and display it: # open3d() # shade3d(readOBJ(url(cometurl), # material = list(col = "gray"))) # Textures are used in a realistic hand image available from # https://free3d.com/3d-model/freerealsichand-85561.html # Thanks to Monte Shaffer for pointing this out. # Decompress the files into the current directory, convert # hand_mapNew.jpg to hand_mapNew.png, then use \dontrun{ open3d() shade3d(readOBJ("hand.OBJ", material = list(color = "white", shininess = 1, texture = "hand_mapNew.png"))) } } \keyword{ graphics } rgl/man/sceneChange.Rd0000644000176200001440000000470214555455305014321 0ustar liggesusers\name{sceneChange} \alias{sceneChange} \alias{registerSceneChange} \title{ Make large change to a scene from Shiny } \description{ These functions allow Shiny apps to make relatively large changes to a scene, adding and removing objects from it. } \usage{ sceneChange(elementId, x = scene3d(minimal), delete = NULL, add = NULL, replace = NULL, material = FALSE, rootSubscene = FALSE, delfromSubscenes = NULL, skipRedraw = FALSE, minimal = TRUE) registerSceneChange() } \arguments{ \item{elementId}{ The id of the element holding the \code{rglClass} instance. } \item{x}{ The new scene to use as a source for objects to add. } \item{delete, add, replace}{ Object ids to modify in the scene. The \code{delete} and \code{replace} ids must be present in the old scene in the browser; the \code{add} and \code{replace} ids must be present in \code{x}. } \item{material}{ Logical to indicate whether default material should be updated. } \item{rootSubscene}{ Logical to indicate whether root subscene should be updated. } \item{delfromSubscenes}{ A vector of subscene ids that may have been changed by deletions. By default, all subscenes in \code{x} are used, but the objects may be included in subscenes in the browser that are different. } \item{skipRedraw}{ If \code{TRUE}, stop the scene from redrawing until \code{skipRedraw=FALSE} is sent. If \code{NA}, don't redraw this time, but don't change the state of the \code{skipRedraw} flag. } \item{minimal}{ See \code{\link{scene3d}}. } } \details{ \code{registerSceneChange} must be called in the UI component of a Shiny app to register the \code{"sceneChange"} custom message. } \value{ \code{registerSceneChange} returns the HTML code to register the message. \code{sceneChange} returns a list to be used as the \code{"sceneChange"} message to change the scene. Use \code{\link[shiny:session]{shiny::session$sendCustomMessage}} to send it. } \author{ Duncan Murdoch } \seealso{ \code{\link{playwidget}} for a different approach to modifying scenes that can be much faster, but may be less flexible. The Shiny demo in this package makes use of all of these approaches. } \examples{ \dontrun{ shinyUI(fluidPage( registerSceneChange(), actionButton("thebutton", "Change") )) shinyServer(function(input, output, session) { observeEvent(input$thebutton, { session$sendCustomMessage("sceneChange", sceneChange("thewidget", delete = deletes, add = adds)) }) }) } } rgl/man/persp3d.Rd0000644000176200001440000001345114771520323013470 0ustar liggesusers\name{persp3d} \alias{persp3d} \alias{persp3d.default} \title{ Surface plots } \description{ This function draws plots of surfaces in 3-space. \code{persp3d} is a generic function.} \usage{ persp3d(x, \dots) \method{persp3d}{default}(x = seq(0, 1, length.out = nrow(z)), y = seq(0, 1, length.out = ncol(z)), z, xlim = NULL, ylim = NULL, zlim = NULL, xlab = NULL, ylab = NULL, zlab = NULL, add = FALSE, aspect = !add, forceClipregion = FALSE, ...) } \arguments{ \item{x, y, z}{points to plot on surface. See Details below.} \item{xlim, ylim, zlim}{x-, y- and z-limits. If present, the plot is clipped to this region.} \item{xlab, ylab, zlab}{titles for the axes. N.B. These must be character strings; expressions are not accepted. Numbers will be coerced to character strings.} \item{add}{whether to add the points to an existing plot.} \item{aspect}{either a logical indicating whether to adjust the aspect ratio, or a new ratio.} \item{forceClipregion}{force a clipping region to be used, whether or not limits are given.} \item{\dots}{additional material parameters to be passed to \code{\link{surface3d}} and \code{\link{decorate3d}}.} } \details{ The default method plots a surface defined as a grid of \code{(x,y,z)} locations in space. The grid may be specified in several ways: \itemize{ \item{As with \code{\link[graphics]{persp}}, \code{x} and \code{y} may be given as vectors in ascending order, with \code{z} given as a matrix. There should be one \code{x} value for each row of \code{z} and one \code{y} value for each column. The surface drawn will have \code{x} constant across rows and \code{y} constant across columns. This is the most convenient format when \code{z} is a function of \code{x} and \code{y} which are measured on a regular grid.} \item{\code{x} and \code{y} may also be given as matrices, in which case they should have the same dimensions as \code{z}. The surface will combine corresponding points in each matrix into locations \code{(x,y,z)} and draw the surface through those. This allows general surfaces to be drawn, as in the example of a spherical Earth shown below.} \item{If \code{x} is a \code{list}, its components \code{x$x}, \code{x$y} and \code{x$z} are used for \code{x}, \code{y} and \code{z} respectively, though an explicitly specified \code{z} value will have priority.}} One difference from \code{\link[graphics]{persp}} is that colors are specified on each vertex, rather than on each facet of the surface. To emulate the \code{\link[graphics]{persp}} color handling, you need to do the following. First, convert the color vector to an \code{(nx - 1)} by \code{(ny - 1)} matrix; then add an extra row before row 1, and an extra column after the last column, to convert it to \code{nx} by \code{ny}. (These extra colors will not be used). For example, \code{col <- rbind(1, cbind(matrix(col, nx - 1, ny - 1), 1))}. Finally, call \code{persp3d} with material property \code{smooth = FALSE}. See the \dQuote{Clipping} section in \code{\link{plot3d}} for more details on \code{xlim, ylim, zlim} and \code{forceClipregion}. } \value{ This function is called for the side effect of drawing the plot. A vector of shape IDs is returned invisibly. } \author{Duncan Murdoch} \seealso{\code{\link{plot3d}}, \code{\link{persp}}. There is a \code{\link{persp3d.function}} method for drawing functions, and \code{\link{persp3d.deldir}} can be used to draw surfaces defined by an irregular collection of points. A formula method \code{\link{persp3d.formula}} draws surfaces using this method. The \code{\link{surface3d}} function is used to draw the surface without the axes etc. } \examples{ # (1) The Obligatory Mathematical surface. # Rotated sinc function. x <- seq(-10, 10, length.out = 20) y <- x f <- function(x, y) { r <- sqrt(x^2 + y^2); 10 * sin(r)/r } z <- outer(x, y, f) z[is.na(z)] <- 1 open3d() # Draw the surface twice: the first draws the solid part, # the second draws the grid. Offset the first so it doesn't # obscure the lines. persp3d(x, y, z, aspect = c(1, 1, 0.5), col = "lightblue", xlab = "X", ylab = "Y", zlab = "Sinc( r )", polygon_offset = 1) persp3d(x, y, z, front = "lines", back = "lines", lit = FALSE, add = TRUE) highlevel() # trigger the plot # (2) Add to existing persp plot: xE <- c(-10, 10); xy <- expand.grid(xE, xE) points3d(xy[, 1], xy[, 2], 6, col = "red") lines3d(x, y = 10, z = 6 + sin(x), col = "green") phi <- seq(0, 2*pi, length.out = 201) r1 <- 7.725 # radius of 2nd maximum xr <- r1 * cos(phi) yr <- r1 * sin(phi) lines3d(xr, yr, f(xr, yr), col = "pink", lwd = 2) # (3) Visualizing a simple DEM model z <- 2 * volcano # Exaggerate the relief x <- 10 * (1:nrow(z)) # 10 meter spacing (S to N) y <- 10 * (1:ncol(z)) # 10 meter spacing (E to W) open3d() invisible(bg3d("slategray")) # suppress display material3d(col = "black") persp3d(x, y, z, col = "green3", aspect = "iso", axes = FALSE, box = FALSE) # (4) A globe lat <- matrix(seq(90, -90, length.out = 50)*pi/180, 50, 50, byrow = TRUE) long <- matrix(seq(-180, 180, length.out = 50)*pi/180, 50, 50) r <- 6378.1 # radius of Earth in km x <- r*cos(lat)*cos(long) y <- r*cos(lat)*sin(long) z <- r*sin(lat) open3d() persp3d(x, y, z, col = "white", texture = system.file("textures/worldsmall.png", package = "rgl"), specular = "black", axes = FALSE, box = FALSE, xlab = "", ylab = "", zlab = "", normal_x = x, normal_y = y, normal_z = z) \dontrun{ # This looks much better, but is slow because the texture is very big persp3d(x, y, z, col = "white", texture = system.file("textures/world.png", package = "rgl"), specular = "black", axes = FALSE, box = FALSE, xlab = "", ylab = "", zlab = "", normal_x = x, normal_y = y, normal_z = z) } } \keyword{ dynamic } \keyword{ graphics } rgl/man/check3d.Rd0000644000176200001440000000070114771520323013406 0ustar liggesusers\name{.check3d} \alias{.check3d} \alias{check3d} \title{ Check for an open RGL window. } \description{ Mostly for internal use, this function returns the current device number if one exists, or opens a new device and returns that. } \usage{ .check3d() } \value{ The device number of an RGL device. } \author{ Duncan Murdoch } \seealso{ \code{\link{open3d}} } \examples{ rgl.dev.list() .check3d() rgl.dev.list() .check3d() rgl.dev.list() close3d() } rgl/man/contourLines3d.Rd0000644000176200001440000001444314771520323015025 0ustar liggesusers\name{contourLines3d} \alias{contourLines3d} \alias{contourLines3d.rglId} \alias{contourLines3d.mesh3d} \alias{filledContour3d} \alias{filledContour3d.rglId} \alias{filledContour3d.mesh3d} \title{ Draw contours on a surface } \description{ \code{contourLines3d} draws contour lines on a surface; \code{filledContour3d} draws filled contours on it. } \usage{ contourLines3d(obj, ...) \method{contourLines3d}{rglId}(obj, ...) \method{contourLines3d}{mesh3d}(obj, fn = "z", nlevels = 10, levels = NULL, minVertices = 0, plot = TRUE, ... ) filledContour3d(obj, ...) \method{filledContour3d}{rglId}(obj, plot = TRUE, replace = plot, ...) \method{filledContour3d}{mesh3d}(obj, fn = "z", nlevels = 20, levels = pretty(range(values), nlevels), color.palette = function(n) hcl.colors(n, "YlOrRd", rev = TRUE), col = color.palette(length(levels) - 1), minVertices = 0, plot = TRUE, keepValues = FALSE, ... ) } \arguments{ \item{obj}{ The object(s) on which to draw contour lines. } \item{fn}{ The function(s) to be contoured. See Details. } \item{nlevels}{ Suggested number of contour levels if \code{levels} is not given. } \item{levels}{ Specified contour values. } \item{minVertices}{ See Details below. } \item{plot}{ Whether to draw the lines or return them in a dataframe. } \item{\dots}{ For the \code{"mesh3d"} methods, additional parameters to pass to \code{\link{segments3d}} when drawing the contour lines or to \code{\link{shade3d}} when drawing the filled contours. For the \code{"rglId"} methods, additional parameters to pass to the \code{"mesh3d"} methods. } \item{replace}{ Whether to delete the objects that are being contoured. } \item{color.palette}{a color palette function to assign colors in the plot} \item{col}{the actual colors to use in the plot.} \item{keepValues}{whether to save the function values at each vertex when \code{plot = FALSE}} } \details{ For \code{contourLines3d}, the \code{fn} argument can be any of the following: \itemize{ \item{ a character vector naming one or more functions} \item{a function} \item{a numeric vector with one value per vertex} \item{\code{NULL}, indicating that the numeric values are saved in \code{obj$values}} \item{a list containing any of the above.} } For \code{filledContour3d}, only one function can be specified. The special names \code{"x", "y", "z"} may be used in \code{fn} to specify functions returning one of those coordinates. (If you have existing functions \code{x()}, \code{y()} or \code{z()} they will be masked by this choice; specify such functions by value rather than name, e.g. \code{fn = x} instead of \code{fn = "x"}.) Functions in \code{fn} with formal arguments \code{x}, \code{y} and \code{z} will receive the coordinates of vertices in those arguments, otherwise they will receive the coordinates in a single n x 3 matrix. They should be vectorized and return one value per vertex. Each of the functions will be evaluated at each vertex of the surface specified by \code{obj}, and contours will be drawn assuming the function is linear between vertices. If contours of a nonlinear function are needed, you may want to increase \code{minVertices} as described below. If \code{levels} is not specified, values will be set separately for each entry in \code{fn}, using \code{pretty(range(values, na.rm = TRUE), nlevels)} where \code{values} are the values on the vertices. The \code{minVertices} argument is used to improve the approximation to the contour when the function is non-linear. In that case, the interpolation between vertices can be inaccurate. If \code{minVertices} is set to a positive number (e.g. \code{10000}), then the mesh is modified by subdivision to have at least that number of vertices, so that pieces are smaller and the linear interpolation is more accurate. } \note{ To draw contours on a surface, the surface should be drawn with material property \code{polygon_offset = 1} (or perhaps some larger positive value) so that the lines of the contour are not obscured by the surface. In R versions prior to 3.6.0, the default \code{color.palette} is \code{grDevices::cm.colors}. } \value{ For both \code{contourLines3d} and \code{filledContour3d} the \code{"rglId"} method converts the given id values to a mesh, and calls the \code{"mesh3d"} method. The \code{"mesh3d"} method returns an object of class \code{"rglId"} corresponding to what was drawn if \code{plot} is \code{TRUE}, If \code{plot} is \code{FALSE}, \code{contourLines3d} returns a dataframe containing columns \code{c("x", "y", "z", "fn", "level")} giving the coordinates of the endpoints of each line segment, the name (or index) of the function for this contour, and the level of the contour. If \code{plot} is \code{FALSE}, \code{filledContour3d} returns a \code{"\link{mesh3d}"} object holding the result. If \code{keepValues} is \code{TRUE}, the mesh will contain the values corresponding to each vertex (with linear approximations at the boundaries). } \author{ Duncan Murdoch } \seealso{ The \pkg{misc3d} package contains the function \code{\link[misc3d]{contour3d}} to draw contour surfaces in space instead of contour lines on surfaces. } \examples{ # Add contourlines in "z" to a persp plot z <- 2 * volcano # Exaggerate the relief x <- 10 * (1:nrow(z)) # 10 meter spacing (S to N) y <- 10 * (1:ncol(z)) # 10 meter spacing (E to W) open3d() id <- persp3d(x, y, z, aspect = "iso", axes = FALSE, box = FALSE, polygon_offset = 1) contourLines3d(id) # "z" is the default function filledContour3d(id, polygon_offset = 1, nlevels = 10, replace = TRUE) # Draw longitude and latitude lines on a globe lat <- matrix(seq(90, -90, length.out = 50)*pi/180, 50, 50, byrow = TRUE) long <- matrix(seq(-180, 180, length.out = 50)*pi/180, 50, 50) r <- 6378.1 # radius of Earth in km x <- r*cos(lat)*cos(long) y <- r*cos(lat)*sin(long) z <- r*sin(lat) open3d() ids <- persp3d(x, y, z, col = "white", texture = system.file("textures/worldsmall.png", package = "rgl"), specular = "black", axes = FALSE, box = FALSE, xlab = "", ylab = "", zlab = "", normal_x = x, normal_y = y, normal_z = z, polygon_offset = 1) contourLines3d(ids, list(latitude = function(x, y, z) asin(z/sqrt(x^2+y^2+z^2))*180/pi, longitude = function(x, y, z) atan2(y, x)*180/pi)) } rgl/man/expect_known_scene.Rd0000644000176200001440000000311314771520323015763 0ustar liggesusers\name{expect_known_scene} \alias{expect_known_scene} \title{ Helper for \pkg{testthat} testing. } \description{ Gets the current scene using \code{\link{scene3d}}, and compares the result to a saved value, optionally closing the window afterwards. } \usage{ expect_known_scene(name, close = TRUE, file = paste0("testdata/", name, ".rds"), ...) } \arguments{ \item{name}{ By default, the base name of the file to save results in. Not used if \code{file} is specified. } \item{close}{ Whether to close the \pkg{rgl} window after the comparison. } \item{file}{ The file in which to save the result. } \item{...}{ Other arguments which will be passed to \code{\link[testthat]{expect_known_value}}. } } \details{ This function uses \code{\link[testthat]{expect_known_value}} to save a representation of the scene. During the comparison, the scene is modified so that non-reproducible aspects are standardized or omitted: \itemize{ \item{object ids are changed to start at 1.} \item{system-specific font names and texture names are deleted.} \item{the window is shifted to the top left of the screen.} } Calls to \code{expect_known_scene()} enable \code{testthat::\link[testthat]{local_edition}(2)} for the duration of the call, so it will work in \pkg{testthat} \dQuote{3rd edition}. } \value{ A value describing the changes to the saved object, suitable for use in \code{\link[testthat]{test_that}()}. } \examples{ \dontrun{ # These lines can be included in testthat::test_that() code. plot3d(1:10, 1:10, 1:10) expect_known_scene("plot") } }rgl/man/shadow3d.Rd0000644000176200001440000000426114771520323013623 0ustar liggesusers\name{shadow3d} \alias{shadow3d} \title{ Project shadows of mesh onto object. } \description{ Project a mesh onto a surface in a scene so that it appears to cast a shadow onto the surface. } \usage{ shadow3d(obj, mesh, plot = TRUE, up = c(0, 0, 1), P = projectDown(up), outside = FALSE, ...) } \arguments{ \item{obj}{ The target object which will show the shadow. } \item{mesh}{ The mesh which will cast the shadow. } \item{plot}{ Whether to plot the result. } \item{up}{ Which direction is \dQuote{up}? } \item{P}{ The projection to use for draping, a 4x4 matrix. See \code{\link{drape3d}} for details on how \code{P} is used. } \item{outside}{ Should the function compute and (possibly) plot the region outside of the shadow? } \item{\dots}{ Other arguments to pass to \code{\link{filledContour3d}}, which will do the boundary calculations and plotting. } } \details{ \code{shadow3d} internally constructs a function that is zero on the boundary of the shadow and positive inside, then draws filled contours of that function. Because the function is nonlinear, the boundaries will be approximate, with the best approximation resulting from a large value of \code{\link{filledContour3d}} parameter \code{minVertices}. If \code{outside = TRUE}, the first color used by \code{\link{filledContour3d}} will indicate the inside of the shadow, and the second color will indicate the exterior. } \value{ The returned value from \code{\link{filledContour3d}}. } \author{ Duncan Murdoch } \seealso{ \code{\link{drape3d}}, \code{\link{facing3d}} } \examples{ open3d() obj <- translate3d(scale3d(oh3d(), 0.3, 0.3, 0.3), 0,0,2) shade3d(obj, col = "red") target <- icosahedron3d() # We offset the target using polygon_offset = 1 so that the # shadow on its surface will appear clearly. shade3d(target, col = "white", polygon_offset = 1) # minVertices = 1000 leaves noticeable artifacts on the edges # of the shadow. A larger value gives a better result, but is # slower. # We use facing3d(target) so the shadow and outside part only # appear on the upper side of the target shadow3d(facing3d(target), obj, minVertices = 1000, plot=TRUE, col = c("yellow", "blue"), outside = TRUE) } rgl/man/planes.Rd0000644000176200001440000000445514771520323013376 0ustar liggesusers\name{planes3d} \alias{planes3d} \alias{clipplanes3d} \title{Add planes} \description{ \code{planes3d} adds mathematical planes to a scene. Their intersection with the current bounding box will be drawn. \code{clipplanes3d} adds clipping planes to a scene. } \usage{ planes3d(a, b = NULL, c = NULL, d = 0, ...) clipplanes3d(a, b = NULL, c = NULL, d = 0) } \arguments{ \item{a, b, c}{ Coordinates of the normal to the plane. Any reasonable way of defining the coordinates is acceptable. See the function \code{\link[grDevices]{xyz.coords}} for details. } \item{d}{ Coordinates of the "offset". See the details. } \item{\dots}{ Material properties. See \code{\link{material3d}} for details. } } \details{ \code{planes3d} draws planes using the parametrization \eqn{a x + b y + c z + d = 0}. Multiple planes may be specified by giving multiple values for any of \code{a, b, c, d}; the other values will be recycled as necessary. \code{clipplanes3d} defines clipping planes using the same equations. Clipping planes suppress the display of other objects (or parts of them) in the subscene, based on their coordinates. Points (or parts of lines or surfaces) where the coordinates \code{x, y, z} satisfy \eqn{a x + b y + c z + d < 0} will be suppressed. The number of clipping planes supported by the OpenGL driver is implementation dependent; use \code{par3d("maxClipPlanes")} to find the limit. } \value{ A shape ID of the planes or clipplanes object is returned invisibly. } \seealso{ \code{\link{abclines3d}} for mathematical lines. \code{\link{triangles3d}} or the corresponding functions for quadrilaterals may be used to draw sections of planes that do not adapt to the bounding box. The example in \link{subscene3d} shows how to combine clipping planes to suppress complex shapes. } \examples{ # Show regression plane with z as dependent variable open3d() x <- rnorm(100) y <- rnorm(100) z <- 0.2*x - 0.3*y + rnorm(100, sd = 0.3) fit <- lm(z ~ x + y) plot3d(x, y, z, type = "s", col = "red", size = 1) coefs <- coef(fit) a <- coefs["x"] b <- coefs["y"] c <- -1 d <- coefs["(Intercept)"] planes3d(a, b, c, d, alpha = 0.5) open3d() ids <- plot3d(x, y, z, type = "s", col = "red", size = 1, forceClipregion = TRUE) oldid <- useSubscene3d(ids["clipregion"]) clipplanes3d(a, b, c, d) useSubscene3d(oldid) } \keyword{dynamic} rgl/man/plot3d.lm.Rd0000644000176200001440000000764415011677075013740 0ustar liggesusers\name{plot3d.lm} \alias{plot3d.lm} \title{ Method for plotting simple linear fit } \description{ This function provides several plots of the result of fitting a two-predictor model. } \usage{ \method{plot3d}{lm}(x, which = 1, plane.col = "gray", plane.alpha = 0.5, sharedMouse = TRUE, use_surface3d, do_grid = TRUE, grid.col = "black", grid.alpha = 1, grid.steps = 5, sub.steps = 4, vars = get_all_vars(terms(x), x$model), clip_to_density = 0, ...) } \arguments{ \item{x}{ An object inheriting from class \code{"lm"} obtained by fitting a two-predictor model. } \item{which}{ Which plot to show? See Details below. } \item{plane.col, plane.alpha}{ These parameters control the colour and transparency of a plane or surface. } \item{sharedMouse}{ If multiple plots are requested, should they share mouse controls, so that they move in sync? } \item{use_surface3d}{ Use the \code{\link{surface3d}} function to plot the surface rather than \code{\link{planes3d}}. This allows curved surfaces to be shown. The default is \code{FALSE} if the model looks like a simple 2 parameter linear fit, otherwise \code{TRUE}. } \item{do_grid}{Plot a grid.} \item{grid.col, grid.alpha, grid.steps}{ Characteristics of the grid. } \item{sub.steps}{If \code{use_surface3d} is \code{TRUE}, use an internal grid of \code{grid.steps*sub.steps} to draw the surface. \code{sub.steps > 1} allows curvature within facets. Similarly, if \code{do_grid} is \code{TRUE}, it allows curvature within grid lines.} \item{vars}{A dataframe containing the variables to plot in the first three columns, with the response assumed to be in column 1. See the Note below.} \item{clip_to_density}{ If positive, the surface, plane or grid will be clipped to a region with sufficient data. } \item{\dots}{ Other parameters to pass to the default \code{\link{plot3d}} method, to control the appearance of aspects of the plot other than the plane. } } \details{ Three plots are possible, depending on the value(s) in \code{which}: \enumerate{ \item{(default) Show the points and the fitted plane or surface.} \item{Show the residuals and the plane at \code{z = 0}.} \item{Show the predicted values on the fitted plane or surface.} } If \code{clip_to_density} is positive, then the surface, plane or grid will be clipped to the region where a non-parametric density estimate (using \code{MASS::\link[MASS]{kde2d}}), normalized to have a maximum value of 1, is greater than the given value. This will suppress parts of the plot that aren't supported by the observed data. } \value{ Called for the side effect of drawing one or more plots. Invisibly returns a high-level vector of object ids. Names of object ids have the plot number (in drawing order) appended. } \note{ The default value for the \code{vars} argument will handle simple linear models with a response and two predictors, and some models with functions of those two predictors. For models that fail (e.g. models using \code{\link{poly}}), you can include the observed values as in the third example below. If \code{clip_to_density > 0}, \enumerate{ \item{The clipping is approximate, so it may not agree perfectly between surfaces, planes and grids.} \item{This option requires the suggested packages \pkg{MASS} and \pkg{interp}, and will be ignored with a warning if either is not installed.} } } \author{ Duncan Murdoch } \examples{ open3d() ids <- plot3d(lm(mpg ~ wt + qsec, data = mtcars), which = 1:3) names(ids) open3d() plot3d(lm(mpg ~ wt + I(wt^2) + qsec, data = mtcars)) open3d() # Specify vars in the order: response, pred1, pred2. plot3d(lm(mpg ~ poly(wt, 3) + qsec, data = mtcars), vars = mtcars[,c("mpg", "wt", "qsec")]) open3d() # Clip parts of the plot with few (wt, qsec) points plot3d(lm(mpg ~ poly(wt, 3) + qsec, data = mtcars), vars = mtcars[,c("mpg", "wt", "qsec")], clip_to_density = 0.1) } rgl/man/sprites.Rd0000644000176200001440000001242615011677075013607 0ustar liggesusers\name{sprites} \alias{sprites3d} \alias{particles3d} \title{Add sprites} \description{ Adds a sprite set shape node to the scene. } \usage{ sprites3d(x, y = NULL, z = NULL, radius = 1, shapes = NULL, userMatrix, fixedSize = FALSE, adj = 0.5, pos = NULL, offset = 0.25, rotating = FALSE, ...) particles3d(x, y = NULL, z = NULL, radius = 1, ...) } \arguments{ \item{ x, y, z }{point coordinates. Any reasonable way of defining the coordinates is acceptable. See the function \code{\link[grDevices]{xyz.coords}} for details.} \item{ radius }{vector or single value defining the sprite radius} \item{ shapes }{\code{NULL} for a simple square, a vector of identifiers of shapes in the scene, or a list of such vectors. See Details.} \item{ userMatrix }{if \code{shape} is not \code{NULL}, the transformation matrix for the shapes} \item{ fixedSize }{should sprites remain at a fixed size, or resize with the scene?} \item{ adj, pos, offset }{positioning arguments; see Details} \item{ rotating }{should sprites remain at a fixed orientation, or rotate with the scene?} \item{ ... }{material properties when \code{shapes = NULL}, texture mapping is supported} } \details{ Simple sprites (used when \code{shapes} is \code{NULL}) are 1 by 1 squares that are directed towards the viewpoint. Their primary use is for fast (and faked) atmospherical effects, e.g. particles and clouds using alpha blended textures. Particles are sprites using an alpha-blended particle texture giving the illusion of clouds and gases. The centre of each square will by default be at the coordinates given by \code{x, y, z}. This may be adjusted using the \code{adj} or \code{pos} parameters. \code{adj} and \code{pos} are treated similarly to the same parameters for \code{\link{text3d}}. \code{adj} has 3 entries, for adjustment to the \code{x}, \code{y} and \code{z} coordinates respectively. For \code{x}, a value of 0 puts the sprite to the right of the specified point, 0.5 centers it there, and 1 puts it to the left. The other coordinates are similar. By default, each value is 0.5 and the sprites are centered at the points given by \code{(x, y, z)}. The \code{pos} parameter overrides \code{adj}. It should be an integer or vector of integers (one per point), interpreted as in \code{\link{text3d}} to position the sprite relative to the \code{(x, y, z)} point: 0 is centered on it, 1 is below, 2 is to the left, 3 is above, 4 is to the right, 5 is in front, and 6 is behind. \code{offset} is the fraction of the sprite size to separate it from the point. When \code{shapes} is not \code{NULL}, it should be a vector of identifiers of objects to plot in the scene (e.g. as returned by plotting functions or by \code{\link{ids3d}}), or a list of such vectors. The referenced objects will be removed from the scene and duplicated as sprite images in a constant orientation, as specified by \code{userMatrix}. By default the origin \code{(0, 0, 0)} will be plotted at the coordinates given by \code{(x, y, z)}, perhaps modified by \code{adj} or \code{pos}. If \code{shapes} is a vector all entries in it will be plotted at every location. If \code{shapes} is a list, different shapes will be plotted at each location. All entries in list entry 1 will be plotted at location 1, all entries in entry 2 at location 2, etc. Entries will be recycled as needed. The \code{userMatrix} argument is ignored for \code{shapes = NULL}. For shapes, \code{sprites3d} defaults the matrix to \code{r3dDefaults$userMatrix}. If any coordinate is \code{NA}, the sprite is not plotted. The id values of the shapes may be retrieved after plotting using \code{rgl.attrib(id, "ids")}, the associated entry in \code{shapes} is retrievable in \code{rgl.attrib(id, "shapenum")}, and the user matrix is retrieved using \code{rgl.attrib(id, "usermatrix")}. } \note{ While any rgl objects can be used as 3D sprites, spheres produced by \code{\link{spheres3d}} and other objects that adapt to the coordinate system may not render properly. To plot spheres, construct them as mesh objects as shown in the example. } \value{ These functions are called for the side effect of displaying the sprites. The shape ID of the displayed object is returned. } \examples{ open3d() particles3d( rnorm(100), rnorm(100), rnorm(100), color = rainbow(100) ) # is the same as sprites3d( rnorm(100), rnorm(100), rnorm(100), color = rainbow(100), lit = FALSE, alpha = .2, textype = "alpha", texture = system.file("textures/particle.png", package = "rgl") ) sprites3d( rnorm(10) + 6, rnorm(10), rnorm(10), shape = shade3d(tetrahedron3d(), col = "red") ) open3d() # Since the symbols are objects in the scene, they need # to be added to the scene after calling plot3d() plot3d(iris, type = "n") # Use list(...) to apply different symbols to different points. symbols <- list(shade3d(cube3d(), col = "red"), shade3d(tetrahedron3d(), col = "blue"), # Construct spheres shade3d(addNormals(subdivision3d(icosahedron3d(), 2)), col = "yellow")) sprites3d(iris, shape = symbols[iris$Species], radius = 0.1) } \seealso{ \code{\link{material3d}}, \code{\link{text3d}}, \code{\link{pch3d}} } \keyword{dynamic} rgl/man/rgl-internal.Rd0000644000176200001440000000246514771520323014511 0ustar liggesusers\name{rgl-internal} \title{Internal RGL functions and data} \alias{rgl.bool} \alias{rgl.numeric} \alias{rgl.vertex} \alias{rgl.nvertex} \alias{rgl.color} \alias{rgl.mcolor} \alias{rgl.clamp} \alias{rgl.attr} \alias{rgl.enum} \alias{rgl.enum.gl2ps} \alias{rgl.enum.nodetype} \alias{rgl.enum.pixfmt} \alias{rgl.enum.polymode} \alias{rgl.enum.textype} \alias{rgl.enum.fogtype} \alias{rgl.enum.primtype} \alias{rgl.enum.texmagfilter} \alias{rgl.enum.texminfilter} \alias{rgl.selectstate} \alias{rgl.setselectstate} \alias{edgemap} \alias{edgeindex} \alias{cube3d.ib} \alias{cube3d.vb} \alias{oh3d.ib} \alias{oh3d.vb} \alias{dev3d} \description{ Internal RGL functions } \usage{ rgl.bool(x) rgl.numeric(x) rgl.vertex(x, y = NULL, z = NULL) rgl.nvertex(vertex) rgl.color(color) rgl.mcolor(colors) rgl.clamp(value, low, high) rgl.attr(vattr, nvertex) rgl.enum(name, ..., multi = FALSE) rgl.enum.gl2ps(postscripttype) rgl.enum.nodetype(type) rgl.enum.pixfmt(fmt) rgl.enum.polymode(mode) rgl.enum.textype(textype) rgl.enum.fogtype(fogtype) rgl.enum.primtype(primtype) rgl.enum.texmagfilter(magfiltertype) rgl.enum.texminfilter(minfiltertype) rgl.selectstate(dev, subscene) rgl.setselectstate(state, dev, subscene) edgemap(size) edgeindex(from, to, size, row, col) } \details{ These are not to be called by the user. } \keyword{internal} rgl/man/mergeVertices.Rd0000644000176200001440000000301214771520323014704 0ustar liggesusers\name{mergeVertices} \alias{mergeVertices} \title{ Merge duplicate vertices in mesh object } \description{ A mesh object can have the same vertex listed twice. Each copy is allowed to have separate normals, texture coordinates, and color. However, it is more efficient to have just a single copy if those differences aren't needed. For automatic smoothing using \code{\link{addNormals}}, triangles and quads need to share vertices. This function merges identical (or similar) vertices to achieve this. } \usage{ mergeVertices(mesh, notEqual = NULL, attribute = "vertices", tolerance = sqrt(.Machine$double.eps)) } \arguments{ \item{mesh}{ A \code{\link{mesh3d}} object. } \item{notEqual}{ A logical matrix indicating that certain pairs should not be merged even if they appear identical. } \item{attribute}{ Which attribute(s) should be considered in comparing vertices? A vector chosen from \code{c("vertices", "colors", "normals", "texcoords"))} } \item{tolerance}{ When comparing vertices using \code{\link{all.equal}}, this tolerance will be used to ignore rounding error. } } \value{ A new mesh object. } \author{ Duncan Murdoch } \seealso{ \code{\link{as.mesh3d.rglId}}, which often constructs mesh objects containing a lot of duplication. } \examples{ open3d() (mesh1 <- cuboctahedron3d(col = rainbow(14), meshColor = "face")) id <- shade3d(mesh1) (mesh2 <- as.mesh3d(id)) shade3d(translate3d(mesh2, 3, 0, 0)) (mesh3 <- mergeVertices(mesh2)) shade3d(translate3d(mesh3, 6, 0, 0)) } rgl/man/spin3d.Rd0000644000176200001440000000416414771520323013311 0ustar liggesusers\name{spin3d} \alias{spin3d} \title{ Create a function to spin a scene at a fixed rate } \description{ This creates a function to use with \code{\link{play3d}} to spin an RGL scene at a fixed rate. } \usage{ spin3d(axis = c(0, 0, 1), rpm = 5, dev = cur3d(), subscene = par3d("listeners", dev = dev)) } \arguments{ \item{axis}{ The desired axis of rotation } \item{rpm}{ The rotation speed in rotations per minute } \item{dev}{ Which RGL device to use } \item{subscene}{ Which subscene to use } } \value{ A function with header \code{function(time, base = M)}, where \code{M} is the result of \code{par3d("userMatrix")} at the time the function is created. This function calculates and returns a list containing \code{userMatrix} updated by spinning the base matrix for \code{time} seconds at \code{rpm} revolutions per minute about the specified \code{axis}. } \note{ Prior to \pkg{rgl} version 0.95.1476, the \code{subscene} argument defaulted to the current subscene, and any additional entries would be ignored by \code{\link{play3d}}. The current default value of \code{par3d("listeners", dev = dev)} means that all subscenes that share mouse responses will also share modifications by this function. } \author{ Duncan Murdoch } \seealso{ \code{\link{play3d}} to play the animation } \examples{ # Spin one object open3d() plot3d(oh3d(col = "lightblue", alpha = 0.5)) if (!rgl.useNULL() && interactive()) play3d(spin3d(axis = c(1, 0, 0), rpm = 30), duration = 2) # Show spinning sprites, and rotate the whole view open3d() spriteid <- NULL spin1 <- spin3d(rpm = 4.5 ) # the scene spinner spin2 <- spin3d(rpm = 9 ) # the sprite spinner f <- function(time) { par3d(skipRedraw = TRUE) # stops intermediate redraws on.exit(par3d(skipRedraw = FALSE)) # redraw at the end pop3d(id = spriteid) # delete the old sprite cubeid <- shade3d(cube3d(), col = "red") spriteid <<- sprites3d(0:1, 0:1, 0:1, shape = cubeid, userMatrix = spin2(time, base = spin1(time)$userMatrix)$userMatrix) spin1(time) } if (!rgl.useNULL() && interactive()) play3d(f, duration = 2) } \keyword{ dplot } rgl/man/texts.Rd0000644000176200001440000001136314771520323013257 0ustar liggesusers\name{text3d} \alias{text3d} \alias{texts3d} \title{Add text to plot} \description{ Adds text to the scene. The text is positioned in 3D space. Text is always oriented towards the camera. } \usage{ text3d(x, y = NULL, z = NULL, texts, adj = 0.5, pos = NULL, offset = 0.5, usePlotmath = is.language(texts), family = par3d("family"), font = par3d("font"), cex = par3d("cex"), useFreeType = par3d("useFreeType"), ...) texts3d(x, y = NULL, z = NULL, texts, adj = 0.5, pos = NULL, offset = 0.5, usePlotmath = is.language(texts), family = par3d("family"), font = par3d("font"), cex = par3d("cex"), useFreeType = par3d("useFreeType"), ...) } \arguments{ \item{x, y, z}{point coordinates. Any reasonable way of defining the coordinates is acceptable. See the function \code{\link[grDevices]{xyz.coords}} for details.} \item{texts}{text character vector to draw} \item{adj}{ one value specifying the horizontal adjustment, or two, specifying horizontal and vertical adjustment respectively, or three, specifying adjustment in all three directions.} \item{pos}{ a position specifier for the text. If specified, this overrides any \code{adj} value given. Values of 0, 1, 2, 3, 4, 5, 6 respectively indicate positions at, below, to the left of, above, to the right of, in front of, and behind the specified coordinates.} \item{offset}{ when \code{pos} is specified, this value gives the offset of the label from the specified coordinate in fractions of a character width.} \item{ usePlotmath }{logical. Should \code{\link{plotmath3d}} be used for the text?} \item{ family }{A device-independent font family name, or "" } \item{ font }{A numeric font number from 1 to 4 } \item{ cex }{A numeric character expansion value } \item{ useFreeType }{logical. Should FreeType be used to draw text? (See details below.)} \item{ ... }{Material properties; see \code{\link{material3d}} for details.} } \details{ The \code{adj} parameter determines the position of the text relative to the specified coordinate. Use \code{adj = c(0, 0)} to place the left bottom corner at \code{(x, y, z)}, \code{adj = c(0.5, 0.5)} to center the text there, and \code{adj = c(1, 1)} to put the right top corner there. The optional second coordinate for vertical adjustment defaults to \code{0.5}. Placement is done using the "advance" of the string and the "ascent" of the font relative to the baseline, when these metrics are known. \code{text3d} and \code{texts3d} draw text using the \link{r3d} conventions. These are synonyms; the former is singular to be consistent with the classic 2-D graphics functions, and the latter is plural to be consistent with all the other graphics primitives. Take your choice! If any coordinate or text is \code{NA}, that text is not plotted. If \code{usePlotmath} is \code{TRUE}, the work will be done by the \code{\link{plotmath3d}} function. This is the default if the \code{texts} parameter is \dQuote{language}, e.g. the result of a call to \code{\link{expression}} or \code{\link{quote}}. } \section{Fonts}{ Fonts are specified using the \code{family}, \code{font}, \code{cex}, and \code{useFreeType} arguments. Defaults for the currently active device may be set using \code{\link{par3d}}, or for future devices using \code{\link{r3dDefaults}}. The \code{family} specification is the same as for standard graphics, i.e. families \cr \code{c("serif", "sans", "mono", "symbol")} \cr are normally available, but users may add additional families. \code{font} numbers are restricted to the range 1 to 4 for standard, bold, italic and bold italic respectively. Font 5 is recoded as family \code{"symbol"} font 1, but that is not supported unless specifically installed, so should be avoided. Using an unrecognized value for \code{"family"} will result in the system standard font as used in RGL up to version 0.76. That font is not resizable and \code{font} values are ignored. If \code{useFreeType} is \code{TRUE}, then RGL will use the FreeType anti-aliased fonts for drawing. This is generally desirable, and it is the default on non-Windows systems if RGL was built to support FreeType. FreeType fonts are specified using the \code{\link{rglFonts}} function. } \value{ The text drawing functions return the object ID of the text object (or sprites, in case of \code{usePlotmath = TRUE}) invisibly. } \examples{ open3d() famnum <- rep(1:3, 8) family <- c("serif", "sans", "mono")[famnum] font <- rep(rep(1:4, each = 3), 2) cex <- rep(1:2, each = 12) text3d(font, cex, famnum, texts = paste(family, font), adj = 0.5, color = "blue", family = family, font = font, cex = cex) } \seealso{ \code{\link{r3d}}, \code{\link{plotmath3d}}, \code{\link{rglExtrafonts}} for adding fonts } \keyword{dynamic} rgl/man/rgl-package.Rd0000644000176200001440000000326714771520323014271 0ustar liggesusers\name{rgl-package} \title{3D visualization device system} \alias{rgl-package} \alias{rgl} \alias{RGL} \description{ 3D real-time rendering system. } \details{ RGL is a 3D real-time rendering system for R. Multiple windows are managed at a time. Windows may be divided into \dQuote{subscenes}, where one has the current focus that receives instructions from the R command-line. The device design is oriented towards the R device metaphor. If you send scene management instructions, and there's no device open, it will be opened automatically. Opened devices automatically get the current device focus. The focus may be changed by using \code{\link{set3d}()} or \code{\link{useSubscene3d}()}. RGL provides medium to high level functions for 3D interactive graphics, including functions modelled on base graphics (\code{\link{plot3d}()}, etc.) as well as functions for constructing geometric objects (\code{\link{cube3d}()}, etc.). Output may be on screen using OpenGL, or to various standard 3D file formats including WebGL, PLY, OBJ, STL as well as 2D image formats, including PNG, Postscript, SVG, PGF. The \code{\link{open3d}()} function attempts to open a new RGL window, using default settings specified by the user. See the first example below to display the ChangeLog. } \seealso{\link{r3d} for a description of the \code{*3d} interface; \code{\link{par3d}} for a description of scene properties and the rendering pipeline; \code{\link{rgl.useNULL}} for a description of how to use RGL on a system with no graphics support.} \examples{ if (!in_pkgdown_example()) file.show(system.file("NEWS", package = "rgl")) example(surface3d) example(plot3d) } \keyword{dynamic} rgl/man/triangulate.Rd0000644000176200001440000000642015011677075014432 0ustar liggesusers\name{triangulate} \alias{triangulate} \title{ Triangulate a two-dimensional polygon } \description{ This algorithm decomposes a general polygon into simple polygons and uses the \dQuote{ear-clipping} algorithm to triangulate it. Polygons with holes are supported. } \usage{ triangulate(x, y = NULL, z = NULL, random = TRUE, plot = FALSE, partial = NA) } \arguments{ \item{x, y, z}{ Coordinates of a two-dimensional polygon in a format supported by \code{\link{xyz.coords}}. See Details for a description of proper input and how \code{z} is handled. } \item{random}{ Currently ignored, the triangulation is deterministic. } \item{plot}{ Whether to plot the triangulation; mainly for debugging purposes. } \item{partial}{ Currently ignored. Improper input will lead to undefined results. } } \details{ Normally \code{triangulate} looks only at the \code{x} and \code{y} coordinates. However, if one of those is constant, it is replaced with the \code{z} coordinate if present. The algorithm works as follows. First, it breaks the polygon into pieces separated by \code{NA} values in \code{x} or \code{y}. Each of these pieces should be a simple, non-self-intersecting polygon, not intersecting the other pieces. (Though some minor exceptions to this rule may work, none are guaranteed). The nesting of these pieces is determined: polygons may contain holes, and the holes may contain other polygons. Vertex order around the polygons does not affect the results: whether a polygon is on the outside or inside of a region is determined by nesting. Polygons should not repeat vertices. An attempt is made to detect if the final vertex matches the first one. If so, it will be deleted with a warning. The \dQuote{outer} polygon(s) are then merged with the polygons that they immediately contain, and each of these pieces is triangulated using the ear-clipping algorithm from the references. Finally, all the triangulated pieces are put together into one result. } \value{ A three-by-n array giving the indices of the vertices of each triangle. (No vertices are added; only the original vertices are used in the triangulation.) The array has an integer vector attribute \code{"nextvert"} with one entry per vertex, giving the index of the next vertex to proceed counter-clockwise around outer polygon boundaries, clockwise around inner boundaries. } \references{ This function uses the C++ version of the \code{earcut} library from \url{https://github.com/mapbox/earcut.hpp}. } \author{ R wrapper code written by Duncan Murdoch; the \code{earcut} library has numerous authors. } \note{ Not all inputs will succeed, though inputs satisfying the rules listed in the Details section should. } \seealso{ \code{\link{extrude3d}} for a solid extrusion of a polygon, \code{\link{polygon3d}} for a flat display; both use \code{triangulate}. } \examples{ theta <- seq(0, 2*pi, length.out = 25)[-25] theta <- c(theta, NA, theta, NA, theta, NA, theta, NA, theta) r <- c(rep(1.5, 24), NA, rep(0.5, 24), NA, rep(0.5, 24), NA, rep(0.3, 24), NA, rep(0.1, 24)) dx <- c(rep(0, 24), NA, rep(0.6, 24), NA, rep(-0.6, 24), NA, rep(-0.6, 24), NA, rep(-0.6, 24)) x <- r*cos(theta) + dx y <- r*sin(theta) plot(x, y, type = "n") polygon(x, y) triangulate(x, y, plot = TRUE) open3d() polygon3d(x, y, x - y, col = "red") } \keyword{ graphics } rgl/man/rgl.init.Rd0000644000176200001440000000550614771520323013640 0ustar liggesusers\name{rgl.init} \title{Initializing RGL} \alias{rgl.init} \description{ Initializing the RGL system. } \usage{ rgl.init(initValue = 0, onlyNULL = FALSE, debug = getOption("rgl.debug", FALSE)) } \arguments{ \item{initValue}{value for internal use only} \item{onlyNULL}{only initialize the null (no display) device} \item{debug}{enable some debugging messages} } \value{ Normally the user doesn't call \code{rgl.init} at all: it is called when the package is loaded. It returns no useful value. } \details{ If \code{useNULL} is \code{TRUE}, RGL will use a \dQuote{null} device. This device records objects as they are plotted, but displays nothing. It is intended for use with \code{\link{rglwidget}} and similar functions. Currently \code{debug} only controls messages printed by the OpenGL library during initialization. In future \code{debug = TRUE} may become more verbose. For display within an OpenGL window in R, RGL requires the OpenGL system to be installed and available. If there is a problem initializing it, you may see the message \verb{'rgl.init' failed, running with 'rgl.useNULL = TRUE'.} There are several causes and remedies: \itemize{ \item{On any system, the OpenGL libraries need to be present for RGL to be able to start an OpenGL device.} \itemize{ \item{On macOS, you need to install XQuartz. It is available from \url{https://www.xquartz.org}.} \item{On Linux, you need to install Mesa 3D. One of these commands may work, depending on your system: \verb{ zypper source-install --build-deps-only Mesa # openSUSE/SLED/SLES yum-builddep mesa # yum Fedora, OpenSuse(?) dnf builddep mesa # dnf Fedora apt-get build-dep mesa # Debian, Ubuntu and related } } \item{Windows should have OpenGL installed by default.} } \item{On Unix-alike systems (macOS and Linux, for example), RGL normally uses the GLX system for creating displays. If the graphic is created on a remote machine, it may need to use \dQuote{Indirect GLX} (IGLX). Due to security concerns, this is often disabled by default. See \url{https://www.x.org/wiki/Development/Security/Advisory-2014-12-09/} for a discussion of the security issues, and \url{https://unix.stackexchange.com/q/317954} for ways to re-enable IGLX.} \item{The \url{https://www.virtualgl.org} project is intended to be a way to avoid IGLX, by rendering remotely and sending bitmaps to the local machine. It's not a simple install...} \item{If you don't need to see RGL displays on screen, you can use the \dQuote{NULL device}. See \code{\link{rgl.useNULL}}.} \item{If you can't build the \pkg{rgl} package with OpenGL support, you can disable it and use the NULL device. (This may happen automatically during configuration, but you'll get a tested result if you specify it explicitly.) See the instructions in the \file{README} file in the source tarball.} } } rgl/man/axes3d.Rd0000644000176200001440000001516215011677075013305 0ustar liggesusers\name{axes3d} \alias{axes3d} \alias{axis3d} \alias{mtext3d} \alias{title3d} \alias{box3d} \title{ Draw boxes, axes and other text outside the data } \description{ These functions draw axes, boxes and text outside the range of the data. \code{axes3d}, \code{box3d} and \code{title3d} are the higher level functions; normally the others need not be called directly by users. } \usage{ axes3d(edges = "bbox", labels = TRUE, tick = TRUE, nticks = 5, box = FALSE, expand = 1.03, ...) box3d(...) title3d(main = NULL, sub = NULL, xlab = NULL, ylab = NULL, zlab = NULL, line = NA, level = NA, floating = NULL, ...) axis3d(edge, at = NULL, labels = TRUE, tick = TRUE, line = 0, pos = NULL, nticks = 5, ...) mtext3d(text, edge, at = NULL, line = 0, level = 0, floating = FALSE, pos = NA, ...) } \arguments{ \item{edges}{ a code to describe which edge(s) of the box to use; see Details below } \item{labels}{ whether to label the axes, or (for \code{axis3d}) the labels to use} \item{tick}{ whether to use tick marks } \item{nticks}{ suggested number of ticks } \item{box}{ draw the full box if \code{"bbox"} axes are used } \item{expand}{ how much to expand the box around the data } \item{main}{ the main title for the plot } \item{sub}{ the subtitle for the plot } \item{xlab, ylab, zlab}{ the axis labels for the plot } \item{line, level}{ the "line" of the plot margin to draw the label on, and "level" above or below it } \item{floating}{ which mode of axis labels? One of \code{TRUE}, \code{FALSE} or \code{NA}. (\code{NULL} may also be used in \code{title3d} calls). See Details for how these are handled.} \item{edge, pos}{ the position at which to draw the axis or text } \item{text}{ the text to draw } \item{at}{ the value of a coordinate at which to draw the axis or labels. } \item{\dots}{ additional parameters which are passed to \code{\link{bbox3d}} or \code{\link{material3d}} } } \details{ The rectangular prism holding the 3D plot has 12 edges. They are identified using 3 character strings. The first character (`x', `y', or `z') selects the direction of the axis. The next two characters are each `-' or `+', selecting the lower or upper end of one of the other coordinates. If only one or two characters are given, the remaining characters normally default to `-' (but with \code{mtext3d(..., floating = TRUE)} the default is `+'; see below). For example \code{edge = 'x+'} draws an x-axis at the high level of y and the low level of z. By default, \code{axes3d} uses the \code{\link{bbox3d}} function to draw the axes. The labels will move so that they do not obscure the data. Alternatively, a vector of arguments as described above may be used, in which case fixed axes are drawn using \code{axis3d}. As of \pkg{rgl} version 0.106.21, axis drawing has changed significantly. Text drawn in the margins will adapt to the margins (see \code{\link{bbox3d}}). The \code{edge} and \code{floating} parameters will be recorded in the \code{margin} and \code{floating} material properties for the object. If \code{floating = FALSE}, they will be drawn on the specified edge. If \code{floating = TRUE}, they will move as the axis labels move when the scene is rotated. The signs on the edge specification are interpreted as agreeing with the axis ticks `+' or disagreeing `-'. For example, \code{"x++"} will draw text on the x axis in the same edge as the ticks, while \code{"x--"} will draw on the opposite edge. The final possible value for \code{floating} in \code{mtext3d} is \code{NA}, which reproduces legacy \pkg{rgl} behaviour. In this case the labels are not tied to the bounding box, so they should be drawn last, or they could appear inside the box, overlapping the data. In \code{title3d} \code{floating = NULL} (the default) indicates the main title and subtitle will be fixed while the axis labels will be floating. The default locations for title and subtitle are \code{line = 2} and \code{level = 2} on edges \code{"x++"} and \code{"x--"} respectively. The axis labels float at \code{line = 4} and \code{level = 1} on the same edge as the ticks. The \code{at} parameter in \code{axis3d} is the location of the ticks, defaulting to \code{\link{pretty}} locations. In \code{mtext3d} the \code{at} parameter is the location on the specified axis at which to draw the text, defaulting to the middle of the bounding box. The \code{line} parameter is the line counting out from the box in the same direction as the axis ticks, and \code{level} is the line out in the orthogonal direction. The ticks run from \code{line = 0} to \code{line = 1}, and the tick labels are drawn at \code{line = 2}. Both are drawn at level 0. The \code{pos} parameter is only supported in legacy mode. If it is a numeric vector of length 3, \code{edge} determines the direction of the axis and the tick marks, and the values of the other two coordinates in \code{pos} determine the position. The \code{level} parameter is ignored in legacy mode. For \code{mtext3d} in \code{floating = TRUE} or \code{floating = FALSE} mode, there are 3 special values for the \code{at} parameter: it may be \code{-Inf}, \code{NA} or \code{+Inf}, referring to the bottom, middle or top of the given axis respectively. } \note{\code{mtext3d} is a wrapper for \code{\link{text3d}} that sets the \code{margin} and \code{floating} material properties. In fact, these properties can be set for many kinds of objects (most kinds where it would make sense), with the effect that the object will be drawn in the margin, with \code{x} coordinate corresponding to \code{at}, \code{y} corresponding to \code{line}, and \code{z} corresponding to \code{level}. } \value{ These functions are called for their side effects. They return the object IDs of objects added to the scene. } \author{ Duncan Murdoch } \seealso{Classic graphics functions \code{\link{axis}}, \code{\link{box}}, \code{\link{title}}, \code{\link{mtext}} are related. See RGL functions \code{\link{bbox3d}} for drawing the box around the plot, and \code{\link{setAxisCallbacks}} for customized axes.} \examples{ open3d() points3d(rnorm(10), rnorm(10), rnorm(10)) # First add standard axes axes3d() # and one in the middle (the NA will be ignored, a number would # do as well) axis3d('x', pos = c(NA, 0, 0)) # add titles title3d('main', 'sub', 'xlab', 'ylab', 'zlab') # Use a log scale for z open3d() x <- rnorm(10) y <- rnorm(10) z <- exp(rnorm(10, mean = 3, sd = 2)) logz <- log10(z) zticks <- axisTicks(range(logz), log = TRUE) zat <- log10(zticks) plot3d(x, y, logz, zlab = "z") axes3d(zat = zat, zlab = zticks, box = TRUE) } \keyword{dynamic}%-- one or more ... rgl/man/setupKnitr.Rd0000644000176200001440000001152115011677075014261 0ustar liggesusers\name{setupKnitr} \alias{hook_rgl} \alias{hook_webgl} \alias{hook_rglchunk} \alias{setupKnitr} \title{ Displaying RGL scenes in \pkg{knitr} documents } \description{ These functions allow RGL graphics to be embedded in \pkg{knitr} documents. The simplest method is to run \code{setupKnitr(autoprint = TRUE)} early in the document. That way RGL commands act a lot like base graphics commands: plots will be automatically inserted where appropriate, according to the \code{fig.keep} chunk option. By default (\code{fig.keep = "high"}), only high-level plots are kept, after low-level changes have been merged into them. See the \pkg{knitr} documentation \url{https://yihui.org/knitr/options/#plots} for more details. To suppress auto-printing, the RGL calls can be wrapped in \code{\link{invisible}()}. Similarly to \pkg{grid} graphics (used by \pkg{lattice} and \pkg{ggplot2}), automatic inclusion requires the object to be printed: only the last statement in a code block in braces is automatically printed. Unlike those packages, auto-printing is the only way to get this to work: calling \code{\link{print}} explicitly doesn't work. Other functions allow embedding either as bitmaps (\code{hook_rgl} with format \code{"png"}), fixed vector graphics (\code{hook_rgl} with format \code{"eps"}, \code{"pdf"} or \code{"postscript"}), or interactive WebGL graphics (\code{hook_webgl}). \code{hook_rglchunk} is not normally invoked by the user; it is the hook that supports automatic creation and deletion of RGL scenes. } \note{The \code{setupKnitr(autoprint = TRUE)} method assumes \emph{all} printing of RGL objects happens through auto-printing of objects produced by the \code{\link{lowlevel}} or \code{\link{highlevel}} functions. All RGL functions that produce graphics do this, but functions in other packages that call them may not return values appropriately. Mixing explicit calls to \code{\link{rglwidget}} with auto-printing is likely to lead to failure of some scenes to display. To avoid this, set \code{options(rgl.printRglwidget = FALSE)} before using such explicit calls. Similarly, use that option before calling the \code{\link{example}} function in a code chunk if the example prints RGL objects. } \usage{ setupKnitr(autoprint = FALSE, rgl.newwindow = autoprint, rgl.closewindows = autoprint) hook_rgl(before, options, envir) hook_webgl(before, options, envir) hook_rglchunk(before, options, envir) } \arguments{ \item{autoprint}{If true, RGL commands automatically plot (with low level plots suppressed by the default value of the \code{fig.keep} chunk option.)} \item{rgl.newwindow, rgl.closewindows}{Default values for the \pkg{knitr} chunk options.} \item{before, options, envir}{ Standard \pkg{knitr} hook function arguments. } } \details{ The \code{setupKnitr()} function needs to be called once at the start of the document to install the \pkg{knitr} hooks. If it is called twice in the same session the second call will override the first. The following chunk options are supported: \itemize{ \item \code{rgl.newwindow}: Whether to open a new window for the chunk. Default is set by \code{setupKnitr} argument. \item \code{rgl.closewindows}: Whether to close windows at the end of the chunk. Default is set by \code{setupKnitr} argument. \item \code{rgl.margin} (default 100): number of pixels by which to indent the WebGL window. \item \code{snapshot}: Logical value: when autoprinting in HTML, should a snapshot be used instead of the dynamic WebGL display? Corresponds to \code{rglwidget(snapshot = TRUE, webgl = FALSE)}. Ignored in LaTeX, where a snapshot will always be produced (unless \code{fig.keep} specifies no figure at all). \item \code{dpi}, \code{fig.retina}, \code{fig.width}, \code{fig.height}: standard \pkg{knitr} chunk options used to set the size of the output. \item \code{fig.keep}, \code{fig.hold}, \code{fig.beforecode}: standard \pkg{knitr} chunk options used to control the display of plots. \item \code{dev}: used by \code{hook_rgl} to set the output format. May be \code{"eps"}, \code{"postscript"}, \code{"pdf"} or \code{"png"} (default: \code{"png"}). \item \code{rgl.keepopen}: no longer used. Ignored with a warning. \item \code{fig.alt} is partially supported: \pkg{rgl} will always use the first entry if \code{fig.alt} is a vector. Other graphics types match the entries in \code{fig.alt} to successive plots within the chunk. (This is due to a limitation in \pkg{knitr}, and may change in the future.) } } \value{ A string to be embedded into the output, or \code{NULL} if called when no output is available. } \author{ The \code{hook*} functions are originally by Yihui Xie in the \pkg{knitr} package; and have been modified by Duncan Murdoch. Some parts of the \code{setupKnitr} function duplicate source code from \pkg{knitr}. } \keyword{ utilities } rgl/man/clipplaneControl.Rd0000644000176200001440000000275015012460301015404 0ustar liggesusers\name{clipplaneControl} \alias{clipplaneControl} \title{ Sets attributes of a clipping plane } \description{ This is a function to produce actions in a web display. A \code{\link{playwidget}} or Shiny input control (e.g. a \code{\link[shiny]{sliderInput}} control) sets a value which controls attributes of one or more clipping planes. } \usage{ clipplaneControl(a = NULL, b = NULL, c = NULL, d = NULL, plane = 1, clipplaneids = tagged3d(tag), tag, ...) } \arguments{ \item{a, b, c, d}{ Parameter values for the clipping planes. } \item{plane}{ Which plane in the clipplane object? } \item{clipplaneids}{ The id of the clipplane object. } \item{tag}{ Select clipplane with matching tag. Ignored if \code{clipplaneid} is specified. } \item{\dots}{ Other parameters passed to \code{\link{propertyControl}}. } } \value{ A list of class \code{"rglControl"} of cleaned up parameter values, to be used in an RGL widget. } \author{ Duncan Murdoch } \seealso{ The \HTMLVignette{WebGL}{}{User Interaction in WebGL} vignette gives more details. } \examples{ open3d() saveopts <- options(rgl.useNULL = TRUE) xyz <- matrix(rnorm(300), ncol = 3) id <- plot3d(xyz, type="s", col = "blue", zlim = c(-3,3))["clipplanes"] dvals <- c(3, -3) widget <- rglwidget() \%>\% playwidget(clipplaneControl(d = dvals, clipplaneids = id), start = 0, stop = 1, step = 0.01, rate = 0.5) if (interactive() || in_pkgdown_example()) widget options(saveopts) } rgl/man/matrices.Rd0000644000176200001440000001103014771520323013706 0ustar liggesusers\name{matrices} \alias{matrices} \alias{identityMatrix} \alias{scaleMatrix} \alias{translationMatrix} \alias{rotationMatrix} \alias{scale3d} \alias{translate3d} \alias{rotate3d} \alias{transform3d} \alias{asHomogeneous} \alias{asEuclidean} \alias{asHomogeneous2} \alias{asEuclidean2} \title{Work with homogeneous coordinates } \description{ These functions construct 4x4 matrices for transformations in the homogeneous coordinate system used by OpenGL, and translate vectors between homogeneous and Euclidean coordinates. } \usage{ identityMatrix() scaleMatrix(x, y, z) translationMatrix(x, y, z) rotationMatrix(angle, x, y, z, matrix) asHomogeneous(x) asEuclidean(x) asHomogeneous2(x) asEuclidean2(x) scale3d(obj, x, y, z, ...) translate3d(obj, x, y, z, ...) rotate3d(obj, angle, x, y, z, matrix, ...) transform3d(obj, matrix, ...) } \arguments{ \item{x, y, z, angle, matrix}{See details} \item{obj}{An object to be transformed} \item{...}{Additional parameters to be passed to methods} } \details{ OpenGL uses homogeneous coordinates to handle perspective and affine transformations. The homogeneous point \code{(x, y, z, w)} corresponds to the Euclidean point \code{(x/w, y/w, z/w)}. The matrices produced by the functions \code{scaleMatrix}, \code{translationMatrix}, and \code{rotationMatrix} are to be left-multiplied by a row vector of homogeneous coordinates; alternatively, the transpose of the result can be right-multiplied by a column vector. The generic functions \code{scale3d}, \code{translate3d} and \code{rotate3d} apply these transformations to the \code{obj} argument. The \code{transform3d} function is a synonym for \code{rotate3d(obj, matrix = matrix)}. By default, it is assumed that \code{obj} is a row vector (or a matrix of row vectors) which will be multiplied on the right by the corresponding matrix, but users may write methods for these generics which operate differently. Methods are supplied for \code{\link{mesh3d}} objects. To compose transformations, use matrix multiplication. The effect is to apply the matrix on the left first, followed by the one on the right. \code{identityMatrix} returns an identity matrix. \code{scaleMatrix} scales each coordinate by the given factor. In Euclidean coordinates, \code{(u, v, w)} is transformed to \code{(x*u, y*v, z*w)}. \code{translationMatrix} translates each coordinate by the given translation, i.e. \code{(u, v, w)} is transformed to \code{(u + x, v + y, w + z)}. \code{rotationMatrix} can be called in three ways. With arguments \code{angle, x, y, z} it represents a rotation of \code{angle} radians about the axis \code{x, y, z}. If \code{matrix} is a 3x3 rotation matrix, it will be converted into the corresponding matrix in 4x4 homogeneous coordinates. Finally, if a 4x4 matrix is given, it will be returned unchanged. (The latter behaviour is used to allow \code{transform3d} to act like a generic function, even though it is not.) Use \code{asHomogeneous(x)} to convert the Euclidean vector \code{x} to homogeneous coordinates, and \code{asEuclidean(x)} for the reverse transformation. These functions accept the following inputs: \itemize{ \item n x 3 matrices: rows are assumed to be Euclidean \item n x 4 matrices: rows are assumed to be homogeneous \item vectors of length 3n or 4n: assumed to be vectors concatenated. For the ambiguous case of vectors that are length 12n (so both 3n and 4n are possible), the assumption is that the conversion is necessary: \code{asEuclidean} assumes the vectors are homogeneous, and \code{asHomogeneous} assumes the vectors are Euclidean. } Outputs are n x 4 or n x 3 matrices for \code{asHomogeneous} and \code{asEuclidean} respectively. The functions \code{asHomogeneous2} and \code{asEuclidean2} act similarly, but they assume inputs are 3 x n or 4 x n and outputs are in similar shapes. } \value{ \code{identityMatrix}, \code{scaleMatrix}, \code{translationMatrix}, and \code{rotationMatrix} produce a 4x4 matrix representing the requested transformation in homogeneous coordinates. \code{scale3d}, \code{translate3d} and \code{rotate3d} transform the object and produce a new object of the same class. } \author{ Duncan Murdoch } \seealso{\code{\link{par3d}} for a description of how RGL uses matrices in rendering.} \examples{ # A 90 degree rotation about the x axis: rotationMatrix(pi/2, 1, 0, 0) # Find what happens when you rotate (2, 0, 0) by 45 degrees about the y axis: x <- asHomogeneous(c(2, 0, 0)) y <- x \%*\% rotationMatrix(pi/4, 0, 1, 0) asEuclidean(y) # or more simply... rotate3d(c(2, 0, 0), pi/4, 0, 1, 0) } \keyword{ dynamic } rgl/man/Buffer.Rd0000644000176200001440000003270014771520323013317 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/buffer.R \name{Buffer} \alias{Buffer} \title{R6 Class for binary buffers in glTF files.} \description{ These files typically have one buffer holding all the binary data for a scene. } \section{Methods}{ \subsection{Public methods}{ \itemize{ \item \href{#method-Buffer-new}{\code{Buffer$new()}} \item \href{#method-Buffer-load}{\code{Buffer$load()}} \item \href{#method-Buffer-saveOpenBuffer}{\code{Buffer$saveOpenBuffer()}} \item \href{#method-Buffer-getBuffer}{\code{Buffer$getBuffer()}} \item \href{#method-Buffer-setBuffer}{\code{Buffer$setBuffer()}} \item \href{#method-Buffer-openBuffer}{\code{Buffer$openBuffer()}} \item \href{#method-Buffer-writeBuffer}{\code{Buffer$writeBuffer()}} \item \href{#method-Buffer-closeBuffer}{\code{Buffer$closeBuffer()}} \item \href{#method-Buffer-closeBuffers}{\code{Buffer$closeBuffers()}} \item \href{#method-Buffer-getBufferview}{\code{Buffer$getBufferview()}} \item \href{#method-Buffer-addBufferView}{\code{Buffer$addBufferView()}} \item \href{#method-Buffer-openBufferview}{\code{Buffer$openBufferview()}} \item \href{#method-Buffer-setBufferview}{\code{Buffer$setBufferview()}} \item \href{#method-Buffer-getAccessor}{\code{Buffer$getAccessor()}} \item \href{#method-Buffer-setAccessor}{\code{Buffer$setAccessor()}} \item \href{#method-Buffer-readAccessor}{\code{Buffer$readAccessor()}} \item \href{#method-Buffer-readAccessor0}{\code{Buffer$readAccessor0()}} \item \href{#method-Buffer-addAccessor}{\code{Buffer$addAccessor()}} \item \href{#method-Buffer-dataURI}{\code{Buffer$dataURI()}} \item \href{#method-Buffer-as.list}{\code{Buffer$as.list()}} \item \href{#method-Buffer-clone}{\code{Buffer$clone()}} } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-new}{}}} \subsection{Method \code{new()}}{ \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$new(json = NULL, binfile = NULL)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{json}}{list read from glTF file.} \item{\code{binfile}}{optional External binary filename, or raw vector} } \if{html}{\out{
}} } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-load}{}}} \subsection{Method \code{load()}}{ Load from file. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$load(uri, buf = 0)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{uri}}{Which file to load.} \item{\code{buf}}{Which buffer number to load.} } \if{html}{\out{
}} } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-saveOpenBuffer}{}}} \subsection{Method \code{saveOpenBuffer()}}{ Write open buffer to connection. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$saveOpenBuffer(con, buf = 0)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{con}}{Output connection.} \item{\code{buf}}{Buffer number.} } \if{html}{\out{
}} } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-getBuffer}{}}} \subsection{Method \code{getBuffer()}}{ Get buffer object. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$getBuffer(buf, default = list(byteLength = 0))}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{buf}}{Buffer number.} \item{\code{default}}{Default buffer object if \code{buf} not found.} } \if{html}{\out{
}} } \subsection{Returns}{ A list containing components described here: \url{https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-buffer}. } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-setBuffer}{}}} \subsection{Method \code{setBuffer()}}{ Set buffer object. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$setBuffer(buf, buffer)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{buf}}{Buffer number.} \item{\code{buffer}}{New value to insert.} } \if{html}{\out{
}} } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-openBuffer}{}}} \subsection{Method \code{openBuffer()}}{ Open a connection for the data in a buffer. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$openBuffer(buf)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{buf}}{Buffer number.} } \if{html}{\out{
}} } \subsection{Returns}{ An open binary connection. } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-writeBuffer}{}}} \subsection{Method \code{writeBuffer()}}{ Write data to buffer. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$writeBuffer(values, type, size, buf = 0)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{values}}{Values to write.} \item{\code{type}}{Type to write.} \item{\code{size}}{Byte size of each value.} \item{\code{buf}}{Which buffer to write to.} } \if{html}{\out{
}} } \subsection{Returns}{ Byte offset of start of bytes written. } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-closeBuffer}{}}} \subsection{Method \code{closeBuffer()}}{ Close the connection in a buffer. If there was a connection open, this will save the contents in the raw vector \code{bytes} within the buffer object. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$closeBuffer(buf)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{buf}}{The buffer number.} } \if{html}{\out{
}} } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-closeBuffers}{}}} \subsection{Method \code{closeBuffers()}}{ Close any open buffers. Call this after working with a GLTF file to avoid warnings from R about closing unused connections. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$closeBuffers()}\if{html}{\out{
}} } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-getBufferview}{}}} \subsection{Method \code{getBufferview()}}{ Get \code{bufferView} object. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$getBufferview(bufv)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{bufv}}{\code{bufferView} number.} } \if{html}{\out{
}} } \subsection{Returns}{ A list containing components described here: \url{https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-bufferview}. } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-addBufferView}{}}} \subsection{Method \code{addBufferView()}}{ Add a new buffer view. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$addBufferView(values, type, size, target = NULL, buf = 0)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{values}}{Values to put in the view.} \item{\code{type}}{Type of values.} \item{\code{size}}{Size of values in bytes.} \item{\code{target}}{Optional target use for values.} \item{\code{buf}}{Which buffer to write to.} } \if{html}{\out{
}} } \subsection{Returns}{ New \code{bufferView} number. } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-openBufferview}{}}} \subsection{Method \code{openBufferview()}}{ Open a connection to a buffer view. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$openBufferview(bufv)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{bufv}}{Which \code{bufferView}.} } \if{html}{\out{
}} } \subsection{Returns}{ A connection. } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-setBufferview}{}}} \subsection{Method \code{setBufferview()}}{ Set \code{bufferView} object. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$setBufferview(bufv, bufferView)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{bufv}}{\code{bufferView} number.} \item{\code{bufferView}}{New value to insert.} } \if{html}{\out{
}} } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-getAccessor}{}}} \subsection{Method \code{getAccessor()}}{ Get accessor object \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$getAccessor(acc)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{acc}}{Accessor number} } \if{html}{\out{
}} } \subsection{Returns}{ A list containing components described here: \url{https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-accessor} } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-setAccessor}{}}} \subsection{Method \code{setAccessor()}}{ Set accessor object. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$setAccessor(acc, accessor)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{acc}}{Accessor number.} \item{\code{accessor}}{New value to insert.} } \if{html}{\out{
}} } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-readAccessor}{}}} \subsection{Method \code{readAccessor()}}{ Read data given by accessor number. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$readAccessor(acc)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{acc}}{Accessor number.} } \if{html}{\out{
}} } \subsection{Returns}{ A vector or array as specified in the accessor. For the \code{MATn} types, the 3rd index indexes the element. } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-readAccessor0}{}}} \subsection{Method \code{readAccessor0()}}{ Read data given by accessor object. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$readAccessor0(accessor)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{accessor}}{Accessor object} } \if{html}{\out{
}} } \subsection{Returns}{ A vector or array as specified in the accessor. For the \code{MATn} types, the 3rd index indexes the element. } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-addAccessor}{}}} \subsection{Method \code{addAccessor()}}{ Write values to accessor, not including \code{min} and \code{max}. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$addAccessor( values, target = NULL, types = "anyGLTF", normalized = FALSE )}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{values}}{Values to write.} \item{\code{target}}{Optional target use for values.} \item{\code{types}}{Which types can be used?} \item{\code{normalized}}{Are normalized integers allowed?} \item{\code{useDouble}}{Whether to write doubles or singles.} } \if{html}{\out{
}} } \subsection{Returns}{ New accessor number } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-dataURI}{}}} \subsection{Method \code{dataURI()}}{ Convert buffer to data URI. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$dataURI(buf = 0)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{buf}}{Buffer to convert.} } \if{html}{\out{
}} } \subsection{Returns}{ String containing data URI. } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-as.list}{}}} \subsection{Method \code{as.list()}}{ Convert to list. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$as.list()}\if{html}{\out{
}} } \subsection{Returns}{ List suitable for writing using JSON. } } \if{html}{\out{
}} \if{html}{\out{}} \if{latex}{\out{\hypertarget{method-Buffer-clone}{}}} \subsection{Method \code{clone()}}{ The objects of this class are cloneable with this method. \subsection{Usage}{ \if{html}{\out{
}}\preformatted{Buffer$clone(deep = FALSE)}\if{html}{\out{
}} } \subsection{Arguments}{ \if{html}{\out{
}} \describe{ \item{\code{deep}}{Whether to make a deep clone.} } \if{html}{\out{
}} } } } rgl/man/safe.dev.off.Rd0000644000176200001440000000226015011677075014355 0ustar liggesusers\name{safe.dev.off} \alias{safe.dev.off} \title{ Close graphics device in a safe way. } \description{ The \code{\link{dev.off}} function in \pkg{grDevices} doesn't restore the previous graphics device when called. This function does. } \usage{ safe.dev.off(which = dev.cur(), prev = dev.prev()) } \arguments{ \item{which}{ Which device to close. } \item{prev}{ Which device to set as current after closing. } } \details{ This function closes device \code{which} if it is not device 1, then calls \code{\link{dev.set}(prev)} if there are any devices still open. } \value{ The number and name of the new active device. It will not necessarily be \code{prev} if that device isn't already open. } \references{ \url{https://bugs.r-project.org/show_bug.cgi?id=18604} } \author{ Duncan Murdoch } \examples{ # Open a graphics device dev.new() first <- dev.cur() # Open a second graphics device dev.new() second <- dev.cur() second # Open another one, and close it using dev.off() dev.new() dev.off() dev.cur() == second # Not the same as second! # Try again with safe.dev.off() dev.set(second) dev.new() safe.dev.off() dev.cur() == second # Close the other two devs safe.dev.off() safe.dev.off() }rgl/man/select3d.Rd0000644000176200001440000000376114771520323013621 0ustar liggesusers\name{select3d} \alias{select3d} \alias{selectionFunction3d} \title{ Select a rectangle in an RGL scene } \description{ This function allows the user to use the mouse to select a region in an RGL scene. } \usage{ select3d(button = c("left", "middle", "right"), dev = cur3d(), subscene = currentSubscene3d(dev)) selectionFunction3d(proj, region = proj$region) } \arguments{ \item{ button }{ Which button to use for selection.} \item{ dev, subscene}{ The RGL device and subscene to work with } \item{proj}{An object returned from \code{\link{rgl.projection}} containing details of the current projection.} \item{region}{Corners of a rectangular region in the display.} } \details{ \code{select3d} selects 3-dimensional regions by allowing the user to use a mouse to draw a rectangle showing the projection of the region onto the screen. It returns a function which tests points for inclusion in the selected region. \code{selectionFunction3d} constructs such a test function given coordinates and current transformation matrices. If the scene is later moved or rotated, the selected region will remain the same, though no longer corresponding to a rectangle on the screen. } \value{ These return a function \code{f(x, y, z)} which tests whether each of the points \code{(x, y, z)} is in the selected region, returning a logical vector. This function accepts input in a wide variety of formats as it uses \code{\link[grDevices]{xyz.coords}} to interpret its parameters. } \author{ Ming Chen / Duncan Murdoch } \seealso{ \code{\link{selectpoints3d}}, \code{\link{locator}} } \examples{ # Allow the user to select some points, and then redraw them # in a different color if (interactive() && !in_pkgdown_example()) { x <- rnorm(1000) y <- rnorm(1000) z <- rnorm(1000) open3d() points3d(x, y, z) f <- select3d() if (!is.null(f)) { keep <- f(x, y, z) pop3d() points3d(x[keep], y[keep], z[keep], color = 'red') points3d(x[!keep], y[!keep], z[!keep]) } } } \keyword{dynamic} rgl/man/rgl.useNULL.Rd0000644000176200001440000000177514771520323014170 0ustar liggesusers\name{rgl.useNULL} \alias{rgl.useNULL} \alias{RGL_USE_NULL} \title{ Report default use of null device } \description{ This function checks the \code{"rgl.useNULL"} option if present, or the \env{RGL_USE_NULL} environment variable if it is not. If the value is \code{TRUE} or a string which matches \dQuote{yes} or \dQuote{true} in a case-insensitive test, \code{TRUE} is returned. } \usage{ rgl.useNULL() } \note{ This function is checked by the initialization code when the \pkg{rgl} package is loaded. Thus if you want to run RGL on a system where there is no graphics support, you should run \code{options(rgl.useNULL = TRUE)} or set the environment variable \code{RGL_USE_NULL=TRUE} *before* calling \code{library(rgl)} (or other code that loads \pkg{rgl}), and it will not fail in its attempt at initialization. } \value{ A logical value indicating the current default for use of the null device. } \author{ Duncan Murdoch } \seealso{ \code{\link{open3d}} and \code{\link{rgl.open}}. } \examples{ rgl.useNULL() } rgl/man/vertexControl.Rd0000644000176200001440000000702215012460301014747 0ustar liggesusers\name{vertexControl} \alias{vertexControl} \title{ Set attributes of vertices } \description{ This is a function to produce actions in a web display. A \code{\link{playwidget}} or Shiny input control (e.g. a \code{\link[shiny]{sliderInput}} control) sets a value which controls attributes of a selection of vertices. } \usage{ vertexControl(value = 0, values = NULL, vertices = 1, attributes, objid = tagged3d(tag), tag, param = seq_len(NROW(values)) - 1, interp = TRUE) } \arguments{ \item{value}{The value to use for input (typically \code{input$value} in a Shiny app.) Not needed with \code{\link{playwidget}}.} \item{values}{ A matrix of values, each row corresponding to an input value. } \item{vertices}{ Which vertices are being controlled? Specify \code{vertices} as a number from 1 to the number of vertices in the \code{objid}. } \item{attributes}{A vector of attributes of a vertex, from \code{c("x", "y", "z", "red", "green", "blue", "alpha", "nx", "ny", "nz", "radii", "ox", "oy", "oz", "ts", "tt", "offset")}. See Details.} \item{objid}{ A single RGL object id. } \item{tag}{ An alternate way to specify \code{objid}. } \item{param}{ Parameter values corresponding to each row of \code{values}. } \item{interp}{ Whether to interpolate between rows of \code{values}. } } \details{ This function modifies attributes of vertices in a single object. The \code{attributes} are properties of each vertex in a scene; not all are applicable to all objects. In order, they are: coordinates of the vertex \code{"x", "y", "z"}, color of the vertex \code{"red", "green", "blue", "alpha"}, normal at the vertex \code{"nx", "ny", "nz"}, radius of a sphere at the vertex \code{"radius"}, origin within a texture \code{"ox", "oy"} and perhaps \code{"oz"}, texture coordinates \code{"ts", "tt"}. Planes are handled specially. The coefficients \code{a, b, c} in the \code{\link{planes3d}} or \code{\link{clipplanes3d}} specification are controlled using \code{"nx", "ny", "nz"}, and \code{d} is handled as \code{"offset"}. The \code{vertices} argument is interpreted as the indices of the planes when these attributes are set. If only one attribute of one vertex is specified, \code{values} may be given as a vector and will be treated as a one-column matrix. Otherwise \code{values} must be given as a matrix with \code{ncol(values) == max(length(vertices), length(attributes))}. The \code{vertices} and \code{attributes} vectors will be recycled to the same length, and entries from column \code{j} of \code{values} will be applied to vertex \code{vertices[j]}, attribute \code{attributes[j]}. The \code{value} argument is translated into a row (or two rows if \code{interp = TRUE}) of \code{values} by finding its location in \code{param}. } \value{ A list of class \code{"rglControl"} of cleaned up parameter values, to be used in an RGL widget. } \author{ Duncan Murdoch } \seealso{ The \HTMLVignette{WebGL}{}{User Interaction in WebGL} vignette gives more details. } \examples{ saveopts <- options(rgl.useNULL = TRUE) theta <- seq(0, 6*pi, length.out = 100) xyz <- cbind(sin(theta), cos(theta), theta) plot3d(xyz, type="l") id <- spheres3d(xyz[1,,drop=FALSE], col="red") widget <- rglwidget(width=500, height=300) \%>\% playwidget(vertexControl(values=xyz, attributes=c("x", "y", "z"), objid = id, param=1:100), start = 1, stop = 100, rate=10) if (interactive() || in_pkgdown_example()) widget options(saveopts) } rgl/man/import.Rd0000644000176200001440000000062614555455305013431 0ustar liggesusers\name{import} \alias{\%>\%} \alias{pipe} \docType{import} \title{Imported from magrittr} \description{ This object is imported from \pkg{magrittr}. Follow the link to its documentation. \describe{ \item{magrittr}{\code{\link[magrittr:pipe]{\%>\%}}} } Pipes can be used to string together \code{\link{rglwidget}} calls and \code{\link{playwidget}} calls. See \code{\link{ageControl}} for an example. } rgl/man/surface3d.Rd0000644000176200001440000000565414771520323013775 0ustar liggesusers\name{surface3d} \title{Add surface} \alias{surface3d} \description{ Adds a surface to the current scene. The surface is defined by a matrix defining the height of each grid point and two vectors or matrices defining the grid. } \usage{ surface3d(x, y, z, ..., normal_x = NULL, normal_y = NULL, normal_z = NULL, texture_s=NULL, texture_t=NULL, flip = FALSE) } \arguments{ \item{ x, y, z }{ vectors or matrices of values. See Details. } \item{ ... }{Material properties. See \code{\link{material3d}} for details.} \item{normal_x, normal_y, normal_z}{ matrices giving the coordinates of normals at each grid point } \item{texture_s, texture_t}{ matrices giving the texture coordinates at each grid point } \item{flip}{ flip definition of \dQuote{up} } } \details{ Adds a surface mesh to the current scene. The surface is typically defined by a matrix of height values in \code{z} (as in \code{\link{persp}}), but any of \code{x}, \code{y}, or \code{z} may be matrices or vectors, as long as at least one is a matrix. (One historical exception is allowed: if all are vectors but the length of \code{z} is the product of the lengths of \code{x} and \code{y}, \code{z} is converted to a matrix.) Dimensions of all matrices must match. If any of the coordinates are vectors, they are interpreted as follows: \itemize{ \item If \code{x} is a vector, it corresponds to rows of the matrix. \item If \code{y} is a vector, it corresponds to columns of the matrix. \item If \code{z} is a vector, it corresponds to columns unless \code{y} is also a vector, in which case it corresponds to rows. } If the normals are not supplied, they will be calculated automatically based on neighbouring points. Texture coordinates run from 0 to 1 over each dimension of the texture bitmap. If texture coordinates are not supplied, they will be calculated to render the texture exactly once over the grid. Values greater than 1 can be used to repeat the texture over the surface. \code{surface3d} always tries to draw the surface with the `front' upwards (typically towards higher \code{z} values). This can be used to render the top and bottom differently; see \code{\link{material3d}} and the example below. If you don't like its choice, set \code{flip = TRUE} to use the opposition definition. \code{NA} values in the height matrix are not drawn. } \examples{ # # volcano example taken from "persp" # z <- 2 * volcano # Exaggerate the relief x <- 10 * (1:nrow(z)) # 10 meter spacing (S to N) y <- 10 * (1:ncol(z)) # 10 meter spacing (E to W) zlim <- range(z) zlen <- zlim[2] - zlim[1] + 1 colorlut <- terrain.colors(zlen) # height color lookup table col <- colorlut[ z - zlim[1] + 1 ] # assign colors to heights for each point open3d() surface3d(x, y, z, color = col, back = "lines") } \seealso{ See \code{\link{persp3d}} for a higher level interface. } \keyword{dynamic} rgl/man/thigmophobe3d.Rd0000644000176200001440000000442514771520323014645 0ustar liggesusers\name{thigmophobe3d} \alias{thigmophobe3d} \title{ Find the direction away from the closest point in a 3d projection } \description{ Jim Lemon's \code{\link[plotrix]{thigmophobe}} function in the \code{\link[plotrix:plotrix-package]{plotrix}} package computes good directions for labels in a 2D plot. This function does the same for a particular projection in a 3D plot by projecting down to 2D and calling his function. } \usage{ thigmophobe3d(x, y = NULL, z = NULL, P = par3d("projMatrix"), M = par3d("modelMatrix"), windowRect = par3d("windowRect")) } \arguments{ \item{x, y, z}{point coordinates. Any reasonable way of defining the coordinates is acceptable. See the function \code{\link[grDevices]{xyz.coords}} for details. } \item{P, M, windowRect}{ The projection and modelview matrices, and the size and position of the display in pixels. } } \details{ Since \code{thigmophobe3d} projects using fixed \code{P} and \code{M}, it will not necessarily choose good directions if the user rotates the display or makes any other change to the projection.} \note{ The example below shows how to update the directions during an animation; I find that the moving labels are distracting, and prefer to live with fixed ones. } \value{ A vector of values from 1 to 4 to be used as the \code{pos} argument in \code{\link{text3d}}. } \references{ \CRANpkg{plotrix} } \author{ Duncan Murdoch } \seealso{ \code{\link{text3d}} } \examples{ if (requireNamespace("plotrix", quietly = TRUE)) { # Simulate some data xyz <- matrix(rnorm(30), ncol = 3) # Plot the data first, to establish the projection plot3d(xyz) # Now thigmophobe3d can choose directions textid <- text3d(xyz, texts = 1:10, pos = thigmophobe3d(xyz)) # Update the label positions during an animation if (interactive() && !rgl.useNULL()) { spin <- spin3d(rpm = 5) f <- function(time) { par3d(skipRedraw = TRUE) on.exit(par3d(skipRedraw = FALSE)) pop3d(id = textid) # Need to rotate before thigmophobe3d is called result <- spin(time) par3d(userMatrix = result$userMatrix) textid <<- text3d(xyz, texts = 1:10, pos = thigmophobe3d(xyz)) result } play3d(f, duration = 5) } else textid # just print the static display } } rgl/man/bgplot3d.Rd0000644000176200001440000000422314771520323013623 0ustar liggesusers\name{bgplot3d} \alias{bgplot3d} \alias{legend3d} \title{Use base graphics for RGL background} \description{ Add a 2D plot or a legend in the background of an RGL window. } \usage{ bgplot3d(expression, bg.color = getr3dDefaults("bg", "color"), magnify = 1, ...) legend3d(...) } \arguments{ \item{expression}{ Any plotting commands to produce a plot. } \item{bg.color}{ The color to use for the background. } \item{magnify}{ Multiplicative factor to apply to size of window when producing background plot. } \item{...}{ For \code{legend3d}, arguments to pass to \code{bgplot3d} or \code{\link{legend}}; for \code{bgplot3d}, arguments to pass to \code{\link{bg3d}}. } } \details{ The \code{bgplot3d} function opens a \code{\link{png}} device and executes \code{expression}, producing a plot there. This plot is then used as a bitmap background for the current RGL subscene. The \code{legend3d} function draws a standard 2D legend to the background of the current subscene by calling \code{bgplot3d} to open a device, and setting up a plot region there to fill the whole display. } \value{ The \code{bgplot3d} function invisibly returns the ID of the background object that was created, with attribute \code{"value"} holding the value returned when the \code{expression} was evaluated. The \code{legend3d} function does similarly. The \code{"value"} attribute is the result of the call to \code{\link{legend}}. The scaling of the coordinates runs from 0 to 1 in X and Y. } \author{ Duncan Murdoch } \note{ Because the background plots are drawn as bitmaps, they do not resize very gracefully. It's best to size your window first, then draw the background at that size. } \seealso{ \code{\link{bg3d}} for other background options. } \examples{ x <- rnorm(100) y <- rnorm(100) z <- rnorm(100) open3d() # Needs to be a bigger window than the default par3d(windowRect = c(100, 100, 612, 612)) parent <- currentSubscene3d() mfrow3d(2, 2) plot3d(x, y, z) next3d(reuse = FALSE) bgplot3d(plot(y, z)) next3d(reuse = FALSE) bgplot3d(plot(x, z)) next3d(reuse = FALSE) legend3d("center", c("2D Points", "3D Points"), pch = c(1, 16)) useSubscene3d(parent) } \keyword{ graphics } rgl/man/open3d.Rd0000644000176200001440000000737214771520323013305 0ustar liggesusers\name{open3d} \alias{open3d} \alias{close3d} \alias{cur3d} \alias{set3d} \alias{getr3dDefaults} \alias{r3dDefaults} \alias{rgl.dev.list} \alias{rgl.quit} \title{Work with RGL windows} \description{ \code{open3d} opens a new RGL window; \code{cur3d} returns the device number of the current window; \code{close3d} closes one or more windows. } \usage{ open3d(\dots, params = getr3dDefaults(), useNULL = rgl.useNULL(), silent = FALSE) close3d(dev = cur3d(), silent = TRUE) cur3d() rgl.dev.list() set3d(dev, silent = FALSE) getr3dDefaults(class = NULL, value = NULL) r3dDefaults rgl.quit() } \arguments{ \item{\dots}{arguments in \code{name = value} form, or a list of named values. The names must come from the graphical parameters described in \code{\link{par3d}}.} \item{params}{a list of graphical parameters} \item{useNULL}{whether to use the null graphics device} \item{dev}{which device to close or use} \item{silent}{whether report on what was done} \item{class, value}{names of components to retrieve} } \details{ \code{open3d} opens a new RGL device, and sets the parameters as requested. The \code{r3dDefaults} list returned by the \code{getr3dDefaults} function will be used as default values for parameters. As installed this sets the point of view to 'world coordinates' (i.e. x running from left to right, y from front to back, z from bottom to top), the \code{mouseMode} to \code{(zAxis, zoom, fov)}, and the field of view to 30 degrees. \code{useFreeType} defaults to \code{FALSE} on Windows; on other systems it indicates the availability of FreeType. Users may create their own variable named \code{r3dDefaults} in the global environment and it will override the installed one. If there is a \code{bg} element in the list or the arguments, it should be a list of arguments to pass to the \code{\link{bg3d}} function to set the background. The arguments to \code{open3d} may include \code{material}, a list of material properties as in \code{\link{r3dDefaults}}, but note that high level functions such as \code{\link{plot3d}} normally use the \code{r3dDefaults} values in preference to this setting. If \code{useNULL} is \code{TRUE}, RGL will use a \dQuote{null} device. This device records objects as they are plotted, but displays nothing. It is intended for use with \code{\link{rglwidget}}. } \value{ The \code{open3d} function returns the device that was opened. If \code{silent = TRUE}, it is returned invisibly. The \code{cur3d} function returns the current device, or the value 0 if there isn't one. \code{rgl.dev.list} returns a vector of all open devices. Items are named according to the type of device: \code{null} for a hidden null device, \code{wgl} for a Windows device, and \code{glX} for an X windows device. \code{set3d} returns the device number of the previously active device. The \code{close3d} function returns the new current device, invisibly. The \code{r3dDefaults} variable is a list containing default settings. The \code{getr3dDefaults} function searches the user's global environment for \code{r3dDefaults} and returns the one in the RGL namespace if it was not found there. The components of the list may include any settable \code{par3d} parameter, or \code{"material"}, which should include a list of default \code{\link{material3d}} properties, or \code{"bg"}, which is a list of defaults to pass to the \code{\link{bg3d}} function. \code{rgl.quit} attempts to unload \pkg{rgl} and then returns \code{NULL} invisibly. } \seealso{ \code{\link{rgl.useNULL}} for default usage of null device. } \examples{ r3dDefaults open3d() shade3d(cube3d(color = rainbow(6), meshColor = "faces")) cur3d() } \keyword{dynamic} rgl/man/mfrow3d.Rd0000644000176200001440000001034214771520323013465 0ustar liggesusers\name{mfrow3d} \alias{mfrow3d} \alias{layout3d} \alias{next3d} \alias{subsceneList} \alias{clearSubsceneList} \title{ Set up multiple figure layouts } \description{ The \code{mfrow3d} and \code{layout3d} functions provide functionality in RGL similar to \code{\link{par}("mfrow")} and \code{\link{layout}} in classic R graphics. } \usage{ subsceneList(value, window = cur3d()) mfrow3d(nr, nc, byrow = TRUE, parent = NA, sharedMouse = FALSE, ...) layout3d(mat, widths = rep.int(1, ncol(mat)), heights = rep.int(1, nrow(mat)), parent = NA, sharedMouse = FALSE, ...) next3d(current = NA, clear = TRUE, reuse = TRUE) clearSubsceneList(delete = currentSubscene3d() \%in\% subsceneList(), window = cur3d()) } \arguments{ \item{value}{ A new subscene list to set. If missing, return the current one (or \code{NULL}). } \item{window}{ Which window to operate on. } \item{nr, nc}{ Number of rows and columns of figures. } \item{byrow}{ Whether figures progress by row (as with \code{\link{par}("mfrow")}) or by column (as with \code{\link{par}("mfcol")}). } \item{mat, widths, heights}{ Layout parameters; see \code{\link{layout}} for their interpretation. } \item{parent}{ The parent subscene. \code{NA} indicates the current subscene. See Details below. } \item{sharedMouse}{ Whether to make all subscenes \code{\link{par3d}("listeners")} to each other. } \item{\dots}{ Additional parameters to pass to \code{\link{newSubscene3d}} as each subscene is created. } \item{current}{ The subscene to move away from. \code{NA} indicates the current subscene. } \item{clear}{ Whether the newly entered subscene should be cleared upon entry. } \item{reuse}{ Whether to skip advancing if the current subscene has no objects in it. } \item{delete}{ If \code{TRUE}, delete the subscenes in the current window. } } \details{ rgl can maintain a list of subscenes; the \code{mfrow3d} and \code{layout3d} functions create that list. When the list is in place, \code{next3d} causes RGL to move to the next scene in the list, or cycle back to the first one. Unlike the classic R graphics versions of these functions, these functions are completely compatible with each other. You can mix them within a single RGL window. In the default case where \code{parent} is missing, \code{mfrow3d} and \code{layout3d} will call \code{clearSubsceneList()} at the start. By default \code{clearSubsceneList()} checks whether the current subscene is in the current subscene list; if so, it will delete all subscenes in the list, and call \code{\link{gc3d}} to delete any objects that are no longer shown. The subscene list will be set to a previous value if one was recorded, or \code{NULL} if not. If \code{parent} is specified in \code{mfrow3d} or \code{layout3d} (even as \code{NA}), the new subscenes will be created within the parent. The \code{next3d()} function first finds out if the current subscene is in the current list. If not, it moves to the previous list, and looks there. Once it finds a list containing the current subscene, it moves to the next entry in that list. If it can't find one, it creates a length one list containing just the current subscene. } \value{ \code{mfrow3d} and \code{layout3d} return a vector of subscene id values that have just been created. If a previous subscene list was in effect and was not automatically cleared, it is attached as an attribute \code{"prev"}. } \author{ Duncan Murdoch } \seealso{ \code{\link{newSubscene3d}}, \code{\link{par}}, \code{\link{layout}}. } \examples{ shapes <- list(Tetrahedron = tetrahedron3d(), Cube = cube3d(), Octahedron = octahedron3d(), Icosahedron = icosahedron3d(), Dodecahedron = dodecahedron3d(), Cuboctahedron = cuboctahedron3d()) col <- rainbow(6) open3d() mfrow3d(3, 2) for (i in 1:6) { next3d() # won't advance the first time, since it is empty shade3d(shapes[[i]], col = col[i]) } highlevel(integer()) # To trigger display as rglwidget open3d() mat <- matrix(1:4, 2, 2) mat <- rbind(mat, mat + 4, mat + 8) layout3d(mat, height = rep(c(3, 1), 3), sharedMouse = TRUE) for (i in 1:6) { next3d() shade3d(shapes[[i]], col = col[i]) next3d() text3d(0, 0, 0, names(shapes)[i]) } highlevel(integer()) } \keyword{graphics } rgl/man/subdivision3d.Rd0000644000176200001440000000510414771520323014671 0ustar liggesusers\name{subdivision3d} \alias{subdivision3d} \alias{subdivision3d.mesh3d} \alias{divide.mesh3d} \alias{normalize.mesh3d} \alias{deform.mesh3d} \title{Subdivide a mesh} \description{ The subdivision surface algorithm divides and refines (deforms) a given mesh recursively to certain degree (depth). The mesh3d algorithm consists of two stages: divide and deform. The divide step generates for each triangle or quad four new triangles or quads, the deform step drags the points (refinement step). } \usage{ subdivision3d( x, ...) \method{subdivision3d}{mesh3d}( x, depth = 1, normalize = FALSE, deform = TRUE, keepTags = FALSE, ... ) divide.mesh3d(mesh, vb = mesh$vb, ib = mesh$ib, it = mesh$it, is = mesh$is, keepTags = FALSE) normalize.mesh3d(mesh) deform.mesh3d(mesh, vb = mesh$vb, ib = mesh$ib, it = mesh$it, is = mesh$is) } \arguments{ \item{x}{3d geometry mesh} \item{mesh}{3d geometry mesh} \item{depth}{recursion depth} \item{normalize}{normalize mesh3d coordinates after division if \code{deform} is \code{TRUE}} \item{deform}{deform mesh} \item{keepTags}{if \code{TRUE}, add a \code{"tags"} component to the output.} \item{is}{indices for segments} \item{it}{indices for triangular faces} \item{ib}{indices for quad faces} \item{vb}{matrix of vertices: 4 x n matrix (rows x, y, z, h) or equivalent vector, where h indicates scaling of each plotted quad} \item{...}{other arguments (unused)} } \details{ \code{subdivision3d} takes a mesh object and replaces each segment with two new ones, and each triangle or quad with 4 new ones by adding vertices half-way along the edges (and one in the centre of a quad). The positions of the vertices are deformed so that the resulting surface is smoother than the original. These operations are repeated \code{depth} times. The other functions do the individual steps of the subdivision. \code{divide.mesh3d} adds the extra vertices. \code{deform.mesh3d} does the smoothing by replacing each vertex with the average of each of its neighbours. \code{normalize.mesh3d} normalizes the homogeneous coordinates, by setting the 4th coordinate to 1. (The 4th coordinate is used as a weight in the deform step.) } \value{ A modified \code{\link{mesh3d}} object. If \code{keepTags} is \code{TRUE}, it will contain a \code{tags} component. For details, see the \code{\link{clipMesh3d}} help topic. } \examples{ open3d() shade3d( subdivision3d( cube3d(), depth = 3 ), color = "red", alpha = 0.5 ) } \seealso{ \code{\link{r3d}} \code{\link{mesh3d}} } \keyword{dynamic} rgl/man/subscene3d.Rd0000644000176200001440000001571014771520323014146 0ustar liggesusers\name{subscene3d} \alias{subscene3d} \alias{newSubscene3d} \alias{currentSubscene3d} \alias{useSubscene3d} \alias{addToSubscene3d} \alias{delFromSubscene3d} \alias{gc3d} \title{ Create, select or modify a subscene } \description{ This creates a new subscene, or selects one by \code{id} value, or adds objects to one. } \usage{ newSubscene3d(viewport = "replace", projection = "replace", model = "replace", mouseMode = "inherit", parent = currentSubscene3d(), copyLights = TRUE, copyShapes = FALSE, copyBBoxDeco = copyShapes, copyBackground = FALSE, newviewport, ignoreExtent) currentSubscene3d(dev = cur3d()) useSubscene3d(subscene) addToSubscene3d(ids = tagged3d(tags), tags, subscene = currentSubscene3d()) delFromSubscene3d(ids = tagged3d(tags), tags, subscene = currentSubscene3d()) gc3d(protect = NULL) } \arguments{ \item{viewport, projection, model, mouseMode}{ How should the new subscene be embedded? Possible values are \code{c("inherit", "modify", "replace")}. See Details below. } \item{parent}{ The parent subscene (defaults to the current subscene). } \item{copyLights, copyShapes, copyBBoxDeco, copyBackground}{ Whether lights, shapes, bounding box decorations and background should be copied to the new subscene. } \item{newviewport}{ Optionally specify the new subscene's viewport (in pixels). } \item{ignoreExtent}{ Whether to ignore the subscene's bounding box when calculating the parent bounding box. Defaults to \code{TRUE} if \code{model} is not \code{"inherit"}. } \item{dev}{ Which RGL device to query for the current subscene. } \item{subscene}{ Which subscene to use or modify. } \item{ids}{ A vector of integer object ids to add to the subscene. } \item{tags}{ Alternate way to specify \code{ids}. Ignored if \code{ids} is given. } \item{protect}{ Object ids to protect from this garbage collection. } } \details{ The \pkg{rgl} package allows multiple windows to be open; each one corresponds to a \dQuote{scene}. Within each scene there are one or more \dQuote{subscenes}. Each subscene corresponds to a rectangular region in the window, and may have its own projection, transformation and behaviour in response to the mouse. There is always a current subscene: most graphic operations make changes there, e.g. by adding an object to it. The scene \dQuote{owns} objects; \code{addToSubscene3d} and \code{delFromSubscene3d} put their ids into or remove them from the list being displayed within a particular subscene. The \code{gc3d} function deletes objects from the scene if they are not visible in any subscene, unless they are protected by having their id included in \code{protect}. The \code{viewport}, \code{projection} and \code{model} parameters each have three possible settings: \code{c("inherit", "modify", "replace")}. \code{"inherit"} means that the corresponding value from the parent subscene will be used. \code{"replace"} means that the new subscene will have its own value of the value, independent of its parent. \code{"modify"} means that the child value will be applied first, and then the parent value will be applied. For viewport, this means that if the parent viewport is changed, the child will maintain its relative position. For the two matrices, \code{"modify"} is unlikely to give satisfactory results, but it is available for possible use. The \code{mouseMode} parameter can only be one of \code{c("inherit", "replace")}. If it is \code{"inherit"}, the subscene will use the mouse controls of the parent, and any change to them will affect the parent and all children that inherit from it. This is the behaviour that was present before \pkg{rgl} version 0.100.13. If it is \code{"replace"}, then it will receive a copy of the parent mouse controls, but modifications to them will affect only this subscene, not the parent. Note that this is orthogonal to the \code{\link{par3d}("listeners")} setting: if another subscene is listed as a listener, it will respond to mouse actions using the same mode as the one receiving them. The \code{viewport} parameter controls the rectangular region in which the subscene is displayed. It is specified using \code{newviewport} (in pixels relative to the whole window), or set to match the parent viewport. The \code{projection} parameter controls settings corresponding to the observer. These include the field of view and the zoom; they also include the position of the observer relative to the model. The \code{par3d("projMatrix")} matrix is determined by the projection. The \code{model} parameter controls settings corresponding to the model. Mouse rotations affect the model, as does scaling. The \code{par3d("modelMatrix")} matrix is determined by these as well as by the position of the observer (since OpenGL assumes that the observer is at (0, 0, 0) after the MODELVIEW transformation). Only those parts concerning the model are inherited when \code{model} specifies inheritance, the observer setting is controlled by \code{projection}. If \code{copyBackground} is \code{TRUE}, the background of the newly created child will overwrite anything displayed in the parent subscene, regardless of depth. } \value{ If successful, each function returns the object id of the subscene, with the exception of \code{gc3d}, which returns the count of objects which have been deleted, and \code{useSubscene3d}, which returns the previously active subscene id. } \author{ Duncan Murdoch and Fang He. } \seealso{ \code{\link{subsceneInfo}} for information about a subscene, \code{\link{mfrow3d}} and \code{\link{layout3d}} to set up multiple panes of subscenes. } \examples{ # Show the Earth with a cutout by using clipplanes in subscenes lat <- matrix(seq(90, -90, length.out = 50)*pi/180, 50, 50, byrow = TRUE) long <- matrix(seq(-180, 180, length.out = 50)*pi/180, 50, 50) r <- 6378.1 # radius of Earth in km x <- r*cos(lat)*cos(long) y <- r*cos(lat)*sin(long) z <- r*sin(lat) open3d() obj <- surface3d(x, y, z, col = "white", texture = system.file("textures/worldsmall.png", package = "rgl"), specular = "black", axes = FALSE, box = FALSE, xlab = "", ylab = "", zlab = "", normal_x = x, normal_y = y, normal_z = z) cols <- c(rep("chocolate4", 4), rep("burlywood1", 4), "darkgoldenrod1") rs <- c(6350, 5639, 4928.5, 4207, 3486, (3486 + 2351)/2, 2351, (2351 + 1216)/2, 1216) for (i in seq_along(rs)) obj <- c(obj, spheres3d(0, 0, col = cols[i], radius = rs[i])) root <- currentSubscene3d() newSubscene3d("inherit", "inherit", "inherit", copyShapes = TRUE, parent = root) clipplanes3d(1, 0, 0, 0) newSubscene3d("inherit", "inherit", "inherit", copyShapes = TRUE, parent = root) clipplanes3d(0, 1, 0, 0) newSubscene3d("inherit", "inherit", "inherit", copyShapes = TRUE, parent = root) clipplanes3d(0, 0, 1, 0) # Now delete the objects from the root subscene, to reveal the clipping planes useSubscene3d(root) delFromSubscene3d(obj) } \keyword{ graphics } rgl/man/observer3d.Rd0000644000176200001440000000312014771520323014156 0ustar liggesusers\name{observer3d} \alias{observer3d} \title{ Set the observer location } \description{ This function sets the location of the viewer. } \usage{ observer3d(x, y = NULL, z = NULL, auto = FALSE) } \arguments{ \item{x, y, z}{ The location as a 3 vector, using the usual \code{xyz.coords} conventions for specification. If \code{x} is missing or any coordinate is \code{NA}, no change will be made to the location. } \item{auto}{ If \code{TRUE}, the location will be set automatically by RGL to make the whole bounding box visible. } } \details{ This function sets the location of the viewer relative to the scene, after the model transformations (scaling, rotation) have been done, but before lighting or projection have been applied. (See \code{\link{par3d}} for details on the rendering pipeline.) The coordinate system is a slightly strange one: the X coordinate moves the observer location from left to right, and the Y coordinate moves up and down. The Z coordinate changes the depth from the viewer. All are measured relative to the center of the bounding box (\code{par("bbox")}) of the subscene. The observer always looks in the positive Z direction after the model rotation have been done. The coordinates are in post-scaling units. } \note{ This function is likely to change in future versions of RGL, to allow more flexibility in the specification of the observer's location and orientation. } \value{ Invisibly returns the previous value. } \author{ Duncan Murdoch } \examples{ example(surface3d) # The volcano data observer3d(0, 0, 440) # Viewed from very close up } \keyword{ graphics } rgl/man/shiny.Rd0000644000176200001440000000366514771520323013250 0ustar liggesusers\name{shiny} \alias{rglwidgetOutput} \alias{renderRglwidget} \alias{playwidgetOutput} \alias{renderPlaywidget} \title{ Functions for integration of RGL widgets into Shiny app } \description{ These functions allow an RGL scene to be embedded in a Shiny app. } \usage{ rglwidgetOutput(outputId, width = "512px", height = "512px") renderRglwidget(expr, env = parent.frame(), quoted = FALSE, outputArgs = list()) playwidgetOutput(outputId, width = "0px", height = "0px") renderPlaywidget(expr, env = parent.frame(), quoted = FALSE, outputArgs = list()) } \arguments{ \item{outputId}{ The name for the control. } \item{width, height}{ Width and height to display the control. } \item{expr}{An R expression returning a \code{\link{rglwidget}} (for \code{renderRglwidget}) or a \code{\link{playwidget}} (for \code{renderPlaywidget}) as output.} \item{env}{The environment in which to evaluate \code{expr}.} \item{quoted}{Is the expression already quoted?} \item{outputArgs}{A list containing arguments; see details below.} } \details{ Use \code{rglwidgetOutput} or \code{playwidgetOutput} as an output object in a Shiny user interface section; use \code{renderRglwidget} or \code{renderPlaywidget} as the render function in the server section. In a dynamic R Markdown document with \code{runtime: shiny}, you only call the render function, and may optionally pass \code{width} and \code{height} to the output function by putting them in a list in \code{outputArgs}. See the example below. } \value{ Used internally by Shiny. } \author{ Duncan Murdoch } \examples{ \dontrun{ # This could be used in a dynamic R Markdown document. See # demo("shinyDemo") and demo("simpleShinyRgl") for Shiny apps. inputPanel( sliderInput("n", label = "n", min = 10, max = 100, value = 10, step = 10) ) renderRglwidget({ n <- input$n try(close3d()) plot3d(rnorm(n), rnorm(n), rnorm(n)) rglwidget() }, outputArgs = list(width = "auto", height = "300px")) } } rgl/man/par3dinterpControl.Rd0000644000176200001440000000310615012460301015664 0ustar liggesusers\name{par3dinterpControl} \alias{par3dinterpControl} \title{ Control RGL widget like par3dinterp() } \description{ This control works with \code{\link{playwidget}} to change settings in a WebGL display in the same way as \code{\link{par3dinterp}} does within R. } \usage{ par3dinterpControl(fn, from, to, steps, subscene = NULL, omitConstant = TRUE, ...) } \arguments{ \item{fn}{A function returned from \code{\link{par3dinterp}}.} \item{from, to, steps}{Values where \code{fn} should be evaluated.} \item{subscene}{Which subscene's properties should be modified?} \item{omitConstant}{If \code{TRUE}, do not set values that are constant across the range.} \item{...}{Additional parameters which will be passed to \code{\link{propertyControl}}.} } \details{ \code{par3dinterpSetter} sets parameters corresponding to values produced by the result of \code{par3dinterp}. } \value{ Returns controller data in a list of class "rglControl". } \author{ Duncan Murdoch } \seealso{ The \HTMLVignette{WebGL}{}{User Interaction in WebGL} vignette gives more details. } \examples{ example(plot3d) M <- r3dDefaults$userMatrix fn <- par3dinterp(times = (0:2)*0.75, userMatrix = list(M, rotate3d(M, pi/2, 1, 0, 0), rotate3d(M, pi/2, 0, 1, 0)), scale = c(0.5, 1, 2)) control <- par3dinterpControl(fn, 0, 3, steps = 15) control if (interactive() || in_pkgdown_example()) rglwidget(width = 500, height = 250) \%>\% playwidget(control, step = 0.01, loop = TRUE, rate = 0.5) } rgl/man/persp3d.tri.Rd0000644000176200001440000001013014771520323014254 0ustar liggesusers\name{persp3d.triSht} \alias{persp3d.triSht} \alias{plot3d.triSht} \alias{as.mesh3d.triSht} \alias{persp3d.tri} \alias{plot3d.tri} \alias{as.mesh3d.tri} \title{ Plot an interp or tripack Delaunay triangulation } \description{ The \code{\link[interp]{tri.mesh}()} functions in the \pkg{interp} and \pkg{tripack} packages compute a Delaunay triangulation of a set of points. These functions display it as a surface. } \usage{ \method{plot3d}{triSht}(x, z, ...) \method{persp3d}{triSht}(x, z, ..., add = FALSE) \method{as.mesh3d}{triSht}(x, z, col = "gray", coords = c("x", "y", "z"), smooth = TRUE, normals = NULL, texcoords = NULL, ...) \method{plot3d}{tri}(x, z, ...) \method{persp3d}{tri}(x, z, ..., add = FALSE) \method{as.mesh3d}{tri}(x, z, col = "gray", coords = c("x", "y", "z"), smooth = TRUE, normals = NULL, texcoords = NULL, ...) } \arguments{ \item{x}{ A \code{"triSht"} or \code{"tri"} object, produced by the \code{\link[interp]{tri.mesh}()} function in the \pkg{interp} or \pkg{tripack} packages respectively. } \item{z}{ z coordinate values corresponding to each of the nodes in \code{x}. } \item{add}{ Whether to add surface to existing plot (\code{add = TRUE}) or create a new plot (\code{add = FALSE}, the default). } \item{col}{ Colors to apply to each vertex in the triangulation. Will be recycled as needed. } \item{coords}{ See Details below. } \item{smooth}{ Whether to average normals at vertices for a smooth appearance. } \item{normals}{ User-specified normals at each vertex. Requires \code{smooth = FALSE}. } \item{texcoords}{ Texture coordinates at each vertex. } \item{...}{ See Details below. } } \details{ These functions construct a \code{\link{mesh3d}} object corresponding to the triangulation in \code{x}. The \code{plot3d} and \code{persp3d} methods plot it. The \code{coords} parameter allows surfaces to be plotted over any coordinate plane. It should be a permutation of the column names \code{c("x", "y", "z")}. The first will be used as the x coordinate, the second as the y coordinate, and the third as the z coordinate. The \code{...} parameters in \code{plot3d.triSht} and \code{plot3d.tri} are passed to \code{persp3d}; in \code{persp3d.triSht} and \code{persp3d.tri} they are passed to both \code{as.mesh3d} and \code{persp3d.mesh3d}; in \code{as.mesh3d.triSht} and \code{as.mesh3d.tri} they are used as material parameters in a \code{\link{tmesh3d}} call. \code{"tri"} objects may contain constraints. These appear internally as extra nodes, representing either the inside or outside of boundaries on the region being triangulated. Each of these nodes should also have a \code{z} value, but triangles corresponding entirely to constraint nodes will not be drawn. In this way complex, non-convex regions can be triangulated. See the second example below. } \note{ If there are duplicate points, the \code{tri.mesh()} functions will optionally delete some of them. If you choose this option, the \code{z} values must correspond to the nodes \emph{after} deletion, not before. } \examples{ x <- rnorm(200, sd = 5) y <- rnorm(200, sd = 5) r <- sqrt(x^2 + y^2) z <- 10 * sin(r)/r col <- cm.colors(20)[1 + round(19*(z - min(z))/diff(range(z)))] save <- NULL if ((haveinterp <- requireNamespace("interp", quietly = TRUE))) { save <- options(rgl.meshColorWarning = FALSE) dxy <- interp::tri.mesh(x, y) open3d() persp3d(dxy, z, col = col, meshColor = "vertices") } if (haveinterp) { open3d() # Do it without smoothing and with a different orientation. persp3d(dxy, z, col = col, coords = c("z", "x", "y"), smooth = FALSE) } if (requireNamespace("tripack", quietly = TRUE)) { if (is.null(save)) save <- options(rgl.meshColorWarning = FALSE) # Leave a circular hole around (3, 0) theta <- seq(0, 2*pi, length.out = 30)[-1] cx <- 2*cos(theta) + 3 cy <- 2*sin(theta) keep <- (x - 3)^2 + y^2 > 4 dxy2 <- tripack::tri.mesh(x[keep], y[keep]) dxy2 <- tripack::add.constraint(dxy2, cx, cy) z <- dxy2$x^2 - dxy2$y^2 col <- terrain.colors(20)[1 + round(19*(z - min(z))/diff(range(z)))] open3d() persp3d(dxy2, z, col = col) } options(save) } \keyword{graphics} rgl/man/persp3d.function.Rd0000644000176200001440000001314115011677075015315 0ustar liggesusers\name{persp3d.function} \alias{plot3d.function} \alias{persp3d.function} \title{ Plot a function of two variables } \description{ Plot a function \code{z(x, y)} or a parametric function \code{(x(s, t), y(s, t), z(s, t))}. } \usage{ \method{persp3d}{`function`}(x, xlim = c(0, 1), ylim = c(0, 1), slim = NULL, tlim = NULL, n = 101, xvals = seq.int(min(xlim), max(xlim), length.out = n[1]), yvals = seq.int(min(ylim), max(ylim), length.out = n[2]), svals = seq.int(min(slim), max(slim), length.out = n[1]), tvals = seq.int(min(tlim), max(tlim), length.out = n[2]), xlab, ylab, zlab, col = "gray", otherargs = list(), normal = NULL, texcoords = NULL, \dots) \S3method{plot3d}{`function`}(x, \ldots) } \arguments{ \item{x}{ A function of two arguments. See the details below. } \item{xlim, ylim}{ By default, the range of x and y values. For a parametric surface, if these are not missing, they are used as limits on the displayed x and y values. } \item{slim, tlim}{ If not \code{NULL}, these give the range of s and t in the parametric specification of the surface. If only one is given, the other defaults to \code{c(0, 1)}. } \item{n}{ A one or two element vector giving the number of steps in the x and y (or s and t) grid. } \item{xvals, yvals}{ The values at which to evaluate x and y. Ignored for a parametric surface. If used, \code{xlim} and/or \code{ylim} are ignored. } \item{svals, tvals}{ The values at which to evaluate s and t for a parametric surface. Only used if \code{slim} or \code{tlim} is not \code{NULL}. As with \code{xvals} and \code{yvals}, these override the corresponding \code{slim} or \code{tlim} specification. } \item{xlab, ylab, zlab}{ The axis labels. See the details below for the defaults. } \item{col}{ The color to use for the plot. See the details below. } \item{otherargs}{ Additional arguments to pass to the function. } \item{normal, texcoords}{ Functions to set surface normals or texture coordinates. See the details below. } \item{\dots}{ Additional arguments to pass to \code{\link{persp3d}}. } } \details{ The \code{"function"} method for \code{plot3d} simply passes all arguments to \code{persp3d}. Thus this description applies to both. The first argument \code{x} is required to be a function. It is named \code{x} only because of the requirements of the S3 system; in the remainder of this help page, we will assume that the assignment \code{f <- x} has been made, and will refer to the function \code{f()}. \code{persp3d.function} evaluates \code{f()} on a two-dimensional grid of values, and displays the resulting surface. The values on the grid will be passed in as vectors in the first two arguments to the function, so \code{f()} needs to be vectorized. Other optional arguments to \code{f()} can be specified in the \code{otherargs} list. In the default form where \code{slim} and \code{tlim} are both \code{NULL}, it is assumed that \code{f(x, y)} returns heights, which will be plotted in the z coordinate. The default axis labels will be taken from the argument names to \code{f()} and the expression passed as argument \code{x} to this function. If \code{slim} or \code{tlim} is specified, a parametric surface is plotted. The function \code{f(s, t)} must return a 3-column matrix, giving x, y and z coordinates of points on the surface. The default axis labels will be the column names if those are present. In this case \code{xlim}, \code{ylim} and \code{zlim} are used to define a clipping region only if specified; the defaults are ignored. The color of the surface may be specified as the name of a color, or a vector or matrix of color names. In this case the colors will be recycled across the points on the grid of values. Alternatively, a function may be given: it should be a function like \code{\link{rainbow}} that takes an integer argument and returns a vector of colors. In this case the colors are mapped to z values. The \code{normal} argument allows specification of a function to compute normal vectors to the surface. This function is passed the same arguments as \code{f()} (including \code{otherargs} if present), and should produce a 3-column matrix containing the x, y and z coordinates of the normals. The \code{texcoords} argument is a function similar to \code{normal}, but it produces a 2-column matrix containing texture coordinates. Both \code{normal} and \code{texcoords} may also contain matrices, with 3 and 2 columns respectively, and rows corresponding to the points that were passed to \code{f()}. } \value{ This function constructs a call to \code{\link{persp3d}} and returns the value from that function. } \author{ Duncan Murdoch } \seealso{ The \code{\link{curve}} function in base graphics does something similar for functions of one variable. See the example below for space curves. } \examples{ # (1) The Obligatory Mathematical surface. # Rotated sinc function, with colors f <- function(x, y) { r <- sqrt(x^2 + y^2) ifelse(r == 0, 10, 10 * sin(r)/r) } open3d() plot3d(f, col = colorRampPalette(c("blue", "white", "red")), xlab = "X", ylab = "Y", zlab = "Sinc( r )", xlim = c(-10, 10), ylim = c(-10, 10), aspect = c(1, 1, 0.5)) # (2) A cylindrical plot f <- function(s, t) { r <- 1 + exp( -pmin( (s - t)^2, (s - t - 1)^2, (s - t + 1)^2 )/0.01 ) cbind(r*cos(t*2*pi), r*sin(t*2*pi), s) } open3d() plot3d(f, slim = c(0, 1), tlim = c(0, 1), col = "red", alpha = 0.8) # Add a curve to the plot, fixing s at 0.5. plot3d(f(0.5, seq.int(0, 1, length.out = 100)), type = "l", add = TRUE, lwd = 3, depth_test = "lequal") } \keyword{ graphics } rgl/man/playwidget.Rd0000644000176200001440000001426415011677075014271 0ustar liggesusers\name{playwidget} \alias{playwidget} \title{ Add a widget to play animations } \description{ This is a widget that can be put in a web page to allow animations with or without Shiny. } \usage{ playwidget(sceneId, controls, start = 0, stop = Inf, interval = 0.05, rate = 1, components = c("Reverse", "Play", "Slower", "Faster", "Reset", "Slider", "Label"), loop = TRUE, step = 1, labels = NULL, precision = 3, elementId = NULL, respondTo = NULL, reinit = NULL, buttonLabels = components, pause = "Pause", height = 40, ...) } \arguments{ \item{sceneId}{ The HTML id of the RGL scene being controlled, or an object. See the Details below. } \item{controls}{ A single \code{"rglControl"} object, e.g. \code{\link{propertyControl}}, or a list of several. } \item{start, stop}{ The starting and stopping values of the animation. If \code{labels} is supplied \code{stop} will default to step through the labels. } \item{interval}{ The requested interval (in seconds) between updates. Updates may occur at longer intervals. } \item{rate}{ The number of units of \dQuote{nominal} time per real world second. } \item{components}{ Which components should be displayed? See Details below. } \item{loop}{ When the player reaches the end of the interval, should it loop back to the beginning? } \item{step}{ Step size in the slider. } \item{labels}{ Optional labels to use, corresponding to slider steps. Set to \code{NULL} for auto-generated labels. } \item{precision}{ If \code{labels=NULL}, the precision to use when displaying timer values. } \item{elementId}{ The HTML id of the generated widget, containing buttons, slider, etc. } \item{respondTo}{ The HTML ID of a Shiny input control (e.g. a \code{\link[shiny]{sliderInput}} control) to respond to.} \item{reinit}{ A vector of ids that will need re-initialization before being drawn again. } \item{buttonLabels, pause}{ These are the labels that will be shown on the buttons if they are displayed. \code{pause} will be shown on the \code{"Play"} button while playing. } \item{height}{ The height of the widget in pixels. In a pipe, this is a relative height. } \item{...}{Additional arguments to pass to to \code{htmlwidgets::\link[htmlwidgets]{createWidget}}.} } \details{ The \code{components} are buttons to control the animation, a slider for manual control, and a label to show the current value. They will be displayed in the order given in \code{components}. Not all need be included. The buttons have the following behaviour: \describe{ \item{Reverse}{Reverse the direction.} \item{Play}{Play the animation.} \item{Slower}{Decrease the playing speed.} \item{Faster}{Increase the playing speed.} \item{Reset}{Stop the animation and reset to the start value.} } If \code{respondTo} is used, no \code{components} are shown, as it is assumed Shiny (or whatever control is being referenced) will provide the UI components. The \code{sceneId} component can be another \code{playwidget}, a \code{\link{rglwidget}} result, or a result of \code{htmltools::\link[htmltools:builder]{tags}} or \code{htmltools::\link[htmltools:tag]{tagList}}. This allows you to use a \pkg{magrittr}-style \dQuote{pipe} command to join an \code{rglwidget} with one or more \code{\link{playwidget}}s. If a \code{playwidget} comes first, \code{sceneId} should be set to \code{NA}. If the \code{\link{rglwidget}} does not come first, previous values should be piped into its \code{controllers} argument. Other HTML code (including other widgets) can be used in the chain if wrapped in \code{htmltools::\link[htmltools:tag]{tagList}}. Each control should inherit from \code{"rglControl"}. They can have the following components in addition to any private ones: \describe{ \item{\code{labels}}{default labels for the slider.} \item{\code{param}}{values to include on the slider.} \item{\code{dependencies}}{additional HTML dependencies to include, after the default \code{rglwidgetClass}.} } } \section{Appearance}{ The appearance of the controls is set by the stylesheet in \code{system.file("htmlwidgets/lib/rglClass/rgl.css")}. The overall widget is of class \code{rglPlayer}, with id set according to \code{elementId}. The buttons are of HTML class \code{rgl-button}, the slider is of class \code{rgl-slider}, and the label is of class \code{rgl-label}. Each element has an id prefixed by the widget id, e.g. \code{elementId-button-Reverse}, \code{elementId-slider}, etc. (where \code{elementId} should be replaced by the actual id). The \code{reinit} parameter handles the case where an object needs re-initialization after each change. For example, plane objects may need this if their intersection with the bounding box changes shape. Note that re-initialization is generally incompatible with the \code{\link{vertexControl}} as it modifies values which are set during initialization. } \value{ A widget suitable for use in an \pkg{Rmarkdown}-generated web page, or elsewhere. } \author{ Duncan Murdoch } \seealso{ \code{\link{subsetControl}}, \code{\link{propertyControl}}, \code{\link{ageControl}} and \code{\link{vertexControl}} are possible controls to use. \code{\link{toggleWidget}} is a wrapper for \code{playwidget} and \code{\link{subsetControl}} to insert a single button to toggle some elements in a display. } \examples{ saveopts <- options(rgl.useNULL = TRUE) objid <- plot3d(1:10, 1:10, rnorm(10), col=c("red", "red"), type = "s")["data"] control <- ageControl(value=0, births=1:10, ages = c(-5,0,5), colors = c("green", "yellow", "red"), objids = objid) \donttest{ # This example uses explicit names rglwidget(elementId = "theplot", controllers = "theplayer", height = 300, width = 300) playwidget("theplot", control, start = -5, stop = 5, rate = 3, elementId = "theplayer", components = c("Play", "Slider")) } # This example uses pipes, and can skip the names widget <- rglwidget(height = 300, width = 300) \%>\% playwidget(control, start = -5, stop = 5, rate = 3, components = c("Play", "Slider")) if (interactive() || in_pkgdown_example()) widget options(saveopts) } rgl/man/plot3d.Rd0000644000176200001440000001003514771520323013310 0ustar liggesusers\name{plot3d} \alias{plot3d} \alias{plot3d.default} \alias{plot3d.mesh3d} \title{3D scatterplot} \description{ Draws a 3D scatterplot. } \usage{ plot3d(x, ...) \method{plot3d}{default}(x, y, z, xlab, ylab, zlab, type = "p", col, size, lwd, radius, add = FALSE, aspect = !add, xlim = NULL, ylim = NULL, zlim = NULL, forceClipregion = FALSE, decorate = !add, ...) \method{plot3d}{mesh3d}(x, xlab = "x", ylab = "y", zlab = "z", type = c("shade", "wire", "dots"), add = FALSE, aspect = !add, ...) } \arguments{ \item{x, y, z}{vectors of points to be plotted. Any reasonable way of defining the coordinates is acceptable. See the function \code{\link[grDevices]{xyz.coords}} for details.} \item{xlab, ylab, zlab}{labels for the coordinates.} \item{type}{For the default method, a single character indicating the type of item to plot. Supported types are: 'p' for points, 's' for spheres, 'l' for lines, 'h' for line segments from \code{z = 0}, and 'n' for nothing. For the \code{mesh3d} method, one of 'shade', 'wire', or 'dots'. Partial matching is used. } \item{col}{the color to be used for plotted items.} \item{size}{the size for plotted points.} \item{lwd}{the line width for plotted items.} \item{radius}{the radius of spheres: see Details below.} \item{add}{whether to add the points to an existing plot.} \item{aspect}{either a logical indicating whether to adjust the aspect ratio, or a new ratio.} \item{xlim, ylim, zlim}{If not \code{NULL}, set clipping limits for the plot.} \item{forceClipregion}{Force a clipping region to be used, whether or not limits are given.} \item{decorate}{Whether to add bounding axes and other decorations.} \item{\dots}{additional parameters which will be passed to \code{\link{par3d}}, \code{\link{material3d}} or \code{\link{decorate3d}}.} } \value{ \code{plot3d} is called for the side effect of drawing the plot; a vector of object IDs is returned. } \details{ \code{plot3d} is a partial 3D analogue of plot.default. Missing values in the data are skipped, as in standard graphics. If \code{aspect} is \code{TRUE}, aspect ratios of \code{c(1, 1, 1)} are passed to \code{\link{aspect3d}}. If \code{FALSE}, no aspect adjustment is done. In other cases, the value is passed to \code{\link{aspect3d}}. With \code{type = "s"}, spheres are drawn centered at the specified locations. The radius may be controlled by \code{size} (specifying the size relative to the plot display, with the default \code{size = 3} giving a radius about 1/20 of the plot region) or \code{radius} (specifying it on the data scale if an isometric aspect ratio is chosen, or on an average scale if not). } \section{Clipping}{ If any of \code{xlim}, \code{ylim} or \code{zlim} are specified, they should be length two vectors giving lower and upper clipping limits for the corresponding coordinate. \code{NA} limits will be ignored. If any clipping limits are given, then the data will be plotted in a newly created subscene within the current one; otherwise plotting will take place directly in the current subscene. This subscene is named \code{"clipregion"} in the results. This may affect the appearance of transparent objects if some are drawn in the \code{plot3d} call and others after, as RGL will not attempt to depth-sort objects if they are in different subscenes. It is best to draw all overlapping transparent objects in the same subscene. See the example in \code{\link{planes3d}}. It will also affect the use of \code{\link{clipplanes3d}}; clipping planes need to be in the same subscene as the objects being clipped. Use \code{forceClipregion = TRUE} to force creation of this subscene even without specifying limits. } \author{ Duncan Murdoch } \seealso{ \code{\link{plot.default}}, \code{\link{open3d}}, \code{\link{par3d}}. There are \code{\link{plot3d.function}} and \code{\link{plot3d.deldir}} methods for plotting surfaces. } \examples{ open3d() x <- sort(rnorm(1000)) y <- rnorm(1000) z <- rnorm(1000) + atan2(x, y) plot3d(x, y, z, col = rainbow(1000)) } \keyword{dynamic} rgl/man/viewpoint.Rd0000644000176200001440000000427514771520323014140 0ustar liggesusers\name{viewpoint} \alias{view3d} \title{Set up viewpoint} \description{ Set the viewpoint orientation. } \usage{ view3d( theta = 0, phi = 15, fov = 60, zoom = 1, scale = par3d("scale"), interactive = TRUE, userMatrix, type = c("userviewpoint", "modelviewpoint") ) } \arguments{ \item{theta, phi}{polar coordinates in degrees. \code{theta} rotates round the vertical axis. \code{phi} rotates round the horizontal axis.} \item{fov}{field-of-view angle in degrees} \item{zoom}{zoom factor} \item{scale}{real length 3 vector specifying the rescaling to apply to each axis} \item{interactive}{logical, specifying if interactive navigation is allowed} \item{userMatrix}{4x4 matrix specifying user point of view} \item{type}{which viewpoint to set?} } \details{ The data model can be rotated using the polar coordinates \code{theta} and \code{phi}. Alternatively, it can be set in a completely general way using the 4x4 matrix \code{userMatrix}. If \code{userMatrix} is specified, \code{theta} and \code{phi} are ignored. The pointing device of your graphics user-interface can also be used to set the viewpoint interactively. With the pointing device the buttons are by default set as follows: \describe{ \item{left}{adjust viewpoint position} \item{middle}{adjust field of view angle} \item{right or wheel}{adjust zoom factor} } The user's view can be set with \code{fov} and \code{zoom}. If the \code{fov} angle is set to 0, a parallel or orthogonal projection is used. Small non-zero values (e.g. 0.01 or less, but not 0.0) are likely to lead to rendering errors due to OpenGL limitations. Prior to version 0.94, all of these characteristics were stored in one viewpoint object. With that release the characteristics are split into those that affect the projection (the user viewpoint) and those that affect the model (the model viewpoint). By default, this function sets both, but the \code{type} argument can be used to limit the effect. } \seealso{\code{\link{par3d}}} \examples{ \dontrun{ # animated round trip tour for 10 seconds open3d() shade3d(oh3d(), color = "red") start <- proc.time()[3] while ((i <- 36*(proc.time()[3] - start)) < 360) { view3d(i, i/4); } } } \keyword{dynamic} rgl/man/rgl-deprecated.Rd0000644000176200001440000000724714771520323015000 0ustar liggesusers\name{rgl-deprecated} \alias{rgl-deprecated} \alias{rgl.antialias} \alias{rgl.bbox} \alias{rgl.primitive} \alias{rgl.points} \alias{rgl.light} \alias{rgl.lines} \alias{rgl.linestrips} \alias{rgl.material} \alias{rgl.primitive} \alias{rgl.select3d} \alias{rgl.triangles} \alias{rgl.quads} \alias{rgl.viewpoint} \alias{rgl.open} \alias{rgl.close} \alias{rgl.set} \alias{rgl.setAxisCallback} \alias{writeWebGL} \alias{rgl.bg} \alias{rgl.surface} \alias{rgl.clear} \alias{rgl.texts} \title{ Deprecated functions in \pkg{rgl} } \description{ These functions are provided for compatibility with older versions of \pkg{rgl} only, and may be defunct as soon as the next release. See the comments for the replacements. } \usage{ rgl.bbox(xat = NULL, xlab = NULL, xunit = 0, xlen = 5, yat = NULL, ylab = NULL, yunit = 0, ylen = 5, zat = NULL, zlab = NULL, zunit = 0, zlen = 5, marklen = 15, marklen.rel = TRUE, expand = 1, draw_front = FALSE, ...) # bbox3d rgl.bg( sphere = FALSE, fogtype = "none", color = c("black", "white"), back = "lines", fogScale = 1, ...) # bg3d rgl.clear( type = "shapes", subscene = 0 ) # clear3d rgl.close() # close3d rgl.light( theta = 0, phi = 0, viewpoint.rel = TRUE, ambient = "#FFFFFF", diffuse = "#FFFFFF", specular = "#FFFFFF", x = NULL, y = NULL, z = NULL) # light3d rgl.lines(x, y = NULL, z = NULL, ... ) # segments3d rgl.linestrips(x, y = NULL, z = NULL, ...) # lines3d rgl.open(useNULL = rgl.useNULL()) # open3d rgl.points(x, y = NULL, z = NULL, ... ) # points3d rgl.primitive(...) rgl.quads(x, y = NULL, z = NULL, normals = NULL, texcoords = NULL, ... ) # quads3d rgl.select3d(button = c("left", "middle", "right"), dev = cur3d(), subscene = currentSubscene3d(dev)) # select3d rgl.set(which, silent = FALSE) # set3d rgl.setAxisCallback(axis, draw = NULL, dev = cur3d(), subscene = currentSubscene3d(dev)) # setAxisCallback rgl.surface(x, z, y, coords = 1:3, ..., normal_x = NULL, normal_y = NULL, normal_z = NULL, texture_s = NULL, texture_t = NULL) # surface3d rgl.texts(x, y = NULL, z = NULL, text, adj = 0.5, pos = NULL, offset = 0.5, family = par3d("family"), font = par3d("font"), cex = par3d("cex"), useFreeType = par3d("useFreeType"), ...) # text3d rgl.triangles(x, y = NULL, z = NULL, normals = NULL, texcoords = NULL, ... ) # triangles3d rgl.viewpoint( theta = 0, phi = 15, fov = 60, zoom = 1, scale = par3d("scale"), interactive = TRUE, userMatrix, type = c("userviewpoint", "modelviewpoint") ) # view3d writeWebGL(dir = "webGL", filename = file.path(dir, "index.html"), template = system.file(file.path("WebGL", "template.html"), package = "rgl"), prefix = "", snapshot = TRUE, commonParts = TRUE, reuse = NULL, font = "Arial", width, height) # rglwidget } \seealso{ \code{\link{Deprecated}, \link{bbox3d}, \link{bg3d}, \link{clear3d}, \link{close3d}, \link{light3d}, \link{lines3d}, \link{open3d}, \link{points3d}, \link{quads3d}, \link{rglwidget}, \link{segments3d}, \link{select3d}, \link{set3d}, \link{surface3d}, \link{text3d}, \link{triangles3d}, \link{view3d}} } \keyword{internal} \keyword{misc}rgl/man/as.mesh3d.default.Rd0000644000176200001440000001023614771520323015316 0ustar liggesusers\name{as.mesh3d} \alias{as.mesh3d} \alias{as.mesh3d.default} \title{ Convert object to mesh object } \description{ The \code{as.mesh3d} generic function converts various objects to \code{\link{mesh3d}} objects. The default method takes takes a matrix of vertices as input and (optionally) merges repeated vertices, producing a \code{\link{mesh3d}} object as output. It will contain either triangles or quads or segments or points according to the \code{type} argument. If the generic is called without any argument, it will pass all RGL ids from the current scene to the \code{\link{as.mesh3d.rglId}} method. } \usage{ as.mesh3d(x, ...) \method{as.mesh3d}{default}(x, y = NULL, z = NULL, type = c("triangles", "quads", "segments", "points"), smooth = FALSE, tolerance = sqrt(.Machine$double.eps), notEqual = NULL, merge = TRUE, ..., triangles) } \arguments{ \item{x, y, z}{ For the generic, \code{x} is the object to convert. For the default method, \code{x}, \code{y} and \code{z} are coordinates. Any reasonable way of defining the coordinates is acceptable. See the function \code{\link{xyz.coords}} for details. } \item{type}{ What type of things should be in the mesh? Tries this list in order until it finds one that works. } \item{smooth}{ If \code{TRUE}, \code{\link{addNormals}} will be called on the mesh object to make it render smoothly. } \item{tolerance}{ The numerical tolerance to be used in \code{\link{all.equal}} to determine whether two vertices should be merged. } \item{notEqual}{ If not \code{NULL}, an n by n matrix of logical values, where n is the number of vertices as input. \code{TRUE} entries indicate that the corresponding pair of vertices should not be merged even if they appear equal. } \item{merge}{ Should apparently equal vertices be merged? } \item{\dots}{ Material properties to pass to \code{\link{tmesh3d}} or \code{\link{qmesh3d}}. } \item{triangles}{ Deprecated. If present, \code{TRUE} indicates \code{type = "triangles"} and \code{FALSE} indicates \code{type = "quads"}. } } \details{ The motivation for this function is the following problem: I was asked whether RGL could render a surface made up of triangles or quadrilaterals to look smooth. It can do that, but needs normals at each vertex; they should be the average of the normals for each polygon sharing that vertex. Then OpenGL will interpolate the normals across the polygons and give the illusion of smoothness. To do this, it needs to know which polygons share each vertex. If the surface is described as a list of triangles or quadrilaterals, that means identifying vertices that are in multiple polygons, and converting the representation to a \code{"\link{mesh3d}"} object (which is a matrix of vertices and a matrix of vertex numbers making up triangles or quads). Then the \code{\link{addNormals}} function will add the normals. Sometimes two polygons will share vertices (within numerical tolerance) without the user wanting them to be considered internal to the surface, or might want one sharp edge in an otherwise smooth surface. This means I needed a way to declare that two vertices from the original list of vertices in the triangles or quads are "not equal", even when they test numerically equal. That's what the \code{notEqual} matrix specifies. } \value{ A \code{"\link{mesh3d}"} object with the same faces as in the input, but (if \code{merge=TRUE}) with vertices that test equal to within \code{tolerance} merged. } \author{ Duncan Murdoch } \examples{ xyz <- matrix(c(-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, 1, 1, -1, 1), byrow = TRUE, ncol = 3) mesh <- as.mesh3d(xyz, type = "quads", col = "red") mesh$vb mesh$ib open3d() shade3d(mesh) # Stop vertices 2 and 5 from being merged notEQ <- matrix(FALSE, 12, 12) notEQ[2, 5] <- TRUE mesh <- as.mesh3d(xyz, type = "quads", notEqual = notEQ) mesh$vb mesh$ib } rgl/man/writeASY.Rd0000644000176200001440000000706115012141513013604 0ustar liggesusers\name{writeASY} \alias{writeASY} \title{ Write Asymptote code for an RGL scene } \description{ Asymptote is a language for 3D graphics that is highly integrated with LaTeX. This is an experimental function to write an Asymptote program to approximate an RGL scene. } \usage{ writeASY(scene = scene3d(), title = "scene", outtype = c("pdf", "eps", "asy", "latex", "pdflatex"), prc = TRUE, runAsy = "asy \%filename\%", defaultFontsize = 12, width = 7, height = 7, ppi = 100, ids = tagged3d(tags), tags = NULL, version = "2.65") } \arguments{ \item{scene}{RGL scene object} \item{outtype}{ What type of file to write? See Details. } \item{prc}{ Whether to produce an interactive PRC scene. } \item{title}{ The base of the filename to produce. } \item{runAsy}{ Code to run the Asymptote program. } \item{defaultFontsize}{ The default fontsize for text. } \item{width, height}{ Width and height of the output image, in inches. } \item{ppi}{ \dQuote{Pixels per inch} to assume when converting line widths and point sizes (which RGL measures in pixels). } \item{ids}{ If not \code{NULL}, write out just these RGL objects. } \item{tags}{ Alternate way to specify \code{ids}. Ignored if \code{ids} is given. } \item{version}{ Asymptote version 2.44 had a definition for its \dQuote{light()} function that was incompatibly changed in versions 2.47 and 2.50. The current code has been tested with version 2.65. If you are using an older version, set \code{version} to your version number and it may work better. } } \details{ Asymptote is both a language describing a 2D or 3D graphic, and a program to interpret that language and produce output in a variety of formats including EPS, PDF (interactive or static), etc. The interactive scene produced with \code{prc = TRUE} requires \code{outtype = "pdf"}, and (as of this writing) has a number of limitations: \itemize{ \item{As far as we know, only Adobe Acrobat Reader of a sufficiently recent version can display these scenes.} \item{Current versions ignore lighting settings.} } } \value{ The filename of the output file is returned invisibly. } \references{ J. C. Bowman and A. Hammerlindl (2008). Asymptote: A vector graphics language, TUGBOAT: The Communications of the TeX Users Group, 29:2, 288-294. } \author{ Duncan Murdoch } \note{ This function is currently under development and limited in the quality of output it produces. Arguments will likely change. There are a number of differences between the interactive display in Asymptote and the display in RGL. In particular, many objects that are a fixed size in RGL will scale with the image in Asymptote. Defaults have been chosen somewhat arbitrarily; tweaking will likely be needed. Material properties of surfaces are not yet implemented. On some systems, the program \command{asy} used to process the output has bugs and may fail. Run the example at your own risk! } \seealso{ \code{\link{scene3d}} saves a copy of a scene to an R variable; \code{\link{rglwidget}}, \code{\link{writePLY}}, \code{\link{writeOBJ}} and \code{\link{writeSTL}} write the scene to a file in various other formats. } \examples{ \dontrun{ # On some systems, the program "asy" used # to process the output has bugs, so this may fail. x <- rnorm(20) y <- rnorm(20) z <- rnorm(20) plot3d(x, y, z, type = "s", col = "red") olddir <- setwd(tempdir()) writeASY(title = "interactive") # Produces interactive.pdf writeASY(title = "noninteractive", prc = FALSE) # Produces noninteractive.pdf setwd(olddir) } } rgl/man/in_pkgdown_example.Rd0000644000176200001440000000077515012460301015753 0ustar liggesusers\name{in_pkgdown_example} \alias{in_pkgdown_example} \alias{in_pkgdown} \title{ Are we running in \pkg{pkgdown} or a \pkg{pkgdown} example? } \description{ This is mainly for internal use to decide whether results should be automatically included in a \pkg{pkgdown} web page. See the \HTMLVignette{pkgdown}{}{Using RGL in pkgdown web sites} vignette for details about using \pkg{pkgdown}. } \usage{ in_pkgdown() in_pkgdown_example() } \value{ \code{TRUE} or \code{FALSE} } \examples{ in_pkgdown_example() } rgl/man/persp3d.deldir.Rd0000644000176200001440000000517614771520323014737 0ustar liggesusers\name{persp3d.deldir} \alias{persp3d.deldir} \alias{plot3d.deldir} \alias{as.mesh3d.deldir} \title{ Plot a Delaunay triangulation } \description{ The \code{\link[deldir]{deldir}()} function in the \pkg{deldir} package computes a Delaunay triangulation of a set of points. These functions display it as a surface. } \usage{ \method{plot3d}{deldir}(x, ...) \method{persp3d}{deldir}(x, ..., add = FALSE) \method{as.mesh3d}{deldir}(x, col = "gray", coords = c("x", "y", "z"), smooth = TRUE, normals = NULL, texcoords = NULL, ...) } \arguments{ \item{x}{ A \code{"deldir"} object, produced by the \code{\link[deldir]{deldir}()} function. It must contain \code{z} values. } \item{add}{ Whether to add surface to existing plot (\code{add = TRUE}) or create a new plot (\code{add = FALSE}, the default). } \item{col}{ Colors to apply to each vertex in the triangulation. Will be recycled as needed. } \item{coords}{ See Details below. } \item{smooth}{ Whether to average normals at vertices for a smooth appearance. } \item{normals}{ User-specified normals at each vertex. Requires \code{smooth = FALSE}. } \item{texcoords}{ Texture coordinates at each vertex. } \item{...}{ See Details below. } } \details{ These functions construct a \code{\link{mesh3d}} object corresponding to the triangulation in \code{x}. The \code{plot3d} and \code{persp3d} methods plot it. The \code{coords} parameter allows surfaces to be plotted over any coordinate plane. It should be a permutation of the column names \code{c("x", "y", "z")} from the \code{"deldir"} object. The first will be used as the x coordinate, the second as the y coordinate, and the third as the z coordinate. The \code{...} parameters in \code{plot3d.deldir} are passed to \code{persp3d.deldir}; in \code{persp3d.deldir} they are passed to both \code{as.mesh3d.deldir} and \code{persp3d.mesh3d}; in \code{as.mesh3d.deldir} they are used as material parameters in a \code{\link{tmesh3d}} call. } \examples{ x <- rnorm(200, sd = 5) y <- rnorm(200, sd = 5) r <- sqrt(x^2 + y^2) z <- 10 * sin(r)/r col <- cm.colors(20)[1 + round(19*(z - min(z))/diff(range(z)))] save <- options(rgl.meshColorWarning = FALSE) # This code is awkward: to work with demo(rglExamples), # we need auto-printing of the plots. This means we # have to repeat the test for deldir. haveDeldir <- checkDeldir() if (haveDeldir) { dxyz <- deldir::deldir(x, y, z = z, suppressMsge = TRUE) persp3d(dxyz, col = col) } if (haveDeldir) { open3d() # Do it without smoothing and with a different orientation. persp3d(dxyz, col = col, coords = c("z", "x", "y"), smooth = FALSE) } options(save) } \keyword{graphics} rgl/DESCRIPTION0000644000176200001440000000741615026777212012565 0ustar liggesusersPackage: rgl Version: 1.3.24 Title: 3D Visualization Using OpenGL Authors@R: c(person("Duncan", "Murdoch", role = c("aut", "cre"), email = "murdoch.duncan@gmail.com"), person("Daniel", "Adler", role = "aut", email = "dadler@dyncall.org"), person("Oleg", "Nenadic", role = "ctb"), person("Simon", "Urbanek", role = "ctb"), person("Ming", "Chen", role = "ctb"), person("Albrecht", "Gebhardt", role = "ctb"), person("Ben", "Bolker", role = "ctb"), person("Gabor", "Csardi", role = "ctb"), person("Adam", "Strzelecki", role = "ctb"), person("Alexander", "Senger", role = "ctb"), person("The R Core Team", role = c("ctb", "cph")), person("Dirk","Eddelbuettel", role = "ctb"), person("The authors of Shiny", role = "cph"), person("The authors of knitr", role = "cph"), person("Jeroen", "Ooms", role = "ctb"), person("Yohann", "Demont", role = "ctb"), person("Joshua", "Ulrich", role = "ctb"), person("Xavier", "Fernandez i Marin", role = "ctb"), person("George", "Helffrich", role = "ctb"), person("Ivan", "Krylov", role = "ctb"), person("Michael", "Sumner", role = "ctb"), person("Mike", "Stein", role = "ctb"), person("Jonathon", "Love", role = "ctb"), person("Mapbox team", role = c("ctb", "cph"))) Depends: R (>= 3.6.0) Suggests: MASS, rmarkdown (>= 2.16), deldir (>= 1.0-4), orientlib, lattice, misc3d, magick, plotrix (>= 3.7-3), tripack, interp, alphashape3d, tcltk, js (>= 1.2), webshot2 (>= 0.1.0), downlit (>= 0.4.0), pkgdown (>= 2.0.0), extrafont, shiny, manipulateWidget (>= 0.9.0), testthat, crosstalk, V8, chromote, jpeg, png, markdown Imports: graphics, grDevices, stats, utils, htmlwidgets (>= 1.6.0), htmltools, knitr (>= 1.33), jsonlite (>= 0.9.20), magrittr, R6, base64enc, mime Enhances: waldo Description: Provides medium to high level functions for 3D interactive graphics, including functions modelled on base graphics (plot3d(), etc.) as well as functions for constructing representations of geometric objects (cube3d(), etc.). Output may be on screen using OpenGL, or to various standard 3D file formats including WebGL, PLY, OBJ, STL as well as 2D image formats, including PNG, Postscript, SVG, PGF. License: GPL URL: https://github.com/dmurdoch/rgl, https://dmurdoch.github.io/rgl/ SystemRequirements: OpenGL and GLU Library (Required for display in R. See "Installing OpenGL support" in README.md. Not needed if only browser displays using rglwidget() are wanted.), zlib (optional), libpng (>=1.2.9, optional), FreeType (optional), pandoc (>=1.14, needed for vignettes) BugReports: https://github.com/dmurdoch/rgl/issues VignetteBuilder: knitr, rmarkdown Biarch: true RoxygenNote: 7.3.2 NeedsCompilation: yes Packaged: 2025-06-24 20:16:05 UTC; murdoch Author: Duncan Murdoch [aut, cre], Daniel Adler [aut], Oleg Nenadic [ctb], Simon Urbanek [ctb], Ming Chen [ctb], Albrecht Gebhardt [ctb], Ben Bolker [ctb], Gabor Csardi [ctb], Adam Strzelecki [ctb], Alexander Senger [ctb], The R Core Team [ctb, cph], Dirk Eddelbuettel [ctb], The authors of Shiny [cph], The authors of knitr [cph], Jeroen Ooms [ctb], Yohann Demont [ctb], Joshua Ulrich [ctb], Xavier Fernandez i Marin [ctb], George Helffrich [ctb], Ivan Krylov [ctb], Michael Sumner [ctb], Mike Stein [ctb], Jonathon Love [ctb], Mapbox team [ctb, cph] Maintainer: Duncan Murdoch Repository: CRAN Date/Publication: 2025-06-25 13:50:02 UTC