├── src ├── edit_interface.jl ├── display │ ├── mousedrag.jl │ ├── postprocessing.jl │ └── renderloop.jl ├── texture_atlas │ ├── saxmono.ttf │ ├── DejaVuSansMono.ttf │ ├── SourceCodePro-Regular.otf │ └── texture_atlas.jl ├── edit │ ├── transformation.jl │ ├── reflection.jl │ ├── color_chooser.jl │ ├── renderobject.jl │ ├── numbers.jl │ └── text.jl ├── shader │ ├── dots.frag │ ├── boundingbox │ │ ├── standard.vert │ │ ├── boundingbox.frag │ │ ├── colorchooser.vert │ │ ├── instance_functions.vert │ │ ├── phongblinn.frag │ │ ├── surface.vert │ │ ├── instance_normal.vert │ │ ├── textshader.vert │ │ └── colorchooser.frag │ ├── texture.frag │ ├── uv_vert.vert │ ├── volume.vert │ ├── colorchooser.vert │ ├── text.frag │ ├── standard.vert │ ├── dots.vert │ ├── blinnphong.frag │ ├── attribute_mesh.vert │ ├── particles.vert │ ├── particles2D_single.vert │ ├── distancefield.frag │ ├── fxaa_combine.frag │ ├── particles2D.vert │ ├── text_single.vert │ ├── standard.frag │ ├── meshgrid.vert │ ├── fxaa.vert │ ├── vectorfield.vert │ ├── colorchooser.frag │ ├── text.vert │ ├── distance_shape.frag │ ├── surface2.vert │ ├── surface.vert │ ├── fxaa.frag │ ├── volume.frag │ ├── util.vert │ └── volume2.frag ├── boundingbox.jl ├── color.jl ├── meshutil.jl ├── visualize │ ├── videos.jl │ ├── text │ │ ├── cairo_text.jl │ │ ├── rectangle_packing.jl │ │ ├── text_test.jl │ │ ├── freetype_text.jl │ │ └── utils.jl │ ├── distancefields.jl │ ├── dots.jl │ ├── grid.jl │ ├── containers.jl │ ├── mesh.jl │ ├── plotlibs.jl │ ├── meshgrid.jl │ ├── image.jl │ ├── particles.jl │ ├── vectorfield.jl │ ├── volume.jl │ ├── color_chooser.jl │ ├── surface.jl │ ├── 2dparticles.jl │ └── text.jl ├── types.jl ├── utils.jl ├── GLVisualize.jl ├── visualize_interface.jl └── share │ └── text.jl ├── test ├── fxaa_test.jl ├── test_obj.jl ├── mri.npz ├── test.gif ├── test.mp4 ├── Thumbs.db ├── drawing.jpg ├── feelsgood.png ├── success.gif ├── success2.gif ├── dealwithit.jpg ├── test_barplot.jl ├── test_orthographiccamera.jl ├── test_textureatlas.jl ├── test.jl ├── test_dots.jl ├── test_slider.jl ├── test_video.jl ├── test_vectorfield.jl ├── test_isosurface.jl ├── test_reactangle.jl ├── test_image.jl ├── test_text.jl ├── test_particles2D.jl ├── test_patch.jl ├── test_arbitrary_surface.jl ├── test_distancefield.jl ├── test_surface.jl ├── test_volume.jl ├── wip_test.jl ├── boundingbox_test.jl ├── test_screens.jl ├── test_particle2.jl ├── test_particles.jl ├── test_lines.jl ├── test_sierpinski_mesh.jl ├── test_mesh.jl ├── wip_text_input.jl ├── runtests.jl ├── test_text_functions.jl ├── texture_buffer.jl ├── test_romeo.jl ├── nbody.jl ├── test_transformation.jl ├── test_color.jl └── utf8_example_text.jl ├── docs ├── dots.jpg ├── obj.jpg ├── Thumbs.db ├── image.jpg ├── volume.jpg ├── barplot.jpg ├── particles.jpg ├── surface.jpg ├── isosurface.jpg ├── particles2D.jpg ├── sierpinski.jpg ├── vectorfield.jpg ├── arbitrary_surf.jpg └── volume_trans.jpg ├── .gitignore ├── REQUIRE ├── .travis.yml ├── LICENSE.md └── README.md /src/edit_interface.jl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/display/mousedrag.jl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/fxaa_test.jl: -------------------------------------------------------------------------------- 1 | a = readall(open("cat.obj")) 2 | println(length(a)) -------------------------------------------------------------------------------- /test/test_obj.jl: -------------------------------------------------------------------------------- 1 | push!(TEST_DATA, GLNormalMesh(file"cat.obj")) 2 | -------------------------------------------------------------------------------- /docs/dots.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/docs/dots.jpg -------------------------------------------------------------------------------- /docs/obj.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/docs/obj.jpg -------------------------------------------------------------------------------- /test/mri.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/test/mri.npz -------------------------------------------------------------------------------- /test/test.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/test/test.gif -------------------------------------------------------------------------------- /test/test.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/test/test.mp4 -------------------------------------------------------------------------------- /docs/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/docs/Thumbs.db -------------------------------------------------------------------------------- /docs/image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/docs/image.jpg -------------------------------------------------------------------------------- /docs/volume.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/docs/volume.jpg -------------------------------------------------------------------------------- /test/Thumbs.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/test/Thumbs.db -------------------------------------------------------------------------------- /docs/barplot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/docs/barplot.jpg -------------------------------------------------------------------------------- /docs/particles.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/docs/particles.jpg -------------------------------------------------------------------------------- /docs/surface.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/docs/surface.jpg -------------------------------------------------------------------------------- /test/drawing.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/test/drawing.jpg -------------------------------------------------------------------------------- /test/feelsgood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/test/feelsgood.png -------------------------------------------------------------------------------- /test/success.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/test/success.gif -------------------------------------------------------------------------------- /test/success2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/test/success2.gif -------------------------------------------------------------------------------- /docs/isosurface.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/docs/isosurface.jpg -------------------------------------------------------------------------------- /docs/particles2D.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/docs/particles2D.jpg -------------------------------------------------------------------------------- /docs/sierpinski.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/docs/sierpinski.jpg -------------------------------------------------------------------------------- /docs/vectorfield.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/docs/vectorfield.jpg -------------------------------------------------------------------------------- /test/dealwithit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/test/dealwithit.jpg -------------------------------------------------------------------------------- /docs/arbitrary_surf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/docs/arbitrary_surf.jpg -------------------------------------------------------------------------------- /docs/volume_trans.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/docs/volume_trans.jpg -------------------------------------------------------------------------------- /test/test_barplot.jl: -------------------------------------------------------------------------------- 1 | 2 | push!(TEST_DATA, Float32[(sin(i/10f0) + cos(j/2f0))/4f0 + 1f0 for i=1:50, j=1:50]) 3 | -------------------------------------------------------------------------------- /test/test_orthographiccamera.jl: -------------------------------------------------------------------------------- 1 | using GLVisualize, GLAbstraction 2 | OrthographicCamera(GLVisualize.ROOT_SCREEN.inputs) -------------------------------------------------------------------------------- /src/texture_atlas/saxmono.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/src/texture_atlas/saxmono.ttf -------------------------------------------------------------------------------- /test/test_textureatlas.jl: -------------------------------------------------------------------------------- 1 | using GLVisualize 2 | 3 | a = GLVisualize.map_fonts(join('\u0000':'\u00ff')) 4 | 5 | println(a) -------------------------------------------------------------------------------- /src/texture_atlas/DejaVuSansMono.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/src/texture_atlas/DejaVuSansMono.ttf -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.jl.cov 2 | *.jl.mem 3 | 4 | docs/Thumbs.db 5 | *.db 6 | docs/Thumbs.db 7 | *.db 8 | *.db 9 | *.db 10 | docs/Thumbs.db -------------------------------------------------------------------------------- /src/edit/transformation.jl: -------------------------------------------------------------------------------- 1 | edit{T}(model::Matrix4x4{T}) = edit(Input(model)) 2 | 3 | function edit{T}(model::Signal{Matrix4x4{T}}) 4 | 5 | end -------------------------------------------------------------------------------- /src/texture_atlas/SourceCodePro-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dpsanders/GLVisualize.jl/master/src/texture_atlas/SourceCodePro-Regular.otf -------------------------------------------------------------------------------- /src/shader/dots.frag: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | 3 | in vec4 o_color; 4 | out vec4 fragment_color; 5 | 6 | void main(){ 7 | fragment_color = o_color; 8 | } 9 | -------------------------------------------------------------------------------- /src/boundingbox.jl: -------------------------------------------------------------------------------- 1 | particle_grid_bb(min_xy::Vector2, max_xy::Vector2, minmax_z::Vector2) = AABB(Vec3(min_xy..., minmax_z[1]), Vec3(max_xy..., minmax_z[2])) 2 | -------------------------------------------------------------------------------- /test/test.jl: -------------------------------------------------------------------------------- 1 | using GLVisualize, NPZ 2 | 3 | volume = npzread("mri.npz")["data"] 4 | 5 | volume = volume./256f0 6 | 7 | view(visualize(volume)) 8 | 9 | renderloop() -------------------------------------------------------------------------------- /src/shader/boundingbox/standard.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | 3 | {{in}} vec3 vertex; 4 | {{out}} vec4 V; 5 | uniform mat4 model; 6 | void main(){ 7 | V = model*vec4(vertex,1); 8 | gl_Position = vec4(0,0,0,1); 9 | } -------------------------------------------------------------------------------- /src/shader/boundingbox/boundingbox.frag: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | 3 | {{in}} vec4 V; 4 | 5 | {{out}} vec4 minbuffer; 6 | {{out}} vec4 maxbuffer; 7 | 8 | void main() 9 | { 10 | minbuffer = -V; 11 | maxbuffer = V; 12 | } -------------------------------------------------------------------------------- /test/test_dots.jl: -------------------------------------------------------------------------------- 1 | function dots_data(N) 2 | start_point = Point3f(0f0) 3 | randrange = -0.1f0:eps(Float32):0.1f0 4 | return (Point3f[(start_point += rand(Point3f, randrange)) for i=1:N], :dots) 5 | end 6 | 7 | push!(TEST_DATA, dots_data(25_000)) 8 | -------------------------------------------------------------------------------- /test/test_slider.jl: -------------------------------------------------------------------------------- 1 | using GLVisualize, Reactive, GeometryTypes, GLAbstraction, ColorTypes, FixedSizeArrays 2 | 3 | 4 | new_num, vizz = vizzedit(Vec3(0,0,0), GLVisualize.ROOT_SCREEN.inputs) 5 | view(vizz) 6 | 7 | renderloop() 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/test_video.jl: -------------------------------------------------------------------------------- 1 | using VideoIO 2 | 3 | function play(f, img) 4 | end 5 | io = VideoIO.open("test.mp4") 6 | f = VideoIO.openvideo(io) 7 | 8 | 9 | img = read(f, Image) 10 | while !eof(f) 11 | read!(f, img) 12 | #sleep(1/30) 13 | end -------------------------------------------------------------------------------- /src/shader/texture.frag: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | 3 | in vec2 o_uv; 4 | out vec4 fragment_color; 5 | 6 | {{image_type}} image; 7 | 8 | void main(){ 9 | vec4 texcolor = texture(image, vec2(o_uv.x,1-o_uv.y)); 10 | fragment_color = texcolor.rgba; 11 | } 12 | -------------------------------------------------------------------------------- /test/test_vectorfield.jl: -------------------------------------------------------------------------------- 1 | vectorfielddata(N, i) = Vec3[Vec3(cos(x/N*3)*i, cos(y/7i), cos(i/5)) for x=1:N, y=1:N, z=1:N] 2 | 3 | const t = bounce(1f0:0.1f0:5f0) 4 | 5 | push!(TEST_DATA, vectorfielddata(14, 1f0)) 6 | push!(TEST_DATA, (lift(vectorfielddata, 7, t), :norm=>Vec2(1, 5))) 7 | 8 | -------------------------------------------------------------------------------- /REQUIRE: -------------------------------------------------------------------------------- 1 | julia 0.4- 2 | 3 | GLFW 4 | GLWindow 5 | GLAbstraction 6 | ModernGL 7 | FixedSizeArrays 8 | GeometryTypes 9 | ColorTypes 10 | Reactive 11 | Quaternions 12 | Compat 13 | FixedPointNumbers 14 | ImageIO 15 | FileIO 16 | MeshIO 17 | Meshes 18 | AbstractGPUArray 19 | FreeType 20 | FreeTypeAbstraction 21 | -------------------------------------------------------------------------------- /src/edit/reflection.jl: -------------------------------------------------------------------------------- 1 | #= 2 | function edit(style::Style, m::Module, custumization::Dict{Symbol,Any}) 3 | 4 | end 5 | 6 | function edit(style::Style, f::Function, custumization::Dict{Symbol,Any}) 7 | 8 | end 9 | 10 | function edit(style::Style, t::Type, custumization::Dict{Symbol,Any}) 11 | 12 | end 13 | =# 14 | -------------------------------------------------------------------------------- /src/shader/uv_vert.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | {{GLSL_EXTENSIONS}} 3 | 4 | in vec2 vertices; 5 | in vec2 texturecoordinates; 6 | 7 | out vec2 o_uv; 8 | 9 | uniform mat4 projectionview, model; 10 | void main(){ 11 | o_uv = texturecoordinates; 12 | gl_Position = projectionview * model * vec4(vertices, 0, 1); 13 | } -------------------------------------------------------------------------------- /test/test_isosurface.jl: -------------------------------------------------------------------------------- 1 | function create_isosurf(N) 2 | volume = Float32[sin(x/15.0)+sin(y/15.0)+sin(z/15.0) for x=1:N, y=1:N, z=1:N] 3 | max = maximum(volume) 4 | min = minimum(volume) 5 | volume = (volume .- min) ./ (max .- min) 6 | return GLNormalMesh(volume, 0.5f0) 7 | end 8 | 9 | push!(TEST_DATA, create_isosurf(64)) -------------------------------------------------------------------------------- /src/shader/volume.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | 3 | in vec3 vertices; 4 | in vec3 texturecoordinates; 5 | 6 | out vec3 frag_vertposition; 7 | 8 | uniform mat4 projectionview, model; 9 | 10 | void main() 11 | { 12 | frag_vertposition = texturecoordinates; 13 | gl_Position = projectionview * model * vec4(vertices, 1); 14 | } -------------------------------------------------------------------------------- /test/test_reactangle.jl: -------------------------------------------------------------------------------- 1 | using GLVisualize, GeometryTypes, GLAbstraction, Reactive, ColorTypes 2 | 3 | 4 | a = Input(Rectangle{Int64}(20,20,900,1000)) 5 | b = Input(Rectangle{Int64}(960,0,960,1280)) 6 | view(visualize(a, color=RGBA(1f0,0f0,1f0,0.5f0))) 7 | #view(visualize(b, color=RGBA(0f0,0f0,1f0,1f0))) 8 | 9 | renderloop() 10 | -------------------------------------------------------------------------------- /src/shader/boundingbox/colorchooser.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | 3 | 4 | {{in}} vec3 vertex; 5 | {{in}} vec2 uv; 6 | 7 | {{out}} vec2 frag_uv; 8 | {{out}} vec4 V; 9 | 10 | 11 | uniform mat4 projection, view, model; 12 | 13 | void main(){ 14 | frag_uv = uv; 15 | V = model * vec4(vertex, 1.0); 16 | gl_Position = vec4(0,0,0,1); 17 | } -------------------------------------------------------------------------------- /test/test_image.jl: -------------------------------------------------------------------------------- 1 | function image_test_data(N) 2 | return ( 3 | file"test.mp4", 4 | RGBA{Float32}[rgba(sin(i), sin(j), cos(i), sin(j)*cos(i)) for i=1:0.1:N, j=1:0.1:N], 5 | file"drawing.jpg", 6 | file"dealwithit.jpg", 7 | file"feelsgood.png", 8 | file"success.gif" 9 | ) 10 | end 11 | 12 | push!(TEST_DATA2D, image_test_data(20)...) -------------------------------------------------------------------------------- /test/test_text.jl: -------------------------------------------------------------------------------- 1 | include("utf8_example_text.jl") 2 | 3 | 4 | push!(TEST_DATA2D, utf8_example_text) 5 | 6 | #using GLVisualize 7 | #text = visualize(utf8_example_text) 8 | 9 | #background, cursor_robj, text_sig = vizzedit(text[:glyphs], text, GLVisualize.ROOT_SCREEN.inputs) 10 | 11 | #view(background) 12 | #view(text) 13 | #view(cursor_robj) 14 | 15 | #renderloop() -------------------------------------------------------------------------------- /test/test_particles2D.jl: -------------------------------------------------------------------------------- 1 | #using GLVisualize, GLAbstraction, GeometryTypes, Reactive, ColorTypes, Meshes, MeshIO 2 | particle_data2D(i, N) = Point2{Float32}[rand(Point2{Float32}, -10f0:eps(Float32):10f0) for x=1:N] 3 | 4 | 5 | push!(TEST_DATA2D, foldl(+, Point2{Float32}[rand(Point2{Float32}, 0f0:eps(Float32):1000f0) for x=1:512], 6 | lift(particle_data2D, bounce(1f0:1f0:50f0), 512))) -------------------------------------------------------------------------------- /src/shader/colorchooser.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | 3 | 4 | in vec2 vertex; 5 | in vec2 uv; 6 | 7 | uniform uint objectid; 8 | 9 | out vec2 frag_uv; 10 | flat out uvec2 fragment_id; 11 | 12 | 13 | uniform mat4 projectionviewmodel; 14 | 15 | void main(){ 16 | frag_uv = uv; 17 | fragment_id = uvec2(objectid, 0); 18 | gl_Position = projectionviewmodel * vec4(vertex, 0.0, 1.0); 19 | } -------------------------------------------------------------------------------- /src/shader/text.frag: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | 3 | in float o_x; 4 | in vec2 o_uv; 5 | in vec4 o_color; 6 | 7 | uniform sampler2D images; 8 | 9 | out vec4 fragment_color; 10 | 11 | void main(){ 12 | 13 | float alphaAbove = texelFetch(images, ivec2(o_uv), 0).r; 14 | float textAlpha = alphaAbove * o_color.a; 15 | fragment_color = vec4(o_color.rgb, textAlpha); 16 | } -------------------------------------------------------------------------------- /test/test_patch.jl: -------------------------------------------------------------------------------- 1 | using GLVisualize, AbstractGPUArray, GLAbstraction, GeometryTypes, Reactive, ColorTypes, Meshes, MeshIO 2 | 3 | 4 | dirlen = 1f0 5 | baselen = 0.02f0 6 | cube = GLNormalMesh(Cube(Vec3(1), Vec3(1))) 7 | patch(verts, faces) = visualize(GLNormalMesh(verts, faces)) 8 | robj1 = patch(cube.vertices, cube.faces) 9 | 10 | push!(GLVisualize.ROOT_SCREEN.renderlist, robj1) 11 | 12 | 13 | renderloop() -------------------------------------------------------------------------------- /test/test_arbitrary_surface.jl: -------------------------------------------------------------------------------- 1 | function arbitrary_surface_data(N) 2 | h = 1./N 3 | r = h:h:1. 4 | t = (-1:h:1+h)*π 5 | x = map(Float32, r*cos(t)') 6 | y = map(Float32, r*sin(t)') 7 | 8 | f(x,y) = exp(-10x.^2-20y.^2) # arbitrary function of f 9 | z = Float32[Float32(f(x[k,j],y[k,j])) for k=1:size(x,1),j=1:size(x,2)] 10 | (x, y, z, :surface) 11 | end 12 | push!(TEST_DATA, arbitrary_surface_data(100)) 13 | 14 | 15 | -------------------------------------------------------------------------------- /test/test_distancefield.jl: -------------------------------------------------------------------------------- 1 | using GLVisualize, GLAbstraction, GeometryTypes, Reactive, ColorTypes, Meshes, MeshIO 2 | 3 | const N = 1000 4 | xy(x,y,i) = Float32(sin(x/i)*sin(y/i)) 5 | 6 | generate(i) = Float32[xy(x,y,i) for x=1:N, y=1:N] 7 | const distancefield = lift(generate, bounce(50f0:500f0)) 8 | 9 | robj1 = visualize(distancefield, :distancefield) 10 | push!(GLVisualize.ROOT_SCREEN.renderlist, robj1) 11 | 12 | 13 | renderloop() -------------------------------------------------------------------------------- /test/test_surface.jl: -------------------------------------------------------------------------------- 1 | function xy_data(x,y,i, N) 2 | x = ((x/N)-0.5f0)*i 3 | y = ((y/N)-0.5f0)*i 4 | r = sqrt(x*x + y*y) 5 | Float32(sin(r)/r) 6 | end 7 | generate(i, N) = Float32[xy_data(Float32(x),Float32(y),Float32(i), N) for x=1:N, y=1:N] 8 | function surface_data(N) 9 | heightfield = lift(generate, bounce(1f0:200f0), N) 10 | return heightfield 11 | end 12 | surface_data(40) 13 | 14 | 15 | push!(TEST_DATA, surface_data(128)) 16 | 17 | surface_data(40) -------------------------------------------------------------------------------- /test/test_volume.jl: -------------------------------------------------------------------------------- 1 | function volume_data(N) 2 | volume = Float32[sin(x/15.0)+sin(y/15.0)+sin(z/15.0) for x=1:N, y=1:N, z=1:N] 3 | max = maximum(volume) 4 | min = minimum(volume) 5 | volume = (volume .- min) ./ (max .- min) 6 | end 7 | 8 | 9 | const vol_data = volume_data(64) 10 | push!(TEST_DATA, (vol_data, :mip)) 11 | push!(TEST_DATA, (vol_data, :absorption, :absorption=>bounce(0f0:1f0:50f0))) 12 | push!(TEST_DATA, (vol_data, :iso, :isovalue=>bounce(0f0:0.01f0:1f0))) 13 | -------------------------------------------------------------------------------- /src/display/postprocessing.jl: -------------------------------------------------------------------------------- 1 | 2 | 3 | function postprocess(screen_texture, screen) 4 | data = merge(Dict( 5 | :resolution => lift(Vec2, screen.inputs[:framebuffer_size]), 6 | :u_texture0 => screen_texture 7 | ), collect_for_gl(GLUVMesh2D(Rectangle(-1f0,-1f0, 2f0, 2f0)))) 8 | program = TemplateProgram( 9 | File(shaderdir, "fxaa.vert"), 10 | File(shaderdir, "fxaa.frag"), 11 | File(shaderdir, "fxaa_combine.frag") 12 | ) 13 | std_renderobject(data, program) 14 | end 15 | 16 | -------------------------------------------------------------------------------- /src/shader/standard.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | 3 | in vec3 vertices; 4 | in vec3 normals; 5 | 6 | uniform vec3 light[4]; 7 | uniform vec4 color; 8 | uniform mat4 projection, view, model; 9 | void render(vec3 vertices, vec3 normals, vec4 color, mat4 viewmodel, mat4 projection, vec3 light[4]); 10 | 11 | uniform uint objectid; 12 | flat out uvec2 o_id; 13 | 14 | void main() 15 | { 16 | o_id = uvec2(objectid, gl_VertexID); 17 | render(vertices, normals, color, view*model, projection, light); 18 | } 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/wip_test.jl: -------------------------------------------------------------------------------- 1 | using GLVisualize, AbstractGPUArray, GLAbstraction, GeometryTypes, Reactive, ColorTypes, MeshIO, Meshes, FileIO 2 | using GLFW, ModernGL 3 | const screen = GLVisualize.ROOT_SCREEN 4 | 5 | t = readall(open("wip_test.jl")) 6 | 7 | text = visualize(t) 8 | 9 | 10 | 11 | 12 | w = GLVisualize.ROOT_SCREEN 13 | view(background, method=:orthographic_pixel) 14 | view(text, method=:orthographic_pixel) 15 | view(cursor(text[:positions], selection), method=:orthographic_pixel) 16 | 17 | 18 | renderloop() 19 | 20 | -------------------------------------------------------------------------------- /test/boundingbox_test.jl: -------------------------------------------------------------------------------- 1 | using GeometryTypes, MeshIO, Meshes, ColorTypes, GLAbstraction, GLVisualize, Reactive 2 | using Base.Test 3 | 4 | const N1 = 7 5 | funcy(x,y,z) = Vec3(sin(x),cos(y),tan(z)) 6 | const directions = Vec3[funcy(x,y,z) for x=1:N1,y=1:N1, z=1:N1] 7 | robj = visualize(directions) 8 | msh = GLNormalMesh(robj.boundingbox.value) 9 | robj2 = visualize(msh) 10 | println(robj2.boundingbox.value) 11 | 12 | push!(GLVisualize.ROOT_SCREEN.renderlist, robj) 13 | push!(GLVisualize.ROOT_SCREEN.renderlist, robj2) 14 | 15 | renderloop() 16 | -------------------------------------------------------------------------------- /src/color.jl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #GLPlot.toopengl{T <: AbstractRGB}(colorinput::Input{T}) = toopengl(lift(x->AlphaColorValue(x, one(T)), RGBA{T}, colorinput)) 5 | #tohsva(rgba) = HSVA(convert(HSV, rgba.c), rgba.alpha) 6 | #torgba(hsva) = AlphaColorValue(convert(RGB, hsva.c), hsva.alpha) 7 | #tohsva(h,s,v,a) = AlphaColorValue(HSV(float32(h), float32(s), float32(v)), float32(a)) 8 | 9 | #Base.convert{T <: AbstractAlphaColorValue}(typ::Type{T}, x::AbstractAlphaColorValue) = AlphaColorValue(convert(RGB{eltype(typ)}, x.c), convert(eltype(typ), x.alpha)) 10 | 11 | -------------------------------------------------------------------------------- /src/meshutil.jl: -------------------------------------------------------------------------------- 1 | export collect_for_gl 2 | 3 | function collect_for_gl{T <: HomogenousMesh}(m::T) 4 | result = Dict{Symbol, Any}() 5 | attribs = attributes(m) 6 | @materialize! vertices, faces = attribs 7 | result[:vertices] = GLBuffer(vertices) 8 | result[:faces] = indexbuffer(faces) 9 | for (field, val) in attribs 10 | if field in [:texturecoordinates, :normals, :attribute_id] 11 | result[field] = GLBuffer(val) 12 | else 13 | result[field] = Texture(val) 14 | end 15 | end 16 | result 17 | end 18 | 19 | -------------------------------------------------------------------------------- /src/shader/dots.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | 3 | in vec3 vertex; 4 | 5 | out vec4 o_color; 6 | 7 | {{color_type}} color; 8 | 9 | ivec2 ind2sub(ivec2 dim, int linearindex) 10 | { 11 | return ivec2(linearindex % dim.x, linearindex / dim.x); 12 | } 13 | vec4 getindex(sampler2D tex, int index) 14 | { 15 | return texelFetch(tex, ind2sub(textureSize(tex, 0), index), 0); 16 | } 17 | 18 | uniform mat4 projectionview, model; 19 | 20 | void main() 21 | { 22 | int index = gl_VertexID; 23 | vec4 c = {{color_calculation}} 24 | o_color = vec4(c.rgb, 1.0); 25 | gl_Position = projectionview*model * vec4(vertex, 1); 26 | } -------------------------------------------------------------------------------- /src/shader/blinnphong.frag: -------------------------------------------------------------------------------- 1 | vec4 blinnphong(vec3 N, vec3 V, vec3 L, vec3 light[4], vec4 mat[4]) 2 | { 3 | float diff_coeff = max(dot(L,N), 0.0); 4 | // specular coefficient 5 | vec3 H = normalize(L+V); 6 | 7 | float spec_coeff = pow(max(dot(H,N), 0.0), mat[specular_exponent].x); 8 | if (diff_coeff <= 0.0) 9 | spec_coeff = 0.0; 10 | 11 | // final lighting model 12 | return vec4( 13 | light[ambient] * mat[ambient].rgb + 14 | light[diffuse] * mat[diffuse].rgb * diff_coeff + 15 | light[specular] * mat[specular].rgb * spec_coeff, 16 | 1); 17 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: cpp 2 | compiler: 3 | - clang 4 | notifications: 5 | email: false 6 | env: 7 | matrix: 8 | - JULIAVERSION="juliareleases" 9 | - JULIAVERSION="julianightlies" 10 | before_install: 11 | - sudo add-apt-repository ppa:staticfloat/julia-deps -y 12 | - sudo add-apt-repository ppa:staticfloat/${JULIAVERSION} -y 13 | - sudo apt-get update -qq -y 14 | - sudo apt-get install libpcre3-dev julia -y 15 | - if [[ -a .git/shallow ]]; then git fetch --unshallow; fi 16 | script: 17 | - julia --check-bounds=yes -e 'versioninfo(); Pkg.init(); Pkg.clone(pwd()); Pkg.build("GLVisualize"); Pkg.test("GLVisualize")' 18 | -------------------------------------------------------------------------------- /src/shader/attribute_mesh.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | 3 | in vec3 vertices; 4 | in vec3 normals; 5 | in float attribute_id; 6 | 7 | uniform vec3 light[4]; 8 | 9 | uniform mat4 projection, view, model; 10 | uniform sampler1D attributes; 11 | 12 | void render(vec3 vertices, vec3 normals, vec4 color, mat4 viewmodel, mat4 projection, vec3 light[4]); 13 | 14 | uniform uint objectid; 15 | flat out uvec2 o_id; 16 | 17 | void main() 18 | { 19 | o_id = uvec2(objectid, attribute_id); 20 | vec4 instance_color = texelFetch(attributes, int(attribute_id), 0); 21 | render(vertices, normals, instance_color, view*model, projection, light); 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /test/test_screens.jl: -------------------------------------------------------------------------------- 1 | using GLVisualize, Reactive, GeometryTypes, GLWindow, ColorTypes 2 | 3 | const rs = GLVisualize.ROOT_SCREEN 4 | xhalf(r) = Rectangle{Int}(r.x,r.y, r.w/2, r.h) 5 | xhalf2(r) = Rectangle{Int}(r.w/2, r.y, r.w/2, r.h) 6 | const screen3D = Screen(rs, area=lift(xhalf, rs.area)) 7 | const screen2D = Screen(rs, area=lift(xhalf2, rs.area)) 8 | 9 | println(screen3D.area) 10 | println(screen2D.area) 11 | 12 | view(visualize(rand(Float32, 10,10)), screen3D) 13 | view(visualize(rand(Float32, 10,10)), screen2D) 14 | 15 | view(visualize(lift(x->Rectangle(0,0,x.w, x.h), screen2D.area), color=RGBA(1f0,0f0,1f0,1f0)), screen2D, method=:fixed_pixel) 16 | view(visualize(lift(x->Rectangle(0,0,x.w, x.h), screen3D.area), color=RGBA(0f0,0f0,1f0,1f0)), screen3D, method=:fixed_pixel) 17 | 18 | 19 | 20 | renderloop() -------------------------------------------------------------------------------- /src/shader/particles.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | {{GLSL_EXTENSIONS}} 3 | in vec3 vertices; 4 | in vec3 normals; 5 | 6 | uniform vec3 light[4]; 7 | 8 | {{color_type}} color; 9 | 10 | uniform samplerBuffer positions; 11 | 12 | uniform vec3 scale; 13 | uniform mat4 view, model, projection; 14 | void render(vec3 vertices, vec3 normals, vec4 color, mat4 viewmodel, mat4 projection, vec3 light[4]); 15 | 16 | vec4 getindex(sampler2D tex, int index); 17 | vec4 getindex(sampler1D tex, int index); 18 | 19 | 20 | uniform uint objectid; 21 | flat out uvec2 o_id; 22 | 23 | void main(){ 24 | int index = gl_InstanceID; 25 | vec3 vert = texelFetch(positions, index).xyz + (scale*vertices); 26 | vec4 c = {{color_calculation}}; 27 | render(vert, normals, c, view*model, projection, light); 28 | o_id = uvec2(objectid, index); 29 | } -------------------------------------------------------------------------------- /src/visualize/videos.jl: -------------------------------------------------------------------------------- 1 | #this is just a temporary solution... Video IO should be integrated via FileIO 2 | export play 3 | 4 | function play{T}(array::Array{T, 3}, slice) 5 | array[:, :, slice] 6 | end 7 | 8 | function play{T}(buffer::Array{T, 2}, video_stream, t) 9 | eof(video_stream) && seekstart(video_stream) 10 | w,h = size(buffer) 11 | buffer = reinterpret(Uint8, buffer, (3, w,h)) 12 | read!(video_stream, buffer) # looses type and shape 13 | return reinterpret(T, buffer, (w,h)) 14 | end 15 | 16 | 17 | Base.read(gif::File{:gif}) = vread(VideoIO.openvideo(abspath(gif))) 18 | Base.read(gif::File{:mp4}) = vread(VideoIO.openvideo(abspath(gif))) 19 | function vread(video_stream::VideoIO.VideoReader) 20 | t0 = read(video_stream) 21 | cd, w, h = size(t0) 22 | giff = foldl(play, reinterpret(RGB{Ufixed8}, t0, (w, h)), Input(video_stream), TIMER_SIGNAL) 23 | end 24 | 25 | -------------------------------------------------------------------------------- /src/visualize/text/cairo_text.jl: -------------------------------------------------------------------------------- 1 | immutable FontExtent{T} 2 | bearing::Vector2{T} 3 | scale::Vector2{T} 4 | advance::Vector2{T} 5 | end 6 | immutable FontDescription 7 | name ::UTF8String 8 | slant ::Int32 9 | weight ::Int32 10 | size ::Float64 11 | end 12 | typealias CairoFontExtent FontExtent{Float64} 13 | FontExtent(cc::CairoContext, c::Char) = FontExtent(cc, string(c)) 14 | FontExtent(cc::CairoContext, t::AbstractString) = reinterpret(CairoFontExtent, text_extents(cc, t), (1,))[1] 15 | GeometryTypes.Rectangle(cc::CairoContext, c::Char) = Rectangle(FontExtent(cc, c)) 16 | GeometryTypes.Rectangle(fe::FontExtent) = Rectangle(0,0,round(Int, fe.scale.x), round(Int, fe.scale.y)) 17 | function Cairo.select_font_face(cc::CairoContext, font::FontDescription) 18 | select_font_face(cc, font.name, font.slant, font.weight) 19 | set_font_size(cc, font.size) 20 | end 21 | 22 | -------------------------------------------------------------------------------- /src/visualize/distancefields.jl: -------------------------------------------------------------------------------- 1 | visualize_default(distancefield::Union(Texture{Float32, 2}, Array{Float32, 2}), ::Style{:distancefield}, kw_args...) = @compat(Dict( 2 | :color => RGBA(1f0, 1f0, 1f0, 1f0), 3 | :primitive => GLUVMesh2D(Rectangle{Float32}(0f0,0f0,size(distancefield)...)) 4 | )) 5 | 6 | @visualize_gen Array{Float32, 2} Texture Style 7 | 8 | function visualize(distancefield::Texture{Float32, 2}, s::Style{:distancefield}, customizations=visualize_default(positions, s)) 9 | @materialize! primitive = customizations 10 | data = merge(@compat(Dict( 11 | :distancefield => distancefield, 12 | )), collect_for_gl(primitive), customizations) 13 | 14 | program = TemplateProgram( 15 | File(shaderdir, "uv_vert.vert"), 16 | File(shaderdir, "distancefield.frag") 17 | ) 18 | std_renderobject(data, program) 19 | end 20 | 21 | 22 | -------------------------------------------------------------------------------- /test/test_particle2.jl: -------------------------------------------------------------------------------- 1 | using GLVisualize, AbstractGPUArray, GLAbstraction, GeometryTypes, Reactive, ColorTypes, Meshes, MeshIO 2 | 3 | # install a time varying signal 4 | const timer = Input(1) 5 | 6 | function mkCube(p::GeometryTypes.Point3{Float32}, hsz::Float32) 7 | cube = GLNormalMesh( Cube( Vec3( p.x, p.y, p.z), Vec3(hsz))) 8 | GLNormalMesh( cube.vertices, cube.faces) 9 | end 10 | 11 | function mkCube(p::GeometryTypes.Point3{Float32}, hsz::Reactive.Signal) 12 | lift(x -> mkCube( p, Float32(x/10)), hsz) 13 | end 14 | 15 | robj1 = visualize([ mkCube(Point3(0.5f0,0.0f0,0.0f0),timer), 16 | mkCube(Point3(0.0f0,0.5f0,0.0f0),timer)]) 17 | 18 | map (x -> push!(GLVisualize.ROOT_SCREEN.renderlist, x), robj1) 19 | 20 | 21 | @async renderloop() 22 | 23 | while GLVisualize.ROOT_SCREEN.inputs[:open].value 24 | yield() 25 | push!(timer, mod1(timer.value+1, 20)) 26 | end -------------------------------------------------------------------------------- /src/shader/particles2D_single.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | {{GLSL_EXTENSIONS}} 3 | 4 | in vec2 vertices; 5 | in vec2 texturecoordinates; 6 | 7 | uniform vec3 light[4]; 8 | 9 | uniform int technique; 10 | uniform int style; 11 | uniform uint objectid; 12 | 13 | uniform vec2 position; 14 | uniform vec2 scale; 15 | 16 | uniform vec4 color; 17 | 18 | uniform mat4 projectionview, model; 19 | 20 | const int SPRITE = 1; 21 | const int CIRCLE = 2; 22 | const int SQUARE = 3; 23 | 24 | out vec2 o_uv; 25 | out vec4 o_color; 26 | 27 | flat out int o_technique; 28 | flat out int o_style; 29 | flat out uvec2 o_id; 30 | 31 | void main(){ 32 | o_uv = texturecoordinates; 33 | o_color = color; 34 | o_technique = technique; 35 | o_style = style; 36 | o_id = uvec2(objectid, gl_VertexID+1); 37 | gl_Position = projectionview * model * vec4(position + (vertices*scale), 0, 1); 38 | 39 | } -------------------------------------------------------------------------------- /src/shader/boundingbox/instance_functions.vert: -------------------------------------------------------------------------------- 1 | mat4 getmodelmatrix(vec3 xyz, vec3 scale) 2 | { 3 | return mat4( 4 | vec4(scale.x, 0, 0, 0), 5 | vec4(0, scale.y, 0, 0), 6 | vec4(0, 0, scale.z, 0), 7 | vec4(xyz, 1)); 8 | } 9 | 10 | vec2 getuv(ivec2 texdim, int index) 11 | { 12 | float x = float(texdim.x); 13 | float y = float(texdim.y); 14 | float i = float(index); 15 | 16 | float u = float((index % texdim.x)) / x; 17 | float v = (i / y) / y; 18 | return vec2(u,v); 19 | } 20 | 21 | 22 | vec2 stretch(vec2 uv, vec2 from, vec2 to) 23 | { 24 | return from + (uv * (to - from)); 25 | } 26 | vec3 getxy(vec3 uv, vec3 from, vec3 to) 27 | { 28 | return from + (uv * (to - from)); 29 | } 30 | 31 | float rangewidth(vec3 range) 32 | { 33 | return abs(range.x - range.z)/range.y; 34 | } 35 | float maptogridcoordinates(int index, vec3 range) 36 | { 37 | return range.x + float((index % int(rangewidth(range) - range.x ))); 38 | } -------------------------------------------------------------------------------- /src/shader/distancefield.frag: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | 3 | uniform vec4 color; 4 | in vec2 o_uv; 5 | 6 | uniform sampler2D distancefield; 7 | 8 | out vec4 fragment_color; 9 | 10 | float aastep(float threshold1, float threshold2,float value) { 11 | float afwidth = length(vec2(dFdx(value), dFdy(value))) * 0.70710678118654757; 12 | return smoothstep(threshold1-afwidth, threshold1+afwidth, value)-smoothstep(threshold2-afwidth, threshold2+afwidth, value); 13 | } 14 | 15 | float aastep(float threshold1,float value) { 16 | float afwidth = length(vec2(dFdx(value), dFdy(value))) * 0.70710678118654757; 17 | return smoothstep(threshold1-afwidth, threshold1+afwidth, value); 18 | } 19 | vec4 radial_grad(float len, vec4 a, vec4 b) { 20 | return mix(a, b, len); 21 | } 22 | 23 | void main(){ 24 | float _distance = texture(distancefield, o_uv).x; 25 | float dist_aa = aastep(0.5, _distance); 26 | fragment_color = mix(color, vec4(0), dist_aa); 27 | } 28 | -------------------------------------------------------------------------------- /src/visualize/dots.jl: -------------------------------------------------------------------------------- 1 | function visualize_default(::Vector{Point3{Float32}}, ::Style{:dots}, kw_args...) 2 | color = get(kw_args[1], :color, RGBA(1f0, 0f0, 0f0, 1f0)) 3 | delete!(kw_args[1], :color) 4 | color = texture_or_scalar(color) 5 | Dict( 6 | :color => color, 7 | :point_size => 1f0 8 | ) 9 | end 10 | 11 | @visualize_gen Vector{Point3{Float32}} GLBuffer Style{:dots} 12 | 13 | function visualize( 14 | positions::GLBuffer{Point3{Float32}}, 15 | s::Style{:dots}, 16 | data=visualize_default(positions, s) 17 | ) 18 | @materialize! point_size = data 19 | data[:vertex] = positions 20 | program = TemplateProgram( 21 | File(shaderdir, "dots.vert"), 22 | File(shaderdir, "dots.frag"), 23 | attributes=data 24 | ) 25 | robj = std_renderobject(data, program, Input(AABB(gpu_data(positions))), GL_POINTS) 26 | prerender!(robj, glPointSize, point_size) 27 | robj 28 | end 29 | 30 | 31 | -------------------------------------------------------------------------------- /test/test_particles.jl: -------------------------------------------------------------------------------- 1 | #using Reactive, GLVisualize, GLAbstraction, GeometryTypes, ColorTypes, FileIO, MeshIO, Meshes, WavefrontObj 2 | typealias Point3f Point3{Float32} 3 | 4 | generate_particles(N,x,i) = Point3f( 5 | sin(i+x/20f0), 6 | cos(i+x/20f0), 7 | (2x/N)+i/10f0 8 | ) 9 | update_particles(i, N) = Point3f[generate_particles(N,x, i) for x=1:N] 10 | particle_color(positions) = RGBAU8[RGBAU8(((cos(pos.x)+1)/2),0.0,((sin(pos.y)+1)/2), 1.0f0) for pos in positions] 11 | 12 | function particle_data(N) 13 | locations = lift(update_particles, bounce(1f0:0.1f0:10f0), N) 14 | #colors = lift(particle_color, locations) 15 | locations 16 | end 17 | particle_data(1024) 18 | 19 | push!(TEST_DATA, particle_data(1024)) 20 | 21 | particle_color_pulse(x) = RGBA(x, 0f0, 1f0-x, 1f0) 22 | push!(TEST_DATA, ( 23 | Point3f[rand(Point3f, 0f0:0.001f0:2f0) for i=1:1024], 24 | :primitive => GLNormalMesh(file"cat.obj"), 25 | :color => lift(particle_color_pulse, bounce(0f0:0.1f0:1f0)), 26 | :scale => Vec3(0.2) 27 | )) -------------------------------------------------------------------------------- /src/shader/fxaa_combine.frag: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | //precision mediump float; 3 | 4 | //texcoords computed in vertex step 5 | //to avoid dependent texture reads 6 | in vec2 v_rgbNW; 7 | in vec2 v_rgbNE; 8 | in vec2 v_rgbSW; 9 | in vec2 v_rgbSE; 10 | in vec2 v_rgbM; 11 | 12 | //make sure to have a resolution uniform set to the screen size 13 | uniform vec2 resolution; 14 | 15 | //some stuff needed for kami-batch 16 | in vec2 vTexCoord0; 17 | 18 | uniform sampler2D u_texture0; 19 | 20 | //import the fxaa function 21 | vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, 22 | vec2 v_rgbNW, vec2 v_rgbNE, 23 | vec2 v_rgbSW, vec2 v_rgbSE, 24 | vec2 v_rgbM); 25 | 26 | out vec4 fragment_color; 27 | 28 | void main() { 29 | //can also use gl_FragCoord.xy 30 | vec2 fragCoord = vTexCoord0 * resolution; 31 | fragment_color = texture(u_texture0, vTexCoord0); 32 | //fragment_color = fxaa(u_texture0, fragCoord, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); // uncomment for anti aliasing 33 | } -------------------------------------------------------------------------------- /src/types.jl: -------------------------------------------------------------------------------- 1 | ######################################################################################################### 2 | #= 3 | Glyph type for Text rendering. 4 | It doesn't offer any functionality, and is only used for multiple dispatch. 5 | =# 6 | immutable GLGlyph{T} <: FixedVector{T, 4} 7 | glyph::T 8 | line::T 9 | row::T 10 | style_group::T 11 | end 12 | 13 | function GLGlyph(glyph::Integer, line::Integer, row::Integer, style_group::Integer) 14 | if !isascii(char(glyph)) 15 | glyph = char('1') 16 | end 17 | GLGlyph{Uint16}(uint16(glyph), uint16(line), uint16(row), uint16(style_group)) 18 | end 19 | function GLGlyph(glyph::Char, line::Integer, row::Integer, style_group::Integer) 20 | if !isascii(glyph) 21 | glyph = char('1') 22 | end 23 | GLGlyph{Uint16}(uint16(glyph), uint16(line), uint16(row), uint16(style_group)) 24 | end 25 | 26 | GLGlyph() = GLGlyph(' ', typemax(Uint16), typemax(Uint16), 0) 27 | 28 | 29 | ######################################################################################################### 30 | 31 | -------------------------------------------------------------------------------- /src/shader/particles2D.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | {{GLSL_EXTENSIONS}} 3 | 4 | in vec2 vertices; 5 | in vec2 texturecoordinates; 6 | 7 | uniform vec3 light[4]; 8 | uniform vec2 scale; 9 | uniform int technique; 10 | uniform uint objectid; 11 | 12 | uniform samplerBuffer positions; 13 | 14 | {{color_type}} color; 15 | 16 | uniform mat4 projectionview, model; 17 | 18 | vec4 getindex(sampler2D tex, int index); 19 | 20 | const int SPRITE = 1; 21 | const int CIRCLE = 2; 22 | const int SQUARE = 3; 23 | 24 | out vec2 o_uv; 25 | out vec4 o_color; 26 | 27 | flat out int o_technique; 28 | flat out int o_style; 29 | flat out uvec2 o_id; 30 | 31 | void main(){ 32 | int index = gl_InstanceID; 33 | o_uv = texturecoordinates; 34 | vec2 position = texelFetch(positions, index).xy; 35 | o_color = {{color_calculation}} 36 | o_technique = technique; 37 | o_style = 5; 38 | o_id = uvec2(objectid, index+1); 39 | gl_Position = projectionview * model * vec4(position + (vertices*scale), 0, 1); 40 | 41 | } -------------------------------------------------------------------------------- /src/shader/text_single.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | {{GLSL_EXTENSIONS}} 3 | 4 | in vec2 vertices; 5 | in vec2 texturecoordinates; 6 | 7 | uniform samplerBuffer positions; 8 | 9 | uniform int offset; 10 | uniform uint glyph; 11 | uniform vec4 color; 12 | 13 | uniform samplerBuffer uvs; 14 | uniform mat4 projectionview, model; 15 | 16 | 17 | out vec2 o_uv; 18 | out vec4 o_color; 19 | 20 | void main(){ 21 | int index = offset-1; //convert from julia indexes 22 | vec4 uv_dims = texelFetch(uvs, int(glyph)); 23 | vec4 attributes2 = texelFetch(uvs, int(glyph) + 1); 24 | 25 | vec2 bearing = attributes2.xy; 26 | vec2 glyph_scale = uv_dims.zw; 27 | 28 | vec2 position = texelFetch(positions, index).xy-vec2(0,4); //hack hack, this is pretty much only to make the text cursor look good, while its only a '|' 29 | 30 | o_uv = (vec2(texturecoordinates.x, 1-texturecoordinates.y)*uv_dims.zw)+uv_dims.xy; 31 | o_color = color; 32 | gl_Position = projectionview * model * vec4(position + (vertices*glyph_scale), 0, 1); 33 | } -------------------------------------------------------------------------------- /src/visualize/grid.jl: -------------------------------------------------------------------------------- 1 | #= 2 | function creategrid(;xrange::(Real, Real)=(-1,1), yrange::(Real, Real)=(-1,1), zrange::(Real, Real)=(-1,1), camera=pcamera) 3 | xyplane = genquad(Vec3(0, 0, 0), Vec3(1, 0, 0), Vec3(0, 1, 0)) 4 | zyplane = genquad(Vec3(0, 0, 0), Vec3(0, 0, 1.2), Vec3(0, 1, 0)) 5 | zxplane = genquad(Vec3(0, 1, 0), Vec3(0, 0, 1.2), Vec3(1, 0, 0)) 6 | 7 | v,uv,n,i = mergemesh(xyplane, zyplane, zxplane) 8 | 9 | gridshader = TemplateProgram(File(shaderdir, "grid.vert"), File(shaderdir, "grid.frag")) 10 | 11 | 12 | grid = RenderObject(@compat(Dict( 13 | :vertexes => GLBuffer(v), 14 | :indexes => indexbuffer(i), 15 | #:grid_color => Float32[0.1,.1,.1, 1.0], 16 | :bg_color => Input(Vec4(1, 1, 1, 0.01)), 17 | :grid_thickness => Input(Vec3(2)), 18 | :gridsteps => Input(Vec3(10)), 19 | :mvp => camera.projectionview 20 | )), gridshader) 21 | prerender!(grid, glDisable, GL_DEPTH_TEST, glDisable, GL_CULL_FACE, enabletransparency) 22 | postrender!(grid, render, grid.vertexarray) 23 | return grid 24 | end 25 | 26 | export creategrid 27 | 28 | =# -------------------------------------------------------------------------------- /src/shader/standard.frag: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | 3 | in vec3 o_normal; 4 | in vec3 o_lightdir; 5 | in vec3 o_vertex; 6 | in vec4 o_color; 7 | flat in uvec2 o_id; 8 | 9 | out vec4 fragment_color; 10 | out uvec2 fragment_groupid; 11 | 12 | 13 | vec3 blinnphong(vec3 N, vec3 V, vec3 L, vec3 color) 14 | { 15 | float diff_coeff = max(dot(L,N), 0.0); 16 | 17 | // specular coefficient 18 | vec3 H = normalize(L+V); 19 | 20 | float spec_coeff = pow(max(dot(H,N), 0.0), 8.0); 21 | if (diff_coeff <= 0.0) 22 | spec_coeff = 0.0; 23 | 24 | // final lighting model 25 | return vec3( 26 | vec3(0.1) * vec3(0.3) + 27 | vec3(0.9) * color * diff_coeff + 28 | vec3(0.3) * spec_coeff); 29 | } 30 | 31 | void main(){ 32 | vec3 L = normalize(o_lightdir); 33 | vec3 N = normalize(o_normal); 34 | vec3 light1 = blinnphong(N, o_vertex, L, o_color.rgb); 35 | vec3 light2 = blinnphong(N, o_vertex, -L, o_color.rgb); 36 | fragment_color = vec4(light1+light2*0.4, o_color.a); 37 | if(fragment_color.a > 0.0) 38 | fragment_groupid = o_id; 39 | } 40 | -------------------------------------------------------------------------------- /test/test_lines.jl: -------------------------------------------------------------------------------- 1 | using GLAbstraction, GLVisualize, ModernGL, GeometryTypes, Reactive 2 | 3 | linevert = vert" 4 | {{GLSL_VERSION}} 5 | 6 | in vec3 vertex; 7 | 8 | uniform mat4 projectionview; 9 | 10 | void main(){ 11 | gl_Position = projectionview * vec4(vertex, 1.0); 12 | } 13 | " 14 | linefrag = frag" 15 | {{GLSL_VERSION}} 16 | 17 | out vec4 frag_color; 18 | void main(){ 19 | frag_color = vec4(1,0,0,1); 20 | } 21 | " 22 | lineshader = TemplateProgram(linevert, linefrag) 23 | 24 | N = 5 25 | PD = 4 26 | verts = Point3{Float32}[Point3{Float32}(sin(i), cos(i), cos(i)) for i=1:N*PD] # Vec3 == Vector3{Float32} GLSL alike alias for immutable array 27 | indexes = vcat([GLuint[0,1,1,2,2,3,3,0] + i for i=0:(N-1)]...) 28 | 29 | lines = std_renderobject(Dict( 30 | :vertex => GLBuffer(verts), #NOT WORKING 31 | :index => indexbuffer(indexes), #NOT WORKING 32 | :projectionview => GLVisualize.ROOT_SCREEN.perspectivecam.projectionview 33 | ), Input(lineshader), Input(AABB(verts)), GL_LINES) #Input(AABB(verts)) -> calculates boundingbox 34 | 35 | push!(GLVisualize.ROOT_SCREEN.renderlist, lines) 36 | 37 | renderloop() -------------------------------------------------------------------------------- /src/visualize/containers.jl: -------------------------------------------------------------------------------- 1 | 2 | visualize_default(::Matrix, ::Style, kw_args...) = @compat(Dict( 3 | :gap => Input(Vec3(0.1, 0.1, 0.0)), 4 | :scale => Vec3(1.0, 1.0, 1.0) 5 | )) 6 | 7 | function visualize(grid::Matrix, s::Style, customizations=visualize_default(grid, s)) 8 | @materialize! gap, model, scale = customizations 9 | results = map(grid) do viz_args 10 | trans = Input(eye(Mat4)) # get a handle to the translation matrix 11 | if isa(viz_args, Tuple) 12 | length(viz_args) < 1 && error("tried to visualize empty tuple ()") 13 | key_args = collect(filter(x->isa(x, Pair), viz_args)) 14 | viz_data = collect(filter(x->!isa(x, Pair), viz_args)) 15 | return (trans, visualize(viz_data...; key_args..., model=trans)) 16 | end 17 | return (trans, visualize(viz_args, model=trans)) 18 | end 19 | 20 | for i=1:size(results, 1), j=1:size(results, 2) 21 | model, robj = results[i,j] 22 | bb = robj.boundingbox.value 23 | width = bb.max-bb.min 24 | model_scale = 1f0/max(width.x, width.y) 25 | push!(model, translationmatrix(Vec3(i-1, j-1, 0).*scale)*scalematrix(model_scale*scale)*translationmatrix(-bb.min)) # update transformation matrix 26 | end 27 | vec(map(last, results)) 28 | end 29 | 30 | 31 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The GLVisualize.jl package is licensed under the MIT "Expat" License: 2 | 3 | > Copyright (c) 2014: SimonDanisch. 4 | > 5 | > Permission is hereby granted, free of charge, to any person obtaining 6 | > a copy of this software and associated documentation files (the 7 | > "Software"), to deal in the Software without restriction, including 8 | > without limitation the rights to use, copy, modify, merge, publish, 9 | > distribute, sublicense, and/or sell copies of the Software, and to 10 | > permit persons to whom the Software is furnished to do so, subject to 11 | > the following conditions: 12 | > 13 | > The above copyright notice and this permission notice shall be 14 | > included in all copies or substantial portions of the Software. 15 | > 16 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | > EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | > MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | > IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | > CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 21 | > TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 22 | > SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /src/shader/meshgrid.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | {{GLSL_EXTENSIONS}} 3 | 4 | struct Rectangle 5 | { 6 | vec2 origin; 7 | vec2 width; 8 | }; 9 | 10 | in vec3 vertices; 11 | in vec3 normals; 12 | 13 | uniform vec3 light[4]; 14 | uniform sampler1D color; 15 | uniform vec2 norm; 16 | 17 | uniform sampler2D y_scale; 18 | uniform vec3 scale; 19 | 20 | uniform vec2 grid_min; 21 | uniform vec2 grid_max; 22 | 23 | uniform mat4 view, model, projection; 24 | 25 | void render(vec3 vertices, vec3 normals, vec4 color, mat4 viewmodel, mat4 projection, vec3 light[4]); 26 | 27 | vec3 position(Rectangle rectangle, ivec2 dims, int index); 28 | vec4 linear_texture(sampler2D tex, int index); 29 | vec4 color_lookup(float intensity, sampler1D color_ramp, vec2 norm); 30 | 31 | uniform uint objectid; 32 | flat out uvec2 o_id; 33 | 34 | void main() 35 | { 36 | vec3 pos = position(Rectangle(grid_min, grid_max), textureSize(y_scale, 0), gl_InstanceID); 37 | float intensity = linear_texture(y_scale, gl_InstanceID).x; 38 | pos += vertices*vec3(scale.xy, scale.z*intensity); 39 | vec4 instance_color = color_lookup(intensity, color, norm); 40 | render(pos, normals, instance_color, view*model, projection, light); 41 | o_id = uvec2(objectid, gl_InstanceID); 42 | } 43 | 44 | 45 | -------------------------------------------------------------------------------- /test/test_sierpinski_mesh.jl: -------------------------------------------------------------------------------- 1 | typealias Point3f Point3{Float32} 2 | 3 | function sierpinski(n, positions=Point3f[]) 4 | if n == 0 5 | push!(positions, Point3f(0)) 6 | positions 7 | else 8 | t = sierpinski(n - 1, positions) 9 | for i=1:length(t) 10 | t[i] = t[i] * 0.5f0 11 | end 12 | t_copy = copy(t) 13 | mv = (0.5^n * 2^n)/2f0 14 | mw = (0.5^n * 2^n)/4f0 15 | append!(t, [p + Point3f(mw, mw, -mv) for p in t_copy]) 16 | append!(t, [p + Point3f(mw, -mw, -mv) for p in t_copy]) 17 | append!(t, [p + Point3f(-mw, -mw, -mv) for p in t_copy]) 18 | append!(t, [p + Point3f(-mw, mw, -mv) for p in t_copy]) 19 | t 20 | end 21 | end 22 | function sierpinski_data(n) 23 | positions = sierpinski(n) 24 | return (positions, :scale => Vec3(0.5^n), :primitive => GLNormalMesh(Pyramid(Point3f(0), 1f0,1f0))) 25 | #return visualize(positions, scale=Vec3(0.5^n), primitive=GLNormalMesh(Pyramid(Point3f(0), 1f0,1f0))) 26 | end 27 | sierpinski_data(4) 28 | push!(TEST_DATA, sierpinski_data(4)) 29 | #= 30 | using GLVisualize, AbstractGPUArray, GLAbstraction, GeometryTypes, Reactive, ColorTypes, MeshIO, Meshes, FileIO 31 | using GLFW, ModernGL 32 | view(sierpinski_data(4)) 33 | renderloop() 34 | =# -------------------------------------------------------------------------------- /src/shader/boundingbox/phongblinn.frag: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | 3 | {{in}} vec3 N; 4 | {{in}} vec3 V; 5 | {{in}} vec4 vert_color; 6 | 7 | {{out}} vec4 fragment_color; 8 | 9 | uniform vec3 light_position; 10 | 11 | struct MyStruct 12 | { 13 | vec2 firstField; 14 | vec4 secondField; 15 | mat2 thirdField; 16 | }; 17 | vec3 blinn_phong(vec3 N, vec3 V, vec3 L, vec3 diffuse) 18 | { 19 | // material properties 20 | // you might want to put this into a bunch or uniforms 21 | vec3 Ka = vec3(0.0); 22 | vec3 Kd = vec3(1.0); 23 | vec3 Ks = vec3(1.0); 24 | float shininess = 50.0; 25 | 26 | // diffuse coefficient 27 | float diff_coeff = max(dot(L,N),0.0); 28 | 29 | // specular coefficient 30 | vec3 H = normalize(L+V); 31 | float spec_coeff = pow(max(dot(H,N), 0.0), shininess); 32 | if (diff_coeff <= 0.0) 33 | spec_coeff = 0.0; 34 | 35 | // final lighting model 36 | return Ka * vec3(0.1) + 37 | Kd * diffuse * diff_coeff + 38 | Ks * vec3(0.1) * spec_coeff ; 39 | } 40 | 41 | 42 | void main(){ 43 | 44 | vec3 L = normalize(light_position - V); 45 | vec3 light1 = blinn_phong(N, V, L, vert_color.rgb); 46 | vec3 light2 = blinn_phong(N, V, -L, vert_color.rgb); 47 | fragment_color = vec4(light1 + light2, vert_color.a); 48 | } 49 | -------------------------------------------------------------------------------- /src/visualize/text/rectangle_packing.jl: -------------------------------------------------------------------------------- 1 | using GeometryTypes 2 | 3 | type Node 4 | children::Vector{Node} 5 | area::Rectangle{Int} 6 | end 7 | Node(area::Rectangle) = Node(Node[], area) 8 | 9 | isleaf(a::Node) = isempty(a.children) 10 | 11 | xwidth(a::Rectangle) = a.w + a.x 12 | yheight(a::Rectangle) = a.h + a.y 13 | area(a::Rectangle) = a.w*a.h 14 | Base.isless(a::Rectangle, b::Rectangle) = isless(area(a), area(b)) 15 | 16 | function Base.push!(node::Node, area::Rectangle) 17 | if !isleaf(node) 18 | a = push!(node.children[1], area) 19 | a == nothing && return push!(node.children[2], area) 20 | return a 21 | end 22 | newarea = Node(area).area 23 | if newarea.w <= node.area.w && newarea.h <= node.area.h 24 | oax,oay,oaxw,oayh = node.area.x+newarea.w, node.area.y, xwidth(node.area), node.area.y + newarea.h 25 | nax,nay,naxw,nayh = node.area.x, node.area.y+newarea.h, xwidth(node.area), yheight(node.area) 26 | rax,ray,raxw,rayh = node.area.x, node.area.y, node.area.x+newarea.w, node.area.y+newarea.h 27 | 28 | push!(node.children, Node(Rectangle(oax, oay, oaxw-oax, oayh-oay))) 29 | push!(node.children, Node(Rectangle(nax,nay, naxw-nax,nayh-nay))) 30 | return Node(Rectangle(rax,ray,raxw-rax,rayh-ray)) 31 | end 32 | end 33 | 34 | -------------------------------------------------------------------------------- /test/test_mesh.jl: -------------------------------------------------------------------------------- 1 | 2 | function mesh_data() 3 | # volume of interest 4 | x_min, x_max = -1, 15 5 | y_min, y_max = -1, 5 6 | z_min, z_max = -1, 5 7 | scale = 8 8 | 9 | b1(x,y,z) = box( x,y,z, 0,0,0,3,3,3) 10 | s1(x,y,z) = sphere(x,y,z, 3,3,3,sqrt(3)) 11 | f1(x,y,z) = min(b1(x,y,z), s1(x,y,z)) # UNION 12 | b2(x,y,z) = box( x,y,z, 5,0,0,8,3,3) 13 | s2(x,y,z) = sphere(x,y,z, 8,3,3,sqrt(3)) 14 | f2(x,y,z) = max(b2(x,y,z), -s2(x,y,z)) # NOT 15 | b3(x,y,z) = box( x,y,z, 10,0,0,13,3,3) 16 | s3(x,y,z) = sphere(x,y,z, 13,3,3,sqrt(3)) 17 | f3(x,y,z) = max(b3(x,y,z), s3(x,y,z)) # INTERSECTION 18 | f(x,y,z) = min(f1(x,y,z), f2(x,y,z), f3(x,y,z)) 19 | 20 | vol = volume(f, x_min,y_min,z_min,x_max,y_max,z_max, scale) 21 | msh = GLNormalMesh(vol, 0.0f0) 22 | 23 | baselen = 0.4f0 24 | dirlen = 2f0 25 | axis = [ 26 | (Cube(Vec3(baselen), Vec3(dirlen, baselen, baselen)), RGBA(1f0,0f0,0f0,1f0)), 27 | (Cube(Vec3(baselen), Vec3(baselen, dirlen, baselen)), RGBA(0f0,1f0,0f0,1f0)), 28 | (Cube(Vec3(baselen), Vec3(baselen, baselen, dirlen)), RGBA(0f0,0f0,1f0,1f0)) 29 | ] 30 | 31 | axis = map(GLNormalMesh, axis) 32 | axis = merge(axis) 33 | 34 | return msh, axis 35 | end 36 | 37 | push!(TEST_DATA, mesh_data()...) 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/shader/fxaa.vert: -------------------------------------------------------------------------------- 1 | //precision mediump float; 2 | {{GLSL_VERSION}} 3 | 4 | //texcoords computed in vertex step 5 | //to avoid dependent texture reads 6 | out vec2 v_rgbNW; 7 | out vec2 v_rgbNE; 8 | out vec2 v_rgbSW; 9 | out vec2 v_rgbSE; 10 | out vec2 v_rgbM; 11 | 12 | //incoming Position attribute from our SpriteBatch 13 | in vec2 vertices; 14 | in vec2 texturecoordinates; 15 | 16 | //uniforms from sprite batch 17 | out vec2 vTexCoord0; 18 | 19 | //a resolution for our optimized shader 20 | uniform vec2 resolution; 21 | 22 | 23 | void texcoords(vec2 fragCoord, vec2 resolution, 24 | out vec2 v_rgbNW, out vec2 v_rgbNE, 25 | out vec2 v_rgbSW, out vec2 v_rgbSE, 26 | out vec2 v_rgbM) { 27 | vec2 inverseVP = 1.0 / resolution.xy; 28 | v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; 29 | v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; 30 | v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; 31 | v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; 32 | v_rgbM = vec2(fragCoord * inverseVP); 33 | } 34 | 35 | void main(void) { 36 | gl_Position = vec4(vertices.x, vertices.y, 0.0, 1.0); 37 | vTexCoord0 = texturecoordinates; 38 | //compute the texture coords and send them to varyings 39 | vec2 fragCoord = vTexCoord0 * resolution; 40 | texcoords(fragCoord, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); 41 | } -------------------------------------------------------------------------------- /src/visualize/mesh.jl: -------------------------------------------------------------------------------- 1 | visualize_default(::Mesh, ::Style, kw_args=Dict()) = Dict{Symbol, Any}() 2 | visualize_default(::GLNormalMesh, ::Style, kw_args=Dict()) = Dict{Symbol, Any}( 3 | :color => RGBA(0.282f0,0.4627f0, 1.0f0, 1.0f0) 4 | ) 5 | 6 | #visualize(mesh::Mesh, s::Style, customizations=visualize_default(mesh, s)) = visualize(convert(GLNormalMesh, mesh), s, customizations) 7 | 8 | function visualize(mesh::GLNormalMesh, s::Style, customizations=visualize_default(mesh, s)) 9 | data = merge(collect_for_gl(mesh), customizations) 10 | shader = TemplateProgram( 11 | File(shaderdir, "util.vert"), 12 | File(shaderdir, "standard.vert"), 13 | File(shaderdir, "standard.frag"), 14 | fragdatalocation=[(0, "fragment_color"), (1, "fragment_groupid")]) 15 | std_renderobject(data, shader, Input(AABB(mesh.vertices))) 16 | end 17 | 18 | function visualize(mesh::GLNormalAttributeMesh, s::Style, customizations=visualize_default(mesh, s)) 19 | data = merge(collect_for_gl(mesh), customizations) 20 | shader = TemplateProgram( 21 | File(shaderdir, "util.vert"), 22 | File(shaderdir, "attribute_mesh.vert"), 23 | File(shaderdir, "standard.frag"), 24 | fragdatalocation=[(0, "fragment_color"), (1, "fragment_groupid")]) 25 | std_renderobject(data, shader, Input(AABB(mesh.vertices))) 26 | end 27 | -------------------------------------------------------------------------------- /src/visualize/plotlibs.jl: -------------------------------------------------------------------------------- 1 | if isdefined(Main, :PyPlot) 2 | begin 3 | wh = [500,500] 4 | f = PyPlot.gcf() 5 | const pyplotplot = visualize(Texture(ARGB{Ufixed8}, wh)) 6 | function visualize(style::Style, plot::Gadfly.Plot, customizations) 7 | ram = convert(Array{Uint8},f[:canvas][:tostring_argb]()) 8 | pyplotplot[:image][1:end, 1:end] = reinterpret(ARGB{Ufixed8}, ram, f[:canvas][:get_width_height]()) 9 | end 10 | end 11 | end 12 | if isdefined(Main, :Gadfly) 13 | using Cairo, FixedPointNumbers 14 | wh = [500,500] 15 | const surface = Cairo.CairoARGBSurface(zeros(Uint32, wh...)) 16 | const cairocontext = CairoContext(surface) 17 | global gadflyplot = 0 18 | visualize(plot::Main.Gadfly.Plot, style::Style=Style(:Default); customizations...) = visualize(style, plot, Dict{Symbol, Any}(customizations)) 19 | function redrawplot(plot::Main.Gadfly.Plot) 20 | set_source_rgba(cairocontext, 1.0,1.0,1.0,1.0) 21 | paint(cairocontext) 22 | Main.Gadfly.draw(Main.Gadfly.PNG(surface), Main.Gadfly.render(plot)) 23 | 24 | end 25 | function visualize(style::Style, plot::Main.Gadfly.Plot, customizations) 26 | global gadflyplot 27 | gadflyplot == 0 && (gadflyplot = visualize(Texture(BGRA{Ufixed8}, wh), screen=customizations[:screen])) 28 | redrawplot(plot) 29 | gadflyplot[:image][1:end, 1:end] = mapslices(reverse, reinterpret(BGRA{Ufixed8}, surface.data),2) 30 | gadflyplot 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /src/edit/color_chooser.jl: -------------------------------------------------------------------------------- 1 | # very bad, but simple implementation 2 | 3 | 4 | drag_xy(drag_id) = drag_id[1] 5 | cuttoff(x) = max(min(1f0, x), 0f0) 6 | isclicked(x) = !isempty(x) 7 | function vizzedit(x::RGBA, inputs) 8 | drag = inputs[:mousedragdiff_objectid] 9 | mbutton_clicked = inputs[:mousebuttonspressed] 10 | 11 | vizz = visualize(Rectangle(0,0,50,50), style=Cint(5)) 12 | is_num(drag_id) = drag_id[2][1] == vizz.id 13 | slide_addition = lift(drag_xy, filter(is_num, (Vec2(0), Vector2(0), Vector2(0)), drag)) 14 | haschanged = foldl((t0, t1) -> (t0[2]!=t1, t1), (false, slide_addition.value), slide_addition) 15 | haschanged = lift(first, haschanged) 16 | slide_addition = keepwhen(haschanged, Vec2(0), slide_addition) 17 | 18 | slide_addition = lift(last, foldl(GLAbstraction.mousediff, (false, Vector2(0.0f0), Vector2(0.0f0)), ## (Note 2) 19 | lift(isclicked, mbutton_clicked), slide_addition)) 20 | 21 | color = foldl(x, lift(/,slide_addition, 1000.0f0), mbutton_clicked) do v0, addition, mpress 22 | if length(mpress) == 1 23 | if mpress == IntSet(1) # leftclick changes blue+trans 24 | return RGBA{Float32}(v0.r, v0.g, cuttoff(v0.b-addition.x), cuttoff(v0.a-addition.y)) 25 | elseif mpress == IntSet(0) 26 | return RGBA{Float32}(cuttoff(v0.r-addition.x), cuttoff(v0.g-addition.y), v0.b, v0.a) 27 | end 28 | end 29 | v0 30 | end 31 | vizz[:color] = color 32 | return color, vizz 33 | end 34 | -------------------------------------------------------------------------------- /src/visualize/meshgrid.jl: -------------------------------------------------------------------------------- 1 | function visualize_default(grid::Union(Texture{Float32, 2}, Matrix{Float32}), ::Style, kw_args=Dict()) 2 | grid_min = get(kw_args, :grid_min, Vec2(-1, -1)) 3 | grid_max = get(kw_args, :grid_max, Vec2( 1, 1)) 4 | grid_length = grid_max - grid_min 5 | scale = Vec3((1f0 ./[size(grid)...])..., 1f0).* Vec3(grid_length..., 1f0) 6 | return Dict( 7 | :primitive => GLNormalMesh(Cube(Vec3(0), Vec3(1.0))), 8 | :color => RGBAU8[rgbaU8(1,0,0,1), rgbaU8(1,1,0,1), rgbaU8(0,1,0,1), rgbaU8(0,1,1,1), rgbaU8(0,0,1,1)], 9 | :grid_min => grid_min, 10 | :grid_max => grid_max, 11 | :scale => scale, 12 | :norm => Vec2(minimum(grid), maximum(grid)) 13 | ) 14 | end 15 | @visualize_gen Matrix{Float32} Texture Style 16 | 17 | function visualize(grid::Texture{Float32, 2}, s::Style, customizations=visualize_defaults(grid, s)) 18 | @materialize! color, primitive = customizations 19 | @materialize grid_min, grid_max, norm = customizations 20 | data = merge(Dict( 21 | :y_scale => grid, 22 | :color => Texture(color), 23 | ), collect_for_gl(primitive), customizations) 24 | program = TemplateProgram( 25 | File(shaderdir, "util.vert"), 26 | File(shaderdir, "meshgrid.vert"), 27 | File(shaderdir, "standard.frag") 28 | ) 29 | instanced_renderobject(data, length(grid), program, lift(particle_grid_bb, grid_min, grid_max, norm)) 30 | end 31 | -------------------------------------------------------------------------------- /test/wip_text_input.jl: -------------------------------------------------------------------------------- 1 | using GLWindow, GLFW, GLAbstraction, Reactive 2 | 3 | w = createwindow("test", 10, 10) 4 | include(Pkg.dir("GLVisualize", "src", "visualize", "text", "utils.jl")) 5 | 6 | unicode = w.inputs[:unicodeinput] 7 | keys = w.inputs[:buttonspressed] 8 | 9 | selection = Input(4:3) 10 | text_raw = TextWithSelection([1,2,3,4], selection.value) 11 | text = Input(text_raw) 12 | lift(s->(text_raw.selection=s), selection) # is there really no other way?! 13 | 14 | Base.IntSet(a...) = IntSet(a) 15 | 16 | strg_v = lift(==, keys, IntSet(GLFW.KEY_LEFT_CONTROL, GLFW.KEY_V)) 17 | strg_c = lift(==, keys, IntSet(GLFW.KEY_LEFT_CONTROL, GLFW.KEY_C)) 18 | strg_x = lift(==, keys, IntSet(GLFW.KEY_LEFT_CONTROL, GLFW.KEY_X)) 19 | del = lift(==, keys, IntSet(GLFW.KEY_DELETE)) 20 | 21 | clipboard_copy = lift(copyclipboard, keepwhen(strg_c, true, strg_v), text) 22 | delete_text = lift(deletetext, keepwhen(del, true, del), text) 23 | 24 | clipboard_paste = lift(clipboardpaste, keepwhen(strg_v, true, strg_v)) 25 | 26 | text_gate = lift(isnotempty, unicode) #lift(AND, lift(is_textinput_modifiers, keys), lift(isnotempty, unicode)) 27 | unicode_input = keepwhen(text_gate, Char['0'], unicode) 28 | text_to_insert = merge(clipboard_paste, unicode_input) 29 | text_to_insert = lift(x->map(GLSprite, map_fonts(x)), text_to_insert) 30 | 31 | lift(inserttext, text, text_to_insert) 32 | 33 | while w.inputs[:open].value 34 | GLFW.PollEvents() 35 | sleep(0.01) 36 | end 37 | 38 | println(text) -------------------------------------------------------------------------------- /test/runtests.jl: -------------------------------------------------------------------------------- 1 | using GLAbstraction, GLVisualize, Reactive, GLWindow 2 | using GeometryTypes, ColorTypes 3 | using MeshIO, Meshes,FileIO, WavefrontObj 4 | 5 | using Base.Test 6 | 7 | const TEST_DATA = Any[] 8 | const TEST_DATA2D = Any[] 9 | typealias Point3f Point3{Float32} 10 | 11 | const tests = [ 12 | "volume", 13 | "barplot", 14 | "surface", 15 | "isosurface", 16 | "vectorfield", 17 | "obj", 18 | "mesh", 19 | "particles", 20 | "dots", 21 | "sierpinski_mesh", 22 | "arbitrary_surface", 23 | "text", 24 | "particles2D", 25 | # "image" 26 | ] 27 | 28 | for test_name in tests 29 | println("loading: ", test_name, "...") 30 | include(string("test_", test_name, ".jl")) 31 | println("...", test_name, " loaded!") 32 | end 33 | 34 | 35 | grid = reshape(TEST_DATA, close_to_square(length(TEST_DATA)) ) 36 | grid2D = reshape(TEST_DATA2D, close_to_square(length(TEST_DATA2D))) 37 | 38 | println("reshape done") 39 | 40 | const rs = GLVisualize.ROOT_SCREEN 41 | xhalf(r) = Rectangle{Int}(r.x,r.y, round(Int, r.w/2), r.h) 42 | xhalf2(r) = Rectangle{Int}(round(Int, r.w/2), r.y, round(Int, r.w/2), r.h) 43 | const screen3D = Screen(rs, area=lift(xhalf, rs.area)) 44 | const screen2D = Screen(rs, area=lift(xhalf2, rs.area)) 45 | println("screens done") 46 | 47 | 48 | view(visualize(grid), screen3D) 49 | println("3d done") 50 | 51 | 52 | view(visualize(grid2D, scale=Vec3(1000,1000,1.0)), screen2D) 53 | println("2d done") 54 | 55 | 56 | println("viewing it now") 57 | renderloop() 58 | -------------------------------------------------------------------------------- /src/visualize/image.jl: -------------------------------------------------------------------------------- 1 | visualize_default{T <: Color}(image::Union(Texture{T, 2}, Matrix{T}), ::Style, kw_args=Dict()) = Dict( 2 | :primitive => GLUVMesh2D(Rectangle{Float32}(0f0,0f0,size(image)...)), 3 | :preferred_camera => :orthographic_pixel 4 | ) 5 | 6 | visualize_default(image::AbstractImage, s::Style, kw_args...) = visualize_default(image.data, s, kw_args...) 7 | 8 | visualize{T <: Color}(img::Array{T, 2}, s::Style, customizations=visualize_default(img, s)) = 9 | visualize(Texture(img), s, customizations) 10 | 11 | 12 | function visualize{T <: Color}(img::Signal{Array{T, 2}}, s::Style, customizations=visualize_default(img.value, s)) 13 | tex = Texture(img.value) 14 | lift(update!, tex, img) 15 | visualize(tex, s, customizations) 16 | end 17 | visualize(img::Image, s::Style, customizations=visualize_default(img, s)) = 18 | visualize(img.data, s, customizations) 19 | 20 | function visualize{T <: Color}(img::Texture{T, 2}, s::Style, data=visualize_default(img, s)) 21 | @materialize! primitive = data 22 | data[:image] = img 23 | merge!(data, collect_for_gl(primitive)) 24 | fragdatalocation = [(0, "fragment_color"),(1, "fragment_groupid")] 25 | textureshader = TemplateProgram( 26 | File(shaderdir, "uv_vert.vert"), 27 | File(shaderdir, "texture.frag"), 28 | attributes=data, 29 | fragdatalocation=fragdatalocation 30 | ) 31 | obj = std_renderobject(data, textureshader, Input(AABB(Vec3(0), Vec3(size(img)...,0)))) # really not a good boundingbox. 32 | end 33 | -------------------------------------------------------------------------------- /src/utils.jl: -------------------------------------------------------------------------------- 1 | function include_all(folder::String) 2 | for file in readdir(folder) 3 | if endswith(file, ".jl") 4 | include(joinpath(folder, file)) 5 | end 6 | end 7 | end 8 | 9 | # Splits a dictionary in two dicts, via a condition 10 | function Base.split(condition::Function, associative::Associative) 11 | A = similar(associative) 12 | B = similar(associative) 13 | for (key, value) in associative 14 | if condition(key, value) 15 | A[key] = value 16 | else 17 | B[key] = value 18 | end 19 | end 20 | A, B 21 | end 22 | 23 | #creates methods to accept signals, which then gets transfert to an OpenGL target type 24 | macro visualize_gen(input, target, S) 25 | esc(quote 26 | visualize(value::$input, s::$S, customizations=visualize_default(value, s)) = 27 | visualize($target(value), s, customizations) 28 | 29 | function visualize(signal::Signal{$input}, s::$S, customizations=visualize_default(signal.value, s)) 30 | tex = $target(signal.value) 31 | lift(update!, Input(tex), signal) 32 | visualize(tex, s, customizations) 33 | end 34 | end) 35 | end 36 | 37 | 38 | # scalars can be uploaded directly to gpu, but not arrays 39 | texture_or_scalar(x) = x 40 | texture_or_scalar(x::Array) = Texture(x) 41 | function texture_or_scalar{A <: Array}(x::Signal{A}) 42 | tex = Texture(x.value) 43 | lift(update!, tex, x) 44 | tex 45 | end 46 | 47 | isnotempty(x) = !isempty(x) 48 | AND(a,b) = a&&b 49 | 50 | -------------------------------------------------------------------------------- /src/shader/vectorfield.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | {{GLSL_EXTENSIONS}} 3 | struct AABB 4 | { 5 | vec3 min; 6 | vec3 max; 7 | }; 8 | 9 | in vec3 vertices; 10 | in vec3 normals; 11 | 12 | uniform vec3 light[4]; 13 | uniform sampler3D vectorfield; 14 | uniform sampler1D color; 15 | uniform vec2 norm; 16 | 17 | uniform vec3 cube_min; 18 | uniform vec3 cube_max; 19 | 20 | uniform mat4 view, model, projection; 21 | 22 | void render(vec3 vertices, vec3 normals, vec4 color, mat4 viewmodel, mat4 projection, vec3 light[4]); 23 | 24 | vec3 position(AABB cube, ivec3 dims, int index); 25 | vec4 getindex(sampler3D tex, int index); 26 | vec4 color_lookup(float intensity, sampler1D color_ramp, vec2 norm); 27 | mat4 rotation(vec3 direction); 28 | mat4 getmodelmatrix(vec3 xyz, vec3 scale); 29 | mat4 rotationmatrix_y(float angle); 30 | 31 | 32 | uniform uint objectid; 33 | flat out uvec2 o_id; 34 | 35 | 36 | void main() 37 | { 38 | ivec3 dims = textureSize(vectorfield, 0); 39 | vec3 cell_size = (cube_max-cube_min)/vec3(dims); 40 | vec3 pos = position(AABB(cube_min, cube_max), dims, gl_InstanceID); 41 | vec3 direction = getindex(vectorfield, gl_InstanceID).xyz; 42 | mat4 rot = rotation(direction); 43 | mat4 trans = getmodelmatrix(pos+(cell_size/2.0), cell_size); 44 | float intensity = length(direction); 45 | vec4 instance_color = color_lookup(intensity, color, norm); 46 | render(vertices, normals, instance_color, view*model*trans*rot, projection, light); 47 | o_id = uvec2(objectid, gl_InstanceID); 48 | } 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/edit/renderobject.jl: -------------------------------------------------------------------------------- 1 | 2 | function edit(style::Style, dict::Dict, customization::Dict{Symbol,Any}) 3 | screen = customization[:screen] 4 | yposition = float32(screen.area.value.h) 5 | 6 | glypharray = Array(Romeo.GLGlyph{Uint16}, 0) 7 | visualizations = RenderObject[] 8 | xgap = 60f0 9 | ygap = 20f0 10 | lineheight = 24f0 11 | currentline = 0 12 | aabb = AABB(Vec3(0), Vec3(0)) 13 | i = 0 14 | for (name,value) in dict 15 | if method_exists(edit, (typeof(value),)) 16 | currentline += int(abs(aabb.max[2]-aabb.min[2])/lineheight) + i 17 | yposition -= lineheight*2 18 | i = 3 19 | append!(glypharray, Romeo.GLGlyph{Uint16}[Romeo.GLGlyph(c, currentline, k, 0) for (k,c) in enumerate(string(name)*":")]) 20 | visual, signal = Romeo.edit(value, style, screen=screen) 21 | aabb = visual.boundingbox(visual) 22 | 23 | translatm = translationmatrix(Vec3(xgap - aabb.min[1], yposition - aabb.max[2], 0)) 24 | visual[:model] = translatm * visual[:model] 25 | dict[name] = signal 26 | yposition -= abs(aabb.max[2]-aabb.min[2]) + lineheight 27 | push!(visualizations, visual) 28 | end 29 | end 30 | labels = visualize(glypharray, screen=screen, color=rgba(0.19, 0.70,0.88,1.0), model=translationmatrix(Vec3(30, float32(screen.area.value.h), 0))) 31 | push!(visualizations, labels) 32 | visualizations 33 | end 34 | function edit(style::Style, obj::RenderObject, customization::Dict{Symbol,Any}) 35 | edit(style, obj.uniforms, customization) 36 | end 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/visualize/particles.jl: -------------------------------------------------------------------------------- 1 | function Base.delete!(dict::Dict, key, default) 2 | haskey(dict, key) && return pop!(dict, key) 3 | return default 4 | end 5 | function visualize_default{T <: Point3}( 6 | particles::Union(Texture{T, 1}, Vector{T}), 7 | s::Style, kw_args=Dict() 8 | ) 9 | color = delete!(kw_args, :color, RGBA(1f0, 0f0, 0f0, 1f0)) 10 | color = texture_or_scalar(color) 11 | Dict( 12 | :primitive => GLNormalMesh(Cube(Vec3(0), Vec3(1))), 13 | :color => color, 14 | :scale => Vec3(0.03) 15 | ) 16 | end 17 | 18 | visualize{T}(value::Vector{Point3{T}}, s::Style, customizations=visualize_default(value, s)) = 19 | visualize(texture_buffer(value), s, customizations) 20 | 21 | function visualize{T}(signal::Signal{Vector{Point3{T}}}, s::Style, customizations=visualize_default(signal.value, s)) 22 | tex = texture_buffer(signal.value) 23 | lift(update!, tex, signal) 24 | visualize(tex, s, customizations) 25 | end 26 | function visualize{T}( 27 | positions::Texture{Point3{T}, 1}, 28 | s::Style, customizations=visualize_default(positions, s) 29 | ) 30 | @materialize! primitive = customizations 31 | data = merge(Dict( 32 | :positions => positions, 33 | ), collect_for_gl(primitive), customizations) 34 | 35 | program = TemplateProgram( 36 | File(shaderdir, "util.vert"), 37 | File(shaderdir, "particles.vert"), 38 | File(shaderdir, "standard.frag"), 39 | attributes=data 40 | ) 41 | instanced_renderobject(data, length(positions), program, Input(AABB(gpu_data(positions)))) 42 | end 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/shader/colorchooser.frag: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | 3 | vec3 hsv2rgb(vec3 c) 4 | { 5 | vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); 6 | vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); 7 | return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); 8 | } 9 | 10 | vec3 rgb2hsv(vec3 c) 11 | { 12 | vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); 13 | vec4 p = c.g < c.b ? vec4(c.bg, K.wz) : vec4(c.gb, K.xy); 14 | vec4 q = c.r < p.x ? vec4(p.xyw, c.r) : vec4(c.r, p.yzx); 15 | float d = q.x - min(q.w, q.y); 16 | float e = 1.0e-10; 17 | return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); 18 | } 19 | 20 | 21 | in vec2 frag_uv; 22 | flat in uvec2 fragment_id; 23 | 24 | uniform vec4 color; 25 | 26 | 27 | out uvec2 fragment_groupid; 28 | out vec4 fragment_color; 29 | 30 | float aastep(float threshold1, float threshold2,float value) { 31 | float afwidth = length(vec2(dFdx(value), dFdy(value))) * 0.70710678118654757; 32 | return smoothstep(threshold1-afwidth, threshold1+afwidth, value)-smoothstep(threshold2-afwidth, threshold2+afwidth, value); 33 | } 34 | vec4 radial_grad(float len, vec4 a, vec4 b) { 35 | return mix(a, b, len); 36 | } 37 | 38 | 39 | void main(){ 40 | float len = frag_uv.y; 41 | float dist_aa = aastep(0.95, 0.99, len)+ aastep(0.95, 0.99, frag_uv.x); 42 | dist_aa += aastep(0.01, 0.05, len)+ aastep(0.01, 0.05, frag_uv.x); 43 | dist_aa -= aastep(0.00, 0.01, len)+ aastep(0.00, 0.01, frag_uv.x); 44 | dist_aa -= aastep(0.99, 1.0, len)+ aastep(0.99, 1.0, frag_uv.x); 45 | vec4 radial = radial_grad(length(frag_uv-0.5), color, vec4(0,0,1,1)); 46 | fragment_color = mix(vec4(0,0,0,0), radial, dist_aa); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/GLVisualize.jl: -------------------------------------------------------------------------------- 1 | module GLVisualize 2 | 3 | using GLFW 4 | using GLWindow 5 | using GLAbstraction 6 | using ModernGL 7 | using FixedSizeArrays 8 | using GeometryTypes 9 | using ColorTypes 10 | using Reactive 11 | using Quaternions 12 | using Compat 13 | using FixedPointNumbers 14 | using ImageIO 15 | using FileIO 16 | using MeshIO 17 | using Meshes 18 | using AbstractGPUArray 19 | using Packing 20 | using FreeTypeAbstraction 21 | using VideoIO 22 | 23 | FreeTypeAbstraction.init() 24 | 25 | import Base: merge, convert, show 26 | 27 | 28 | 29 | include("meshutil.jl") 30 | 31 | const sourcedir = Pkg.dir("GLVisualize", "src") 32 | const shaderdir = joinpath(sourcedir, "shader") 33 | 34 | 35 | include(joinpath( sourcedir, "utils.jl")) 36 | include(joinpath( sourcedir, "boundingbox.jl")) 37 | export loop 38 | export bounce 39 | 40 | include(joinpath( sourcedir, "types.jl")) 41 | include_all(joinpath( sourcedir, "display")) 42 | 43 | 44 | include(joinpath( sourcedir, "visualize_interface.jl")) 45 | export view 46 | export visualize # Visualize an object 47 | export visualize_default # get the default parameter for a visualization 48 | 49 | include(joinpath("texture_atlas", "texture_atlas.jl")) 50 | export Sprite 51 | export GLSprite 52 | export SpriteStyle 53 | export GLSpriteStyle 54 | 55 | include(joinpath( sourcedir, "color.jl")) 56 | include_all(joinpath( sourcedir, "share")) 57 | include_all(joinpath( sourcedir, "edit")) 58 | include_all(joinpath( sourcedir, "visualize")) 59 | include(joinpath( sourcedir, "visualize", "text", "utils.jl")) 60 | 61 | include(joinpath( sourcedir, "edit_interface.jl")) 62 | 63 | export renderloop # starts the renderloop 64 | export vizzedit # Edit an object 65 | 66 | 67 | end # module 68 | -------------------------------------------------------------------------------- /src/visualize/text/text_test.jl: -------------------------------------------------------------------------------- 1 | using Cairo, GeometryTypes, FixedSizeArrays, GLAbstraction, ModernGL, GLVisualize, ColorTypes, FixedPointNumbers, Compat, MeshIO, Meshes 2 | using FileIO 3 | include("cairo_text.jl") 4 | include("rectangle_packing.jl") 5 | include("texture_atlas.jl") 6 | 7 | 8 | # This is the low-level text interface, which simply prepares the correct shader and cameras 9 | function GLVisualize.visualize(glyphs::Texture{GLGlyph, 2}, positions::Texture{Point2{Float16},2}, atlas::TextureAtlas=TEXTURE_ATLAS)#, ::Style{:default}, customization::Dict{Symbol, Any}) 10 | screen = GLVisualize.ROOT_SCREEN 11 | camera = screen.orthographiccam 12 | data = merge(@compat(Dict( 13 | :positions => positions, 14 | :glyphs => glyphs, 15 | :projectionviewmodel => camera.projectionview, 16 | :uvs => atlas.attributes, 17 | :images => atlas.images, 18 | :styles => Texture([RGBAU8(0,0,0,1)]), 19 | )), collect_for_gl(GLMesh2D(Rectangle(0f0,0f0,1f0,1f0)))) 20 | shader = TemplateProgram(File(GLVisualize.shaderdir, "util.vert"), File(GLVisualize.shaderdir, "text.vert"), File(GLVisualize.shaderdir, "text.frag")) 21 | 22 | instanced_renderobject(data, length(glyphs), shader) 23 | end 24 | 25 | 26 | 27 | letters = "abcdefghijklmnobqrstuvwxyz" 28 | lettersuc = uppercase(letters) 29 | numbers = join(0:9) 30 | glyphs = join([letters, lettersuc, numbers]) 31 | glyphs = map_fonts(glyphs) 32 | 33 | glyphs = Texture(reshape(map(x->GLGlyph(x, 0), glyphs), (62, 1))) 34 | positions = Texture(reshape(Point2{Float16}[Point2{Float16}(i*100,100) for i=1:length(glyphs)], (62, 1))) 35 | 36 | robj3 = visualize(glyphs, positions) 37 | push!(GLVisualize.ROOT_SCREEN.renderlist, robj3) 38 | glClearColor(1,1,1,1) 39 | renderloop() 40 | 41 | -------------------------------------------------------------------------------- /src/shader/text.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | {{GLSL_EXTENSIONS}} 3 | 4 | in vec2 vertices; 5 | in vec2 texturecoordinates; 6 | 7 | uniform usamplerBuffer glyphs; 8 | uniform samplerBuffer positions; 9 | uniform usamplerBuffer style_index; 10 | 11 | uniform samplerBuffer uvs; 12 | uniform sampler1D styles; 13 | 14 | uniform int technique; 15 | uniform uint objectid; 16 | 17 | uniform mat4 projectionview, model; 18 | 19 | out vec2 o_uv; 20 | out vec4 o_color; 21 | 22 | flat out int o_technique; 23 | flat out int o_style; 24 | flat out uvec2 o_id; 25 | 26 | const int SPRITE = 1; 27 | const int CIRCLE = 2; 28 | const int SQUARE = 3; 29 | 30 | void main(){ 31 | vec2 glyph_scale, bearing; 32 | int index = gl_InstanceID; 33 | int glyph = int(texelFetch(glyphs, index).x); 34 | vec4 attributes2 = texelFetch(uvs, glyph+1); 35 | 36 | if(technique == SPRITE){ 37 | vec4 uv_dims = texelFetch(uvs, glyph); 38 | bearing = attributes2.xy; 39 | glyph_scale = uv_dims.zw; 40 | //flip uv and resize it to the correct size (for lookup in texture atlas) 41 | o_uv = (vec2(texturecoordinates.x, 1-texturecoordinates.y)*uv_dims.zw)+uv_dims.xy; 42 | }else{ // special casing for particles. 43 | bearing = vec2(0.0, -6.0); 44 | glyph_scale = attributes2.zw; //use advance instead of uv dimensions 45 | o_uv = texturecoordinates; //texture coordinates need to be unscaled 46 | } 47 | uvec2 style_i = texelFetch(style_index, index).xy; 48 | vec2 position = texelFetch(positions, index).xy; 49 | o_color = texelFetch(styles, int(style_i.x), 0); 50 | o_style = 5; 51 | o_id = uvec2(objectid, index+1); 52 | o_technique = technique; 53 | gl_Position = projectionview * model * vec4( 54 | position + bearing + (vertices*glyph_scale), 55 | 0, 1 56 | ); 57 | } -------------------------------------------------------------------------------- /test/test_text_functions.jl: -------------------------------------------------------------------------------- 1 | using AbstractGPUArray, GLAbstraction, GLWindow, GeometryTypes 2 | using Base.Test 3 | include(Pkg.dir("GLVisualize", "src", "visualize", "text", "utils.jl")) 4 | w = createwindow("test", 10,10, debugging=true) # dummy window for opengl context 5 | 6 | 7 | test_data = GPUVector(texture_buffer(map(Cint, collect("\nhallo_dolly jau whatup\ngragragagagag\n ima gangstaaa")))) 8 | @test next_newline(test_data, 1) == 1 9 | @test next_newline(test_data, 2) == 24 10 | @test test_data[24] == '\n' 11 | 12 | @test next_newline(test_data, 25) == 38 13 | @test test_data[38] == '\n' 14 | 15 | @test next_newline(test_data, 39) == 52 16 | @test length(test_data) == 52 17 | 18 | 19 | @test previous_newline(test_data, 1) == 1 20 | @test previous_newline(test_data, 2) == 1 21 | @test previous_newline(test_data, 27) == 24 22 | 23 | @test previous_newline(test_data, 40) == 38 24 | 25 | @test previous_newline(test_data, 52) == 38 26 | 27 | test_text_selection = TextWithSelection(test_data, 1:3) 28 | 29 | l = length(test_text_selection.text) 30 | inserttext(test_text_selection, Cint[77,77,77,77,77]) 31 | 32 | @test l+2 == length(test_text_selection.text) 33 | @test test_text_selection.text[1:5] == Cint[77,77,77,77,77] 34 | @test test_text_selection.selection == 6:4 35 | 36 | l = length(test_text_selection.text) 37 | inserttext(test_text_selection, Cint[99,99,99,99,99]) 38 | 39 | @test test_text_selection.selection == 11:10 40 | @test l+5 == length(test_text_selection.text) 41 | 42 | l = length(test_text_selection.text) 43 | test_text_selection.selection = 3:20 44 | inserttext(test_text_selection, Cint[42]) 45 | @test l-length(3:20)+1 == length(test_text_selection.text) 46 | @test test_text_selection.selection == 4:3 47 | 48 | 49 | l = length(test_text_selection.text) 50 | deletetext(test_text_selection) 51 | 52 | @test test_text_selection.selection == 3:2 53 | @test test_text_selection.text[3] != 42 54 | @test l-1 == length(test_text_selection.text) -------------------------------------------------------------------------------- /src/visualize/vectorfield.jl: -------------------------------------------------------------------------------- 1 | visualize_default(::Union(Array{Vector3{Float32}, 3}, Texture{Vector3{Float32}, 3}), ::Style, kw_args) = @compat Dict( 2 | :primitive => GLNormalMesh(Pyramid(Point3{Float32}(0,0,-0.5), 1f0, 0.2f0)), 3 | :boundingbox => AABB(Vec3(-1), Vec3(1)), 4 | :norm => Vec2(-1,1), 5 | :color => RGBA{Ufixed8}[rgbaU8(1,0,0,1), rgbaU8(1,1,0,1), rgbaU8(0,1,0,1)] 6 | ) 7 | 8 | function visualize(vectorfield::Texture{Vector3{Float32}, 3}, s::Style, customizations=visualize_default(vectorfield, s)) 9 | @materialize! color, primitive, boundingbox = customizations 10 | data = merge(Dict( 11 | :vectorfield => vectorfield, 12 | :cube_min => boundingbox.min, 13 | :cube_max => boundingbox.max, 14 | :color => Texture(color), 15 | ), customizations, collect_for_gl(primitive)) 16 | # Depending on what the is, additional values have to be calculated 17 | program = TemplateProgram( 18 | File(shaderdir, "util.vert"), 19 | File(shaderdir, "vectorfield.vert"), 20 | File(shaderdir, "standard.frag"), 21 | ) 22 | instanced_renderobject(data, length(vectorfield), program, Input(boundingbox)) 23 | end 24 | 25 | let texture_parameters = [ 26 | (GL_TEXTURE_MIN_FILTER, GL_NEAREST), 27 | (GL_TEXTURE_MAG_FILTER, GL_NEAREST), 28 | (GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE), 29 | (GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE), 30 | (GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE), 31 | ] 32 | 33 | function visualize(vectorfield::Signal{Array{Vector3{Float32}, 3}}, s::Style, customizations=visualize_default(vectorfield, s)) 34 | tex = Texture(vectorfield.value, parameters=texture_parameters) 35 | lift(update!, tex, vectorfield) 36 | visualize(tex, s, customizations) 37 | end 38 | function visualize(vectorfield::Array{Vector3{Float32}, 3}, s::Style, customizations=visualize_default(vectorfield, s)) 39 | _norm = map(norm, vectorfield) 40 | customizations[:norm] = Vec2(minimum(_norm), maximum(_norm)) 41 | visualize(Texture(vectorfield, parameters=texture_parameters), s, customizations) 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /src/visualize/volume.jl: -------------------------------------------------------------------------------- 1 | visualize_default(::Union(Array{Float32, 3}, Texture{Float32, 3}), ::Style, kw_args...) = Dict( 2 | :hull => GLUVWMesh(Cube(Vec3(0), Vec3(1))), 3 | :light_position => Vec3(0.25, 1.0, 3.0), 4 | :color => RGBA(0.9f0, 0.0f0, 0.2f0, 1f0), 5 | :light_intensity => Vec3(15.0), 6 | :isovalue => 0.5f0, 7 | :absorption => 1f0, 8 | :algorithm => Cint(3), 9 | ) 10 | 11 | visualize_default(::Union(Array{Float32, 3}, Texture{Float32, 3}), ::Style{:mip}, kw_args...) = Dict( 12 | :hull => GLUVWMesh(Cube(Vec3(0), Vec3(1))), 13 | :light_position => Vec3(0.25, 1.0, 3.0), 14 | :light_intensity => Vec3(15.0), 15 | :algorithm => Cint(3), 16 | :color => RGBA(0.9f0, 0.0f0, 0.2f0, 1f0), 17 | ) 18 | visualize_default(::Union(Array{Float32, 3}, Texture{Float32, 3}), ::Style{:iso}, kw_args...) = Dict( 19 | :hull => GLUVWMesh(Cube(Vec3(0), Vec3(1))), 20 | :light_position => Vec3(0.25, 1.0, 3.0), 21 | :light_intensity => Vec3(15.0), 22 | :isovalue => 0.5f0, 23 | :algorithm => Cint(2), 24 | :color => RGBA(0.9f0, 0.0f0, 0.2f0, 1f0), 25 | ) 26 | visualize_default(::Union(Array{Float32, 3}, Texture{Float32, 3}), ::Style{:absorption}, kw_args...) = Dict( 27 | :hull => GLUVWMesh(Cube(Vec3(0), Vec3(1))), 28 | :light_position => Vec3(0.25, 1.0, 3.0), 29 | :light_intensity => Vec3(15.0), 30 | :absorption => 1f0, 31 | :algorithm => Cint(1), 32 | ) 33 | 34 | @visualize_gen Array{Float32, 3} Texture Style 35 | 36 | to_modelspace(x, model) = Vec3(inv(model)*Vec4(x...,1)) 37 | 38 | function visualize(intensities::Texture{Float32, 3}, s::Style, customizations=visualize_default(intensities, s)) 39 | @materialize! hull = customizations # pull out variables to avoid duplications 40 | customizations[:intensities] = intensities 41 | data = merge(customizations, collect_for_gl(hull)) 42 | shader = TemplateProgram(File(shaderdir, "volume.vert"), File(shaderdir, "volume.frag")) 43 | std_renderobject(data, shader, Input(AABB(hull.vertices))) 44 | end 45 | -------------------------------------------------------------------------------- /src/visualize_interface.jl: -------------------------------------------------------------------------------- 1 | const SHARED_DEFAULTS = @compat(Dict( 2 | :model => Input(eye(Mat4)), 3 | :light => Input(Vec3[Vec3(1.0,1.0,1.0), Vec3(0.1,0.1,0.1), Vec3(0.9,0.9,0.9), Vec4(20,20,20,1)]), 4 | :preferred_camera => :perspective 5 | )) 6 | 7 | visualize_default(value::Any, style::Style, kw_args=Dict{Symbol, Any}) = error("""There are no defaults for the type $(typeof(value)), 8 | which either means the implementation is incomplete or not implemented yet. 9 | Consider defining visualize_default(::$(typeof(value)), ::Style, parameters::Dict{Symbol, Any}) => Dict{Symbol, Any} and 10 | visualize(::$(typeof(value)), ::Style, parameters::Dict{Symbol, Any}) => RenderObject""") 11 | 12 | function visualize_default(value::Any, style::Symbol, kw_args::Vector{Any}, defaults=SHARED_DEFAULTS) 13 | parameters_dict = Dict{Symbol, Any}(kw_args) 14 | parameters_calculated = visualize_default(value, Style{style}(), parameters_dict) 15 | merge(defaults, parameters_calculated, parameters_dict) 16 | end 17 | 18 | visualize(value::Any, style::Symbol=:default; kw_args...) = visualize(value, Style{style}(), visualize_default(value, style, kw_args)) 19 | visualize(signal::Signal, style::Symbol=:default; kw_args...) = visualize(signal, Style{style}(), visualize_default(signal.value, style, kw_args)) 20 | visualize(file::File, style::Symbol=:default; kw_args...) = visualize(read(file), style; kw_args...) 21 | 22 | 23 | function view( 24 | robj::RenderObject, screen=ROOT_SCREEN; 25 | method = robj.uniforms[:preferred_camera], 26 | position = Vec3(2), lookat=Vec3(0) 27 | ) 28 | if method == :perspective 29 | camera = get!(screen.cameras, :perspective) do 30 | PerspectiveCamera(screen.inputs, position, lookat) 31 | end 32 | elseif method == :fixed_pixel 33 | camera = get!(screen.cameras, :fixed_pixel) do 34 | DummyCamera(window_size=screen.area) 35 | end 36 | elseif method == :orthographic_pixel 37 | camera = get!(screen.cameras, :orthographic_pixel) do 38 | OrthographicPixelCamera(screen.inputs) 39 | end 40 | else 41 | error("Method $method not a known camera type") 42 | end 43 | merge!(robj.uniforms, collect(camera)) 44 | push!(screen.renderlist, robj) 45 | end 46 | view(robjs::Vector{RenderObject}, screen=ROOT_SCREEN) = for robj in robjs 47 | view(robj, screen) 48 | end 49 | -------------------------------------------------------------------------------- /test/texture_buffer.jl: -------------------------------------------------------------------------------- 1 | using GLAbstraction, GeometryTypes, ModernGL, Compat, FileIO 2 | using GLFW # <- need GLFW for context initialization.. Hopefully replaced by some native initialization 3 | using Base.Test 4 | 5 | # initilization, with GLWindow this reduces to "createwindow("name", w,h)" 6 | GLFW.Init() 7 | GLFW.WindowHint(GLFW.SAMPLES, 4) 8 | 9 | GLFW.WindowHint(GLFW.CONTEXT_VERSION_MAJOR, 3) 10 | GLFW.WindowHint(GLFW.CONTEXT_VERSION_MINOR, 3) 11 | GLFW.WindowHint(GLFW.OPENGL_FORWARD_COMPAT, GL_TRUE) 12 | GLFW.WindowHint(GLFW.OPENGL_PROFILE, GLFW.OPENGL_CORE_PROFILE) 13 | 14 | window = GLFW.CreateWindow(512,512, "test") 15 | GLFW.MakeContextCurrent(window) 16 | GLFW.ShowWindow(window) 17 | 18 | init_glutils() 19 | 20 | 21 | # Test for creating a GLBuffer with a 1D Julia Array 22 | # You need to supply the cardinality, as it can't be inferred 23 | # indexbuffer is a shortcut for GLBuffer(GLUint[0,1,2,2,3,0], 1, buffertype = GL_ELEMENT_ARRAY_BUFFER) 24 | indexes = indexbuffer(GLuint[0,1,2]) 25 | # Test for creating a GLBuffer with a 1D Julia Array of Vectors 26 | #v = Vec2f[Vec2f(0.0, 0.5), Vec2f(0.5, -0.5), Vec2f(-0.5,-0.5)] 27 | 28 | v = Vector2{Float32}[Vector2{Float32}(0.0, 0.5), Vector2{Float32}(0.5, -0.5), Vector2{Float32}(-0.5,-0.5)] 29 | 30 | verts = GLBuffer(v) 31 | # lets define some uniforms 32 | # uniforms are shader variables, which are supposed to stay the same for an entire draw call 33 | 34 | const fragsh = frag""" 35 | {{GLSL_VERSION}} 36 | 37 | out vec4 frag_color; 38 | 39 | void main() { 40 | frag_color = vec4(1.0, 0, 0.0, 1.0); 41 | } 42 | """ 43 | const vertsh = vert""" 44 | {{GLSL_VERSION}} 45 | 46 | in vec2 vertex; 47 | 48 | uniform samplerBuffer test; 49 | 50 | void main() { 51 | gl_Position = vec4(vertex, texelFetch(test, 1).x, 1.0); 52 | } 53 | """ 54 | test = texture_buffer(rand(Float32, 7)) 55 | const triangle = RenderObject( 56 | Dict( 57 | :vertex => verts, 58 | :test => test, 59 | :name_doesnt_matter_for_indexes => indexes 60 | ), 61 | TemplateProgram(fragsh, vertsh)) 62 | 63 | postrender!(triangle, render, triangle.vertexarray) 64 | 65 | glClearColor(0,0,0,1) 66 | while !GLFW.WindowShouldClose(window) 67 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 68 | render(triangle) 69 | GLFW.SwapBuffers(window) 70 | GLFW.PollEvents() 71 | sleep(0.01) 72 | end 73 | 74 | 75 | 76 | GLFW.Terminate() 77 | 78 | 79 | -------------------------------------------------------------------------------- /src/shader/distance_shape.frag: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | 3 | in vec4 o_color; 4 | in vec2 o_uv; 5 | 6 | flat in int o_technique; 7 | flat in int o_style; 8 | flat in uvec2 o_id; 9 | 10 | 11 | uniform vec2 scale; 12 | uniform sampler2D images; 13 | uniform float thickness = 4.0; 14 | 15 | const int SPRITE = 1; 16 | const int CIRCLE = 2; 17 | const int SQUARE = 3; 18 | 19 | const int OUTLINED = 4; 20 | const int FILLED = 5; 21 | 22 | const float ALIASING_CONST = 0.70710678118654757; 23 | 24 | float aastep(float threshold1, float threshold2, float value) { 25 | float afwidth = length(vec2(dFdx(value), dFdy(value))) * ALIASING_CONST; 26 | return smoothstep(threshold1-afwidth, threshold1+afwidth, value)-smoothstep(threshold2-afwidth, threshold2+afwidth, value); 27 | } 28 | 29 | float aastep(float threshold1,float value) { 30 | float afwidth = length(vec2(dFdx(value), dFdy(value))) * ALIASING_CONST; 31 | return smoothstep(threshold1-afwidth, threshold1+afwidth, value); 32 | } 33 | vec4 radial_grad(float len, vec4 a, vec4 b) { 34 | return mix(a, b, len); 35 | } 36 | 37 | float circle(vec2 uv) 38 | { 39 | float len = 1-length(uv-0.5); 40 | if(o_style==FILLED) 41 | return aastep(0.5, len); 42 | if(o_style==OUTLINED) 43 | return aastep(0.5, 0.5-thickness, len); 44 | } 45 | float square(vec2 uv) 46 | { 47 | float edge = 0.0; 48 | if(o_style==FILLED) 49 | return (uv.x*0.0)+1; //silly way of using uv, which otherwise would be removed by the unused code elimination 50 | if(o_style==OUTLINED) 51 | { 52 | float xmin = aastep(0.0, 0.0+thickness/scale.x, uv.x); 53 | float xmax = aastep(1.0-thickness/scale.x, 1.0, uv.x); 54 | float ymin = aastep(0.0, 0.0+thickness/scale.y, uv.y); 55 | float ymax = aastep(1.0-thickness/scale.y, 1.0, uv.y); 56 | return xmin + 57 | xmax + 58 | ((1-xmin)*(1-xmax))*ymin + 59 | ((1-xmin)*(1-xmax))*ymax; 60 | } 61 | } 62 | 63 | out uvec2 fragment_groupid; 64 | out vec4 fragment_color; 65 | 66 | void main(){ 67 | float alpha = 0; 68 | if(o_technique == SPRITE) 69 | alpha = texelFetch(images, ivec2(o_uv), 0).r; 70 | if(o_technique == CIRCLE) 71 | alpha = circle(o_uv); 72 | if(o_technique == SQUARE) 73 | alpha = square(o_uv); 74 | alpha *= o_color.a; 75 | fragment_color = vec4(o_color.rgb, alpha); 76 | fragment_groupid = o_id; 77 | } 78 | -------------------------------------------------------------------------------- /src/shader/boundingbox/surface.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | {{GLSL_EXTENSIONS}} 3 | 4 | {{vertex_type}} vertex; 5 | {{normal_vector_type}} normal_vector; // normal might not be an uniform, whereas the other will be allways uniforms 6 | {{offset_type}} offset; //offset for texture look up. Needed to get neighbouring vertexes, when rendering the surface 7 | 8 | {{x_type}} x; 9 | {{y_type}} y; 10 | {{z_type}} z; 11 | 12 | {{xscale_type}} xscale; 13 | {{yscale_type}} yscale; 14 | {{zscale_type}} zscale; 15 | 16 | {{color_type}} color; 17 | 18 | uniform vec2 griddimensions; 19 | uniform mat3 normalmatrix; 20 | uniform mat4 projection, view, model; 21 | uniform bool interpolate; 22 | 23 | 24 | {{out}} vec3 V; 25 | 26 | /** 27 | Function that fetches a float value, depending on what type is given 28 | */ 29 | float fetch1stvalue(ivec2 position, sampler2D tex) 30 | { 31 | return texelFetch(tex, position, 0).x; 32 | } 33 | float fetch1stvalue(int index, vec2 range) 34 | { 35 | float from = range.x; 36 | float to = range.y; 37 | return from + (float(index)/griddimensions.x) * (to - from); 38 | } 39 | float fetch1stvalue(int index, float value) 40 | { 41 | return value; 42 | } 43 | 44 | float fetch1stvalue(vec2 position, sampler2D tex) 45 | { 46 | return texture(tex, position).x; 47 | } 48 | float fetch1stvalue(vec2 index, float value) 49 | { 50 | return value; 51 | } 52 | float fetch1stvalue(float position, vec2 range) 53 | { 54 | float from = range.x; 55 | float to = range.y; 56 | return from + position * (to - from); 57 | } 58 | 59 | 60 | mat4 getmodelmatrix(vec3 xyz, vec3 scale) 61 | { 62 | return mat4( 63 | vec4(scale.x, 0, 0, 0), 64 | vec4(0, scale.y, 0, 0), 65 | vec4(0, 0, scale.z, 0), 66 | vec4(xyz, 1)); 67 | } 68 | 69 | void main(){ 70 | vec3 xyz, scale, normal, vert; 71 | int index = gl_InstanceID; 72 | ivec2 ij = ivec2(index / int(griddimensions.x), index % int(griddimensions.x)); 73 | vec2 uv = (vec2(ij)+offset) / griddimensions; 74 | 75 | xyz.x = fetch1stvalue(uv.x, x); 76 | xyz.y = fetch1stvalue(uv.y, y); 77 | xyz.z = fetch1stvalue(ij, z); 78 | 79 | scale.x = fetch1stvalue(ij, xscale); 80 | scale.y = fetch1stvalue(ij, yscale); 81 | scale.z = fetch1stvalue(ij, zscale); 82 | 83 | vert = {{vertex_calculation}} 84 | V = xyz; 85 | gl_Position = vec4(0,0,0,1); 86 | } 87 | -------------------------------------------------------------------------------- /src/shader/surface2.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | {{GLSL_EXTENSIONS}} 3 | in vec2 vertices; 4 | 5 | uniform vec3 light[4]; 6 | uniform sampler1D color; 7 | uniform vec2 color_norm; 8 | 9 | uniform sampler2D x; 10 | uniform sampler2D y; 11 | uniform sampler2D z; 12 | 13 | 14 | uniform vec2 grid_min; 15 | uniform vec2 grid_max; 16 | 17 | uniform vec3 scale; 18 | 19 | uniform mat4 view, model, projection; 20 | 21 | void render(vec3 vertices, vec3 normal, vec4 color, mat4 viewmodel, mat4 projection, vec3 light[4]); 22 | ivec2 ind2sub(ivec2 dim, int linearindex); 23 | vec2 linear_index(ivec2 dims, int index, vec2 offset); 24 | vec4 linear_texture(sampler2D tex, int index, vec2 offset); 25 | vec4 color_lookup(float intensity, sampler1D color_ramp, vec2 norm); 26 | 27 | 28 | bool isinbounds(vec2 uv) 29 | { 30 | return (uv.x <= 1.0 && uv.y <= 1.0 && uv.x >= 0.0 && uv.y >= 0.0); 31 | } 32 | vec3 getnormal(sampler2D zvalues, vec2 uv) 33 | { 34 | float weps = 1.0/textureSize(zvalues,0).x; 35 | float heps = 1.0/textureSize(zvalues,0).y; 36 | 37 | vec3 result = vec3(0); 38 | 39 | vec3 s0 = vec3(uv, texture(zvalues, uv).x); 40 | 41 | vec2 off1 = uv + vec2(-weps,0); 42 | vec2 off2 = uv + vec2(0, heps); 43 | vec2 off3 = uv + vec2(weps, 0); 44 | vec2 off4 = uv + vec2(0,-heps); 45 | vec3 s1, s2, s3, s4; 46 | 47 | s1 = vec3((off1), texture(zvalues, off1).x); 48 | s2 = vec3((off2), texture(zvalues, off2).x); 49 | s3 = vec3((off3), texture(zvalues, off3).x); 50 | s4 = vec3((off4), texture(zvalues, off4).x); 51 | 52 | if(isinbounds(off1) && isinbounds(off2)) 53 | { 54 | result += cross(s2-s0, s1-s0); 55 | } 56 | if(isinbounds(off2) && isinbounds(off3)) 57 | { 58 | result += cross(s3-s0, s2-s0); 59 | } 60 | if(isinbounds(off3) && isinbounds(off4)) 61 | { 62 | result += cross(s4-s0, s3-s0); 63 | } 64 | if(isinbounds(off4) && isinbounds(off1)) 65 | { 66 | result += cross(s1-s0, s4-s0); 67 | } 68 | 69 | return normalize(result); // normal should be zero, but needs to be here, because the dead-code elimanation of GLSL is overly enthusiastic 70 | } 71 | 72 | uniform uint objectid; 73 | flat out uvec2 o_id; 74 | 75 | void main() 76 | { 77 | ivec2 dims = textureSize(z, 0); 78 | vec3 pos; 79 | pos.x = linear_texture(x, gl_InstanceID, vertices).x; 80 | pos.y = linear_texture(y, gl_InstanceID, vertices).x; 81 | pos.z = linear_texture(z, gl_InstanceID, vertices).x; 82 | //pos += vec3(vertices*scale.xy, 0.0); 83 | vec4 instance_color = color_lookup(pos.z, color, color_norm); 84 | vec3 normalvec = getnormal(z, linear_index(dims, gl_InstanceID, vertices)); 85 | render(pos, normalvec, instance_color, view * model, projection, light); 86 | o_id = uvec2(objectid, gl_InstanceID); 87 | } 88 | 89 | 90 | -------------------------------------------------------------------------------- /src/edit/numbers.jl: -------------------------------------------------------------------------------- 1 | 2 | drag_x(drag_id) = drag_id[1][1] 3 | 4 | printforslider(io::IOBuffer, x::FloatingPoint, numberwidth::Int=5) = print(io, @sprintf("%0.5f", x)[1:numberwidth]) 5 | printforslider(io::IOBuffer, x::Integer, numberwidth::Int=5) = print(io, @sprintf("%5d", x)[1:numberwidth]) 6 | printforslider(x::Integer, numberwidth::Int=5) = @sprintf("%5d", x)[1:numberwidth] 7 | printforslider(x::FloatingPoint, numberwidth::Int=5) = @sprintf("%0.5f", x)[1:numberwidth] 8 | function printforslider(x::FixedVector, numberwidth=5) 9 | io = IOBuffer() 10 | for elem in x 11 | printforslider(io, elem, numberwidth) 12 | print(io, " ") 13 | end 14 | takebuf_string(io) 15 | end 16 | num2glstring(x, numberwidth) = GLVisualize.process_for_gl(printforslider(x, numberwidth)) 17 | 18 | FixedSizeArrays.unit{T <: Real}(::Type{T}, _) = one(T) 19 | 20 | 21 | function add_mouse_drags(t0, mouse_down1, mouseposition1, objectid, id_tolookfor, glyph_width) 22 | accum, mouse_down0, draggstart, idstart, v0, index0 = t0 23 | VT = typeof(v0) 24 | if (!mouse_down0 && mouse_down1) && (objectid[1] == id_tolookfor) #drag starts 25 | return (accum, mouse_down1, mouseposition1, id_tolookfor, accum, objectid[2]) # reset values 26 | elseif (mouse_down0 && mouse_down1) && (idstart == id_tolookfor) 27 | diff = eltype(VT)(Vec2(mouseposition1-draggstart)[1]) 28 | # lets act as if the text glyph array is 2d, with numberwidth as width, and height is the amount of numbers 29 | zero_indexed = index0-1 #linear index from glyph array 30 | number_glyph_group = div(zero_indexed, glyph_width) # 31 | i = number_glyph_group+1#to 1 based index 32 | return (v0 + (unit(VT, i)*diff), mouse_down1, draggstart, id_tolookfor, v0, index0) 33 | end 34 | (accum, mouse_down1, Vec2(0), 0, accum, 0) 35 | end 36 | 37 | function vizzedit{T <: Union(FixedVector, Real)}(x::T, inputs, numberwidth=5) 38 | vizz = visualize(printforslider(x, numberwidth)) 39 | mbutton_clicked = inputs[:mousebuttonspressed] 40 | 41 | mousedown = lift(isnotempty, mbutton_clicked) 42 | mouse_add_drag_id = foldl( 43 | add_mouse_drags, 44 | (zero(T), false, Vec2(0), 0, zero(T), 0), 45 | mousedown, inputs[:mouseposition], inputs[:mouse_hover], Input(Int(vizz.id)), Input(numberwidth+1) #plus space 46 | ) 47 | addition_vec = lift(first, mouse_add_drag_id) 48 | ET = eltype(T) 49 | if ET <: FloatingPoint 50 | new_num = lift(+, x, lift(/, addition_vec, ET(500))) 51 | else 52 | new_num = lift(+, x, lift(div, addition_vec, ET(10))) 53 | end 54 | 55 | new_num_gl = lift(num2glstring, new_num, numberwidth) 56 | lift(update!, vizz[:glyphs], new_num_gl) 57 | return new_num, vizz 58 | end 59 | -------------------------------------------------------------------------------- /src/shader/surface.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | {{GLSL_EXTENSIONS}} 3 | struct Rectangle 4 | { 5 | vec2 origin; 6 | vec2 width; 7 | }; 8 | 9 | in vec2 vertices; 10 | 11 | uniform vec3 light[4]; 12 | uniform sampler1D color; 13 | uniform vec2 color_norm; 14 | 15 | uniform sampler2D z; 16 | uniform sampler2D normal; 17 | 18 | uniform vec2 grid_min; 19 | uniform vec2 grid_max; 20 | 21 | uniform vec3 scale; 22 | 23 | uniform mat4 view, model, projection; 24 | 25 | void render(vec3 vertices, vec3 normal, vec4 color, mat4 viewmodel, mat4 projection, vec3 light[4]); 26 | ivec2 ind2sub(ivec2 dim, int linearindex); 27 | vec2 linear_index(ivec2 dims, int index, vec2 offset); 28 | vec3 position(Rectangle rectangle, ivec2 dims, int index); 29 | vec4 linear_texture(sampler2D tex, int index, vec2 offset); 30 | vec4 color_lookup(float intensity, sampler1D color, vec2 norm); 31 | 32 | 33 | bool isinbounds(vec2 uv) 34 | { 35 | return (uv.x <= 1.0 && uv.y <= 1.0 && uv.x >= 0.0 && uv.y >= 0.0); 36 | } 37 | vec3 getnormal(sampler2D zvalues, vec2 uv) 38 | { 39 | float weps = 1.0/textureSize(zvalues,0).x; 40 | float heps = 1.0/textureSize(zvalues,0).y; 41 | 42 | vec3 result = vec3(0); 43 | 44 | vec3 s0 = vec3(uv, texture(zvalues, uv).x); 45 | 46 | vec2 off1 = uv + vec2(-weps,0); 47 | vec2 off2 = uv + vec2(0, heps); 48 | vec2 off3 = uv + vec2(weps, 0); 49 | vec2 off4 = uv + vec2(0,-heps); 50 | vec3 s1, s2, s3, s4; 51 | 52 | s1 = vec3((off1), texture(zvalues, off1).x); 53 | s2 = vec3((off2), texture(zvalues, off2).x); 54 | s3 = vec3((off3), texture(zvalues, off3).x); 55 | s4 = vec3((off4), texture(zvalues, off4).x); 56 | 57 | if(isinbounds(off1) && isinbounds(off2)) 58 | { 59 | result += cross(s2-s0, s1-s0); 60 | } 61 | if(isinbounds(off2) && isinbounds(off3)) 62 | { 63 | result += cross(s3-s0, s2-s0); 64 | } 65 | if(isinbounds(off3) && isinbounds(off4)) 66 | { 67 | result += cross(s4-s0, s3-s0); 68 | } 69 | if(isinbounds(off4) && isinbounds(off1)) 70 | { 71 | result += cross(s1-s0, s4-s0); 72 | } 73 | 74 | return normalize(result); // normal should be zero, but needs to be here, because the dead-code elimanation of GLSL is overly enthusiastic 75 | } 76 | 77 | uniform uint objectid; 78 | flat out uvec2 o_id; 79 | 80 | void main() 81 | { 82 | ivec2 dims = textureSize(z, 0); 83 | vec3 pos = position(Rectangle(grid_min, grid_max), dims, gl_InstanceID); 84 | float intensity = linear_texture(z, gl_InstanceID, vertices).x; 85 | pos += vec3(vertices*scale.xy, scale.z*intensity); 86 | o_id = uvec2(objectid, gl_InstanceID); 87 | vec4 instance_color = color_lookup(intensity, color, color_norm); 88 | vec3 normalvec = getnormal(z, linear_index(dims, gl_InstanceID, vertices)); 89 | render(pos, normalvec, instance_color, view * model, projection, light); 90 | } 91 | 92 | 93 | -------------------------------------------------------------------------------- /test/test_romeo.jl: -------------------------------------------------------------------------------- 1 | using GLVisualize, GLFW, GLAbstraction, Reactive, ModernGL, GLWindow, Color 2 | 3 | 4 | # From behaviour, we understand that loading GLFW opens the window 5 | 6 | function clear!(x::Vector{RenderObject}) 7 | while !isempty(x) 8 | value = pop!(x) 9 | delete!(value) 10 | end 11 | end 12 | 13 | 14 | function dropequal(a::Signal) 15 | is_equal = foldl((false, a.value), a) do v0, v1 16 | (v0[2] == v1, v1) 17 | end 18 | dropwhen(lift(first, is_equal), a.value, a) 19 | end 20 | 21 | function eval_visualize(source::AbstractString, _, visualize_screen, edit_screen) 22 | expr = parse(strip(source), raise=false) 23 | val = "not found" 24 | try 25 | val = eval(Main, expr) 26 | catch e 27 | return nothing 28 | end 29 | if applicable(visualize, val) 30 | clear!(visualize_screen.renderlist) 31 | clear!(edit_screen.renderlist) 32 | obj = visualize(val, screen=visualize_screen) 33 | 34 | push!(visualize_screen.renderlist, obj) 35 | end 36 | nothing 37 | end 38 | 39 | function init_romeo() 40 | sourcecode_area = lift(GLVisualize.ROOT_SCREEN.area) do x 41 | Rectangle(0, 0, div(x.w, 7)*3, x.h) 42 | end 43 | visualize_area = lift(GLVisualize.ROOT_SCREEN.area) do x 44 | Rectangle(div(x.w,7)*3, 0, div(x.w, 7)*3, x.h) 45 | end 46 | search_area = lift(visualize_area) do x 47 | Rectangle(x.x, x.y, x.w, div(x.h,10)) 48 | end 49 | edit_area = lift(GLVisualize.ROOT_SCREEN.area) do x 50 | Rectangle(div(x.w, 7)*6, 0, div(x.w, 7), x.h) 51 | end 52 | 53 | 54 | sourcecode_screen = Screen(GLVisualize.ROOT_SCREEN, area=sourcecode_area) 55 | visualize_screen = Screen(GLVisualize.ROOT_SCREEN, area=visualize_area) 56 | search_screen = Screen(visualize_screen, area=search_area) 57 | edit_screen = Screen(GLVisualize.ROOT_SCREEN, area=edit_area) 58 | 59 | w_height = lift(GLVisualize.ROOT_SCREEN.area) do x 60 | x.h 61 | end 62 | source_offset = lift(w_height) do x 63 | translationmatrix(Vec3(30,x-30,0)) 64 | end 65 | w_height_search = lift(search_screen.area) do x 66 | x.h 67 | end 68 | search_offset = lift(w_height_search) do x 69 | translationmatrix(Vec3(30,x-30,0)) 70 | end 71 | 72 | #const sourcecode = visualize("barplot = Float32[(sin(i/10f0) + cos(j/2f0))/4f0 \n for i=1:10, j=1:10]\n", model=source_offset, screen=sourcecode_screen) 73 | barplot = visualize(Float32[(sin(i/10f0) + cos(j/2f0))/4f0 + 1f0 for i=1:10, j=1:10], screen=visualize_screen) 74 | #search = visualize("barplot\n", model=search_offset, color=rgba(0.9,0,0.2,1), screen=search_screen) 75 | 76 | push!(visualize_screen.renderlist, barplot) 77 | glClearColor(0,0,0,0) 78 | end 79 | 80 | init_romeo() 81 | 82 | renderloop() 83 | 84 | -------------------------------------------------------------------------------- /src/visualize/color_chooser.jl: -------------------------------------------------------------------------------- 1 | #= 2 | COLOR_QUAD = genquad(Vec3(0, 0, 0), Vec3(1, 0, 0), Vec3(0, 1, 0)) 3 | 4 | #GLPlot.toopengl{T <: AbstractRGB}(colorinput::Input{T}) = toopengl(lift(x->AlphaColorValue(x, one(T)), RGBA{T}, colorinput)) 5 | 6 | function visualize{X <: AlphaColor}(style::Style, color::X, data) 7 | 8 | screen = data[:screen] 9 | camera = screen.orthographiccam 10 | 11 | rdata = merge(@compat(Dict( 12 | :vertex => GLBuffer(COLOR_QUAD[1]), 13 | :uv => GLBuffer(COLOR_QUAD[2]), 14 | :index => indexbuffer(COLOR_QUAD[4]), 15 | )), data) 16 | 17 | rdata[:view] = camera.view 18 | rdata[:projection] = camera.projection 19 | rdata[:color] = color 20 | 21 | obj = RenderObject(rdata, color_chooser_shader, color_chooser_boundingbox) 22 | 23 | prerender!(obj, glEnable, GL_DEPTH_TEST, glDepthFunc, GL_LESS, glDisable, GL_CULL_FACE, enabletransparency)# 24 | postrender!(obj, render, obj.vertexarray) # Render the vertexarray 25 | 26 | # hover is true, if mouse 27 | hover = lift(SELECTION[:mouse_hover]) do selection 28 | selection[1][1] == obj.id 29 | end 30 | 31 | 32 | all_signals = foldl((tohsva(color), false, false, Vec2(0)), SELECTION[:mouse_hover]) do v0, selection 33 | 34 | hsv, hue_sat0, bright_trans0, mouse0 = v0 35 | mouse = screen.inputs[:mouseposition].value 36 | mouse_clicked = screen.inputs[:mousebuttonspressed].value 37 | 38 | hue_sat = in(0, mouse_clicked) && selection[1][1] == obj.id 39 | bright_trans = in(1, mouse_clicked) && selection[1][1] == obj.id 40 | 41 | 42 | if hue_sat && hue_sat0 43 | diff = mouse - mouse0 44 | hue = mod(hsv.c.h + diff[1], 360) 45 | sat = max(min(hsv.c.s + (diff[2] / 30.0), 1.0), 0.0) 46 | 47 | return (tohsva(hue, sat, hsv.c.v, hsv.alpha), hue_sat, bright_trans, mouse) 48 | elseif hue_sat && !hue_sat0 49 | return (hsv, hue_sat, bright_trans, mouse) 50 | end 51 | 52 | if bright_trans && bright_trans0 53 | diff = mouse - mouse0 54 | brightness = max(min(hsv.c.v - (diff[2]/100.0), 1.0), 0.0) 55 | alpha = max(min(hsv.alpha + (diff[1]/100.0), 1.0), 0.0) 56 | 57 | return (tohsva(hsv.c.h, hsv.c.s, brightness, alpha), hue_sat0, bright_trans, mouse) 58 | elseif bright_trans && !bright_trans0 59 | return (hsv, hue_sat0, bright_trans, mouse) 60 | end 61 | 62 | return (hsv, hue_sat, bright_trans, mouse) 63 | end 64 | color1 = lift(x -> torgba(x[1]), all_signals) 65 | color1 = lift(x -> Vec4(x.c.r, x.c.g, x.c.b, x.alpha), Vec4, color1) 66 | hue_saturation = lift(x -> x[2], all_signals) 67 | brightness_transparency = lift(x -> x[3], all_signals) 68 | 69 | 70 | obj.uniforms[:color] = color1 71 | obj.uniforms[:hover] = hover 72 | obj.uniforms[:hue_saturation] = hue_saturation 73 | obj.uniforms[:brightness_transparency] = brightness_transparency 74 | 75 | return obj, color1 76 | end 77 | 78 | function color_chooser_boundingbox(obj) 79 | middle = obj[:middle] 80 | swatchsize = obj[:swatchsize] 81 | border_size = obj[:border_size] 82 | model = obj[:model] 83 | verts = COLOR_QUAD[1] 84 | minv = Vec3(model*Vec4(minimum(verts)...,0f0)) 85 | maxv = Vec3(model*Vec4(maximum(verts)...,0f0)) 86 | AABB(minv,maxv) 87 | end 88 | =# -------------------------------------------------------------------------------- /test/nbody.jl: -------------------------------------------------------------------------------- 1 | using ODE 2 | using GLVisualize, AbstractGPUArray, GLAbstraction, MeshIO, GeometryTypes, Reactive, ColorTypes 3 | 4 | function F(t,y) 5 | 6 | #Number of Planets (note we're solving the n-body problem, rather than just a 3-body problem) 7 | n = int(length(y)/6) 8 | 9 | #Extract current position and velocity 10 | r = zeros(n,3) 11 | v = zeros(n,3) 12 | for i=1:n 13 | r[i,:] = y[(i-1)*6+1:(i-1)*6+3] 14 | v[i,:] = y[(i-1)*6+4:(i-1)*6+6] 15 | end 16 | 17 | #Calculate spatial derivatives 18 | drdt = v 19 | 20 | #Work out velocity derivatives (ie accelerations) 21 | dvdt = zeros(n,3) 22 | for i = 1:n 23 | for j = 1:n 24 | if i != j 25 | dvdt[i,:] += -G*m[j]*(r[i,:]-r[j,:])/(norm(r[i,:]-r[j,:])^3) 26 | end 27 | end 28 | end 29 | 30 | #Combine back together into dydt vector 31 | dydt = zeros(6*n) 32 | for i = 1:n 33 | dydt[6(i-1)+1] = drdt[i,1] 34 | dydt[6(i-1)+2] = drdt[i,2] 35 | dydt[6(i-1)+3] = drdt[i,3] 36 | dydt[6(i-1)+4] = dvdt[i,1] 37 | dydt[6(i-1)+5] = dvdt[i,2] 38 | dydt[6(i-1)+6] = dvdt[i,3] 39 | end 40 | return dydt 41 | end 42 | 43 | 44 | m = [5,4,3,5] 45 | n = length(m) 46 | 47 | #Set the gravitational field strength 48 | G = 1 49 | 50 | #Set initial positions and velocities 51 | r0 = zeros(n,3) 52 | r0[1,:] = [1.0,-1.0,1.0] 53 | r0[2,:] = [1,3,0.0] 54 | r0[3,:] = [-1,-2,0.0] 55 | r0[4,:] = [0,0,0.0] 56 | 57 | v0 = zeros(n,3) 58 | 59 | #Define y0 60 | y0 = zeros(6*n) 61 | for i = 1:n 62 | y0[6(i-1)+1] = r0[i,1] 63 | y0[6(i-1)+2] = r0[i,2] 64 | y0[6(i-1)+3] = r0[i,3] 65 | y0[6(i-1)+4] = v0[i,1] 66 | y0[6(i-1)+5] = v0[i,2] 67 | y0[6(i-1)+6] = v0[i,3] 68 | end 69 | 70 | #Solve the system 71 | tf = 50 72 | stepsPerUnitTime = 500 73 | tspan = linspace(0,tf,tf*stepsPerUnitTime) 74 | t,y = ode23s(F, y0, tspan; points=:specified); 75 | 76 | #Extract the data into a useful form 77 | ymat= hcat(y...) 78 | rcoords = sort([[6(i-1)+1 for i = 1:n],[6(i-1)+2 for i = 1:n],[6(i-1)+3 for i = 1:n]]) 79 | rcoords = convert(Array{Int64,1}, rcoords) 80 | const r = map(Float32, ymat[rcoords,:]) 81 | 82 | const planets = hcat([reinterpret(Point3{Float32}, r[3(i-1)+1:3(i-1)+3,:], (size(r, 2),)) for i=1:n]...); 83 | 84 | function send_frame(i, planets) 85 | p = planets[i, 1:4] 86 | reshape(p, (2,2)) 87 | end 88 | 89 | const time_i = Input(1) 90 | println(size(planets[:, 1])) 91 | const positions = lift(send_frame, time_i, Input(planets)) 92 | const robj = visualize(positions, model=scalematrix(Vec3(0.1f0))) 93 | len = length(planets[:, 1]) 94 | const planet_lines = [visualize(reshape(planets[:, i], (250, 100)), particle_color=RGBA(rand(Float32,3)..., 0.4f0), model=scalematrix(Vec3(0.01f0))) for i=1:4] 95 | 96 | push!(GLVisualize.ROOT_SCREEN.renderlist, robj) 97 | append!(GLVisualize.ROOT_SCREEN.renderlist, planet_lines) 98 | 99 | 100 | @async renderloop() 101 | # you can also "manually" push into the signal. For that the renderloop has to be started asynchronous 102 | # while the loop that updates the signal is the blocking one 103 | while GLVisualize.ROOT_SCREEN.inputs[:open].value 104 | yield() 105 | push!(time_i, mod1(time_i.value+1, size(planets,1))) 106 | end 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /src/visualize/surface.jl: -------------------------------------------------------------------------------- 1 | Base.minimum(t::Texture) = minimum(gpu_data(t)) 2 | Base.maximum(t::Texture) = maximum(gpu_data(t)) 3 | 4 | function visualize_default(grid::Union(Texture{Float32, 2}, Matrix{Float32}), ::Style{:surface}, kw_args...) 5 | grid_min = get(kw_args[1], :grid_min, Vec2(-1, -1)) 6 | grid_max = get(kw_args[1], :grid_max, Vec2( 1, 1)) 7 | grid_length = grid_max - grid_min 8 | scale = Vec3((1f0 ./[size(grid)...])..., 1f0) 9 | Dict( 10 | :primitive => GLMesh2D(Rectangle(0f0,0f0,1f0,1f0)), 11 | :color => RGBAU8[rgbaU8(1,0,0,1), rgbaU8(1,1,0,1), rgbaU8(0,1,0,1), rgbaU8(0,1,1,1), rgbaU8(0,0,1,1)], 12 | :grid_min => grid_min, 13 | :grid_max => grid_max, 14 | :color_norm => Vec2(minimum(grid), maximum(grid)), 15 | :scale => scale .* Vec3(grid_length..., 1f0) 16 | ) 17 | end 18 | 19 | 20 | function visualize(grid::Texture{Float32, 2}, s::Style{:surface}, customizations=visualize_defaults(grid, s)) 21 | @materialize! color, primitive = customizations 22 | @materialize grid_min, grid_max, color_norm = customizations 23 | data = merge(Dict( 24 | :z => grid, 25 | :color => Texture(color), 26 | ), collect_for_gl(primitive), customizations) 27 | 28 | bb = lift(particle_grid_bb, grid_min, grid_max, color_norm) # This is not accurate. color_norm doesn't need to reflect the real height. also it doesn't get recalculated when the texture changes. 29 | 30 | program = TemplateProgram( 31 | File(shaderdir, "util.vert"), 32 | File(shaderdir, "surface.vert"), 33 | File(shaderdir, "standard.frag") 34 | ) 35 | instanced_renderobject(data, length(grid), program, bb) 36 | end 37 | 38 | 39 | 40 | #Surface from x,y,z matrices 41 | 42 | visualize{T <: Matrix{Float32}}(x::T, y::T, z::T, style=:default; kw_args...) = visualize(x,y,z, Style{style}(), visualize_default(z, style, kw_args)) 43 | 44 | 45 | #Can't be handled by the @gen_visualize macro 46 | function visualize{T <: Input{Matrix{Float32}}}(x::T, y::T, z::T, s::Style{:surface}, customizations=visualize_defaults(z.value, s)) 47 | xt, yt, zt = Texture(x.value), Texture(y.value), Texture(z.value) 48 | lift(update!, xt, x); lift(update!, yt, y); lift(update!, yt, y) 49 | visualize(xt, yt, zt, s, customizations) 50 | end 51 | visualize{T <: Matrix{Float32}}(x::T, y::T, z::T, s::Style{:surface}, customizations=visualize_defaults(z, s)) = 52 | visualize(Texture(x),Texture(y), Texture(z), s, customizations) 53 | 54 | function visualize{T <: Texture{Float32, 2}}(x::T, y::T, z::T, s::Style{:surface}, customizations=visualize_defaults(z, s)) 55 | @materialize! color, primitive = customizations 56 | data = merge(@compat(Dict( 57 | :x => x, 58 | :y => y, 59 | :z => z, 60 | :color => Texture(color) 61 | )), collect_for_gl(primitive), customizations) 62 | 63 | min_x, min_y, min_z = minimum(x), minimum(y), minimum(z) 64 | max_x, max_y, max_z = maximum(x), maximum(y), maximum(z) 65 | 66 | bb = lift(AABB, min_x, min_y, min_z, max_x, max_y, max_z) # This is not accurate as I'm not recalcuting the data when something updates 67 | 68 | program = TemplateProgram(File(shaderdir, "util.vert"), File(shaderdir, "surface2.vert"), File(shaderdir, "standard.frag")) 69 | instanced_renderobject(data, length(x), program, bb) 70 | end 71 | -------------------------------------------------------------------------------- /src/texture_atlas/texture_atlas.jl: -------------------------------------------------------------------------------- 1 | immutable Sprite{T} <: FixedVector{T, 1} 2 | attribute_id::T # lookup attribute_id for attribute texture 3 | end 4 | immutable SpriteStyle{T} <: FixedVector{T, 2} 5 | color_id::T # lookup attribute_id for attribute texture 6 | technique::T 7 | end 8 | 9 | typealias GLSprite Sprite{Uint32} 10 | typealias GLSpriteStyle SpriteStyle{Uint16} 11 | 12 | immutable SpriteAttribute{T} <: FixedVector{T, 4} 13 | u::T 14 | v::T 15 | x_scale::T 16 | y_scale::T 17 | end 18 | 19 | typealias GLSpriteAttribute SpriteAttribute{Float16} 20 | 21 | type TextureAtlas 22 | rectangle_packer::RectanglePacker 23 | mapping ::Dict{Any, Int} # styled glyph to index in sprite_attributes 24 | index ::Int 25 | images ::Texture{Ufixed8, 2} 26 | attributes ::GPUVector{GLSpriteAttribute} 27 | # sprite_attributes layout 28 | # can be compressed quite a bit more 29 | # ID Vertex1 Vertex2 Vertex3 Vertex4 30 | # 0 [u,v,xs,ys] [u,v,xs,ys] [u,v,xs,ys] [u,v,xs,ys] # uv -> rectangular section in TextureAtlas 31 | # 1 ... 32 | # . 33 | # . 34 | # . 35 | TextureAtlas(initial_size=(4096, 4096)) = new( 36 | RectanglePacker(Rectangle(0, 0, initial_size...)), 37 | Dict{Any, Int}(), 38 | 1, 39 | Texture(fill(Ufixed8(0.0), initial_size...)), 40 | GPUVector(texture_buffer(GLSpriteAttribute[])) 41 | ) 42 | end 43 | const fn = Pkg.dir("GLVisualize", "src", "texture_atlas", "DejaVuSansMono.ttf") 44 | @assert isfile(fn) 45 | 46 | const DEFAULT_FONT_FACE = newface(fn) 47 | const FONT_EXTENDS = Dict{Int, FontExtent}() 48 | const ID_TO_CHAR = Dict{Int, Char}() 49 | 50 | 51 | begin 52 | const local TEXTURE_ATLAS = TextureAtlas[] 53 | get_texture_atlas() = isempty(TEXTURE_ATLAS) ? push!(TEXTURE_ATLAS, TextureAtlas())[] : TEXTURE_ATLAS[] # initialize only on demand 54 | end 55 | Base.get!(texture_atlas::TextureAtlas, glyph::Char, font) = get!(texture_atlas.mapping, (glyph, font)) do 56 | uv, rect, extent = render(glyph, font, texture_atlas) 57 | 58 | bearing = extent.horizontal_bearing 59 | attributes = GLSpriteAttribute[ 60 | GLSpriteAttribute(uv.x, uv.y, uv.w, uv.h), # last remaining digits are optional, so we use them to cache this calculation 61 | GLSpriteAttribute(bearing.x, -(uv.h-bearing.y), extent.advance...), 62 | ] 63 | i = texture_atlas.index 64 | push!(texture_atlas.attributes, attributes) 65 | texture_atlas.index = i+2 66 | FONT_EXTENDS[i-1] = extent # extends get saved for the attribute id 67 | ID_TO_CHAR[i-1] = glyph 68 | return i-1 # zero indexed for OpenGL 69 | end 70 | 71 | 72 | Base.get!(texture_atlas::TextureAtlas, glyphs, font) = 73 | map(glyph->get!(texture_atlas, glyph, font), collect(glyphs)) 74 | 75 | map_fonts( 76 | text, 77 | font = DEFAULT_FONT_FACE, 78 | texture_atlas = get_texture_atlas() 79 | ) = get!(texture_atlas, text, font) 80 | get_font!(char::Char, 81 | font = DEFAULT_FONT_FACE, 82 | texture_atlas = get_texture_atlas() 83 | ) = get!(texture_atlas, char, font) 84 | 85 | 86 | function GLAbstraction.render(glyph::Char, font, ta::TextureAtlas, face=DEFAULT_FONT_FACE) 87 | #select_font_face(cc, font) 88 | bitmap, extent = renderface(face, glyph) 89 | rect = Rectangle(0,0,size(bitmap)...) 90 | uv = push!(ta.rectangle_packer, rect).area #find out where to place the rectangle 91 | uv == nothing && error("texture atlas is too small.") #TODO resize surface 92 | ta.images[uv] = reinterpret(Ufixed8, bitmap) 93 | uv, rect, extent 94 | end 95 | -------------------------------------------------------------------------------- /src/shader/boundingbox/instance_normal.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | {{GLSL_EXTENSIONS}} 3 | 4 | {{vertex_type}} vertex; 5 | {{normal_vector_type}} normal_vector; // normal might not be an uniform, whereas the other will be allways uniforms 6 | {{offset_type}} offset; //offset for texture look up. Needed to get neighbouring vertexes, when rendering the surface 7 | 8 | 9 | {{xrange_type}} xrange; 10 | {{yrange_type}} yrange; 11 | {{z_type}} z; 12 | 13 | {{xscale_type}} xscale; 14 | {{yscale_type}} yscale; 15 | {{zscale_type}} zscale; 16 | {{color_type}} color; 17 | 18 | uniform vec2 texdimension; 19 | 20 | uniform mat3 normalmatrix; 21 | uniform mat4 modelmatrix; 22 | uniform mat4 projection, view; 23 | 24 | {{out}} vec3 N; 25 | {{out}} vec3 V; 26 | {{out}} vec4 vert_color; 27 | 28 | {{instance_functions}} //It's rather a bad idea, but I outsourced the functions to another file 29 | 30 | vec3 getnormal(sampler2D zvalues, vec2 uv) 31 | { 32 | float weps = 1.0/textureSize(zvalues,0).x; 33 | float heps = 1.0/textureSize(zvalues,0).y; 34 | 35 | vec2 off1 = uv + vec2(-weps,0); 36 | vec2 off2 = uv + vec2(0, heps); 37 | vec2 off3 = uv + vec2(weps, 0); 38 | vec2 off4 = uv + vec2(0,-heps); 39 | 40 | vec3 s0 = vec3(uv, texture(zvalues, uv).x); 41 | 42 | vec3 s1 = vec3((off1), texture(zvalues, off1).x); 43 | vec3 s2 = vec3((off2), texture(zvalues, off2).x); 44 | vec3 s3 = vec3((off3), texture(zvalues, off3).x); 45 | vec3 s4 = vec3((off4), texture(zvalues, off4).x); 46 | 47 | return normalize( 48 | cross(s0-s1, s0-s2) + 49 | cross(s0-s2, s0-s3) + 50 | cross(s0-s3, s0-s4) + 51 | cross(s0-s4, s0-s1) 52 | ); 53 | } 54 | vec3 getnormal(float zvalues, vec2 uv) 55 | { 56 | return normal_vector; 57 | } 58 | 59 | vec2 getcoordinate(sampler2D xvalues, sampler2D yvalues, vec2 uv) 60 | { 61 | return vec2(texture(xvalues, uv).x, texture(yvalues, uv).x); 62 | } 63 | vec2 getcoordinate(vec2 xrange, vec2 yrange, vec2 uv) 64 | { 65 | vec2 from = vec2(xrange.x, yrange.x); 66 | vec2 to = vec2(xrange.y, yrange.y); 67 | return from + (uv * (to - from)); 68 | } 69 | vec2 getuv(vec2 texdim, int index, vec2 offset) 70 | { 71 | float u = float((index % int(texdim.x))); 72 | float v = float((index / int(texdim.x))); 73 | return (vec2(u,v) + offset) / (texdim+1); 74 | } 75 | 76 | mat3 rotation(vec3 X, vec3 Y) 77 | { 78 | mat3 M; 79 | M[0] = normalize(X); 80 | M[2] = normalize(cross(X,Y)); 81 | M[1] = normalize(cross(M[2], X)); 82 | return M; 83 | } 84 | 85 | 86 | void main(){ 87 | 88 | vec3 xyz, scale, normal, vert; 89 | vec2 uv = getuv(texdimension, gl_InstanceID, offset); 90 | xyz.xy = getcoordinate(xrange, yrange, uv); 91 | xyz.z = {{z_calculation}} 92 | 93 | scale.x = {{xscale_calculation}} 94 | scale.y = {{yscale_calculation}} 95 | scale.z = {{zscale_calculation}} 96 | 97 | vec3 surfnormal = getnormal(z, uv); 98 | 99 | normal = normal_vector; 100 | 101 | vert_color = vec4(surfnormal,1); 102 | 103 | 104 | N = normalize(normalmatrix*normal); 105 | V = vec3(view * vec4(xyz, 1.0)); 106 | float linestartend = {{vertex_calculation}} 107 | 108 | if( linestartend == 1.0) 109 | { 110 | gl_Position = projection * view * modelmatrix * vec4(xyz, 1.0); 111 | } 112 | else 113 | { 114 | gl_Position = projection * view * modelmatrix * vec4(xyz + surfnormal*0.1, 1.0); 115 | } 116 | 117 | } -------------------------------------------------------------------------------- /src/visualize/2dparticles.jl: -------------------------------------------------------------------------------- 1 | visualize_default{T <: Real}(::Union(Texture{Point2{T}, 1}, Vector{Point2{T}}), ::Style, kw_args=Dict()) = Dict( 2 | :primitive => GLUVMesh2D(Rectangle(0f0, 0f0, 1f0, 1f0)), 3 | :color => RGBA(1f0, 0f0, 0f0, 1f0), 4 | :scale => Vec2(50, 50), 5 | :technique => :circle, 6 | :preferred_camera => :orthographic_pixel 7 | ) 8 | 9 | visualize(locations::Vector{Point2{Float32}}, s::Style, customizations=visualize_default(locations, s)) = 10 | visualize(texture_buffer(locations), s, customizations) 11 | 12 | function visualize(locations::Signal{Vector{Point2{Float32}}}, s::Style, customizations=visualize_default(locations.value, s)) 13 | start_val = texture_buffer(locations.value) 14 | lift(update!, start_val, locations) 15 | visualize(start_val, s, customizations) 16 | end 17 | 18 | function visualize{T <: Real}( 19 | positions::Texture{Point2{T}, 1}, 20 | s::Style, customizations=visualize_default(positions, s) 21 | ) 22 | @materialize! primitive, technique = customizations 23 | data = merge(@compat(Dict( 24 | :positions => positions, 25 | :technique => lift(to_gl_technique, technique) 26 | )), collect_for_gl(primitive), customizations) 27 | 28 | program = TemplateProgram( 29 | File(shaderdir, "util.vert"), 30 | File(shaderdir, "particles2D.vert"), 31 | File(shaderdir, "distance_shape.frag"), 32 | attributes=data, 33 | fragdatalocation=[(0, "fragment_color"), (1, "fragment_groupid")] 34 | ) 35 | instanced_renderobject(data, length(positions), program, Input(AABB{Float32}(AABB(gpu_data(positions))))) 36 | end 37 | 38 | #= 39 | begin 40 | local const POSITIONS = GPUVector{Point2{Float32}}[] 41 | local const SCALE = GPUVector{Vector2{Float32}}[] 42 | getposition() = isempty(POSITIONS) ? push!(POSITIONS, GPUVector(texture_buffer(Point2{Float32}[])))[] : POSITIONS[] 43 | getscale() = isempty(SCALE) ? push!(SCALE, GPUVector(texture_buffer(Point2{Float32}[])))[] : SCALE[] 44 | end 45 | =# 46 | 47 | 48 | 49 | visualize_default{T <: Real}(::Rectangle{T}, ::Style, kw_args=Dict()) = Dict( 50 | :primitive => GLUVMesh2D(Rectangle(0f0, 0f0, 1f0, 1f0)), 51 | :color => RGBA(1f0, 0f0, 0f0, 1f0), 52 | :style => Cint(4), 53 | :preferred_camera => :orthographic_pixel, 54 | :technique => to_gl_technique(:square) 55 | ) 56 | rectangle_position(r::Rectangle) = Point2{Float32}(r.x, r.y) 57 | rectangle_scale(r::Rectangle) = Vector2{Float32}(r.w, r.h) 58 | 59 | visualize{T}(r::Rectangle{T}, s::Style, customizations=visualize_default(r.value, s)) = visualize(Input(r), s, customizations) 60 | function visualize{T}(r::Signal{Rectangle{T}}, s::Style, customizations=visualize_default(r.value, s)) 61 | @materialize! primitive = customizations 62 | 63 | data = merge(Dict( 64 | :position => lift(rectangle_position, r), 65 | :scale => lift(rectangle_scale, r), 66 | ), collect_for_gl(primitive), customizations) 67 | program = TemplateProgram( 68 | File(shaderdir, "particles2D_single.vert"), 69 | File(shaderdir, "distance_shape.frag"), 70 | attributes=data, 71 | fragdatalocation=[(0, "fragment_color"), (1, "fragment_groupid")] 72 | ) 73 | robj = RenderObject(data, program, Input(AABB{Float32}(AABB(r.value)))) 74 | prerender!(robj, 75 | glDisable, GL_DEPTH_TEST, 76 | glDepthMask, GL_FALSE, 77 | glDisable, GL_CULL_FACE, 78 | enabletransparency) 79 | postrender!(robj, 80 | render, robj.vertexarray) 81 | robj 82 | end -------------------------------------------------------------------------------- /src/shader/boundingbox/textshader.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | {{GLSL_EXTENSIONS}} 3 | 4 | // Input vertex data, different for all executions of this shader. 5 | {{in}} int uv_index; 6 | 7 | // Values that stay constant for the whole mesh. 8 | 9 | {{offset_type}} offset; 10 | 11 | {{color_type}} color; 12 | uniform sampler1D style_group; 13 | {{backgroundcolor_type}} backgroundcolor; 14 | //{{style_type}} style; 15 | 16 | {{text_type}} text; 17 | 18 | uniform vec3 newline; 19 | uniform vec3 advance; 20 | 21 | uniform sampler2D uv; 22 | 23 | uniform mat4 model; 24 | 25 | {{out}} vec4 V; 26 | 27 | 28 | int texturewidth(usampler1D x) 29 | { 30 | return textureSize(x, 0); 31 | } 32 | int texturewidth(sampler1D x) 33 | { 34 | return textureSize(x, 0); 35 | } 36 | int texturewidth(usampler2D x) 37 | { 38 | return textureSize(x, 0).x; 39 | } 40 | int texturewidth(sampler2D x) 41 | { 42 | return textureSize(x, 0).x; 43 | } 44 | vec3 qmult(vec4 q, vec3 v) 45 | { 46 | vec3 t = 2 * cross(vec3(q.y, q.z, q.w), v); 47 | return v + q.x * t + cross(vec3(q.y, q.z, q.w), t); 48 | } 49 | 50 | int fetchglyph(usampler1D glyphs, int index) 51 | { 52 | return int(texelFetch(glyphs, index, 0).r); 53 | } 54 | uvec4 fetchglyph(usampler2D glyphs, int index) 55 | { 56 | int width = texturewidth(glyphs); 57 | return texelFetch(glyphs, ivec2(index % width, index/width), 0).rgba; 58 | } 59 | 60 | vec3 position(int index, usampler2D offset) 61 | { 62 | int width = texturewidth(offset); 63 | ivec2 tindex = ivec2(index % width, index / width); 64 | float linemultiplikator = float(texelFetch(offset, tindex, 0).x); 65 | float advancemultiplikator = float(texelFetch(offset, tindex, 0).y); 66 | return (linemultiplikator * newline) + (advancemultiplikator * advance); 67 | } 68 | vec3 position(int index, sampler2D offset) 69 | { 70 | int width = texturewidth(offset); 71 | return texelFetch(offset, ivec2(index % width, index / width), 0).xyz; 72 | } 73 | 74 | vec3 position(int index, sampler1D offset) 75 | { 76 | int width = texturewidth(offset); 77 | int line = index % width; 78 | int linepos = index / width; 79 | vec3 advance = texelFetch(offset, line, 0).xyz; 80 | vec3 newline = texelFetch(offset, line, 0).xyz; 81 | 82 | return (line*newline) + (linepos*advance); 83 | } 84 | 85 | vec3 position(int index, vec2 offset) 86 | { 87 | int width = texturewidth(text); 88 | int linemultiplikator = index / width; 89 | int advancemultiplikator = index % width; 90 | 91 | return (linemultiplikator * newline) + (advancemultiplikator * advance); 92 | } 93 | vec3 position(int index, vec3 offset) 94 | { 95 | return index*offset; 96 | } 97 | 98 | vec4 fetchtexture(sampler2D tex, int index) 99 | { 100 | int width = texturewidth(tex); 101 | return texelFetch(tex, ivec2(index % width, index/width), 0).rgba; 102 | } 103 | uvec4 fetchtexture(usampler2D tex, int index) 104 | { 105 | int width = texturewidth(tex); 106 | return texelFetch(tex, ivec2(index % width, index/width), 0).rgba; 107 | } 108 | const int SPACE = 32; 109 | const int NEWLINE = 10; 110 | 111 | void main(){ 112 | 113 | int index = gl_InstanceID; 114 | 115 | ivec4 textvalues = ivec4(fetchglyph(text, index)); 116 | int glyph = textvalues.x; 117 | 118 | vec3 glyphposition = (textvalues.y * newline) + (textvalues.z * advance); 119 | 120 | vec3 vertex = glyphposition; // if uv_index is vert 1 or 6 121 | if (uv_index == 2) 122 | { 123 | vertex = glyphposition + vec3(0,24,0); 124 | } 125 | else if ((uv_index == 3) || (uv_index == 4)) 126 | { 127 | vertex = glyphposition + vec3(12, 24,0); 128 | } 129 | else if (uv_index == 5) 130 | { 131 | vertex = glyphposition + vec3(12,0,0); 132 | } 133 | 134 | V = vec4(vertex, 0); 135 | gl_Position = vec4(0,0,0,1); 136 | } 137 | -------------------------------------------------------------------------------- /src/share/text.jl: -------------------------------------------------------------------------------- 1 | Base.utf16(glypharray::Array{GLGlyph{Uint16}}) = utf16(Uint16[c.glyph for c in glypharray]) 2 | Base.utf8(glypharray::Array{GLGlyph{Uint16}}) = utf8(Uint8[uint8(c.glyph) for c in glypharray]) 3 | 4 | function escape_regex(x::String) 5 | result = "" 6 | for elem in x 7 | if elem in regex_literals 8 | result *= string('\\') 9 | end 10 | result *= string(elem) 11 | end 12 | result 13 | end 14 | regreduce(arr, prefix="(", suffix=")") = Regex(reduce((v0, x) -> v0*"|"*prefix*escape_regex(x)*suffix, prefix*escape_regex(arr[1])*suffix, arr[2:end])) 15 | 16 | 17 | function update_groups!{T}(textGPU::Texture{GLGlyph{T}, 2}, regexs::Dict{T, Regex}, start=1, stop=length(text_array)) 18 | textRam = textGPU.data[start:stop] 19 | text = utf8(map(textRam) do x 20 | char(x.glyph) 21 | end) 22 | for (group,regex) in regexs 23 | for match in matchall(regex, text) 24 | startorigin = match.offset+1 25 | stoporigin = match.offset+match.endof 26 | setindex1D!(textGPU, group, startorigin:stoporigin, 4) # Set group 27 | end 28 | end 29 | end 30 | 31 | function update_glyphpositions!{T}(text_array::AbstractArray{GLGlyph{T}}, start=1, stop=length(text_array)) 32 | line = text_array[start].line 33 | row = text_array[start].row 34 | for i=1:stop 35 | glyph = text_array[i].glyph 36 | setindex1D!(text_array, T[line, row], i, 2:3) 37 | if glyph == '\n' 38 | row = zero(T) 39 | line += one(T) 40 | else 41 | row += one(T) 42 | end 43 | end 44 | end 45 | function update_glyphpositions!{T}(text_array::Texture{GLGlyph{T},2}, start=1, stop=length(text_array)) 46 | textarray = data(text_array) 47 | line = textarray[start].line 48 | row = textarray[start].row 49 | for i=1:stop-1 50 | glyph = textarray[i].glyph 51 | setindex1D!(textarray, T[line, row], i, 2:3) 52 | if glyph == '\n' 53 | row = 0 54 | line += 1 55 | else 56 | row += 1 57 | end 58 | end 59 | text_array[1:end, 1:end] = textarray 60 | end 61 | function makedisplayable(text::String, tab=3) 62 | result = map(collect(text)) do x 63 | str = string(x) 64 | if !is_valid_utf8(str) 65 | return utf8([one(Uint8)]) # replace with something that yields a missing symbol 66 | elseif str == "\r" 67 | return "\n" 68 | else 69 | return str == "\t" ? utf8(" "^tab) : utf8(str) # also replace tabs 70 | end 71 | end 72 | join(result) 73 | end 74 | 75 | function toglypharray(text::String, tab=3) 76 | #@assert is_valid_utf16(text) # future support for utf16 77 | text = makedisplayable(text,tab) 78 | #Allocate some more memory, to reduce growing the texture residing on VRAM 79 | texturesize = div(length(text), 1024)+1 # a texture size of 1024 should be supported on every GPU 80 | text_array = Array(GLGlyph{Uint16}, 1024, texturesize) 81 | setindex1D!(text_array, 1, 1, 2) # set first line 82 | setindex1D!(text_array, 0, 1, 3) # set first row 83 | #Set text 84 | for (i, elem) in enumerate(text) 85 | setindex1D!(text_array, uint16(char(elem)), i, 1) 86 | setindex1D!(text_array, 0, i, 4) 87 | end 88 | update_glyphpositions!(text_array) # calculate glyph positions 89 | text_array 90 | end 91 | 92 | 93 | operators = [":", ";","=", "+", "-", "!", "¬", "~", "<", ">","=", "/", "&", "|", "\$", "*"] 94 | brackets = ["(", ")", "[", "]", "{", "}"] 95 | keywords = ["for", "end", "while", "if", "elseif", "using", "return", "in", "function", "local", "global", "let", "quote", "begin", "const", "do", "false", "true"] 96 | regex_literals = ['|', '[', ']', '*', '.', '?', '\\', '(', ')', '{', '}', '+', '-', '$'] 97 | 98 | julia_groups = @compat Dict( 99 | 1 => regreduce(operators), 100 | 2 => regreduce(brackets), 101 | 3 => regreduce(keywords, "((? r"(#=.*=#)|(#.*[\n\r])", #Comments 103 | 5 => r"(\".*\")|('.*')|((? r"(? lumaMax)) 89 | color = vec4(rgbA, texColor.a); 90 | else 91 | color = vec4(rgbB, texColor.a); 92 | return color; 93 | } 94 | 95 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GLVisualize 2 | 3 | 4 | |[![](https://github.com/JuliaGL/GLVisualize.jl/blob/master/docs/vectorfield.jpg?raw=true)](https://github.com/JuliaGL/GLVisualize.jl/blob/master/test/test_vectorfield.jl)|[![](https://github.com/JuliaGL/GLVisualize.jl/blob/master/docs/isosurface.jpg?raw=true)](https://github.com/JuliaGL/GLVisualize.jl/blob/master/test/test_isosurface.jl)|[![](https://github.com/JuliaGL/GLVisualize.jl/blob/master/docs/surface.jpg?raw=true)](https://github.com/JuliaGL/GLVisualize.jl/blob/master/test/test_surface.jl) | 5 | | --- | --- | --- | 6 | | [![](https://github.com/JuliaGL/GLVisualize.jl/blob/master/docs/volume.jpg?raw=true)](https://github.com/JuliaGL/GLVisualize.jl/blob/master/test/test_volume.jl)|[![](https://github.com/JuliaGL/GLVisualize.jl/blob/master/docs/obj.jpg?raw=true)](https://github.com/JuliaGL/GLVisualize.jl/blob/master/test/test_obj.jl)|[![](https://github.com/JuliaGL/GLVisualize.jl/blob/master/docs/particles2D.jpg?raw=true)](https://github.com/JuliaGL/GLVisualize.jl/blob/master/test/test_particles2D.jl) | 7 | | --- | --- | --- | 8 | | [![](https://github.com/JuliaGL/GLVisualize.jl/blob/master/docs/dots.jpg?raw=true)](https://github.com/JuliaGL/GLVisualize.jl/blob/master/test/test_dots.jl)|[![](https://github.com/JuliaGL/GLVisualize.jl/blob/master/docs/barplot.jpg?raw=true)](https://github.com/JuliaGL/GLVisualize.jl/blob/master/test/test_barplot.jl)|[![](https://github.com/JuliaGL/GLVisualize.jl/blob/master/docs/particles.jpg?raw=true)](https://github.com/JuliaGL/GLVisualize.jl/blob/master/test/test_particles.jl) | 9 | | --- | --- | --- | 10 | | [![](https://github.com/JuliaGL/GLVisualize.jl/blob/master/docs/arbitrary_surf.jpg?raw=true)](https://github.com/JuliaGL/GLVisualize.jl/blob/master/test/test_arbitrary_surface.jl)|[![](https://github.com/JuliaGL/GLVisualize.jl/blob/master/docs/image.jpg?raw=true)](https://github.com/JuliaGL/GLVisualize.jl/blob/master/test/test_image.jl)|[![](https://github.com/JuliaGL/GLVisualize.jl/blob/master/docs/sierpinski.jpg?raw=true)](https://github.com/JuliaGL/GLVisualize.jl/blob/master/test/test_sierpinski_mesh.jl) | 11 | Please click on the examples to see the code, which produced the image. 12 | 13 | This is basically the successor of GLPlot, and will soon be its new rendering core. 14 | Right now it relies on a mixture of packages not in METADATA and different branches in these packages, so installation is a little tricky. 15 | But here is a script adding the packages and checking out the correct branches. 16 | Run it two times, because packages fail as they have unregistered packages in their require file. 17 | ```Julia 18 | Pkg.clone("https://github.com/JuliaGL/GLVisualize.jl.git") 19 | 20 | Pkg.add("GLWindow") 21 | Pkg.checkout("GLWindow", "screen_rebuild") 22 | 23 | Pkg.add("GLAbstraction") 24 | Pkg.checkout("GLAbstraction", "julia04") 25 | 26 | Pkg.add("ModernGL") 27 | Pkg.checkout("ModernGL", "master") 28 | 29 | Pkg.clone("https://github.com/SimonDanisch/FixedSizeArrays.jl.git") 30 | Pkg.checkout("FixedSizeArrays", "master") 31 | 32 | Pkg.clone("https://github.com/JuliaGeometry/GeometryTypes.jl.git") 33 | Pkg.checkout("GeometryTypes", "master") 34 | 35 | Pkg.clone("https://github.com/SimonDanisch/ColorTypes.jl.git") 36 | Pkg.checkout("ColorTypes", "master") 37 | 38 | Pkg.add("Reactive") 39 | Pkg.checkout("Reactive", "master") 40 | Pkg.add("GLFW") 41 | Pkg.checkout("GLFW", "julia04") 42 | 43 | Pkg.add("Compat") 44 | Pkg.checkout("Compat", "master") 45 | 46 | Pkg.clone("https://github.com/JuliaIO/ImageIO.jl.git") 47 | Pkg.checkout("ImageIO", "master") 48 | 49 | Pkg.clone("https://github.com/JuliaIO/ImageMagick.jl.git") 50 | Pkg.checkout("ImageMagick", "master") 51 | Pkg.build("ImageMagick") 52 | 53 | Pkg.clone("https://github.com/JuliaIO/WavefrontObj.jl.git") 54 | Pkg.checkout("WavefrontObj", "master") 55 | 56 | 57 | Pkg.clone("https://github.com/JuliaIO/FileIO.jl.git") 58 | Pkg.checkout("FileIO", "master") 59 | 60 | Pkg.clone("https://github.com/JuliaIO/MeshIO.jl.git") 61 | Pkg.checkout("MeshIO", "master") 62 | 63 | Pkg.add("Meshes") 64 | Pkg.checkout("Meshes", "meshes2.0") 65 | 66 | Pkg.clone("https://github.com/JuliaGPU/AbstractGPUArray.jl.git") 67 | Pkg.checkout("AbstractGPUArray", "master") 68 | 69 | Pkg.clone("https://github.com/JuliaGeometry/Packing.jl.git") 70 | Pkg.checkout("Packing", "master") 71 | 72 | Pkg.clone("https://github.com/jhasse/FreeType.jl") 73 | Pkg.checkout("FreeType", "master") 74 | 75 | 76 | Pkg.clone("https://github.com/SimonDanisch/FreeTypeAbstraction.jl") 77 | Pkg.checkout("FreeTypeAbstraction", "master") 78 | 79 | Pkg.clone("https://github.com/JuliaGeometry/Packing.jl.git") 80 | Pkg.checkout("Packing", "master") 81 | 82 | Pkg.add("VideoIO") 83 | Pkg.checkout("VideoIO") 84 | Pkg.build("VideoIO") 85 | 86 | ``` 87 | -------------------------------------------------------------------------------- /src/shader/boundingbox/colorchooser.frag: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | 3 | {{out}} vec4 minbuffer; 4 | {{out}} vec4 maxbuffer; 5 | 6 | 7 | vec3 hsv2rgb(vec3 c) 8 | { 9 | vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); 10 | vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); 11 | return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); 12 | } 13 | 14 | vec3 rgb2hsv(vec3 c) 15 | { 16 | vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); 17 | vec4 p = c.g < c.b ? vec4(c.bg, K.wz) : vec4(c.gb, K.xy); 18 | vec4 q = c.r < p.x ? vec4(p.xyw, c.r) : vec4(c.r, p.yzx); 19 | float d = q.x - min(q.w, q.y); 20 | float e = 1.0e-10; 21 | return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); 22 | } 23 | 24 | const float floatmax = 99999999999999999999999999999999999999.0; //Todo fill in correct floatmax 25 | 26 | {{in}} vec2 frag_uv; 27 | {{in}} vec4 V; 28 | uniform vec2 middle; 29 | uniform vec4 color; 30 | 31 | uniform float swatchsize; 32 | uniform vec4 border_color; 33 | uniform float border_size; 34 | uniform bool hover; 35 | uniform bool hue_saturation; 36 | uniform bool brightness_transparency; 37 | 38 | uniform float antialiasing_value; 39 | 40 | 41 | void main(){ 42 | vec3 hsv = rgb2hsv(color.rgb); 43 | vec4 result_color = vec4(0); 44 | vec2 radius_vec = middle - frag_uv; 45 | float radius = length(radius_vec); 46 | float swatchborder = swatchsize + border_size; 47 | float avalue = 0.001; 48 | 49 | 50 | if(radius < swatchsize - (avalue / 2.0)) 51 | { 52 | result_color = color; 53 | }else if( (radius >= swatchsize - (avalue / 2.0)) && radius < swatchborder) 54 | { 55 | result_color = border_color; 56 | if(radius <= swatchsize + (avalue / 2.0)) 57 | { 58 | float interpolationvalue = radius - (swatchsize - (avalue / 2.0)); 59 | interpolationvalue /= avalue; 60 | result_color = mix(color, border_color, interpolationvalue); 61 | 62 | }else if(radius >= swatchborder - avalue) 63 | { 64 | float interpolationvalue = radius - (swatchborder - avalue); 65 | interpolationvalue /= avalue; 66 | result_color = vec4(border_color.rgb, interpolationvalue); 67 | } 68 | 69 | } 70 | else if(hover) 71 | { 72 | // start from border of switch 73 | float normed_distfromborder = radius - swatchborder; 74 | // norm range between 0-1 75 | normed_distfromborder = normed_distfromborder / (1.0-swatchborder); 76 | // account for radius vs diameter 77 | normed_distfromborder *= 3; 78 | 79 | float alpha = smoothstep(0.0, 0.05, 1-normed_distfromborder); 80 | 81 | if(hue_saturation) 82 | { 83 | // for the saturation calculation, we want to get back the sign of the xplane 84 | // polar coordinates for hue, just taking the fraction part, to keep it between 0-1 85 | float hue = fract(hsv.x + atan(abs(radius_vec.x), abs(radius_vec.y)) / 3.0); 86 | 87 | float yradius = radius_vec.y; 88 | float xradius = radius_vec.x; 89 | if(abs(xradius) < swatchsize) 90 | { 91 | result_color = vec4(hsv2rgb(vec3(hsv.x, clamp(hsv.y - yradius, 0.0, 1.0), hsv.z)),alpha); 92 | 93 | }else if(abs(xradius) < swatchborder) 94 | { 95 | result_color = vec4(0); 96 | }else 97 | { 98 | float hue = fract((hsv.x + atan(radius_vec.x, radius_vec.y))/5); 99 | result_color = vec4(hsv2rgb(vec3(hsv.x + normed_distfromborder/5, hsv.yz)), alpha); 100 | } 101 | } 102 | else if(brightness_transparency) 103 | { 104 | // brightness gets varied on an y column, with the width of the color swatch 105 | float yradius = radius_vec.y; 106 | float xradius = radius_vec.x; 107 | if(abs(xradius) < swatchsize) 108 | { 109 | 110 | float brightness = hsv.z; 111 | if(radius_vec.y < 0.0) 112 | { 113 | normed_distfromborder = -normed_distfromborder; 114 | } 115 | brightness = clamp(brightness - normed_distfromborder, 0.0, 1.0); 116 | result_color = vec4(hsv2rgb(vec3(hsv.xy, brightness)), alpha); 117 | }else if(abs(xradius) < swatchborder) 118 | { 119 | result_color = vec4(0); 120 | }else 121 | { 122 | result_color = vec4(hsv2rgb(hsv), clamp(1-(-xradius), 0.0, alpha)); 123 | } 124 | } 125 | 126 | } 127 | 128 | if (result_color.a > 0.0) 129 | { 130 | minbuffer = -V; 131 | maxbuffer = V; 132 | }else{ 133 | minbuffer = vec4(0); 134 | maxbuffer = vec4(0); 135 | } 136 | } 137 | 138 | 139 | -------------------------------------------------------------------------------- /src/shader/volume.frag: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | 3 | out vec4 frag_color; 4 | in vec3 frag_vertposition; 5 | 6 | uniform sampler3D intensities; 7 | 8 | uniform vec3 light_position = vec3(1.0, 1.0, 3.0); 9 | uniform vec3 light_intensity = vec3(15.0); 10 | uniform vec4 color; 11 | uniform float absorption = 1.0; 12 | 13 | uniform vec3 eyeposition; 14 | 15 | uniform mat4 model; 16 | 17 | uniform vec3 ambient = vec3(0.15, 0.15, 0.20); 18 | 19 | uniform int algorithm; 20 | uniform float isovalue; 21 | 22 | const int view_samples = 512; 23 | const float max_distance = sqrt(1.0); 24 | 25 | const int num_samples = 256; 26 | const float step_size = max_distance/float(num_samples); 27 | const int num_ligth_samples = 16; 28 | const float lscale = max_distance / float(num_ligth_samples); 29 | const float density_factor =9; 30 | 31 | 32 | 33 | float GetDensity(vec3 pos) 34 | { 35 | return texture(intensities, pos).x; 36 | } 37 | 38 | vec3 gennormal(vec3 uvw, vec3 gradient_delta) 39 | { 40 | vec3 a,b; 41 | a.x = texture(intensities, uvw -vec3(gradient_delta.x,0.0,0.0) ).r; 42 | b.x = texture(intensities, uvw +vec3(gradient_delta.x,0.0,0.0) ).r; 43 | a.y = texture(intensities, uvw -vec3(0.0,gradient_delta.y,0.0) ).r; 44 | b.y = texture(intensities, uvw +vec3(0.0,gradient_delta.y,0.0) ).r; 45 | a.z = texture(intensities, uvw -vec3(0.0,0.0,gradient_delta.z) ).r; 46 | b.z = texture(intensities, uvw +vec3(0.0,0.0,gradient_delta.z) ).r; 47 | return normalize(a - b); 48 | } 49 | vec3 blinn_phong(vec3 N, vec3 V, vec3 L, vec3 diffuse) 50 | { 51 | // material properties 52 | vec3 Ka = vec3(0.1); 53 | vec3 Kd = vec3(1.0, 1.0, 1.0); 54 | vec3 Ks = vec3(1.0, 1.0, 1.0); 55 | float shininess = 50.0; 56 | 57 | // diffuse coefficient 58 | float diff_coeff = max(dot(L,N),0.0); 59 | 60 | // specular coefficient 61 | vec3 H = normalize(L+V); 62 | float spec_coeff = pow(max(dot(H,N), 0.0), shininess); 63 | if (diff_coeff <= 0.0) 64 | spec_coeff = 0.0; 65 | 66 | // final lighting model 67 | return Ka * vec3(0.5) + 68 | Kd * diffuse * diff_coeff + 69 | Ks * vec3(0.3) * spec_coeff ; 70 | } 71 | 72 | bool is_outside(vec3 position) 73 | { 74 | return (position.x > 1.0 || position.y > 1.0 || position.z > 1.0 || position.x < 0.0 || position.y < 0.0 || position.z < 0.0); 75 | } 76 | 77 | 78 | vec4 volume(vec3 front, vec3 dir, float stepsize) 79 | { 80 | vec3 stepsize_dir = normalize(dir) * stepsize; 81 | vec3 pos = front; 82 | float T = 1.0; 83 | vec3 Lo = vec3(0.0); 84 | int i = 0; 85 | pos += stepsize_dir;//apply first, to padd 86 | for (i; i < num_samples && (!is_outside(pos) || i<3); ++i, pos += stepsize_dir) { 87 | 88 | float density = texture(intensities, pos).x * density_factor; 89 | if (density <= 0.0) 90 | continue; 91 | 92 | T *= 1.0-density*stepsize*absorption; 93 | if (T <= 0.01) 94 | break; 95 | 96 | vec3 lightDir = normalize(light_position-pos)*lscale; 97 | float Tl = 1.0; 98 | vec3 lpos = pos + lightDir; 99 | int s=0; 100 | for (s; s < num_ligth_samples; ++s) { 101 | float ld = texture(intensities, lpos).x; 102 | Tl *= 1.0-absorption*stepsize*ld; 103 | if (Tl <= 0.01) 104 | lpos += lightDir; 105 | } 106 | 107 | vec3 Li = light_intensity*Tl; 108 | Lo += Li*T*density*stepsize; 109 | } 110 | return vec4(Lo, 1-T); 111 | } 112 | vec4 isosurface(vec3 front, vec3 dir, float stepsize) 113 | { 114 | vec3 stepsize_dir = dir * stepsize; 115 | vec3 pos = front; 116 | vec3 Lo = vec3(0.0); 117 | int i = 0; 118 | vec4 _color = vec4(0.0); 119 | pos += stepsize_dir;//apply first, to padd 120 | for (i; i < num_samples && (!is_outside(pos) || i==1); ++i, pos += stepsize_dir) 121 | { 122 | float density = texture(intensities, pos).x; 123 | if (density <= 0.0) 124 | continue; 125 | if(abs(density - isovalue) < 0.03) 126 | { 127 | vec3 N = gennormal(pos, vec3(stepsize)); 128 | vec3 L = normalize(light_position - pos); 129 | vec3 L2 = -L; 130 | Lo = blinn_phong(N, pos, L, color.rgb); 131 | Lo += blinn_phong(N, pos, L2, color.rgb); 132 | _color = vec4(Lo, 1); 133 | break; 134 | } 135 | } 136 | return _color; 137 | } 138 | vec4 mip(vec3 front, vec3 dir, float stepsize) 139 | { 140 | vec3 stepsize_dir = dir * stepsize; 141 | vec3 pos = front; 142 | vec3 Lo = vec3(0.0); 143 | int i = 0; 144 | pos += stepsize_dir;//apply first, to padd 145 | float maximum = 0.0; 146 | for (i; i < num_samples && (!is_outside(pos) || i==1); ++i, pos += stepsize_dir) 147 | { 148 | float density = texture(intensities, pos).x; 149 | if (density <= 0.0) 150 | continue; 151 | if(maximum < density) 152 | { 153 | maximum = density; 154 | } 155 | } 156 | return vec4(maximum); 157 | } 158 | void main() 159 | { 160 | if(algorithm == 1) 161 | frag_color = volume(frag_vertposition, normalize(frag_vertposition-eyeposition), step_size); 162 | else if(algorithm == 2) 163 | frag_color = isosurface(frag_vertposition, normalize(frag_vertposition-eyeposition), step_size); 164 | else 165 | frag_color = mip(frag_vertposition, normalize(frag_vertposition-eyeposition), step_size); 166 | } 167 | 168 | -------------------------------------------------------------------------------- /src/shader/util.vert: -------------------------------------------------------------------------------- 1 | {{GLSL_VERSION}} 2 | 3 | struct AABB 4 | { 5 | vec3 min; 6 | vec3 max; 7 | }; 8 | struct Rectangle 9 | { 10 | vec2 origin; 11 | vec2 width; 12 | }; 13 | 14 | // stretch is 15 | vec3 stretch(vec3 val, vec3 from, vec3 to) 16 | { 17 | return from + (val * (to - from)); 18 | } 19 | vec2 stretch(vec2 val, vec2 from, vec2 to) 20 | { 21 | return from + (val * (to - from)); 22 | } 23 | float stretch(float val, float from, float to) 24 | { 25 | return from + (val * (to - from)); 26 | } 27 | 28 | float _normalize(float val, float from, float to) 29 | { 30 | return (val-from) / (to - from); 31 | } 32 | vec2 _normalize(vec2 val, vec2 from, vec2 to) 33 | { 34 | return (val-from) * (to - from); 35 | } 36 | vec3 _normalize(vec3 val, vec3 from, vec3 to) 37 | { 38 | return (val-from) * (to - from); 39 | } 40 | 41 | 42 | mat4 getmodelmatrix(vec3 xyz, vec3 scale) 43 | { 44 | return mat4( 45 | vec4(scale.x, 0, 0, 0), 46 | vec4(0, scale.y, 0, 0), 47 | vec4(0, 0, scale.z, 0), 48 | vec4(xyz, 1)); 49 | } 50 | 51 | mat4 rotationmatrix_z(float angle) 52 | { 53 | return mat4( 54 | cos(angle), -sin(angle), 0, 0, 55 | sin(angle), cos(angle), 0, 0, 56 | 0, 0, 1, 0, 57 | 0, 0, 0, 1); 58 | } 59 | mat4 rotationmatrix_y(float angle) 60 | { 61 | return mat4( 62 | cos(angle), 0, sin(angle), 0, 63 | 0, 1, 0, 0, 64 | -sin(angle), 0, cos(angle), 0, 65 | 0, 0, 0, 1); 66 | } 67 | 68 | const vec3 UP_VECTOR = vec3(0,0,1); 69 | 70 | mat4 rotation(vec3 direction) 71 | { 72 | direction = normalize(direction); 73 | mat4 rot = mat4(1.0); 74 | if(direction == UP_VECTOR) 75 | return rot; 76 | vec3 xaxis = normalize(cross(UP_VECTOR, direction)); 77 | 78 | vec3 yaxis = normalize(cross(direction, xaxis)); 79 | 80 | rot[0][0] = xaxis.x; 81 | rot[1][0] = yaxis.x; 82 | rot[2][0] = direction.x; 83 | 84 | rot[0][1] = xaxis.y; 85 | rot[1][1] = yaxis.y; 86 | rot[2][1] = direction.y; 87 | 88 | rot[0][2] = xaxis.z; 89 | rot[1][2] = yaxis.z; 90 | rot[2][2] = direction.z; 91 | 92 | return rot; 93 | } 94 | 95 | mat4 translate_scale(vec3 xyz, vec3 scale) 96 | { 97 | return mat4( 98 | vec4(scale.x, 0, 0, 0), 99 | vec4(0, scale.y, 0, 0), 100 | vec4(0, 0, scale.z, 0), 101 | vec4(xyz, 1)); 102 | } 103 | 104 | //Mapping 1D index to 1D, 2D and 3D arrays 105 | int ind2sub(int dim, int linearindex) 106 | { 107 | return linearindex; 108 | } 109 | ivec2 ind2sub(ivec2 dim, int linearindex) 110 | { 111 | return ivec2(linearindex % dim.x, linearindex / dim.x); 112 | } 113 | ivec3 ind2sub(ivec3 dim, int linearindex) 114 | { 115 | return ivec3(linearindex / (dim.y * dim.z), (linearindex / dim.z) % dim.y, linearindex % dim.z); 116 | } 117 | 118 | 119 | vec2 linear_index(ivec2 dims, int index) 120 | { 121 | ivec2 index2D = ind2sub(dims, index); 122 | return vec2(index2D) / vec2(dims); 123 | } 124 | vec2 linear_index(ivec2 dims, int index, vec2 offset) 125 | { 126 | vec2 index2D = vec2(ind2sub(dims, index))+offset; 127 | return index2D / vec2(dims); 128 | } 129 | vec3 linear_index(ivec3 dims, int index) 130 | { 131 | ivec3 index3D = ind2sub(dims, index); 132 | return vec3(index3D) / vec3(dims); 133 | } 134 | vec4 linear_texture(sampler2D tex, int index) 135 | { 136 | return texture(tex, linear_index(textureSize(tex, 0), index)); 137 | } 138 | 139 | vec4 linear_texture(sampler2D tex, int index, vec2 offset) 140 | { 141 | ivec2 dims = textureSize(tex, 0); 142 | return texture(tex, linear_index(dims, index) + (offset/vec2(dims))); 143 | } 144 | 145 | vec4 linear_texture(sampler3D tex, int index) 146 | { 147 | return texture(tex, linear_index(textureSize(tex, 0), index)); 148 | } 149 | uvec4 getindex(usampler2D tex, int index) 150 | { 151 | return texelFetch(tex, ind2sub(textureSize(tex, 0), index), 0); 152 | } 153 | vec4 getindex(sampler1D tex, int index) 154 | { 155 | return texelFetch(tex, index, 0); 156 | } 157 | vec4 getindex(sampler2D tex, int index) 158 | { 159 | return texelFetch(tex, ind2sub(textureSize(tex, 0), index), 0); 160 | } 161 | vec4 getindex(sampler3D tex, int index) 162 | { 163 | return texelFetch(tex, ind2sub(textureSize(tex, 0), index), 0); 164 | } 165 | 166 | //Implicit grid in a Cube via a 3D array 167 | vec3 position(AABB cube, ivec3 dims, int index) 168 | { 169 | return stretch(linear_index(dims, index), cube.min, cube.max); 170 | } 171 | //Implicit grid on a plane via a 2D array 172 | vec3 position(Rectangle rectangle, ivec2 dims, int index, vec2 offset) 173 | { 174 | return vec3(stretch(linear_index(dims, index) + offset, rectangle.origin, rectangle.width), 0); 175 | } 176 | vec3 position(Rectangle rectangle, ivec2 dims, int index) 177 | { 178 | return vec3(stretch(linear_index(dims, index), rectangle.origin, rectangle.width), 0); 179 | } 180 | 181 | 182 | vec4 color_lookup(float intensity, sampler1D color_ramp, vec2 norm) 183 | { 184 | return texture(color_ramp, _normalize(intensity, norm.x, norm.y)); 185 | } 186 | 187 | out vec3 o_normal; 188 | out vec3 o_lightdir; 189 | out vec3 o_vertex; 190 | out vec4 o_color; 191 | 192 | 193 | void render(vec3 vertex, vec3 normal, vec4 color, mat4 viewmodel, mat4 projection, vec3 light[4]) 194 | { 195 | vec4 position_camspace = viewmodel * vec4(vertex, 1); 196 | // normal in world space 197 | o_normal = normal; 198 | // direction to light 199 | o_lightdir = normalize(light[3] - vertex); 200 | // direction to camera 201 | o_vertex = -position_camspace.xyz; 202 | // 203 | o_color = color; 204 | // screen space coordinates of the vertex 205 | gl_Position = projection * position_camspace; 206 | } -------------------------------------------------------------------------------- /src/edit/text.jl: -------------------------------------------------------------------------------- 1 | function filtereselection(v0, selection, buttons) 2 | if !isempty(buttons) && first(buttons) == 0 # if any button is pressed && its the left button 3 | selection #return diffed index 4 | else 5 | Vector2(-1) 6 | end 7 | end 8 | 9 | function haschanged(v0, selection) 10 | (v0[2] != selection, selection) 11 | end 12 | function edit(style::Style{:Default}, text::String, custumization::Dict{Symbol, Any}) 13 | obj = visualize(text, style; custumization...) 14 | edit(obj[:text], obj) 15 | end 16 | function edit(style::Style{:Default}, textGPU::Texture{GLGlyph{Uint16}, 2}, obj::RenderObject, custumizatinhhon::Dict{Symbol, Any}) 17 | screen = custumization[:screen] 18 | specialkeys = filteritems(screen.inputs[:buttonspressed], [GLFW.KEY_LEFT_CONTROL, GLFW.KEY_ENTER, GLFW.KEY_BACKSPACE], IntSet()) 19 | 20 | selectiondata = lift(first, SELECTION[:mouse_hover]) 21 | # Filter out the selected index, 22 | changed = lift(first, foldl(haschanged, (true, selectiondata.value), selectiondata)) 23 | 24 | leftclick_selection = foldl(filtereselection, Vector2(-1), keepwhen(changed, Vector2(-1), selectiondata), screen.inputs[:mousebuttonspressed]) 25 | glypharray = vec(data(textGPU)) 26 | changed = false 27 | v00 = (obj, obj.alluniforms[:textlength], textGPU, glypharray, leftclick_selection.value, changed) 28 | output = foldl(edit_text, v00, leftclick_selection, screen.inputs[:unicodeinput], specialkeys) 29 | textsignal = lift(filter(v00, output) do x 30 | x[end] # <-has changed 31 | end) do x 32 | utf16(x[4][1:x[2]]) #x[4] <- glypharray, x[2] <- textlength 33 | end 34 | return (obj, textsignal) 35 | end 36 | function pressed{T<:Integer}(keys::Vector{T}, keyset) 37 | length(keyset) == length(keys) && all(keys) do x 38 | in(x, keyset) 39 | end 40 | end 41 | function edit_text(v0, selection1, unicode_keys, special_keys) 42 | # selection0 tracks, where the carsor is after a new character addition, selection10 tracks the old selection 43 | obj, textlength, textGPU, glypharray, selection0, changed = v0 44 | selected_object, selected_index = selection0 45 | selected_index += 1 46 | chars_added = 0 47 | edit_inbound = selected_index<=textlength+1 && selected_index>0 && selected_object == obj.id 48 | if selection1 != Vector2(-1) # if a new index was selected update selection 49 | return (obj, textlength, textGPU, glypharray, selection1, false) 50 | elseif edit_inbound && !(!isempty(unicode_keys) && IntSet(GLFW.MOD_SHIFT)==special_keys) && (!isempty(special_keys) || !isempty(unicode_keys))# something will get edited 51 | if !isempty(special_keys) && isempty(unicode_keys) 52 | if in(GLFW.KEY_BACKSPACE, special_keys) && selected_index>1 53 | splice!(glypharray, selected_index-1) 54 | chars_added = -1 55 | elseif in(GLFW.KEY_ENTER, special_keys) 56 | insert!(glypharray, selected_index, GLGlyph('\n', 0,0,0)) 57 | chars_added = 1 58 | elseif pressed([GLFW.KEY_LEFT_CONTROL, GLFW.KEY_V], special_keys) 59 | p = clipboard() 60 | pasted = [GLGlyph(c,0,0,0) for c in p] 61 | if selected_index == 1 62 | glypharray = [pasted, glypharray] 63 | elseif selected_index == textlength+1 64 | glypharray = [glypharray, pasted] 65 | elseif selected_index>1 && selected_index>=textlength 66 | glypharray = [sub(glypharray, 1:selected_index), pasted, sub(glypharray, selected_index:length(glypharray))] 67 | else 68 | error("invalid text cursor index. Index: ", selected_index) 69 | end 70 | chars_added = length(p) 71 | end 72 | elseif edit_inbound && !isempty(unicode_keys) && (isempty(special_keys) || IntSet(GLFW.MOD_SHIFT)==special_keys)# else unicode input must have occured 73 | insert!(glypharray, selected_index, GLGlyph(first(unicode_keys), 0,0,0)) 74 | chars_added = 1 75 | end 76 | if chars_added != 0 77 | textlength += chars_added 78 | newselection = chars_added + selected_index 79 | selection0 = Vector2(selected_object, max(min(newselection, textlength+1), 1)-1) 80 | update_glyphpositions!(glypharray) 81 | if textlength > length(textGPU) 82 | resize!(textGPU, [size(textGPU,1), size(textGPU,2)*2]) 83 | end 84 | remaining = div(textlength, 1024) 85 | if remaining < 1 86 | textGPU[1:textlength, 1:1] = reshape(glypharray[1:textlength], textlength) 87 | else 88 | textGPU[1:end, 1:remaining] = reshape(glypharray[1:1024*remaining], 1024, remaining) 89 | end 90 | obj[:postrender, renderinstanced] = (obj.vertexarray, textlength) 91 | end 92 | return (obj, textlength, textGPU, glypharray, selection0, true) 93 | end 94 | return (obj, textlength, textGPU, glypharray, selection0, false) 95 | end 96 | 97 | 98 | # Filters a signal. If any of the items is in the signal, the signal is returned. 99 | # Otherwise default is returned 100 | function filteritems{T}(a::Signal{T}, items, default::T) 101 | lift(a) do signal 102 | if any(item-> in(item, signal), items) 103 | signal 104 | else 105 | default 106 | end 107 | end 108 | end 109 | 110 | 111 | 112 | function Base.delete!(s::Array{GLGlyph{Uint16}, 1}, Index::Integer) 113 | if Index == 0 114 | return s 115 | elseif Index == length(s) 116 | return s[1:end-1] 117 | end 118 | return [s[1:max(Index-1, 0)], s[min(Index+1,length(s)):end]] 119 | end 120 | 121 | addchar(s::Array{GLGlyph{Uint16}, 1}, glyph::Char, Index::Integer) = addchar(s, GLGlyph(glyph, 0, 0, 0), int(Index)) 122 | function addchar(s::Array{GLGlyph{Uint16}, 1}, glyph::GLGlyph{Uint16}, i::Integer) 123 | if i == 0 124 | return [glyph, s] 125 | elseif i == length(s) 126 | return [s, glyph] 127 | elseif i > length(s) || i < 0 128 | return s 129 | end 130 | return [s[1:i], glyph, s[i+1:end]] 131 | end 132 | -------------------------------------------------------------------------------- /src/visualize/text/freetype_text.jl: -------------------------------------------------------------------------------- 1 | using FreeType 2 | 3 | type Glyph 4 | char::Char 5 | box::Rect{Int} 6 | origin::Vec2 7 | advance::Vec2 8 | end 9 | 10 | type Font 11 | family::String 12 | style::String 13 | size::Vec2 14 | lineDistance::Float32 15 | ascent::Float32 16 | descent::Float32 17 | glyphs::Dict{Char, Glyph} 18 | kerning::Dict{(Char, Char), Vec2{Float32}} 19 | bitmap::Array{Uint8, 2} 20 | fallbackGlyph::Glyph 21 | 22 | Font(family, style, sizeX, sizeY, lineDistance, ascent, descent, bmpWidth, bmpHeight) = 23 | new(family, style, Vec2{Float32}(sizeX, sizeY), lineDistance, ascent, descent, Dict{Char, Glyph}(), Dict{(Char, Char), Vec2{Float32}}(), zeros(Uint8, bmpWidth, bmpHeight)) 24 | end 25 | 26 | Font(family, style, sizeX, sizeY, lineDistance, ascent, descent, maxCharWidth, maxCharHeight, charCount) = 27 | Font(family, style, sizeX, sizeY, lineDistance, ascent, descent, font_bitmap_size(maxCharWidth + 1, maxCharHeight + 1, charCount)...) 28 | 29 | 30 | function addkerning(font::Font, c1::Char, c2::Char, distance::Vec2{Float32}) 31 | @assert haskey(font.glyphs, c1) && haskey(font.glyphs, c2) 32 | @assert !haskey(font.kerning, (c1, c2)) 33 | font.kerning[(c1, c2)] = distance 34 | end 35 | 36 | function adding_done(font::Font) 37 | # maybe calculate the real ascent and descent from the glyph data as well, since the FreeType data can be off 38 | corner = one(Vec2{Int}) 39 | for g in values(font.glyphs) 40 | corner = max(corner, g.box.max) 41 | end 42 | corner += one(Vec2{Int}) 43 | if corner.x < size(font.bitmap, 1) || corner.y < size(font.bitmap, 2) 44 | font.bitmap = font.bitmap[1:corner.x, 1:corner.y] 45 | end 46 | end 47 | 48 | 49 | function drawtext(drawRect::Function, font::Font, cursor::TextCursor, s::String) 50 | for c in s 51 | glyph = get(font.glyphs, c, font.fallbackGlyph) 52 | if cursor.lastChar != 0 53 | cursor.pos += get(font.kerning, (cursor.lastChar, c), zero(Vec2{Float32})) 54 | end 55 | drawRect(cursor.pos - glyph.origin, font.bitmap, glyph.box) 56 | cursor.pos += glyph.advance 57 | cursor.lastChar = c 58 | end 59 | end 60 | 61 | function textbox(font::Font, cursor::TextCursor, s::String) 62 | tempCursor = TextCursor(cursor) 63 | boxMax = rect(Float32) 64 | drawtext(font, tempCursor, s) do pos, bmp, box 65 | boxMax.min = min(boxMax.min, pos) 66 | boxMax.max = max(boxMax.max, pos + size(box)) 67 | end 68 | return boxMax 69 | end 70 | 71 | fontname(font::Font) = "$(font.family)_$(font.style)($(font.size.x)x$(font.size.y))" 72 | 73 | const ftLib = (FT_Library)[C_NULL] 74 | 75 | function init() 76 | global ftLib 77 | @assert ftLib[1] == C_NULL 78 | err = FT_Init_FreeType(ftLib) 79 | return err == 0 80 | end 81 | 82 | function done() 83 | global ftLib 84 | @assert ftLib[1] != C_NULL 85 | err = FT_Done_FreeType(ftLib[1]) 86 | ftLib[1] = C_NULL 87 | return err == 0 88 | end 89 | 90 | 91 | 92 | function newface(ftlib, facename, faceindex::Real=0) 93 | face = (FT_Face)[C_NULL] 94 | err = FT_New_Face(ftlib[1], facename, int32(faceindex), face) 95 | if err != 0 96 | info("Couldn't load font $faceName with error $err") 97 | return face[1] 98 | end 99 | face 100 | end 101 | setpixelsize(face, x, y) = setpixelsize(face, (x, y)) 102 | function setpixelsize(face, size) 103 | err = FT_Set_Pixel_Sizes(face[1], uint32(size[1]), uint32(size[2])) 104 | if err != 0 105 | info("Couldn't set the pixel size for font $faceName with error $err") 106 | end 107 | end 108 | 109 | function loadfont(faceName::String; sizeXY::(Real, Real) = (25, 25), faceIndex::Real = 0, chars = '\u0000':'\u00ff') 110 | face = (FT_Face)[C_NULL] 111 | err = FT_New_Face(ftLib[1], faceName, int32(faceIndex), face) 112 | if err != 0 113 | info("Couldn't load font $faceName with error $err") 114 | return nothing 115 | end 116 | 117 | err = FT_Set_Pixel_Sizes(face[1], uint32(sizeXY[1]), uint32(sizeXY[2])) 118 | font = nothing 119 | if err != 0 120 | info("Couldn't set the pixel size for font $faceName with error $err") 121 | else 122 | faceRec = unsafe_load(face[1]) 123 | 124 | maxCharWidth, maxCharHeight = max_glyph_size(face[1], faceRec, chars) 125 | 126 | emScale = float32(sizeXY[2]) / faceRec.units_per_EM 127 | lineDist = round(faceRec.height * emScale) 128 | ascent = round(faceRec.ascender * emScale) 129 | descent = round(faceRec.descender * emScale) 130 | 131 | font = Font(bytestring(faceRec.family_name), 132 | bytestring(faceRec.style_name), 133 | sizeXY[1], sizeXY[2], 134 | lineDist, ascent, descent, 135 | maxCharWidth, maxCharHeight, length(chars)) 136 | 137 | # load glyphs 138 | charPos = GlyphPosition() 139 | for c in chars 140 | err = FT_Load_Char(face[1], c, FT_LOAD_RENDER) 141 | @assert err == 0 142 | glyphRec = unsafe_load(faceRec.glyph) 143 | @assert glyphRec.format == FreeType.FT_GLYPH_FORMAT_BITMAP 144 | glyphBmp = glyph_bitmap(glyphRec.bitmap) 145 | 146 | addglyph(font, c, glyphBmp, 147 | Vec2{Float32}(-glyphRec.bitmap_left, glyphRec.bitmap_top), 148 | Vec2{Float32}(glyphRec.advance.x / 64f0, glyphRec.advance.y / 64f0), 149 | charPos) 150 | end 151 | 152 | # query kerning info 153 | if faceRec.face_flags & FreeType.FT_FACE_FLAG_KERNING != 0 154 | kernDivisor = (faceRec.face_flags & FreeType.FT_FACE_FLAG_SCALABLE != 0) ? 64f0 : 1f0 155 | for c1 in chars, c2 in chars 156 | kerning = get_kerning(face[1], c1, c2, kernDivisor) 157 | if kerning != zero(Vec2) 158 | addkerning(font, c1, c2, kerning) 159 | end 160 | end 161 | end 162 | 163 | adding_done(font) 164 | end 165 | 166 | err = FT_Done_Face(face[1]) 167 | @assert err == 0 168 | return font 169 | end 170 | 171 | -------------------------------------------------------------------------------- /src/shader/volume2.frag: -------------------------------------------------------------------------------- 1 | // uniforms 2 | uniform $sampler_type u_volumetex; 3 | uniform vec3 u_shape; 4 | uniform float u_threshold; 5 | uniform float u_relative_step_size; 6 | //varyings 7 | varying vec3 v_texcoord; 8 | varying vec3 v_position; 9 | varying vec4 v_nearpos; 10 | varying vec4 v_farpos; 11 | // uniforms for lighting. Hard coded until we figure out how to do lights 12 | const vec4 u_ambient = vec4(0.2, 0.4, 0.2, 1.0); 13 | const vec4 u_diffuse = vec4(0.8, 0.2, 0.2, 1.0); 14 | const vec4 u_specular = vec4(1.0, 1.0, 1.0, 1.0); 15 | const float u_shininess = 40.0; 16 | //varying vec3 lightDirs[1]; 17 | // global holding view direction in local coordinates 18 | vec3 view_ray; 19 | vec4 calculateColor(vec4, vec3, vec3); 20 | float rand(vec2 co); 21 | void main() {{ 22 | vec3 farpos = v_farpos.xyz / v_farpos.w; 23 | vec3 nearpos = v_nearpos.xyz / v_nearpos.w; 24 | 25 | // Calculate unit vector pointing in the view direction through this 26 | // fragment. 27 | view_ray = normalize(farpos.xyz - nearpos.xyz); 28 | 29 | // Compute the distance to the front surface or near clipping plane 30 | float distance = dot(nearpos-v_position, view_ray); 31 | distance = max(distance, min((-0.5 - v_position.x) / view_ray.x, 32 | (u_shape.x - 0.5 - v_position.x) / view_ray.x)); 33 | distance = max(distance, min((-0.5 - v_position.y) / view_ray.y, 34 | (u_shape.y - 0.5 - v_position.y) / view_ray.y)); 35 | distance = max(distance, min((-0.5 - v_position.z) / view_ray.z, 36 | (u_shape.z - 0.5 - v_position.z) / view_ray.z)); 37 | 38 | // Now we have the starting position on the front surface 39 | vec3 front = v_position + view_ray * distance; 40 | 41 | // Decide how many steps to take 42 | int nsteps = int(-distance / u_relative_step_size + 0.5); 43 | if( nsteps < 1 ) 44 | discard; 45 | 46 | // Get starting location and step vector in texture coordinates 47 | vec3 step = ((v_position - front) / u_shape) / nsteps; 48 | vec3 start_loc = front / u_shape; 49 | 50 | // For testing: show the number of steps. This helps to establish 51 | // whether the rays are correctly oriented 52 | //gl_FragColor = vec4(0.0, nsteps / 3.0 / u_shape.x, 1.0, 1.0); 53 | //return; 54 | 55 | {before_loop} 56 | 57 | // This outer loop seems necessary on some systems for large 58 | // datasets. Ugly, but it works ... 59 | vec3 loc = start_loc; 60 | int iter = 0; 61 | while (iter < nsteps) {{ 62 | for (iter=iter; iter 0.0); 126 | N = (2.0*Nselect - 1.0) * N; // == Nselect * N - (1.0-Nselect)*N; 127 | 128 | // Get color of the texture (albeido) 129 | color1 = betterColor; 130 | color2 = color1; 131 | // todo: parametrise color1_to_color2 132 | 133 | // Init colors 134 | vec4 ambient_color = vec4(0.0, 0.0, 0.0, 0.0); 135 | vec4 diffuse_color = vec4(0.0, 0.0, 0.0, 0.0); 136 | vec4 specular_color = vec4(0.0, 0.0, 0.0, 0.0); 137 | vec4 final_color; 138 | 139 | // todo: allow multiple light, define lights on viewvox or subscene 140 | int nlights = 1; 141 | for (int i=0; i 0.0 ); 146 | L = normalize(L+(1.0-lightEnabled)); 147 | 148 | // Calculate lighting properties 149 | float lambertTerm = clamp( dot(N,L), 0.0, 1.0 ); 150 | vec3 H = normalize(L+V); // Halfway vector 151 | float specularTerm = pow( max(dot(H,N),0.0), u_shininess); 152 | 153 | // Calculate mask 154 | float mask1 = lightEnabled; 155 | 156 | // Calculate colors 157 | ambient_color += mask1 * u_ambient; // * gl_LightSource[i].ambient; 158 | diffuse_color += mask1 * lambertTerm; 159 | specular_color += mask1 * specularTerm * u_specular; 160 | }} 161 | 162 | // Calculate final color by componing different components 163 | final_color = color2 * ( ambient_color + diffuse_color) + specular_color; 164 | final_color.a = color2.a; 165 | 166 | // Done 167 | return final_color; -------------------------------------------------------------------------------- /test/utf8_example_text.jl: -------------------------------------------------------------------------------- 1 | const utf8_example_text = """ 2 | ∮ E⋅da = Q, n → ∞, ∑ f(i) = ∏ g(i), ∀x∈ℝ: ⌈x⌉ = −⌊−x⌋, α ∧ ¬β = ¬(¬α ∨ β), 3 | 4 | ℕ ⊆ ℕ₀ ⊂ ℤ ⊂ ℚ ⊂ ℝ ⊂ ℂ, ⊥ < a ≠ b ≡ c ≤ d ≪ ⊤ ⇒ (A ⇔ B), 5 | 6 | 2H₂ + O₂ ⇌ 2H₂O, R = 4.7 kΩ, ⌀ 200 mm 7 | 8 | Linguistics and dictionaries: 9 | 10 | ði ıntəˈnæʃənəl fəˈnɛtık əsoʊsiˈeıʃn 11 | Y [ˈʏpsilɔn], Yen [jɛn], Yoga [ˈjoːgɑ] 12 | 13 | APL: 14 | 15 | ((V⍳V)=⍳⍴V)/V←,V ⌷←⍳→⍴∆∇⊃‾⍎⍕⌈ 16 | 17 | Nicer typography in plain text files: 18 | 19 | ╔══════════════════════════════════════════╗ 20 | ║ ║ 21 | ║ • ‘single’ and “double” quotes ║ 22 | ║ ║ 23 | ║ • Curly apostrophes: “We’ve been here” ║ 24 | ║ ║ 25 | ║ • Latin-1 apostrophe and accents: '´` ║ 26 | ║ ║ 27 | ║ • ‚deutsche‘ „Anführungszeichen“ ║ 28 | ║ ║ 29 | ║ • †, ‡, ‰, •, 3–4, —, −5/+5, ™, … ║ 30 | ║ ║ 31 | ║ • ASCII safety test: 1lI|, 0OD, 8B ║ 32 | ║ ╭─────────╮ ║ 33 | ║ • the euro symbol: │ 14.95 € │ ║ 34 | ║ ╰─────────╯ ║ 35 | ╚══════════════════════════════════════════╝ 36 | 37 | Greek (in Polytonic): 38 | 39 | The Greek anthem: 40 | 41 | Σὲ γνωρίζω ἀπὸ τὴν κόψη 42 | τοῦ σπαθιοῦ τὴν τρομερή, 43 | σὲ γνωρίζω ἀπὸ τὴν ὄψη 44 | ποὺ μὲ βία μετράει τὴ γῆ. 45 | 46 | ᾿Απ᾿ τὰ κόκκαλα βγαλμένη 47 | τῶν ῾Ελλήνων τὰ ἱερά 48 | καὶ σὰν πρῶτα ἀνδρειωμένη 49 | χαῖρε, ὦ χαῖρε, ᾿Ελευθεριά! 50 | 51 | From a speech of Demosthenes in the 4th century BC: 52 | 53 | Οὐχὶ ταὐτὰ παρίσταταί μοι γιγνώσκειν, ὦ ἄνδρες ᾿Αθηναῖοι, 54 | ὅταν τ᾿ εἰς τὰ πράγματα ἀποβλέψω καὶ ὅταν πρὸς τοὺς 55 | λόγους οὓς ἀκούω· τοὺς μὲν γὰρ λόγους περὶ τοῦ 56 | τιμωρήσασθαι Φίλιππον ὁρῶ γιγνομένους, τὰ δὲ πράγματ᾿ 57 | εἰς τοῦτο προήκοντα, ὥσθ᾿ ὅπως μὴ πεισόμεθ᾿ αὐτοὶ 58 | πρότερον κακῶς σκέψασθαι δέον. οὐδέν οὖν ἄλλο μοι δοκοῦσιν 59 | οἱ τὰ τοιαῦτα λέγοντες ἢ τὴν ὑπόθεσιν, περὶ ἧς βουλεύεσθαι, 60 | οὐχὶ τὴν οὖσαν παριστάντες ὑμῖν ἁμαρτάνειν. ἐγὼ δέ, ὅτι μέν 61 | ποτ᾿ ἐξῆν τῇ πόλει καὶ τὰ αὑτῆς ἔχειν ἀσφαλῶς καὶ Φίλιππον 62 | τιμωρήσασθαι, καὶ μάλ᾿ ἀκριβῶς οἶδα· ἐπ᾿ ἐμοῦ γάρ, οὐ πάλαι 63 | γέγονεν ταῦτ᾿ ἀμφότερα· νῦν μέντοι πέπεισμαι τοῦθ᾿ ἱκανὸν 64 | προλαβεῖν ἡμῖν εἶναι τὴν πρώτην, ὅπως τοὺς συμμάχους 65 | σώσομεν. ἐὰν γὰρ τοῦτο βεβαίως ὑπάρξῃ, τότε καὶ περὶ τοῦ 66 | τίνα τιμωρήσεταί τις καὶ ὃν τρόπον ἐξέσται σκοπεῖν· πρὶν δὲ 67 | τὴν ἀρχὴν ὀρθῶς ὑποθέσθαι, μάταιον ἡγοῦμαι περὶ τῆς 68 | τελευτῆς ὁντινοῦν ποιεῖσθαι λόγον. 69 | 70 | Δημοσθένους, Γ´ ᾿Ολυνθιακὸς 71 | 72 | Georgian: 73 | 74 | From a Unicode conference invitation: 75 | 76 | გთხოვთ ახლავე გაიაროთ რეგისტრაცია Unicode-ის მეათე საერთაშორისო 77 | კონფერენციაზე დასასწრებად, რომელიც გაიმართება 10-12 მარტს, 78 | ქ. მაინცში, გერმანიაში. კონფერენცია შეჰკრებს ერთად მსოფლიოს 79 | ექსპერტებს ისეთ დარგებში როგორიცაა ინტერნეტი და Unicode-ი, 80 | ინტერნაციონალიზაცია და ლოკალიზაცია, Unicode-ის გამოყენება 81 | ოპერაციულ სისტემებსა, და გამოყენებით პროგრამებში, შრიფტებში, 82 | ტექსტების დამუშავებასა და მრავალენოვან კომპიუტერულ სისტემებში. 83 | 84 | Russian: 85 | 86 | From a Unicode conference invitation: 87 | 88 | Зарегистрируйтесь сейчас на Десятую Международную Конференцию по 89 | Unicode, которая состоится 10-12 марта 1997 года в Майнце в Германии. 90 | Конференция соберет широкий круг экспертов по вопросам глобального 91 | Интернета и Unicode, локализации и интернационализации, воплощению и 92 | применению Unicode в различных операционных системах и программных 93 | приложениях, шрифтах, верстке и многоязычных компьютерных системах. 94 | 95 | Thai (UCS Level 2): 96 | 97 | Excerpt from a poetry on The Romance of The Three Kingdoms (a Chinese 98 | classic 'San Gua'): 99 | 100 | [----------------------------|------------------------] 101 | ๏ แผ่นดินฮั่นเสื่อมโทรมแสนสังเวช พระปกเกศกองบู๊กู้ขึ้นใหม่ 102 | สิบสองกษัตริย์ก่อนหน้าแลถัดไป สององค์ไซร้โง่เขลาเบาปัญญา 103 | ทรงนับถือขันทีเป็นที่พึ่ง บ้านเมืองจึงวิปริตเป็นนักหนา 104 | โฮจิ๋นเรียกทัพทั่วหัวเมืองมา หมายจะฆ่ามดชั่วตัวสำคัญ 105 | เหมือนขับไสไล่เสือจากเคหา รับหมาป่าเข้ามาเลยอาสัญ 106 | ฝ่ายอ้องอุ้นยุแยกให้แตกกัน ใช้สาวนั้นเป็นชนวนชื่นชวนใจ 107 | พลันลิฉุยกุยกีกลับก่อเหตุ ช่างอาเพศจริงหนาฟ้าร้องไห้ 108 | ต้องรบราฆ่าฟันจนบรรลัย ฤๅหาใครค้ำชูกู้บรรลังก์ ฯ 109 | 110 | (The above is a two-column text. If combining characters are handled 111 | correctly, the lines of the second column should be aligned with the 112 | | character above.) 113 | 114 | Ethiopian: 115 | 116 | Proverbs in the Amharic language: 117 | 118 | ሰማይ አይታረስ ንጉሥ አይከሰስ። 119 | ብላ ካለኝ እንደአባቴ በቆመጠኝ። 120 | ጌጥ ያለቤቱ ቁምጥና ነው። 121 | ደሀ በሕልሙ ቅቤ ባይጠጣ ንጣት በገደለው። 122 | የአፍ ወለምታ በቅቤ አይታሽም። 123 | አይጥ በበላ ዳዋ ተመታ። 124 | ሲተረጉሙ ይደረግሙ። 125 | ቀስ በቀስ፥ ዕንቁላል በእግሩ ይሄዳል። 126 | ድር ቢያብር አንበሳ ያስር። 127 | ሰው እንደቤቱ እንጅ እንደ ጉረቤቱ አይተዳደርም። 128 | እግዜር የከፈተውን ጉሮሮ ሳይዘጋው አይድርም። 129 | የጎረቤት ሌባ፥ ቢያዩት ይስቅ ባያዩት ያጠልቅ። 130 | ሥራ ከመፍታት ልጄን ላፋታት። 131 | ዓባይ ማደሪያ የለው፥ ግንድ ይዞ ይዞራል። 132 | የእስላም አገሩ መካ የአሞራ አገሩ ዋርካ። 133 | ተንጋሎ ቢተፉ ተመልሶ ባፉ። 134 | ወዳጅህ ማር ቢሆን ጨርስህ አትላሰው። 135 | እግርህን በፍራሽህ ልክ ዘርጋ። 136 | 137 | Runes: 138 | 139 | ᚻᛖ ᚳᚹᚫᚦ ᚦᚫᛏ ᚻᛖ ᛒᚢᛞᛖ ᚩᚾ ᚦᚫᛗ ᛚᚪᚾᛞᛖ ᚾᚩᚱᚦᚹᛖᚪᚱᛞᚢᛗ ᚹᛁᚦ ᚦᚪ ᚹᛖᛥᚫ 140 | 141 | (Old English, which transcribed into Latin reads 'He cwaeth that he 142 | bude thaem lande northweardum with tha Westsae.' and means 'He said 143 | that he lived in the northern land near the Western Sea.') 144 | 145 | Braille: 146 | 147 | ⡌⠁⠧⠑ ⠼⠁⠒ ⡍⠜⠇⠑⠹⠰⠎ ⡣⠕⠌ 148 | 149 | ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠙⠑⠁⠙⠒ ⠞⠕ ⠃⠑⠛⠔ ⠺⠊⠹⠲ ⡹⠻⠑ ⠊⠎ ⠝⠕ ⠙⠳⠃⠞ 150 | ⠱⠁⠞⠑⠧⠻ ⠁⠃⠳⠞ ⠹⠁⠞⠲ ⡹⠑ ⠗⠑⠛⠊⠌⠻ ⠕⠋ ⠙⠊⠎ ⠃⠥⠗⠊⠁⠇ ⠺⠁⠎ 151 | ⠎⠊⠛⠝⠫ ⠃⠹ ⠹⠑ ⠊⠇⠻⠛⠹⠍⠁⠝⠂ ⠹⠑ ⠊⠇⠻⠅⠂ ⠹⠑ ⠥⠝⠙⠻⠞⠁⠅⠻⠂ 152 | ⠁⠝⠙ ⠹⠑ ⠡⠊⠑⠋ ⠍⠳⠗⠝⠻⠲ ⡎⠊⠗⠕⠕⠛⠑ ⠎⠊⠛⠝⠫ ⠊⠞⠲ ⡁⠝⠙ 153 | ⡎⠊⠗⠕⠕⠛⠑⠰⠎ ⠝⠁⠍⠑ ⠺⠁⠎ ⠛⠕⠕⠙ ⠥⠏⠕⠝ ⠰⡡⠁⠝⠛⠑⠂ ⠋⠕⠗ ⠁⠝⠹⠹⠔⠛ ⠙⠑ 154 | ⠡⠕⠎⠑ ⠞⠕ ⠏⠥⠞ ⠙⠊⠎ ⠙⠁⠝⠙ ⠞⠕⠲ 155 | 156 | ⡕⠇⠙ ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ 157 | 158 | ⡍⠔⠙⠖ ⡊ ⠙⠕⠝⠰⠞ ⠍⠑⠁⠝ ⠞⠕ ⠎⠁⠹ ⠹⠁⠞ ⡊ ⠅⠝⠪⠂ ⠕⠋ ⠍⠹ 159 | ⠪⠝ ⠅⠝⠪⠇⠫⠛⠑⠂ ⠱⠁⠞ ⠹⠻⠑ ⠊⠎ ⠏⠜⠞⠊⠊⠥⠇⠜⠇⠹ ⠙⠑⠁⠙ ⠁⠃⠳⠞ 160 | ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ ⡊ ⠍⠊⠣⠞ ⠙⠁⠧⠑ ⠃⠑⠲ ⠔⠊⠇⠔⠫⠂ ⠍⠹⠎⠑⠇⠋⠂ ⠞⠕ 161 | ⠗⠑⠛⠜⠙ ⠁ ⠊⠕⠋⠋⠔⠤⠝⠁⠊⠇ ⠁⠎ ⠹⠑ ⠙⠑⠁⠙⠑⠌ ⠏⠊⠑⠊⠑ ⠕⠋ ⠊⠗⠕⠝⠍⠕⠝⠛⠻⠹ 162 | ⠔ ⠹⠑ ⠞⠗⠁⠙⠑⠲ ⡃⠥⠞ ⠹⠑ ⠺⠊⠎⠙⠕⠍ ⠕⠋ ⠳⠗ ⠁⠝⠊⠑⠌⠕⠗⠎ 163 | ⠊⠎ ⠔ ⠹⠑ ⠎⠊⠍⠊⠇⠑⠆ ⠁⠝⠙ ⠍⠹ ⠥⠝⠙⠁⠇⠇⠪⠫ ⠙⠁⠝⠙⠎ 164 | ⠩⠁⠇⠇ ⠝⠕⠞ ⠙⠊⠌⠥⠗⠃ ⠊⠞⠂ ⠕⠗ ⠹⠑ ⡊⠳⠝⠞⠗⠹⠰⠎ ⠙⠕⠝⠑ ⠋⠕⠗⠲ ⡹⠳ 165 | ⠺⠊⠇⠇ ⠹⠻⠑⠋⠕⠗⠑ ⠏⠻⠍⠊⠞ ⠍⠑ ⠞⠕ ⠗⠑⠏⠑⠁⠞⠂ ⠑⠍⠏⠙⠁⠞⠊⠊⠁⠇⠇⠹⠂ ⠹⠁⠞ 166 | ⡍⠜⠇⠑⠹ ⠺⠁⠎ ⠁⠎ ⠙⠑⠁⠙ ⠁⠎ ⠁ ⠙⠕⠕⠗⠤⠝⠁⠊⠇⠲ 167 | 168 | (The first couple of paragraphs of "A Christmas Carol" by Dickens) 169 | 170 | Compact font selection example text: 171 | 172 | ABCDEFGHIJKLMNOPQRSTUVWXYZ /0123456789 173 | abcdefghijklmnopqrstuvwxyz £©µÀÆÖÞßéöÿ 174 | –—‘“”„†•…‰™œŠŸž€ ΑΒΓΔΩαβγδω АБВГДабвгд 175 | ∀∂∈ℝ∧∪≡∞ ↑↗↨↻⇣ ┐┼╔╘░►☺♀ fi�⑀₂ἠḂӥẄɐː⍎אԱა 176 | 177 | Greetings in various languages: 178 | 179 | Hello world, Καλημέρα κόσμε, コンニチハ 180 | 181 | Box drawing alignment tests: █ 182 | ▉ 183 | ╔══╦══╗ ┌──┬──┐ ╭──┬──╮ ╭──┬──╮ ┏━━┳━━┓ ┎┒┏┑ ╷ ╻ ┏┯┓ ┌┰┐ ▊ ╱╲╱╲╳╳╳ 184 | ║┌─╨─┐║ │╔═╧═╗│ │╒═╪═╕│ │╓─╁─╖│ ┃┌─╂─┐┃ ┗╃╄┙ ╶┼╴╺╋╸┠┼┨ ┝╋┥ ▋ ╲╱╲╱╳╳╳ 185 | ║│╲ ╱│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╿ │┃ ┍╅╆┓ ╵ ╹ ┗┷┛ └┸┘ ▌ ╱╲╱╲╳╳╳ 186 | ╠╡ ╳ ╞╣ ├╢ ╟┤ ├┼─┼─┼┤ ├╫─╂─╫┤ ┣┿╾┼╼┿┫ ┕┛┖┚ ┌┄┄┐ ╎ ┏┅┅┓ ┋ ▍ ╲╱╲╱╳╳╳ 187 | ║│╱ ╲│║ │║ ║│ ││ │ ││ │║ ┃ ║│ ┃│ ╽ │┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▎ 188 | ║└─╥─┘║ │╚═╤═╝│ │╘═╪═╛│ │╙─╀─╜│ ┃└─╂─┘┃ ░░▒▒▓▓██ ┊ ┆ ╎ ╏ ┇ ┋ ▏ 189 | ╚══╩══╝ └──┴──┘ ╰──┴──╯ ╰──┴──╯ ┗━━┻━━┛ └╌╌┘ ╎ ┗╍╍┛ ┋ ▁▂▃▄▅▆▇█ 190 | """ -------------------------------------------------------------------------------- /src/visualize/text.jl: -------------------------------------------------------------------------------- 1 | visualize_default(::Union(GPUVector{GLSprite}, AbstractString), ::Style, kw_args=Dict()) = Dict( 2 | :primitive => GLUVMesh2D(Rectangle(0f0, 0f0, 1f0, 1f0)), 3 | :styles => Texture([RGBAU8(1.0,1.0,1.0,1.0)]), 4 | :atlas => get_texture_atlas(), 5 | :technique => :sprite, 6 | :preferred_camera => :orthographic_pixel 7 | ) 8 | 9 | function visualize_default(::Union(GPUVector{GLSprite}, AbstractString), ::Style{:square}, kw_args=Dict()) 10 | return Dict( 11 | :primitive => GLUVMesh2D(Rectangle(0f0, 0f0, 1f0, 1f0)), 12 | :styles => Texture([RGBAU8(0,0,0,0), RGBAU8(0.7,.5,1.,0.5)]), 13 | :atlas => get_texture_atlas(), 14 | :technique => :square, 15 | :preferred_camera => :orthographic_pixel, 16 | ) 17 | end 18 | 19 | let TECHNIQUE_MAP = Dict( 20 | :sprite => Cint(1), 21 | :circle => Cint(2), 22 | :square => Cint(3), 23 | ) 24 | global to_gl_technique 25 | to_gl_technique(technique) = TECHNIQUE_MAP[technique] 26 | end 27 | 28 | 29 | function visualize(text::AbstractString, s::Style, customizations=visualize_default(text, s)) 30 | glyphs = GPUVector(texture_buffer(process_for_gl(text))) 31 | positions = GPUVector(texture_buffer(calc_position(glyphs))) 32 | style_index = GPUVector(texture_buffer(fill(GLSpriteStyle(0,0), length(text)))) 33 | visualize(glyphs, positions, style_index, customizations[:model], s, customizations) 34 | end 35 | 36 | function visualize( 37 | glyphs ::GPUVector{GLSprite}, 38 | positions ::GPUVector{Point2{Float16}}, 39 | style_index ::GPUVector{GLSpriteStyle}, 40 | model, 41 | s::Style, customizations=visualize_default(glyphs, s)) 42 | 43 | @materialize! atlas, primitive, technique = customizations 44 | data = merge(customizations, Dict( 45 | :model => model, 46 | :positions => positions, 47 | :glyphs => glyphs, 48 | :uvs => atlas.attributes, 49 | :images => atlas.images, 50 | :style_index => style_index, 51 | :technique => lift(to_gl_technique, technique) 52 | ), collect_for_gl(primitive)) 53 | 54 | shader = TemplateProgram( 55 | File(GLVisualize.shaderdir, "util.vert"), 56 | File(GLVisualize.shaderdir, "text.vert"), 57 | File(GLVisualize.shaderdir, "distance_shape.frag") 58 | ) 59 | bb = AABB(gpu_data(positions)) 60 | extent = FONT_EXTENDS[glyphs[1][1]] 61 | instanced_renderobject(data, glyphs, shader, Input(AABB{Float32}(bb.min, Vec3(bb.max)+Vec3(extent.advance..., 0f0)))) 62 | end 63 | 64 | 65 | cursor_visible(range) = isempty(range) && first(range) > 0 66 | cool_color(i) = RGBA(sin(i), 1f0, 1f0, 1f0) 67 | function cursor(positions, range, model) 68 | atlas = GLVisualize.get_texture_atlas() 69 | data = merge(Dict( 70 | :model => model, 71 | :visible => lift(cursor_visible, range), 72 | :offset => lift(Cint, lift(first, range)), 73 | :color => lift(cool_color, bounce(0f0:0.2f0:1f0)), 74 | :positions => positions, 75 | :glyph => Sprite{GLuint}(GLVisualize.get_font!('|')), 76 | :uvs => atlas.attributes.buffer, 77 | :images => atlas.images, 78 | :preferred_camera => :orthographic_pixel 79 | ), collect_for_gl(GLUVMesh2D(Rectangle(0f0, 0f0, 1f0, 1f0)))) 80 | 81 | shader = TemplateProgram( 82 | File(GLVisualize.shaderdir, "util.vert"), 83 | File(GLVisualize.shaderdir, "text_single.vert"), 84 | File(GLVisualize.shaderdir, "text.frag") 85 | ) 86 | std_renderobject(data, shader) 87 | end 88 | export cursor 89 | 90 | function update_positions(glyphs, text, styles_index) 91 | oldpos = text[:positions] 92 | positions = GLVisualize.calc_position(glyphs) 93 | if length(oldpos) != length(positions) 94 | oldlength = length(oldpos) 95 | newlength = length(positions) 96 | resize!(oldpos, newlength) 97 | resize!(styles_index, newlength) 98 | resize!(text[:style_index], newlength) 99 | styles_index[1:newlength] = fill(GLSpriteStyle(0,0), newlength) 100 | end 101 | update!(oldpos, positions) 102 | end 103 | 104 | function textedit_signals(inputs, background, text) 105 | @materialize unicodeinput, selection, buttonspressed, arrow_navigation, mousedragdiff_objectid = inputs 106 | # create object which can globally hold the text and selection 107 | text_raw = TextWithSelection(text[:glyphs], 0:0) 108 | text_edit = Input(text_raw) 109 | 110 | selection = lift( 111 | last, 112 | foldl( 113 | move_cursor, 114 | (selection.value, selection.value), 115 | arrow_navigation, selection, 116 | text_edit 117 | ) 118 | ) 119 | 120 | is_text(x) = x[2][1] == background.id || x[2][1] == text.id 121 | selection = keepwhen( 122 | lift(is_text, mousedragdiff_objectid), 123 | 0:0, selection 124 | ) 125 | lift(s->(text_edit.value.selection=s), selection) # is there really no other way?! 126 | 127 | strg_v = lift(==, buttonspressed, IntSet(GLFW.KEY_LEFT_CONTROL, GLFW.KEY_V)) 128 | strg_c = lift(==, buttonspressed, IntSet(GLFW.KEY_LEFT_CONTROL, GLFW.KEY_C)) 129 | strg_x = lift(==, buttonspressed, IntSet(GLFW.KEY_LEFT_CONTROL, GLFW.KEY_X)) 130 | del = lift(==, buttonspressed, IntSet(GLFW.KEY_BACKSPACE)) 131 | 132 | clipboard_copy = lift(copyclipboard, keepwhen(strg_c, true, strg_v), text_edit) 133 | 134 | delete_text = lift(deletetext, keepwhen(del, true, del), text_edit) 135 | cut_text = lift(deletetext, keepwhen(strg_x, true, strg_x), text_edit) 136 | 137 | 138 | clipboard_paste = lift(clipboardpaste, keepwhen(strg_v, true, strg_v)) 139 | 140 | text_gate = lift(isnotempty, unicodeinput) 141 | unicode_input = keepwhen(text_gate, Char['0'], unicodeinput) 142 | text_to_insert = merge(clipboard_paste, unicode_input) 143 | text_to_insert = lift(process_for_gl, text_to_insert) 144 | 145 | text_inserted = lift(inserttext, text_edit, text_to_insert) 146 | 147 | text_updates = merge( 148 | lift(return_nothing, text_inserted), 149 | lift(return_nothing, clipboard_copy), 150 | lift(return_nothing, delete_text), 151 | lift(return_nothing, cut_text), 152 | lift(return_nothing, selection) 153 | ) 154 | text_selection_signal = sampleon(text_updates, text_edit) 155 | 156 | selection = lift(x->x.selection, text_selection_signal) 157 | text_sig = lift(x->x.text, text_selection_signal) 158 | 159 | lift(update_positions, text_sig, Input(text), Input(background[:style_index])) 160 | foldl(visualize_selection, 0:0, selection, Input(background[:style_index])) 161 | lift(utf8, text_sig), selection 162 | end 163 | 164 | 165 | function vizzedit(glyphs::GPUVector{GLSprite}, text::RenderObject, inputs) 166 | background = visualize( 167 | glyphs, 168 | text[:positions], 169 | GPUVector(texture_buffer(fill(GLSpriteStyle(0,0), length(text[:positions])))), 170 | text[:model], 171 | Style{:square}() 172 | ) 173 | text_sig, selection = textedit_signals(inputs, background, text) 174 | cursor_robj = cursor(text[:positions], selection, text[:model]) 175 | 176 | (background, cursor_robj, text_sig) 177 | end 178 | export vizzedit -------------------------------------------------------------------------------- /src/visualize/text/utils.jl: -------------------------------------------------------------------------------- 1 | const newline_id = get_font!(Char(0x02E5)) 2 | isnewline(x) = x[1] == newline_id 3 | # i must be a valid character index 4 | function next_newline(text, i::Integer) 5 | res = findnext(isnewline, text, i) 6 | res == 0 ? length(text) : res 7 | end 8 | previous_newline(text, i::Integer) = max(1, findprev(isnewline, text, i)) 9 | 10 | export previous_newline 11 | export next_newline 12 | 13 | 14 | 15 | #= 16 | textextetext\n 17 | texttexttexttext\n 18 | texttexttext\n 19 | =# 20 | function down_after_newline(text, current_position) 21 | i = current_position 22 | pnl = previous_newline(text, i) 23 | nnl = next_newline(text, i) 24 | nl_distance = i-pnl # distance from previous newline 25 | min(length(text), nnl+nl_distance) 26 | end 27 | #= 28 | textextetext\n 29 | texttexttexttext\n 30 | texttexttext\n 31 | =# 32 | function up_before_newline(text, current_position) 33 | i = current_position 34 | pnl = previous_newline(text, i) 35 | ppnl = previous_newline(text, max(1, pnl-1)) 36 | nl_distance = i-pnl # distance from previous newline 37 | min(length(text), ppnl+nl_distance) 38 | end 39 | function move_cursor(t0, dir, mouseselection, text_selection) 40 | text, selection = text_selection.text, text_selection.selection 41 | mouseselection0, selection0 = t0 42 | selection0 = selection 43 | mouseselection0 != mouseselection && return (mouseselection, mouseselection) # if mouse selection has changed, return the new position 44 | if selection0 != 0:0 45 | first_i = first(selection0) # first is always valid, if its not zero 46 | # last is not valid, if selection is in between characters 47 | last_i = isempty(selection0) ? first(selection0) : last(selection0) # if only single char selected use first, otherwise last position of selection 48 | if dir == :up 49 | return (mouseselection, up_before_newline(text, first_i):0) #:0 -> movement changes selection into single point selection 50 | elseif dir == :down 51 | return (mouseselection, down_after_newline(text, last_i):0) 52 | elseif dir == :left 53 | return (mouseselection, max(1, first_i-1):0) 54 | elseif dir == :right 55 | return (mouseselection, min(length(text)+1,last_i+1):0) 56 | end 57 | end 58 | (mouseselection0, selection0) 59 | end 60 | export move_cursor 61 | 62 | 63 | function visualize_selection( 64 | last_selection::UnitRange{Int}, 65 | selection ::UnitRange{Int}, 66 | style ::GPUVector{GLSpriteStyle} 67 | ) 68 | fl, ll = first(last_selection), last(last_selection) 69 | if !isempty(last_selection) && fl > 0 && ll > 0 && (fl <= length(style)) && (ll <= length(style)) 70 | style[last_selection] = fill(GLSpriteStyle(0,0), length(last_selection)) 71 | end 72 | fs, ls = first(selection), last(selection) 73 | if !isempty(selection) && fs > 0 && ls > 0 && (fs <= length(style)) && (ls <= length(style)) 74 | style[selection] = fill(GLSpriteStyle(1,0), length(selection)) 75 | end 76 | selection 77 | end 78 | 79 | 80 | AND(a,b) = a&&b 81 | isnotempty(x) = !isempty(x) 82 | return_nothing(x...) = nothing 83 | export AND 84 | export isnotempty 85 | export return_nothing 86 | 87 | single_selection(selection::UnitRange) = isempty(selection) && first(selection)!=0 88 | is_textinput_modifiers(buttons::IntSet) = isempty(buttons) || buttons == IntSet(GLFW.KEY_LEFT_SHIFT) 89 | function clipboardpaste(_) 90 | clipboard_data = "" 91 | try 92 | clipboard_data = clipboard() 93 | catch e # clipboard throws error when there is no data (WTF) 94 | end 95 | return utf8(clipboard_data) 96 | end 97 | 98 | export clipboardpaste 99 | export copyclipboard 100 | 101 | function back2julia(x::GLSprite) 102 | isnewline(x[1]) && return '\n' 103 | ID_TO_CHAR[x[1]] 104 | end 105 | function Base.utf8(v::GPUVector{GLSprite}) 106 | data = gpu_data(v) 107 | utf8(join(map(back2julia, data))) 108 | end 109 | # lift will have a boolean value at first argument position 110 | copyclipboard(_, text_selection) = copyclipboard(text_selection) 111 | function copyclipboard(text_selection) 112 | selection, text = text_selection.selection, text_selection.text 113 | if first(selection) > 0 114 | if single_selection(selection) # for single selection we do a sublime style line copy 115 | #i = chr2ind(text, first(selection)) 116 | i = min(length(text), first(selection)) # can be on position behind last character 117 | pnl = previous_newline(text, i) 118 | nnl = next_newline(text, i) 119 | tocopy = text[pnl:nnl] 120 | else # must be range selection 121 | tocopy = text[selection] 122 | end 123 | clipboard(join(map(x->ID_TO_CHAR[x[1]], tocopy))) 124 | end 125 | nothing 126 | end 127 | export cutclipboard 128 | cutclipboard(_, text_selection) = cutclipboard(text_selection) 129 | function cutclipboard(text_selection) 130 | copyclipboard(text_selection) 131 | deletetext(text_selection) 132 | nothing 133 | end 134 | export deletetext 135 | deletetext(_, text_selection) = deletetext(text_selection) 136 | function deletetext(text_selection) 137 | selection, text = text_selection.selection, text_selection.text 138 | offset = 0 139 | if first(selection) > 0 && last(selection) > 0 140 | if single_selection(selection) 141 | splice!(text, last(selection)) 142 | offset = -1 143 | else 144 | splice!(text, selection) 145 | end 146 | text_selection.selection = max(1, first(selection)+offset):0 # when text gets removed, selection will turn into single selection 147 | end 148 | nothing 149 | end 150 | export inserttext 151 | inserttext(_, text_selection) = inserttext(text_selection) 152 | function inserttext(text_selection, to_insert) 153 | selection, text = text_selection.selection, text_selection.text 154 | if first(selection) > 0 155 | splice!(text, selection, to_insert) 156 | chars_added = length(to_insert) 157 | text_selection.selection = (first(selection)+chars_added):0 # when text gets removed, selection will turn into single selection 158 | end 159 | nothing 160 | end 161 | 162 | type TextWithSelection{S } #<: AbstractString} 163 | text::S 164 | selection::UnitRange{Int} 165 | end 166 | export TextWithSelection 167 | 168 | 169 | 170 | 171 | export visualize_selection 172 | 173 | 174 | calc_position(glyphs::GPUVector) = calc_position(gpu_data(glyphs)) 175 | function calc_position(glyphs) 176 | const PF16 = Point2{Float16} 177 | positions = fill(PF16(0.0), length(glyphs)) 178 | if !isempty(glyphs) 179 | global FONT_EXTENDS, ID_TO_CHAR 180 | last_pos = PF16(0.0) 181 | lastglyph = first(glyphs) 182 | newline_id = get_font!('\n') 183 | for (i,glyph) in enumerate(glyphs) 184 | extent = FONT_EXTENDS[glyph[1]] 185 | if isnewline(lastglyph) 186 | if i<2 187 | last_pos = PF16(last_pos.x, last_pos.y-extent.advance.y) 188 | else 189 | last_pos = PF16(first(positions).x, positions[i-1].y-extent.advance.y) 190 | end 191 | positions[i] = last_pos 192 | else 193 | last_pos += PF16(extent.advance.x, 0) 194 | finalpos = last_pos 195 | #finalpos = PF16(last_pos.x+extent.horizontal_bearing.x, last_pos.y-(extent.scale.y-extent.horizontal_bearing.y)) 196 | (i>1) && (finalpos += PF16(kerning(ID_TO_CHAR[lastglyph[1]], ID_TO_CHAR[glyph[1]], DEFAULT_FONT_FACE, 64f0))) 197 | positions[i] = finalpos 198 | end 199 | lastglyph = glyph 200 | end 201 | end 202 | positions 203 | end 204 | 205 | export process_for_gl 206 | 207 | function process_for_gl(text, tabs=4) 208 | result = GLSprite[] 209 | sizehint!(result, length(text)) 210 | for elem in text 211 | if elem == '\t' 212 | push!(result, fill(GLSprite(get_font!(' ')), tabs)...) 213 | elseif elem == '\r' 214 | #don't add 215 | elseif elem == '\n' 216 | push!(result, GLSprite(get_font!(Char(0x02E5)))) 217 | else 218 | push!(result, GLSprite(get_font!(elem))) 219 | end 220 | end 221 | return result 222 | end -------------------------------------------------------------------------------- /src/display/renderloop.jl: -------------------------------------------------------------------------------- 1 | const SELECTION = Dict{Symbol, Input{Matrix{Vector2{Int}}}}() 2 | const SELECTION_QUERIES = Dict{Symbol, Rectangle{Int}}() 3 | immutable SelectionID{T} 4 | objectid::T 5 | index::T 6 | end 7 | typealias GLSelection SelectionID{Uint16} 8 | typealias ISelection SelectionID{Int} 9 | function insert_selectionquery!(name::Symbol, value::Rectangle) 10 | SELECTION_QUERIES[name] = value 11 | SELECTION[name] = Input(Vector2{Int}[]') 12 | SELECTION[name] 13 | end 14 | function insert_selectionquery!(name::Symbol, value::Signal{Rectangle{Int}}) 15 | lift(value) do v 16 | SELECTION_QUERIES[name] = v 17 | end 18 | SELECTION[name] = Input(Array(Vector2{Int}, value.value.w, value.value.h)) 19 | SELECTION[name] 20 | end 21 | function delete_selectionquery!(name::Symbol) 22 | delete!(SELECTION_QUERIES, name) 23 | delete!(SELECTION, name) 24 | end 25 | 26 | 27 | windowhints = [ 28 | (GLFW.SAMPLES, 0), 29 | (GLFW.DEPTH_BITS, 0), 30 | (GLFW.ALPHA_BITS, 0), 31 | (GLFW.STENCIL_BITS, 0), 32 | (GLFW.AUX_BUFFERS, 0) 33 | ] 34 | 35 | const ROOT_SCREEN = createwindow("Romeo", 1920, 1280, windowhints=windowhints, debugging=false) 36 | const TIMER_SIGNAL = fpswhen(GLVisualize.ROOT_SCREEN.inputs[:open], 30.0) 37 | 38 | function fold_loop(v0, timediff_range) 39 | _, range = timediff_range 40 | v0 == last(range) && return first(range) 41 | v0+step(range) 42 | end 43 | 44 | loop(range::Range; t=TIMER_SIGNAL) = 45 | foldl(fold_loop, first(range), lift(tuple, t, range)) 46 | 47 | 48 | function fold_bounce(v0, v1) 49 | _, range = v1 50 | val, direction = v0 51 | val += step(range)*direction 52 | if val > last(range) || val < first(range) 53 | direction = -direction 54 | val += step(range)*direction 55 | end 56 | (val, direction) 57 | end 58 | 59 | bounce{T}(range::Range{T}; t=TIMER_SIGNAL) = 60 | lift(first, foldl(fold_bounce, (first(range), one(T)), lift(tuple, t, range))) 61 | 62 | insert_selectionquery!(:mouse_hover, lift(ROOT_SCREEN.inputs[:mouseposition]) do mpos 63 | Rectangle{Int}(round(Int, mpos[1]), round(Int, mpos[2]), 1,1) 64 | end) 65 | 66 | 67 | const FRAME_BUFFER_PARAMETERS = [ 68 | (GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE), 69 | (GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ), 70 | 71 | (GL_TEXTURE_MIN_FILTER, GL_NEAREST), 72 | (GL_TEXTURE_MAG_FILTER, GL_NEAREST) 73 | ] 74 | 75 | global const RENDER_FRAMEBUFFER = glGenFramebuffers() 76 | glBindFramebuffer(GL_FRAMEBUFFER, RENDER_FRAMEBUFFER) 77 | 78 | 79 | framebuffsize = [ROOT_SCREEN.inputs[:framebuffer_size].value...] 80 | const COLOR_BUFFER = Texture(RGBA{Ufixed8}, framebuffsize, parameters=FRAME_BUFFER_PARAMETERS) 81 | const STENCIL_BUFFER = Texture(Vector2{GLushort}, framebuffsize, parameters=FRAME_BUFFER_PARAMETERS) 82 | 83 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, COLOR_BUFFER.id, 0) 84 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, STENCIL_BUFFER.id, 0) 85 | 86 | const rboDepthStencil = GLuint[0] 87 | 88 | glGenRenderbuffers(1, rboDepthStencil) 89 | glBindRenderbuffer(GL_RENDERBUFFER, rboDepthStencil[1]) 90 | glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, framebuffsize...) 91 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rboDepthStencil[1]) 92 | 93 | lift(ROOT_SCREEN.inputs[:framebuffer_size]) do window_size 94 | if all(x->x>0, window_size) 95 | resize_nocopy!(COLOR_BUFFER, tuple(window_size...)) 96 | resize_nocopy!(STENCIL_BUFFER, tuple(window_size...)) 97 | glBindRenderbuffer(GL_RENDERBUFFER, rboDepthStencil[1]) 98 | glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, (window_size)...) 99 | end 100 | end 101 | 102 | 103 | postprocess_robj = postprocess(COLOR_BUFFER, ROOT_SCREEN) 104 | 105 | function renderloop() 106 | global ROOT_SCREEN 107 | while ROOT_SCREEN.inputs[:open].value 108 | renderloop(ROOT_SCREEN) 109 | end 110 | GLFW.Terminate() 111 | FreeTypeAbstraction.done() 112 | end 113 | 114 | 115 | function renderloop(screen) 116 | glDisable(GL_SCISSOR_TEST) 117 | glBindFramebuffer(GL_FRAMEBUFFER, RENDER_FRAMEBUFFER) 118 | glDrawBuffers(2, [GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1]) 119 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) 120 | 121 | render(screen) 122 | #Read all the selection queries 123 | if !isempty(SELECTION_QUERIES) 124 | glReadBuffer(GL_COLOR_ATTACHMENT1) 125 | for (key, value) in SELECTION_QUERIES 126 | if value.w < 1 || value.w > 5000 127 | println(value.w) # debug output 128 | end 129 | if value.h < 1 || value.h > 5000 130 | println(value.h) # debug output 131 | end 132 | const data = Array(Vector2{Uint16}, value.w, value.h) 133 | glReadPixels(value.x, value.y, value.w, value.h, STENCIL_BUFFER.format, STENCIL_BUFFER.pixeltype, data) 134 | push!(SELECTION[key], convert(Matrix{Vector2{Int}}, data)) 135 | end 136 | end 137 | glDisable(GL_SCISSOR_TEST) 138 | glFlush() 139 | glBindFramebuffer(GL_FRAMEBUFFER, 0) 140 | glViewport(screen.area.value) 141 | glClear(GL_COLOR_BUFFER_BIT) 142 | render(postprocess_robj) 143 | GLFW.SwapBuffers(screen.nativewindow) 144 | GLFW.PollEvents() 145 | yield() 146 | sleep(0.001) 147 | end 148 | 149 | glClearColor(0.09411764705882353,0.24058823529411763,0.2401960784313726, 0) 150 | 151 | 152 | 153 | 154 | 155 | # Transforms a mouse drag into a selection from drag start to drag end 156 | function drag2selectionrange(v0, selection) 157 | mousediff, id_start, current_id = selection 158 | if mousediff != Vec2(0) # Mouse Moved 159 | if current_id[1] == id_start[1] 160 | return min(id_start[2],current_id[2]):max(id_start[2],current_id[2]) 161 | end 162 | else # if mouse did not move while dragging, make a single point selection 163 | if current_id[1] == id_start[1] 164 | return current_id[2]:0 # this is the type stable way of indicating, that the selection is between currend_index 165 | end 166 | end 167 | v0 168 | end 169 | 170 | #Calculates mouse drag and supplies ID 171 | function to_mousedragg_id(t0, mouse_down1, mouseposition1, objectid) 172 | mouse_down0, draggstart, objectidstart, mouseposition0, objectid0 = t0 173 | if !mouse_down0 && mouse_down1 174 | return (mouse_down1, mouseposition1, objectid, mouseposition1, objectid) 175 | elseif mouse_down0 && mouse_down1 176 | return (mouse_down1, draggstart, objectidstart, mouseposition1, objectid) 177 | end 178 | (false, Vec2(0), Vector2(0), Vec2(0), Vector2(0)) 179 | end 180 | function diff_mouse(mouse_down_draggstart_mouseposition) 181 | mouse_down, draggstart, objectid_start, mouseposition, objectid_end = mouse_down_draggstart_mouseposition 182 | (draggstart - mouseposition, objectid_start, objectid_end) 183 | end 184 | function mousedragdiff_objectid(inputs, mouse_hover) 185 | @materialize mousebuttonspressed, mousereleased, mouseposition = inputs 186 | mousedown = lift(isnotempty, mousebuttonspressed) 187 | mousedraggdiff = lift(diff_mouse, 188 | foldl(to_mousedragg_id, (false, Vec2(0), Vector2(0), Vec2(0), Vector2(0)), 189 | mousedown, mouseposition, mouse_hover 190 | ) 191 | ) 192 | return keepwhen(mousedown, (Vec2(0), Vector2(0), Vector2(0)), mousedraggdiff) 193 | end 194 | 195 | function to_arrow_symbol(button_set) 196 | isempty(button_set) && return :nothing 197 | button = first(button_set) 198 | button == GLFW.KEY_RIGHT && return :right 199 | button == GLFW.KEY_LEFT && return :left 200 | button == GLFW.KEY_DOWN && return :down 201 | button == GLFW.KEY_UP && return :up 202 | return :nothing 203 | end 204 | 205 | function add_complex_signals(screen, selection) 206 | const mouse_hover = lift(first, selection[:mouse_hover]) 207 | 208 | mousedragdiff_id = mousedragdiff_objectid(screen.inputs, mouse_hover) 209 | selection = foldl(drag2selectionrange, 0:0, mousedragdiff_id) 210 | arrow_navigation = lift(to_arrow_symbol, screen.inputs[:buttonspressed]) 211 | 212 | screen.inputs[:mouse_hover] = mouse_hover 213 | screen.inputs[:mousedragdiff_objectid] = mousedragdiff_id 214 | screen.inputs[:selection] = selection 215 | screen.inputs[:arrow_navigation] = arrow_navigation 216 | end 217 | 218 | add_complex_signals(ROOT_SCREEN, SELECTION) #add the drag events and such --------------------------------------------------------------------------------