diff --git a/Project.toml b/Project.toml index 6781823..00c9cbc 100644 --- a/Project.toml +++ b/Project.toml @@ -1,15 +1,24 @@ name = "GLAbstraction" uuid = "ca6e7d0a-b0c9-59ca-8aba-aebf11497e1c" repo = "https://github.com/JuliaGL/GLAbstraction.jl.git" -version = "0.7.0" +version = "0.8.1" [deps] +ColorTypes = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" FixedPointNumbers = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" +Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" ModernGL = "66fc600b-dfda-50eb-8b99-91cfa97b1301" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" StaticArrays = "90137ffa-7385-5640-81b9-e52037218182" ThreadPools = "b189fb0b-2eb5-4ed4-bc0c-d34c51242431" +[compat] +FixedPointNumbers = "^0.8" +ModernGL = "^1" +StaticArrays = "^1" +ThreadPools = "^2" +julia = "^1" + [extras] ColorTypes = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" @@ -19,12 +28,5 @@ Images = "916415d5-f1e6-5110-898d-aaa5f9f070e0" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" -[compat] -FixedPointNumbers = "^0.8" -ModernGL = "^1" -StaticArrays = "^1" -ThreadPools = "^2" -julia = "^1" - [targets] test = ["Test", "GeometryBasics", "GLFW", "ColorTypes", "Images", "LinearAlgebra", "Downloads"] diff --git a/src/AbstractGPUArray.jl b/src/AbstractGPUArray.jl index 09e4d13..d526d71 100644 --- a/src/AbstractGPUArray.jl +++ b/src/AbstractGPUArray.jl @@ -11,17 +11,17 @@ import Base: eltype import Base: ndims import Base: size -abstract type GPUArray{T, NDim} <: AbstractArray{T, NDim} end +abstract type GPUArray{T,NDim} <: AbstractArray{T,NDim} end length(A::GPUArray) = prod(size(A)) -eltype(b::GPUArray{T, NDim}) where {T, NDim} = T +eltype(b::GPUArray{T,NDim}) where {T,NDim} = T endof(A::GPUArray) = length(A) -ndims(A::GPUArray{T, NDim}) where {T, NDim} = NDim +ndims(A::GPUArray{T,NDim}) where {T,NDim} = NDim size(A::GPUArray) = (A.len,) size(A::GPUArray, i::Integer) = i <= ndims(A) ? A.size[i] : 1 -function checkdimensions(value::Array, ranges::Union{Integer, UnitRange}...) - array_size = size(value) +function checkdimensions(value::Array, ranges::Union{Integer,UnitRange}...) + array_size = size(value) indexes_size = map(length, ranges) (array_size != indexes_size) && throw(DimensionMismatch("asigning a $array_size to a $(indexes_size) location")) true @@ -33,26 +33,26 @@ function to_range(index) @error "Indexing only defined for integers or ranges. Found: $val" end end -setindex!(A::GPUArray{T, N}, value::Union{T, Array{T, N}}) where {T, N} = (A[1] = value) +setindex!(A::GPUArray{T,N}, value::Union{T,Array{T,N}}) where {T,N} = (A[1] = value) -function setindex!(A::GPUArray{T, N}, value, indexes...) where {T, N} +function setindex!(A::GPUArray{T,N}, value, indexes...) where {T,N} ranges = to_range(indexes) v = isa(value, T) ? [value] : convert(Array{T,N}, value) setindex!(A, v, ranges...) nothing end -setindex!(A::GPUArray{T, 2}, value::Vector{T}, i::Integer, range::UnitRange) where {T} = - (A[i, range] = reshape(value, (length(value),1))) +setindex!(A::GPUArray{T,2}, value::Vector{T}, i::Integer, range::UnitRange) where {T} = + (A[i, range] = reshape(value, (length(value), 1))) -function setindex!(A::GPUArray{T, N}, value::Array{T, N}, ranges::UnitRange...) where {T, N} +function setindex!(A::GPUArray{T,N}, value::Array{T,N}, ranges::UnitRange...) where {T,N} checkbounds(A, ranges...) checkdimensions(value, ranges...) gpu_setindex!(A, value, ranges...) nothing end -function update!(A::GPUArray{T, N}, value::Array{T, N}) where {T, N} +function update!(A::GPUArray{T,N}, value::Array{T,N}) where {T,N} if length(A) != length(value) if isa(A, Buffer) resize!(A, length(value)) @@ -62,37 +62,37 @@ function update!(A::GPUArray{T, N}, value::Array{T, N}) where {T, N} @error "Dynamic resizing not implemented for $(typeof(A))" end end - dims = map(x->1:x, size(A)) + dims = map(x -> 1:x, size(A)) A[dims...] = value nothing end -function getindex(A::GPUArray{T, N}, i::Int) where {T, N} +function getindex(A::GPUArray{T,N}, i::Int) where {T,N} checkbounds(A, i) gpu_getindex(A, i:i)[1] # not as bad as its looks, as so far gpu data must be loaded into an array anyways end -function getindex(A::GPUArray{T, N}, ranges::UnitRange...) where {T, N} +function getindex(A::GPUArray{T,N}, ranges::UnitRange...) where {T,N} checkbounds(A, ranges...) gpu_getindex(A, ranges...) end -resize!(A::GPUArray{T, NDim}, dims::Int...) where {T, NDim} = resize!(A, dims) -function resize!(A::GPUArray{T, NDim}, newdims::NTuple{NDim, Int}) where {T, NDim} +resize!(A::GPUArray{T,NDim}, dims::Int...) where {T,NDim} = resize!(A, dims) +function resize!(A::GPUArray{T,NDim}, newdims::NTuple{NDim,Int}) where {T,NDim} newdims == size(A) && return A gpu_resize!(A, newdims) A end -copy!(a::GPUArray, a_offset::Int, b::Vector, b_offset::Int, amount::Int) = _copy!(a, a_offset, b, b_offset, amount) -copy!(a::Vector, a_offset::Int, b::GPUArray, b_offset::Int, amount::Int) = _copy!(a, a_offset, b, b_offset, amount) +copy!(a::GPUArray, a_offset::Int, b::Vector, b_offset::Int, amount::Int) = _copy!(a, a_offset, b, b_offset, amount) +copy!(a::Vector, a_offset::Int, b::GPUArray, b_offset::Int, amount::Int) = _copy!(a, a_offset, b, b_offset, amount) copy!(a::GPUArray, a_offset::Int, b::GPUArray, b_offset::Int, amount::Int) = _copy!(a, a_offset, b, b_offset, amount) #don't overwrite Base.copy! with a::Vector, b::Vector -function _copy!(a::Union{Vector, GPUArray}, a_offset::Int, b::Union{Vector, GPUArray}, b_offset::Int, amount::Int) +function _copy!(a::Union{Vector,GPUArray}, a_offset::Int, b::Union{Vector,GPUArray}, b_offset::Int, amount::Int) (amount <= 0) && return nothing - @assert a_offset > 0 && (a_offset-1) + amount <= length(a) "a_offset $a_offset, amount $amount, lengtha $(length(a))" - @assert b_offset > 0 && (b_offset-1) + amount <= length(b) "b_offset $b_offset, amount $amount, lengthb $(length(b))" + @assert a_offset > 0 && (a_offset - 1) + amount <= length(a) "a_offset $a_offset, amount $amount, lengtha $(length(a))" + @assert b_offset > 0 && (b_offset - 1) + amount <= length(b) "b_offset $b_offset, amount $amount, lengthb $(length(b))" unsafe_copy!(a, a_offset, b, b_offset, amount) return nothing end @@ -104,25 +104,6 @@ gpu_getindex(t) = @error "gpu_getindex not implemented for: $(typeof(t)). This h gpu_setindex!(t) = @error "gpu_setindex! not implemented for: $(typeof(t)). This happens, when you call setindex! on an array, without implementing the GPUArray interface" max_dim(t) = @error "max_dim not implemented for: $(typeof(t)). This happens, when you call setindex! on an array, without implementing the GPUArray interface" - -# const BaseSerializer = if isdefined(Base, :AbstractSerializer) -# Base.AbstractSerializer -# elseif isdefined(Base, :SerializationState) -# Base.SerializationState -# else -# error("No Serialization type found. Probably unsupported Julia version") -# end - -# function Base.serialize(s::BaseSerializer, t::T) where T<:GPUArray -# Base.serialize_type(s, T) -# serialize(s, Array(t)) -# end -# function Base.deserialize(s::BaseSerializer, ::Type{T}) where T<:GPUArray -# A = deserialize(s) -# T(A) -# end - - export data export resize export GPUArray diff --git a/src/GLAbstraction.jl b/src/GLAbstraction.jl index 2d8332b..2a8fb7f 100644 --- a/src/GLAbstraction.jl +++ b/src/GLAbstraction.jl @@ -1,15 +1,17 @@ module GLAbstraction +using ColorTypes using ModernGL using FixedPointNumbers using Printf using StaticArrays using ThreadPools using Base.Threads +using Logging import FixedPointNumbers: N0f8, N0f16, N0f8, Normed -import Base: merge, resize!, similar, length, getindex, setindex! +import Base: merge, resize!, similar, length, getindex, setindex! include("context.jl") @@ -40,7 +42,6 @@ include("utils.jl") include("buffer.jl") include("texture.jl") include("framebuffer.jl") -include("uniformbuffer.jl") include("shader/uniforms.jl") include("shader/shader.jl") include("shader/program.jl") diff --git a/src/buffer.jl b/src/buffer.jl index 02846cf..9eea35b 100644 --- a/src/buffer.jl +++ b/src/buffer.jl @@ -1,12 +1,12 @@ import Base.Iterators.Repeated -mutable struct Buffer{T} <: GPUArray{T, 1} - id ::GLuint - len ::Int +mutable struct Buffer{T} <: GPUArray{T,1} + id::GLuint + len::Int buffertype::GLenum - usage ::GLenum - context ::Context - function Buffer{T}(cpu_data_ptr::Ptr{T}, buff_length::Int, buffertype::GLenum, usage::GLenum) where T + usage::GLenum + context::Context + function Buffer{T}(cpu_data_ptr::Ptr{T}, buff_length::Int, buffertype::GLenum, usage::GLenum) where {T} id = glGenBuffers() # size of 0 can segfault it seems buff_length = buff_length == 0 ? 1 : buff_length @@ -18,33 +18,33 @@ mutable struct Buffer{T} <: GPUArray{T, 1} end #Function to deal with any Immutable type with Real as Subtype function Buffer( - buffer::Union{DenseVector{T}, SubArray{T}}; - buffertype::GLenum = GL_ARRAY_BUFFER, usage::GLenum = GL_STATIC_DRAW - ) where T <: Real + buffer::Union{DenseVector{T},SubArray{T}}; + buffertype::GLenum=GL_ARRAY_BUFFER, usage::GLenum=GL_STATIC_DRAW +) where {T<:Real} Buffer{T}(pointer(buffer), length(buffer), buffertype, usage) end function Buffer( - buffer::Union{DenseVector{T}, SubArray{T}}; - buffertype::GLenum = GL_ARRAY_BUFFER, usage::GLenum = GL_STATIC_DRAW - ) where T + buffer::Union{DenseVector{T},SubArray{T}}; + buffertype::GLenum=GL_ARRAY_BUFFER, usage::GLenum=GL_STATIC_DRAW +) where {T} glasserteltype(T) Buffer{T}(pointer(buffer), length(buffer), buffertype, usage) end function Buffer( - ::Type{T}, len::Int; - buffertype::GLenum = GL_ARRAY_BUFFER, usage::GLenum = GL_STATIC_DRAW - ) where T + ::Type{T}, len::Int; + buffertype::GLenum=GL_ARRAY_BUFFER, usage::GLenum=GL_STATIC_DRAW +) where {T} glasserteltype(T) Buffer{T}(Ptr{T}(C_NULL), len, buffertype, usage) end free!(x::Buffer) = - context_command( () -> glDeleteBuffers(1, [x.id]), x.context) + context_command(() -> glDeleteBuffers(1, [x.id]), x.context) Base.show(io::IO, ::MIME"text/plain", b::Buffer) = show(io, b) function Base.show(io::IO, b::Buffer) - + if !get(io, :compact, false) println(io, "$(b.len)-element $(typeof(b)):") println(io, "\tid = $(b.id)") @@ -53,17 +53,16 @@ function Base.show(io::IO, b::Buffer) else print(io, "$(typeof(b))") end -end +end function indexbuffer( - buffer::Vector{T}; - usage::GLenum = GL_STATIC_DRAW - ) where T + buffer::Vector{T}; + usage::GLenum=GL_STATIC_DRAW +) where {T} glasserteltype(T) - Buffer(buffer, buffertype = GL_ELEMENT_ARRAY_BUFFER, usage=usage) + Buffer(buffer, buffertype=GL_ELEMENT_ARRAY_BUFFER, usage=usage) end indexbuffer(x::Buffer) = x.buffertype == GL_ELEMENT_ARRAY_BUFFER ? x : @error "Indexbuffer must be of enum GL_ELEMENT_ARRAY_BUFFER!" -#-------------------------------- END CONSTRUCTORS -------------------------------------# Base.length(x::Buffer) = x.len @@ -94,69 +93,67 @@ cardinality(::Buffer{T}) where {T} = cardinality(T) bind(buffer::Buffer) = glBindBuffer(buffer.buffertype, buffer.id) #used to reset buffer target bind(buffer::Buffer, other_target) = glBindBuffer(buffer.buffertype, other_target) -unbind(buffer::Buffer) = glBindBuffer(buffer.buffertype, buffer.id) +unbind(buffer::Buffer) = glBindBuffer(buffer.buffertype, 0) -Base.convert(::Type{Buffer}, x::Buffer) = x -Base.convert(::Type{Buffer}, x::Array) = Buffer(x) +Base.convert(::Type{Buffer}, x::Buffer) = x +Base.convert(::Type{Buffer}, x::Array) = Buffer(x) Base.convert(::Type{Buffer}, x::Repeated) = convert(Buffer, x.xs.x) #TODO: implement iteration -function Base.similar(x::Buffer{T}, buff_length::Int) where T +function Base.similar(x::Buffer{T}, buff_length::Int) where {T} Buffer{T}(Ptr{T}(C_NULL), buff_length, x.buffertype, x.usage) end # copy between two buffers # could be a setindex! operation, with subarrays for buffers -function Base.unsafe_copyto!(a::Buffer{T}, readoffset::Int, b::Buffer{T}, writeoffset::Int, len::Int) where T +function Base.unsafe_copyto!(a::Buffer{T}, readoffset::Int, b::Buffer{T}, writeoffset::Int, len::Int) where {T} multiplicator = sizeof(T) glBindBuffer(GL_COPY_READ_BUFFER, a.id) glBindBuffer(GL_COPY_WRITE_BUFFER, b.id) glCopyBufferSubData( GL_COPY_READ_BUFFER, GL_COPY_WRITE_BUFFER, - multiplicator*(readoffset-1), - multiplicator*(writeoffset-1), - multiplicator*len + multiplicator * (readoffset - 1), + multiplicator * (writeoffset - 1), + multiplicator * len ) glBindBuffer(GL_COPY_READ_BUFFER, 0) glBindBuffer(GL_COPY_WRITE_BUFFER, 0) return nothing end #copy inside one buffer -function Base.unsafe_copyto!(buffer::Buffer{T}, readoffset::Int, writeoffset::Int, len::Int) where T +function Base.unsafe_copyto!(buffer::Buffer{T}, readoffset::Int, writeoffset::Int, len::Int) where {T} len <= 0 && return nothing bind(buffer) ptr = Ptr{T}(glMapBuffer(buffer.buffertype, GL_READ_WRITE)) - for i=1:len+1 - unsafe_store!(ptr, unsafe_load(ptr, i+readoffset-1), i+writeoffset-1) + for i = 1:len+1 + unsafe_store!(ptr, unsafe_load(ptr, i + readoffset - 1), i + writeoffset - 1) end glUnmapBuffer(buffer.buffertype) - bind(buffer,0) + bind(buffer, 0) return nothing end -function Base.unsafe_copyto!(a::Vector{T}, readoffset::Int, b::Buffer{T}, writeoffset::Int, len::Int) where T +function Base.unsafe_copyto!(a::Vector{T}, readoffset::Int, b::Buffer{T}, writeoffset::Int, len::Int) where {T} bind(b) ptr = Ptr{T}(glMapBuffer(b.buffertype, GL_WRITE_ONLY)) - for i=1:len - unsafe_store!(ptr, a[i+readoffset-1], i+writeoffset-1) + for i = 1:len + unsafe_store!(ptr, a[i+readoffset-1], i + writeoffset - 1) end glUnmapBuffer(b.buffertype) - bind(b,0) + bind(b, 0) end -function Base.unsafe_copyto!(a::Buffer{T}, readoffset::Int, b::Vector{T}, writeoffset::Int, len::Int) where T +function Base.unsafe_copyto!(a::Buffer{T}, readoffset::Int, b::Vector{T}, writeoffset::Int, len::Int) where {T} bind(a) ptr = Ptr{T}(glMapBuffer(a.buffertype, GL_READ_ONLY)) - for i=1:len - b[i+writeoffset-1] = unsafe_load(ptr, i+readoffset-2) #-2 => -1 to zero offset, -1 gl indexing starts at 0 + for i = 1:len + b[i+writeoffset-1] = unsafe_load(ptr, i + readoffset - 2) #-2 => -1 to zero offset, -1 gl indexing starts at 0 end glUnmapBuffer(a.buffertype) - bind(a,0) + bind(a, 0) end -#--------------------------------- END BASEOVERLOADS-----------------------------------# - # GPUArray interface -function gpu_data(b::Buffer{T}) where T +function gpu_data(b::Buffer{T}) where {T} data = Vector{T}(undef, length(b)) bind(b) glGetBufferSubData(b.buffertype, 0, sizeof(data), data) @@ -165,50 +162,45 @@ function gpu_data(b::Buffer{T}) where T end # Resize buffer -function gpu_resize!(buffer::Buffer{T}, newdims::NTuple{1, Int}) where T +function gpu_resize!(buffer::Buffer{T}, newdims::NTuple{1,Int}) where {T} #TODO make this safe! newlength = newdims[1] - oldlen = length(buffer) + oldlen = length(buffer) if oldlen > 0 old_data = gpu_data(buffer) end bind(buffer) - glBufferData(buffer.buffertype, newlength*sizeof(T), C_NULL, buffer.usage) + glBufferData(buffer.buffertype, newlength * sizeof(T), C_NULL, buffer.usage) bind(buffer, 0) buffer.length = newdims - if oldlen>0 + if oldlen > 0 max_len = min(length(old_data), newlength) #might also shrink buffer[1:max_len] = old_data[1:max_len] end - #probably faster, but changes the buffer ID - # newbuff = similar(buffer, newdims...) - # unsafe_copy!(buffer, 1, newbuff, 1, length(buffer)) - # buffer.id = newbuff.id - # buffer.length = newbuff.length nothing end -function gpu_setindex!(b::Buffer{T}, value::Vector{T}, offset::Integer) where T +function gpu_setindex!(b::Buffer{T}, value::Vector{T}, offset::Integer) where {T} multiplicator = sizeof(T) bind(b) - glBufferSubData(b.buffertype, multiplicator*offset-1, sizeof(value), value) + glBufferSubData(b.buffertype, multiplicator * offset - 1, sizeof(value), value) bind(b, 0) end -function gpu_setindex!(b::Buffer{T}, value::Vector{T}, offset::UnitRange{Int}) where T +function gpu_setindex!(b::Buffer{T}, value::Vector{T}, offset::UnitRange{Int}) where {T} multiplicator = sizeof(T) bind(b) - glBufferSubData(b.buffertype, multiplicator*(first(offset)-1), sizeof(value), value) + glBufferSubData(b.buffertype, multiplicator * (first(offset) - 1), sizeof(value), value) bind(b, 0) return nothing end -function gpu_getindex(b::Buffer{T}, range::UnitRange) where T +function gpu_getindex(b::Buffer{T}, range::UnitRange) where {T} multiplicator = sizeof(T) - offset = first(range)-1 - value = Vector{T}(undef, length(range)) + offset = first(range) - 1 + value = Vector{T}(undef, length(range)) bind(b) - glGetBufferSubData(b.buffertype, multiplicator*offset, sizeof(value), value) + glGetBufferSubData(b.buffertype, multiplicator * offset, sizeof(value), value) bind(b, 0) value end diff --git a/src/for_moderngl.jl b/src/for_moderngl.jl index 1ede135..bf8d8de 100644 --- a/src/for_moderngl.jl +++ b/src/for_moderngl.jl @@ -20,9 +20,9 @@ function glShaderSource(shaderID::GLuint, shadercode::Vector{UInt8}) end glShaderSource(shaderID::GLuint, shadercode::String) = glShaderSource(shaderID, Vector{UInt8}(shadercode)) function glGetAttachedShaders(program::GLuint) - shader_count = glGetProgramiv(program, GL_ATTACHED_SHADERS) + shader_count = glGetProgramiv(program, GL_ATTACHED_SHADERS) length_written = GLsizei[0] - shaders = zeros(GLuint, shader_count) + shaders = Array{GLuint}(undef, shader_count) glGetAttachedShaders(program, shader_count, length_written, shaders) shaders[1:first(length_written)] @@ -35,15 +35,15 @@ function ModernGL.glGetActiveUniformsiv(program::GLuint, index, var::GLenum) end function glGetActiveUniform(programID::GLuint, index::Integer) - actualLength = GLsizei[1] - uniformSize = GLint[1] - typ = GLenum[1] - maxcharsize = glGetProgramiv(programID, GL_ACTIVE_UNIFORM_MAX_LENGTH) - name = zeros(GLchar, maxcharsize) + actualLength = GLsizei[1] + uniformSize = GLint[1] + typ = GLenum[1] + maxcharsize = glGetProgramiv(programID, GL_ACTIVE_UNIFORM_MAX_LENGTH) + name = Array{GLchar}(undef, maxcharsize) glGetActiveUniform(programID, index, maxcharsize, actualLength, uniformSize, typ, name) - actualLength[1] <= 0 && @error "No active uniform at given index. Index: $index" + actualLength[1] <= 0 && @error "No active uniform at given index. Index: $index" uname = unsafe_string(pointer(name), actualLength[1]) uname = Symbol(replace(uname, r"\[\d*\]" => "")) # replace array brackets. This is not really a good solution. @@ -52,11 +52,11 @@ end glGetActiveUniformName(program::GLuint, index::Integer) = glGetActiveUniform(program, index)[1] function glGetActiveAttrib(programID::GLuint, index::Integer) - actualLength = GLsizei[1] - attributeSize = GLint[1] - typ = GLenum[1] - maxcharsize = glGetProgramiv(programID, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH) - name = zeros(GLchar, maxcharsize) + actualLength = GLsizei[1] + attributeSize = GLint[1] + typ = GLenum[1] + maxcharsize = glGetProgramiv(programID, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH) + name = Array{GLchar}(undef, maxcharsize) glGetActiveAttrib(programID, index, maxcharsize, actualLength, attributeSize, typ, name) @@ -77,7 +77,7 @@ function glGetIntegerv(variable::GLenum) result[] end -function glGenBuffers(n=1) +function glGenBuffers(n = 1) result = GLuint[0] glGenBuffers(1, result) id = result[] @@ -115,41 +115,32 @@ function glGenFramebuffers() end function glDeleteTextures(id::GLuint) - arr = [id] - glDeleteTextures(1, arr) + arr = [id] + glDeleteTextures(1, arr) end function glDeleteVertexArrays(id::GLuint) - arr = [id] - glDeleteVertexArrays(1, arr) + arr = [id] + glDeleteVertexArrays(1, arr) end function glDeleteBuffers(id::GLuint) - arr = [id] - glDeleteBuffers(1, arr) + arr = [id] + glDeleteBuffers(1, arr) end function glGetTexLevelParameteriv(target::GLenum, level, name::GLenum) - result = GLint[0] - glGetTexLevelParameteriv(target, level, name, result) - result[1] -end - -function glGenRenderbuffers(format::GLenum, attachment::GLenum, dimensions) - renderbuffer = GLuint[0] - glGenRenderbuffers(1, renderbuffer) - glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer[1]) - glRenderbufferStorage(GL_RENDERBUFFER, format, dimensions...) - glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, renderbuffer[1]) - renderbuffer[1] + result = GLint[0] + glGetTexLevelParameteriv(target, level, name, result) + result[1] end function glTexImage(ttype::GLenum, level::Integer, internalFormat::GLenum, w::Integer, h::Integer, d::Integer, border::Integer, format::GLenum, datatype::GLenum, data) glTexImage3D(GL_PROXY_TEXTURE_3D, level, internalFormat, w, h, d, border, format, datatype, C_NULL) - for l in 0:level + for l in 0:level result = glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, l, GL_TEXTURE_WIDTH) if result == 0 @error "glTexImage 3D: width too large. Width: $w" end - result = glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, l,GL_TEXTURE_HEIGHT) + result = glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, l, GL_TEXTURE_HEIGHT) if result == 0 @error "glTexImage 3D: height too large. height: $h" end diff --git a/src/framebuffer.jl b/src/framebuffer.jl index 5938d0b..b472b57 100644 --- a/src/framebuffer.jl +++ b/src/framebuffer.jl @@ -4,36 +4,49 @@ GL_COLOR_ATTACHMENT(i) = GLuint(GL_COLOR_ATTACHMENT0 + i) Holds the id, format and attachment of an OpenGL RenderBuffer. RenderBuffers cannot be read by Shaders. """ -mutable struct RenderBuffer - id ::GLuint - format ::GLenum - attachment::GLenum - context ::Context - size ::Tuple{Int, Int} - function RenderBuffer(format::GLenum, attachment::GLenum, dimensions) +mutable struct RenderBuffer{T} + id::GLuint + format::GLenum + pixeltype::GLenum + context::Context + size::Tuple{Int,Int} + function RenderBuffer{T}(format::GLenum, dimensions) where {T} @assert length(dimensions) == 2 - id = glGenRenderbuffers(format, attachment, dimensions) - obj = new(id, format, attachment, current_context(), dimensions) + rbo = GLuint[0] + glGenRenderbuffers(1, rbo) + id = rbo[1] + glBindRenderbuffer(GL_RENDERBUFFER, id) + glRenderbufferStorage(GL_RENDERBUFFER, format, dimensions...) + if T <: DepthFormat + obj = new(id, format, GL_FLOAT, current_context(), dimensions) + else + obj = new(id, format, julia2glenum(eltype(T)), current_context(), dimensions) + end finalizer(free!, obj) obj end end -"Creates a `RenderBuffer` with purpose for the `depth` component of a `FrameBuffer`." -function RenderBuffer(depth_format, dimensions) - return RenderBuffer(gl_internal_format(depth_format), gl_attachment(depth_format), dimensions) +"Creates a `RenderBuffer` with purpose for the depth component `T` of a `FrameBuffer`." +function RenderBuffer(::Type{T}, dimensions) where {T<:DepthFormat} + RenderBuffer{T}(gl_internal_format(T), dimensions) +end + +function RenderBuffer(::Type{T}, dimensions) where {T} + RenderBuffer{T}(textureformat_from_type(T), dimensions) end free!(rb::RenderBuffer) = context_command(() -> glDeleteRenderbuffers(1, [rb.id]), rb.context) bind(b::RenderBuffer) = glBindRenderbuffer(GL_RENDERBUFFER, b.id) -unbind(b::RenderBuffer) = glBindRenderbuffer(GL_RENDERBUFFER, b.id) +unbind(::RenderBuffer) = glBindRenderbuffer(GL_RENDERBUFFER, 0) Base.size(b::RenderBuffer) = b.size -width(b::RenderBuffer) = size(b, 1) +Base.eltype(r::RenderBuffer{T}) where {T} = T +width(b::RenderBuffer) = size(b, 1) height(b::RenderBuffer) = size(b, 2) -depth(b::RenderBuffer) = size(b, 3) #possible need to assert +depth(b::RenderBuffer) = size(b, 3) #possible need to assert function resize_nocopy!(b::RenderBuffer, dimensions) bind(b) @@ -46,24 +59,23 @@ A FrameBuffer holds all the data related to the usual OpenGL FrameBufferObjects. The `attachments` field gets mapped to the different possible GL_COLOR_ATTACHMENTs, which is bound by GL_MAX_COLOR_ATTACHMENTS, and to one of either a GL_DEPTH_ATTACHMENT or GL_DEPTH_STENCIL_ATTACHMENT. """ -mutable struct FrameBuffer{ElementTypes, T} - id ::GLuint +mutable struct FrameBuffer{ElementTypes,T} + id::GLuint attachments::T - context ::Context - function FrameBuffer(fb_size::NTuple{2, Int}, attachments::Union{Texture, RenderBuffer}...; kwargs...) + context::Context + function FrameBuffer(fb_size::NTuple{2,Int}, attachments::Union{Texture,RenderBuffer}...; kwargs...) framebuffer = glGenFramebuffers() glBindFramebuffer(GL_FRAMEBUFFER, framebuffer) max_ca = glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS) - depth_attachments = Union{Texture, RenderBuffer}[] + depth_attachments = Union{Texture,RenderBuffer}[] for (i, a) in enumerate(attachments) if eltype(a) <: DepthFormat push!(depth_attachments, a) else - attach2framebuffer(a, GL_COLOR_ATTACHMENT(i-1)) + attach2framebuffer(a, GL_COLOR_ATTACHMENT(i - 1)) end end - if length(depth_attachments) > 1 error("The amount of DepthFormat types in texture types exceeds the maximum of 1.") @@ -73,65 +85,79 @@ mutable struct FrameBuffer{ElementTypes, T} if N > max_ca error("The length of texture types exceeds the maximum amount of framebuffer color attachments! Found: $N, allowed: $max_ca") end - + !isempty(depth_attachments) && attach2framebuffer(depth_attachments[1]) - #this is done so it's a tuple. Not entirely sure why thats better than an - #array? - _attachments = (attachments...,depth_attachments...,) - @assert glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE "FrameBuffer (id $framebuffer) with attachments $attachment_types failed to be created." + @assert glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE "FrameBuffer (id $framebuffer) with attachments $attachments failed to be created." glBindFramebuffer(GL_FRAMEBUFFER, 0) - obj = new{Tuple{eltype.(_attachments)...}, typeof(_attachments)}(framebuffer, _attachments, current_context()) + obj = new{Tuple{eltype.(attachments)...},typeof(attachments)}(framebuffer, attachments, current_context()) finalizer(free!, obj) return obj end function FrameBuffer(::Val{0}) - obj = new{Val{0}, Vector{Nothing}}(0, [nothing]) + obj = new{Val{0},Vector{Nothing}}(0, [nothing]) return obj end end # Constructor that takes care of creating the FBO with the specified types and then filling in the data # Might be a bit stupid not to just put this into the main constructor -function FrameBuffer(fb_size::Tuple{<: Integer, <: Integer}, texture_types, texture_data::Vector{<:Matrix}; kwargs...) - fbo = FrameBuffer(fb_size, texture_types; kwargs...) - for (data, attachment) in zip(texture_data, fbo.attachments) - xrange = 1:size(data)[1] - yrange = 1:size(data)[2] - gpu_setindex!(attachment, data, xrange, yrange) - end - return fbo +function FrameBuffer(fb_size::Tuple{<:Integer,<:Integer}, texture_types, texture_data::Vector{<:Matrix}; kwargs...) + fbo = FrameBuffer(fb_size, texture_types; kwargs...) + for (data, attachment) in zip(texture_data, fbo.attachments) + xrange = 1:size(data)[1] + yrange = 1:size(data)[2] + gpu_setindex!(attachment, data, xrange, yrange) + end + return fbo +end + +function Base.show(io::IO, f::GLAbstraction.FrameBuffer{ET,Internals}) where {ET,Internals} + println(io, "Framebuffer: ") + println(io, " ID: ", f.id) + for a in f.attachments + println() + show(io, a) + end end +Base.display(f::GLAbstraction.FrameBuffer{ET,Internals}) where {ET,Internals} = Base.show(stdout, f) context_framebuffer() = FrameBuffer(Val(0)) -function attach2framebuffer(t::Texture{T, 2}, attachment) where T +function attach2framebuffer(t::Texture, attachment) glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, t.id, 0) end -function attach2framebuffer(t::Texture{T, 2}) where {T <: DepthFormat} +function attach2framebuffer(t::Texture{<:Any,3}, attachment) + glFramebufferTexture3D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_3D, t.id, 0, 0) +end +function attach2framebuffer(x::RenderBuffer, attachment) + glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, x.id) +end +function attach2framebuffer(t::Texture{T,2}) where {T<:DepthFormat} glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attachment(T), GL_TEXTURE_2D, t.id, 0) end -function attach2framebuffer(x::RenderBuffer) - glFramebufferRenderbuffer(GL_FRAMEBUFFER, x.attachment, GL_RENDERBUFFER, x.id) +function attach2framebuffer(x::RenderBuffer{T}) where {T<:DepthFormat} + glFramebufferRenderbuffer(GL_FRAMEBUFFER, gl_attachment(T), GL_RENDERBUFFER, x.id) end + function free!(fb::FrameBuffer) for attachment in fb.attachments free!(attachment) end - context_command(fb.context, () -> glDeleteFramebuffers(1, [fb.id])) + context_command(() -> glDeleteFramebuffers(1, [fb.id]), fb.context) return end Base.size(fb::FrameBuffer) = size(fb.attachments[1]) -width(fb::FrameBuffer) = size(fb, 1) -height(fb::FrameBuffer) = size(fb, 2) -depth(fb::FrameBuffer) = size(fb, 3) +width(fb::FrameBuffer) = size(fb, 1) +height(fb::FrameBuffer) = size(fb, 2) +depth(fb::FrameBuffer) = size(fb, 3) -eltypes(fb::FrameBuffer{elt}) where elt = elt.parameters -attachtypes(fb::FrameBuffer{elt, int}) where {elt,int} = int.parameters +eltypes(fb::FrameBuffer{elt}) where {elt} = elt.parameters +attachtypes(fb::FrameBuffer{elt,int}) where {elt,int} = int.parameters -Base.resize!(fb::FrameBuffer{Val{0}, Vector{Nothing}}, dimensions) = glViewport(0, 0, dimensions...) +Base.resize!(fb::FrameBuffer{Val{0},Vector{Nothing}}, dimensions) = glViewport(0, 0, dimensions...) function Base.resize!(fb::FrameBuffer, dimensions) ws = dimensions[1], dimensions[2] @@ -145,7 +171,7 @@ function Base.resize!(fb::FrameBuffer, dimensions) end bind(fb::FrameBuffer, target=GL_FRAMEBUFFER) = glBindFramebuffer(target, fb.id) -unbind(fb::FrameBuffer) = glBindFramebuffer(GL_FRAMEBUFFER, 0) +unbind(::FrameBuffer, target=GL_FRAMEBUFFER) = glBindFramebuffer(target, 0) #I think a lot could be optimized when knowing for sure whether an FBO has depth @@ -154,12 +180,12 @@ function draw(fb::FrameBuffer) ntexts = length(color_attachments(fb)) glDrawBuffers(GLuint(ntexts), GL_COLOR_ATTACHMENT.(0:ntexts-1)) end -draw(fb::FrameBuffer, i::Int) = glDrawBuffer(GL_COLOR_ATTACHMENT.(i-1)) +draw(fb::FrameBuffer, i::Int) = glDrawBuffer(GL_COLOR_ATTACHMENT.(i - 1)) function draw(fb::FrameBuffer, i::AbstractUnitRange) ntexts = length(color_attachments(fb)[i]) - glDrawBuffers(GLuint(ntexts), GL_COLOR_ATTACHMENT.(i.-1)) + glDrawBuffers(GLuint(ntexts), GL_COLOR_ATTACHMENT.(i .- 1)) end -draw(fb::FrameBuffer{Val{0}, Nothing}) = nothing +draw(fb::FrameBuffer{Val{0},Nothing}) = nothing #All this is not very focussed on performance yet @@ -176,7 +202,7 @@ function clear!(fb::FrameBuffer, color) end end clear!(fb::FrameBuffer) = clear!(fb, (0.0, 0.0, 0.0, 0.0)) -clear!(fb::FrameBuffer{Val{0}, Vector{Nothing}}) = nothing +clear!(fb::FrameBuffer{Val{0},Vector{Nothing}}) = nothing color_attachments(fb::FrameBuffer) = fb.attachments[findall(x -> !(x <: DepthFormat), eltypes(fb))] @@ -195,5 +221,62 @@ function depthformat(fb::FrameBuffer) end end -gpu_data(fb::FrameBuffer, i) = gpu_data(fb.attachments[i]) +# Implementing the GPUArray interface for RenderBuffer + +""" + gpu_data(r, framebuffer) +Loads the data from the renderbuffer attachment of the framebuffer via glReadPixels. +Possibly slower than the specialized functions for textures +""" +function gpu_data(r::RenderBuffer{T}, framebuffer::FrameBuffer) where {T} + result = Array{T}(undef, size(r)...) + unsafe_copyto!(result, r, framebuffer) + return result +end + +""" + unsafe_copyto!(dest, source, framebuffer, x, y) +Loads the data from the source attachment of the framebuffer via glReadPixels. +Allows specifying the upper left corner (Julia: starting at 1). +The size is inferred form dest. +Possibly slower than the specialized functions for textures. +""" +function Base.unsafe_copyto!(dest::Array{T}, source::RenderBuffer{T}, framebuffer::FrameBuffer, x::Integer=1, y::Integer=1) where {T} + bind(framebuffer, GL_READ_FRAMEBUFFER) + width, height = size(dest) + buf_size = width * height * sizeof(T) + glReadnPixels(x, y, width, height, source.format, source.pixeltype, buf_size, dest) + unbind(framebuffer, GL_READ_FRAMEBUFFER) + nothing +end + +# Implementing the GPUArray interface for Framebuffer + +""" + gpu_data(source) +Loads the data from the first attachment of the framebuffer via glReadPixels. +""" +function gpu_data(source::FrameBuffer) + attachment = source.attachments[1] + if attachment isa RenderBuffer + gpu_data(attachment, source) + else + gpu_data(attachment) + end +end +""" + unsafe_copyto!(dest, source, x, y) +Loads the data from the first attachment of the framebuffer. +Allows specifying the upper left corner (Julia: starting at 1). +The size is inferred form dest. +Possibly slower than the specialized functions for textures. +""" +function Base.unsafe_copyto!(dest::Array, source::FrameBuffer, x::Integer=1, y::Integer=1) + attachment = source.attachments[1] + if attachment isa RenderBuffer + unsafe_copyto!(dest, attachment, source, x, y) + else + unsafe_copyto!(dest, attachment, x, y) + end +end diff --git a/src/shader/glsl_typenames.jl b/src/shader/glsl_typenames.jl index 6a75555..48c907a 100644 --- a/src/shader/glsl_typenames.jl +++ b/src/shader/glsl_typenames.jl @@ -3,56 +3,54 @@ const GLSL_COMPATIBLE_NUMBER_TYPES = (GLfloat, GLint, GLuint, GLdouble) const NATIVE_TYPES = Union{ GLSL_COMPATIBLE_NUMBER_TYPES..., - Buffer, GPUArray, Shader, Program + Buffer,GPUArray,Shader,Program } isa_gl_struct(x::NATIVE_TYPES) = false -opengl_prefix(T) = @error "Object $T is not a supported uniform element type" +opengl_prefix(T) = @error "Object $T is not a supported uniform element type" opengl_postfix(T) = @error "Object $T is not a supported uniform element type" -opengl_prefix(x::Type{T}) where {T <: Union{FixedPoint, Float32, Float16}} = "" -opengl_prefix(x::Type{T}) where {T <: Float64} = "d" +opengl_prefix(x::Type{T}) where {T<:Union{FixedPoint,Float32,Float16}} = "" +opengl_prefix(x::Type{T}) where {T<:Float64} = "d" opengl_prefix(x::Type{Cint}) = "i" -opengl_prefix(x::Type{T}) where {T <: Union{Cuint, UInt8, UInt16}} = "u" +opengl_prefix(x::Type{T}) where {T<:Union{Cuint,UInt8,UInt16}} = "u" opengl_postfix(x::Type{Float64}) = "dv" opengl_postfix(x::Type{Float32}) = "fv" -opengl_postfix(x::Type{Cint}) = "iv" -opengl_postfix(x::Type{Cuint}) = "uiv" +opengl_postfix(x::Type{Cint}) = "iv" +opengl_postfix(x::Type{Cuint}) = "uiv" #Came from GLUniforms or GLInfo.jl -glsl_type(::Type{T}) where {T <: AbstractFloat} = Float32 -glsl_type(::UniformBuffer{T}) where T = T -glsl_type(::Texture) where {T, N} = gli.GLTexture{glsl_type(T), N} +glsl_type(::Type{T}) where {T<:AbstractFloat} = Float32 +glsl_type(::Texture{T,N}) where {T,N} = gli.GLTexture{glsl_type(T),N} glsl_typename(x::T) where {T} = glsl_typename(T) -glsl_typename(t::Type{Nothing}) = "Nothing" -glsl_typename(t::Type{GLfloat}) = "float" +glsl_typename(t::Type{Nothing}) = "Nothing" +glsl_typename(t::Type{GLfloat}) = "float" glsl_typename(t::Type{GLdouble}) = "double" -glsl_typename(t::Type{GLuint}) = "uint" -glsl_typename(t::Type{GLint}) = "int" +glsl_typename(t::Type{GLuint}) = "uint" +glsl_typename(t::Type{GLint}) = "int" function glsl_typename(t::Type{T}) where {T} glasserteltype(T) string(opengl_prefix(eltype(T)), "vec", length(T)) end -glsl_typename(t::Type{TextureBuffer{T}}) where {T} = string(opengl_prefix(eltype(T)), "samplerBuffer") -function glsl_typename(t::Texture{T, D}) where {T, D} +function glsl_typename(t::Texture{T,D}) where {T,D} str = string(opengl_prefix(eltype(T)), "sampler", D, "D") t.texturetype == GL_TEXTURE_2D_ARRAY && (str *= "Array") str end -function glsl_typename(t::Type{T}) where T <: Matrix +function glsl_typename(t::Type{T}) where {T<:Matrix} M, N = size(t) - string(opengl_prefix(eltype(t)), "mat", M==N ? M : string(M, "x", N)) + string(opengl_prefix(eltype(t)), "mat", M == N ? M : string(M, "x", N)) end -toglsltype_string(x::T) where {T<:Union{Real, Texture, TextureBuffer, Nothing}} = "uniform $(glsl_typename(x))" + #Handle GLSL structs, which need to be addressed via single fields -function toglsltype_string(x::T) where T +function toglsltype_string(x::T) where {T} if isa_gl_struct(x) string("uniform ", T.name.name) else @@ -60,7 +58,7 @@ function toglsltype_string(x::T) where T end end # Gets used to access a -function glsl_variable_access(keystring, t::Texture{T, D}) where {T,D} +function glsl_variable_access(keystring, t::Texture{T,D}) where {T,D} fields = SubString("rgba", 1, length(T)) if t.texturetype == GL_TEXTURE_BUFFER return string("texelFetch(", keystring, "index).", fields, ";") @@ -77,7 +75,7 @@ function glsl_version_string() if length(glsl) >= 2 glsl = VersionNumber(parse(Int, glsl[1]), parse(Int, glsl[2])) glsl.major == 1 && glsl.minor <= 2 && (@error "OpenGL shading Language version too low. Try updating graphic driver!") - glsl_version = string(glsl.major) * rpad(string(glsl.minor),2,"0") + glsl_version = string(glsl.major) * rpad(string(glsl.minor), 2, "0") return "#version $(glsl_version)\n" else @error "could not parse GLSL version: $glsl" diff --git a/src/shader/program.jl b/src/shader/program.jl index f29334a..9e51bd5 100644 --- a/src/shader/program.jl +++ b/src/shader/program.jl @@ -1,17 +1,17 @@ islinked(program::GLuint) = glGetProgramiv(program, GL_LINK_STATUS) == GL_TRUE -const AttributeTuple = NamedTuple{(:name, :location, :T, :size), Tuple{Symbol, GLint, GLenum, GLint}} +const AttributeTuple = NamedTuple{(:name, :location, :T, :size),Tuple{Symbol,GLint,GLenum,GLint}} const UniformTuple = AttributeTuple const INVALID_ATTRIBUTE = GLint(-1) -const INVALID_UNIFORM = GLint(-1) +const INVALID_UNIFORM = GLint(-1) function setup_uniforms(program::GLuint) info = UniformTuple[] nuniforms = glGetProgramiv(program, GL_ACTIVE_UNIFORMS) - for i=1:nuniforms - name, typ, size = glGetActiveUniform(program, i-1) + for i = 1:nuniforms + name, typ, size = glGetActiveUniform(program, i - 1) loc = glGetUniformLocation(program, name) - push!(info, (name = name, location = loc, T = typ, size = size)) + push!(info, (name=name, location=loc, T=typ, size=size)) end return info end @@ -19,26 +19,26 @@ end function setup_attributes(program::GLuint) info = AttributeTuple[] nattribs = glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES) - for i=1:nattribs - name, typ, size = glGetActiveAttrib(program, i-1) + for i = 1:nattribs + name, typ, size = glGetActiveAttrib(program, i - 1) loc = glGetAttribLocation(program, name) - push!(info, (name = name, location = loc, T = typ, size = size)) + push!(info, (name=name, location=loc, T=typ, size=size)) end return info end abstract type AbstractProgram end mutable struct Program <: AbstractProgram - id ::GLuint - shaders ::Vector{Shader} - uniforms ::Vector{UniformTuple} + id::GLuint + shaders::Vector{Shader} + uniforms::Vector{UniformTuple} attributes::Vector{AttributeTuple} context - function Program(shaders::Vector{Shader}, fragdatalocation::Vector{Tuple{Int, String}}) + function Program(shaders::Vector{Shader}, fragdatalocation::Vector{Tuple{Int,String}}) # Remove old shaders exists_context() - program = glCreateProgram()::GLuint - glUseProgram(program) + program = glCreateProgram() + #attach new ones foreach(shaders) do shader glAttachShader(program, shader.id) @@ -61,24 +61,24 @@ mutable struct Program <: AbstractProgram # generate the link locations uniforms = setup_uniforms(program) - attribs = setup_attributes(program) + attribs = setup_attributes(program) prog = new(program, shaders, uniforms, attribs, current_context()) finalizer(free!, prog) prog end end -Program(shaders::Vector{Shader}) = Program(shaders, Tuple{Int, String}[]) +Program(shaders::Vector{Shader}) = Program(shaders, Tuple{Int,String}[]) Program(shaders::Shader...) = Program([shaders...]) #REVIEW: This is a bit redundant seen as there is `load(source)` from FilIO for shaders but ok -Program(sh_string_typ...) = - Program([map(x -> Shader(x), sh_string_typ)...]) +Program(sh_string_typ...) = + Program([map(x -> Shader(x...), sh_string_typ)...]) free!(x::Program) = context_command(() -> glDeleteProgram(x.id), x.context) attributes(program::Program) = program.attributes -uniforms(program::Program) = program.uniforms +uniforms(program::Program) = program.uniforms uniform_names(program::Program) = [x.name for x in program.uniforms] attribute(program::Program, name::Symbol) = @@ -148,7 +148,7 @@ infolog(program::Program) = getinfolog(program.id) # display program's information function program_info(p::Program) - result = Dict{Symbol, Any}() + result = Dict{Symbol,Any}() program = p.id # check if name is really a program result[:program] = program @@ -177,12 +177,12 @@ end mutable struct LazyProgram <: AbstractProgram sources::Vector data::Dict - compiled_program::Union{Program, Nothing} + compiled_program::Union{Program,Nothing} end LazyProgram(sources...; data...) = LazyProgram(Vector(sources), Dict(data), nothing) function Program(lazy_program::LazyProgram) - fragdatalocation = get(lazy_program.data, :fragdatalocation, Tuple{Int, String}[]) + fragdatalocation = get(lazy_program.data, :fragdatalocation, Tuple{Int,String}[]) shaders = haskey(lazy_program.data, :arguments) ? Shader.(lazy_program.sources, Ref(lazy_program.data[:arguments])) : Shader.() return Program([shaders...], fragdatalocation) end @@ -206,7 +206,7 @@ end # display the values for a uniform in a named block function uniform_in_block_info(p::Program, blockName, uniName) - result = Dict{Symbol, Any}() + result = Dict{Symbol,Any}() program = p.id result[:index] = glGetUniformBlockIndex(program, blockName) diff --git a/src/shader/shader.jl b/src/shader/shader.jl index 1d8898c..0a82dbe 100644 --- a/src/shader/shader.jl +++ b/src/shader/shader.jl @@ -7,9 +7,9 @@ end abstract type AbstractShader end struct Shader <: AbstractShader - id ::GLuint - typ ::GLenum - source ::Vector{UInt8} #UInt representation of the source program string, + id::GLuint + typ::GLenum + source::Vector{UInt8} #UInt representation of the source program string, end function Shader(typ, source) @@ -55,8 +55,8 @@ function shadertype(path::AbstractString) @error "$ext not a valid shader extension." end function shadertype(typ::Symbol) - (typ == :compute || typ == :comp) && return GL_COMPUTE_SHADER - (typ == :vertex || typ == :vert) && return GL_VERTEX_SHADER + (typ == :compute || typ == :comp) && return GL_COMPUTE_SHADER + (typ == :vertex || typ == :vert) && return GL_VERTEX_SHADER (typ == :fragment || typ == :frag) && return GL_FRAGMENT_SHADER (typ == :geometry || typ == :geom) && return GL_GEOMETRY_SHADER @error "$typ not a valid shader symbol." @@ -91,7 +91,7 @@ function getinfolog(id::GLuint) maxlength = first(maxlength) # Return the text of the message if there is any if maxlength > 0 - buffer = zeros(GLchar, maxlength) + buffer = Array{GLchar}(undef, maxlength) sizei = GLsizei[0] glGetShaderInfoLog(id, maxlength, sizei, buffer) length = first(sizei) diff --git a/src/shader/uniforms.jl b/src/shader/uniforms.jl index f05931b..a76ea6a 100644 --- a/src/shader/uniforms.jl +++ b/src/shader/uniforms.jl @@ -11,7 +11,7 @@ const GLSL_COMPATIBLE_NUMBER_TYPES = (GLfloat, GLint, GLuint, GLdouble) function uniformfunc(typ::DataType, dims::Tuple{Int}) Symbol(string("glUniform", first(dims), opengl_postfix(typ))) end -function uniformfunc(typ::DataType, dims::Tuple{Int, Int}) +function uniformfunc(typ::DataType, dims::Tuple{Int,Int}) M, N = dims Symbol(string("glUniformMatrix", M == N ? "$M" : "$(M)x$(N)", opengl_postfix(typ))) end @@ -21,7 +21,7 @@ function gluniform(location::Integer, x::StaticArray) gluniform(location, xref) end -@generated function gluniform(location::Integer, x::Vector{FSA}) where FSA <: StaticArray +@generated function gluniform(location::Integer, x::Vector{FSA}) where {FSA<:StaticArray} func = uniformfunc(eltype(FSA), size(FSA)) callexpr = if ndims(FSA) == 2 :($func(location, length(x), GL_FALSE, xref)) @@ -33,30 +33,21 @@ end $callexpr end end - -#Some additional uniform functions, not related to Imutable Arrays -# gluniform(location::Integer, target::Integer, t::Texture) = gluniform(GLint(location), GLint(target), t) -# gluniform(location::Integer, target::Integer, t::GPUVector) = gluniform(GLint(location), GLint(target), t.buffer) -# gluniform(location::Integer, target::Integer, t::TextureBuffer) = gluniform(GLint(location), GLint(target), t.texture) -# gluniform(location::Integer, t::TextureBuffer) = gluniform(GLint(location), GLint(target), t.texture) -#REVIEW: scary, binding and making texture active seems like something that shouldn't be in gluniform... -#TODO: We have the tools to figure out what texture unit a texture with a given name should be bound to, but we have to make it so that low level functionality remains to avoid slowness -gluniform(location::Integer, target::Integer, t::TextureBuffer) = gluniform(GLint(location), GLint(target), t.texture) function gluniform(location::GLint, texture_unit, t::Texture) tu = GL_TEXTURE0 + UInt32(texture_unit) glActiveTexture(tu) glBindTexture(t.texturetype, t.id) gluniform(location, GLint(texture_unit)) end -gluniform(location::Integer, x::Enum) = gluniform(GLint(location), GLint(x)) -gluniform(location::Integer, x::Union{GLubyte, GLushort, GLuint}) = glUniform1ui(GLint(location), x) -gluniform(location::Integer, x::Union{GLbyte, GLshort, GLint, Bool}) = glUniform1i(GLint(location), x) -gluniform(location::Integer, x::GLfloat) = glUniform1f(GLint(location), x) -gluniform(location::Integer, x::GLdouble) = glUniform1d(GLint(location), x) +gluniform(location::Integer, x::Enum) = gluniform(GLint(location), GLint(x)) +gluniform(location::Integer, x::Union{GLubyte,GLushort,GLuint}) = glUniform1ui(GLint(location), x) +gluniform(location::Integer, x::Union{GLbyte,GLshort,GLint,Bool}) = glUniform1i(GLint(location), x) +gluniform(location::Integer, x::GLfloat) = glUniform1f(GLint(location), x) +gluniform(location::Integer, x::GLdouble) = glUniform1d(GLint(location), x) #Uniform upload functions for julia arrays... -gluniform(location::GLint, x::Vector{Float32}) = glUniform1fv(location, length(x), x) -gluniform(location::GLint, x::Vector{GLdouble}) = glUniform1dv(location, length(x), x) -gluniform(location::GLint, x::Vector{GLint}) = glUniform1iv(location, length(x), x) -gluniform(location::GLint, x::Vector{GLuint}) = glUniform1uiv(location, length(x), x) +gluniform(location::GLint, x::Vector{Float32}) = glUniform1fv(location, length(x), x) +gluniform(location::GLint, x::Vector{GLdouble}) = glUniform1dv(location, length(x), x) +gluniform(location::GLint, x::Vector{GLint}) = glUniform1iv(location, length(x), x) +gluniform(location::GLint, x::Vector{GLuint}) = glUniform1uiv(location, length(x), x) diff --git a/src/texture.jl b/src/texture.jl index c1464b4..31d4821 100644 --- a/src/texture.jl +++ b/src/texture.jl @@ -7,7 +7,7 @@ end # TODO maybe we should implement this as a 32 bit wide primitive type # and overload getproperty (getfield on 0.7) to implement depthstencil.depth with masking # since you almost always want to have depthstencil.depth::Float32 -struct DepthStencil{DT, ST} <: DepthFormat +struct DepthStencil{DT,ST} <: DepthFormat depth::DT stencil::ST end @@ -18,10 +18,14 @@ Float24 storage type for depth """ primitive type Float24 <: AbstractFloat 24 end -gl_internal_format(::Type{Depth{Float32}}) = GL_DEPTH_COMPONENT32F -gl_internal_format(::Type{DepthStencil{Float24, N0f8}}) = GL_DEPTH24_STENCIL8 +gl_internal_format(::Type{Depth{Float32}})::GLenum = GL_DEPTH_COMPONENT32F +gl_internal_format(::Type{DepthStencil{Float24,N0f8}})::GLenum = GL_DEPTH24_STENCIL8 -function gl_internal_format(::T) where T +function gl_internal_format(::Type{T}) where {T<:Colorant} + textureformat_internal_from_type(T) +end + +function gl_internal_format(::T) where {T} error("$T doesn't have a valid mapping to an OpenGL internal format enum. Please use DepthStencil/Depth/Color, or overload `gl_internal_format(x::$T)` to return the correct OpenGL format enum. ") @@ -29,7 +33,9 @@ end gl_attachment(::Type{<:Depth}) = GL_DEPTH_ATTACHMENT gl_attachment(::Type{<:DepthStencil}) = GL_DEPTH_STENCIL_ATTACHMENT -function gl_attachment(::T) where T +# gl_attachment(::Type{<:Colorant}) = GL_COLOR_ATTACHMENT0 + +function gl_attachment(::T) where {T} error("$T doesn't have a valid mapping to an OpenGL attachment enum. Please use DepthStencil/Depth, or overload `gl_attachment(x::$T)` to return the correct OpenGL depth attachment. ") @@ -38,7 +44,7 @@ end const GL_TEXTURE_MAX_ANISOTROPY_EXT = GLenum(0x84FE) colordim(::Type{T}) where {T} = cardinality(T) -colordim(::Type{T}) where {T <: Real} = 1 +colordim(::Type{T}) where {T<:Real} = 1 #Supported texture modes/dimensions function texturetype_from_dimensions(ndim::Integer) @@ -52,13 +58,13 @@ function textureformat_internal_from_type(::Type{T}) where {T} glasserteltype(T) if T <: Depth{Float32} return GL_DEPTH_COMPONENT32F - elseif T <: DepthStencil{Float24, N0f8} + elseif T <: DepthStencil{Float24,N0f8} return GL_DEPTH24_STENCIL8 end return textureformat_internal_from_type(Val{length(T)}(), eltype(T)) end - -@generated function textureformat_internal_from_type(::Val{dim}, ::Type{eltyp}) where {dim, eltyp} + +@generated function textureformat_internal_from_type(::Val{dim}, ::Type{eltyp}) where {dim,eltyp} @assert (dim <= 4 && dim >= 1) "No Textureformat that fits $dim-dimensional eltypes." sym = "GL_" sym *= "RGBA"[1:dim] @@ -90,17 +96,17 @@ function textureformat_from_type_sym(dim::Integer, isinteger::Bool, order::Abstr sym *= color * integer glenumsym = Symbol(sym) @assert isdefined(ModernGL, glenumsym) "Type doesn't have a proper mapping to an OpenGL format" - return glenumsym + return glenumsym end -@generated textureformat_from_type_sym(::Type{T}, ::Val{dim} where dim, ::Val{isinteger}) where {T <: Real, isinteger} = +@generated textureformat_from_type_sym(::Type{T}, ::Val{dim} where {dim}, ::Val{isinteger}) where {T<:Real,isinteger} = :($(textureformat_from_type_sym(1, isinteger, "RED"))) -@generated textureformat_from_type_sym(::Type{T}, ::Val{dim}, ::Val{isinteger}) where {T <: AbstractArray, dim, isinteger} = +@generated textureformat_from_type_sym(::Type{T}, ::Val{dim}, ::Val{isinteger}) where {T<:AbstractArray,dim,isinteger} = :($(textureformat_from_type_sym(dim, isinteger, "RGBA"))) -@generated function textureformat_from_type_sym(::Type{T}, ::Val{dim}, ::Val{isinteger}) where {T, dim, isinteger} +@generated function textureformat_from_type_sym(::Type{T}, ::Val{dim}, ::Val{isinteger}) where {T,dim,isinteger} typenamestring = string(Base.typename(T).name) - if typenamestring ∉ ("RGB", "BGR", "RGBA", "ARGB", "ABGR", "RGBA","BGRA") + if typenamestring ∉ ("RGB", "BGR", "RGBA", "ARGB", "ABGR", "RGBA", "BGRA") typenamestring = "RGBA" end return :($(textureformat_from_type_sym(dim, isinteger, typenamestring))) @@ -108,85 +114,83 @@ end textureformat_from_type(::Type{<:DepthFormat}) = GL_DEPTH_COMPONENT -function textureformat_from_type(::Type{T}) where T +function textureformat_from_type(::Type{T}) where {T} return textureformat_from_type_sym(T, Val{length(T)}(), Val{eltype(T)<:Integer}()) end struct TextureParameters{NDim} - minfilter ::Symbol - magfilter ::Symbol # magnification - repeat ::NTuple{NDim, Symbol} - anisotropic ::Float32 - swizzle_mask ::Vector{GLenum} + minfilter::Symbol + magfilter::Symbol # magnification + repeat::NTuple{NDim,Symbol} + anisotropic::Float32 + swizzle_mask::Vector{GLenum} end function TextureParameters(T, NDim; - minfilter = T <: Integer ? :nearest : :linear, - magfilter = minfilter, # magnification - x_repeat = :clamp_to_edge, #wrap_s - y_repeat = x_repeat, #wrap_t - z_repeat = x_repeat, #wrap_r - anisotropic = 1f0 - ) + minfilter=T <: Integer ? :nearest : :linear, + magfilter=minfilter, # magnification + x_repeat=:clamp_to_edge, #wrap_s + y_repeat=x_repeat, #wrap_t + z_repeat=x_repeat, #wrap_r + anisotropic=1.0f0 +) T <: Integer && (minfilter == :linear || magfilter == :linear) && (@error "Wrong Texture Parameter: Integer texture can't interpolate. Try :nearest") repeat = (x_repeat, y_repeat, z_repeat) dim = T <: DepthFormat ? 1 : length(T) swizzle_mask = if dim == 3 #<: Gray - GLenum[GL_RED, GL_GREEN, GL_BLUE, GL_ONE] + GLenum[GL_RED, GL_GREEN, GL_BLUE, GL_ONE] elseif dim == 4 #<: GrayA - GLenum[GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA] + GLenum[GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA] else GLenum[] end TextureParameters( - minfilter, magfilter, ntuple(i->repeat[i], NDim), + minfilter, magfilter, ntuple(i -> repeat[i], NDim), anisotropic, swizzle_mask ) end -map_texture_paramers(s::NTuple{N, Symbol}) where {N} = map(map_texture_paramers, s) +map_texture_paramers(s::NTuple{N,Symbol}) where {N} = map(map_texture_paramers, s) function map_texture_paramers(s::Symbol) - s == :clamp_to_edge && return GL_CLAMP_TO_EDGE - s == :mirrored_repeat && return GL_MIRRORED_REPEAT - s == :repeat && return GL_REPEAT - s == :linear && return GL_LINEAR - s == :nearest && return GL_NEAREST + s == :clamp_to_edge && return GL_CLAMP_TO_EDGE + s == :mirrored_repeat && return GL_MIRRORED_REPEAT + s == :repeat && return GL_REPEAT + s == :linear && return GL_LINEAR + s == :nearest && return GL_NEAREST s == :nearest_mipmap_nearest && return GL_NEAREST_MIPMAP_NEAREST - s == :linear_mipmap_nearest && return GL_LINEAR_MIPMAP_NEAREST - s == :nearest_mipmap_linear && return GL_NEAREST_MIPMAP_LINEAR - s == :linear_mipmap_linear && return GL_LINEAR_MIPMAP_LINEAR + s == :linear_mipmap_nearest && return GL_LINEAR_MIPMAP_NEAREST + s == :nearest_mipmap_linear && return GL_NEAREST_MIPMAP_LINEAR + s == :linear_mipmap_linear && return GL_LINEAR_MIPMAP_LINEAR @error "$s is not a valid texture parameter" end #This is used in the construction of Textures function set_packing_alignment(a) # at some point we should specialize to array/ptr a - glPixelStorei(GL_UNPACK_ALIGNMENT, 1) - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0) + glPixelStorei(GL_UNPACK_ALIGNMENT, 1) + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0) glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0) - glPixelStorei(GL_UNPACK_SKIP_ROWS, 0) + glPixelStorei(GL_UNPACK_SKIP_ROWS, 0) end -abstract type OpenglTexture{T, NDIM} <: GPUArray{T, NDIM} end - -mutable struct Texture{T, NDIM} <: OpenglTexture{T, NDIM} - id ::GLuint - texturetype ::GLenum - pixeltype ::GLenum +mutable struct Texture{T,NDIM} + id::GLuint + texturetype::GLenum + pixeltype::GLenum internalformat::GLenum - format ::GLenum - parameters ::TextureParameters{NDIM} - size ::NTuple{NDIM, Int} - context ::Context - function Texture{T, NDIM}( - id ::GLuint, - texturetype ::GLenum, - pixeltype ::GLenum, - internalformat::GLenum, - format ::GLenum, - parameters ::TextureParameters{NDIM}, - size ::NTuple{NDIM, Int} - ) where {T, NDIM} + format::GLenum + parameters::TextureParameters{NDIM} + size::NTuple{NDIM,Int} + context::Context + function Texture{T,NDIM}( + id::GLuint, + texturetype::GLenum, + pixeltype::GLenum, + internalformat::GLenum, + format::GLenum, + parameters::TextureParameters{NDIM}, + size::NTuple{NDIM,Int} + ) where {T,NDIM} tex = new( id, texturetype, @@ -203,13 +207,13 @@ mutable struct Texture{T, NDIM} <: OpenglTexture{T, NDIM} end function Texture( - data::Ptr{T}, dims::NTuple{NDim, Int}; - internalformat::GLenum = textureformat_internal_from_type(T), - texturetype ::GLenum = texturetype_from_dimensions(NDim), - format ::GLenum = textureformat_from_type(T), - mipmap = false, - parameters... # rest should be texture parameters - ) where {T, NDim} + data::Ptr{T}, dims::NTuple{NDim,Int}; + internalformat::GLenum=textureformat_internal_from_type(T), + texturetype::GLenum=texturetype_from_dimensions(NDim), + format::GLenum=textureformat_from_type(T), + mipmap=false, + parameters... # rest should be texture parameters +) where {T,NDim} glasserteltype(T) texparams = TextureParameters(T, NDim; parameters...) id = glGenTextures() @@ -222,25 +226,25 @@ function Texture( end glTexImage(texturetype, 0, internalformat, dims..., 0, format, numbertype, data) mipmap && glGenerateMipmap(texturetype) - texture = Texture{T, NDim}( + texture = Texture{T,NDim}( id, texturetype, numbertype, internalformat, format, texparams, dims ) set_parameters(texture) - texture::Texture{T, NDim} + texture::Texture{T,NDim} end """ Constructor for Array Texture """ function Texture( - data::Vector{Array{T, 2}}; - internalformat::GLenum = textureformat_internal_from_type(T), - texturetype::GLenum = GL_TEXTURE_2D_ARRAY, - format::GLenum = textureformat_from_type(T), - parameters... - ) where T + data::Vector{Array{T,2}}; + internalformat::GLenum=textureformat_internal_from_type(T), + texturetype::GLenum=GL_TEXTURE_2D_ARRAY, + format::GLenum=textureformat_from_type(T), + parameters... +) where {T} glasserteltype(T) texparams = TextureParameters(T, 2; parameters...) id = glGenTextures() @@ -249,21 +253,21 @@ function Texture( numbertype = julia2glenum(eltype(T)) - layers = length(data) - dims = map(size, data) - maxdims = foldl((0,0), dims) do v0, x + layers = length(data) + dims = map(size, data) + maxdims = foldl((0, 0), dims) do v0, x a = max(v0[1], x[1]) b = max(v0[2], x[2]) - (a,b) + (a, b) end set_packing_alignment(data) glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, internalformat, maxdims..., layers) for (layer, texel) in enumerate(data) width, height = size(texel) - glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, layer-1, width, height, 1, format, numbertype, texel) + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, layer - 1, width, height, 1, format, numbertype, texel) end - texture = Texture{T, 2}( + texture = Texture{T,2}( id, texturetype, numbertype, internalformat, format, texparams, tuple(maxdims...) @@ -277,9 +281,9 @@ Constructor for empty initialization with NULL pointer instead of an array with You just need to pass the wanted color/vector type and the dimensions. To which values the texture gets initialized is driver dependent """ -function Texture(::Type{T}, dims::NTuple{N, Int}; kw_args...) where {T, N} +function Texture(::Type{T}, dims::NTuple{N,Int}; kw_args...) where {T,N} glasserteltype(T) - Texture(convert(Ptr{T}, C_NULL), dims; kw_args...)::Texture{T, N} + Texture(convert(Ptr{T}, C_NULL), dims; kw_args...)::Texture{T,N} end """ @@ -288,15 +292,15 @@ So Array{Real, 2} == Texture2D with 1D Colorant dimension Array{Vec1/2/3/4, 2} == Texture2D with 1/2/3/4D Colorant dimension Colors from Colors.jl should mostly work as well """ -function Texture(image::Array{T, NDim}; kw_args...) where {T, NDim} +function Texture(image::Array{T,NDim}; kw_args...) where {T,NDim} glasserteltype(T) - Texture(pointer(image), size(image); kw_args...)::Texture{T, NDim} + Texture(pointer(image), size(image); kw_args...)::Texture{T,NDim} end -function set_parameters(t::Texture{T, N}, params::TextureParameters=t.parameters) where {T, N} - fnames = (:minfilter, :magfilter, :repeat) - data = Dict([(name, map_texture_paramers(getfield(params, name))) for name in fnames]) - result = Tuple{GLenum, Any}[] +function set_parameters(t::Texture{T,N}, params::TextureParameters=t.parameters) where {T,N} + fnames = (:minfilter, :magfilter, :repeat) + data = Dict([(name, map_texture_paramers(getfield(params, name))) for name in fnames]) + result = Tuple{GLenum,Any}[] push!(result, (GL_TEXTURE_MIN_FILTER, data[:minfilter])) push!(result, (GL_TEXTURE_MAG_FILTER, data[:magfilter])) push!(result, (GL_TEXTURE_WRAP_S, data[:repeat][1])) @@ -323,7 +327,7 @@ function texparameter(t::Texture, key::GLenum, val::Float32) glTexParameterf(t.texturetype, key, val) end -function set_parameters(t::Texture, parameters::Vector{Tuple{GLenum, Any}}) +function set_parameters(t::Texture, parameters::Vector{Tuple{GLenum,Any}}) bind(t) for elem in parameters texparameter(t, elem...) @@ -334,25 +338,23 @@ end free!(x::Texture) = context_command(() -> glDeleteTextures(x.id), x.context) Base.size(t::Texture) = t.size -Base.eltype(t::Texture{T}) where {T} = T -width(t::Texture) = size(t, 1) -height(t::Texture) = size(t, 2) -depth(t::Texture) = size(t, 3) -id(t::Texture) = t.id +Base.eltype(::Texture{T}) where {T} = T +width(t::Texture) = size(t, 1) +height(t::Texture) = size(t, 2) +depth(t::Texture) = size(t, 3) +id(t::Texture) = t.id function Base.show(io::IO, t::Texture{T,D}) where {T,D} println(io, "Texture$(D)D: ") println(io, " ID: ", t.id) println(io, " Size: Dimensions: $(size(t))") - # println(io, " Size: ", reduce("Dimensions: ", size(t)) do v0, v1 - # v0*"x"*string(v1) - # end) println(io, " Julia pixel type: ", T) println(io, " OpenGL pixel type: ", GLENUM(t.pixeltype).name) println(io, " Format: ", GLENUM(t.format).name) println(io, " Internal format: ", GLENUM(t.internalformat).name) println(io, " Parameters: ", t.parameters) end +Base.display(t::GLAbstraction.Texture{T,D}) where {T,D} = Base.show(stdout, t) is_texturearray(t::Texture) = t.texturetype == GL_TEXTURE_2D_ARRAY is_texturebuffer(t::Texture) = t.texturetype == GL_TEXTURE_BUFFER @@ -360,7 +362,7 @@ is_texturebuffer(t::Texture) = t.texturetype == GL_TEXTURE_BUFFER bind(t::Texture) = glBindTexture(t.texturetype, t.id) bind(t::Texture, id) = glBindTexture(t.texturetype, id) -function resize_nocopy!(t::Texture{T, ND}, newdims::NTuple{ND, Int}) where {T, ND} +function resize_nocopy!(t::Texture{T,ND}, newdims::NTuple{ND,Int}) where {T,ND} bind(t) glTexImage(t.texturetype, 0, t.internalformat, newdims..., 0, t.format, t.pixeltype, C_NULL) t.size = newdims @@ -369,72 +371,112 @@ function resize_nocopy!(t::Texture{T, ND}, newdims::NTuple{ND, Int}) where {T, N end # Resize Texture -function gpu_resize!(t::Texture{T, ND}, newdims::NTuple{ND, Int}) where {T, ND} +function gpu_resize!(t::Texture{T,ND}, newdims::NTuple{ND,Int}) where {T,ND} # dangerous code right here...Better write a few tests for this - newtex = similar(t, newdims) + newtex = similar(t, newdims) old_size = size(t) gpu_setindex!(newtex, t) - t.size = newdims + t.size = newdims free(t) - t.id = newtex.id + t.id = newtex.id return t end -function gpu_setindex!(t::Texture{T, 1}, newvalue::Array{T, 1}, indexes::UnitRange{I}) where {T, I <: Integer} +function gpu_setindex!(t::Texture{T,1}, newvalue::Array{T,1}, indexes::UnitRange{I}) where {T,I<:Integer} glBindTexture(t.texturetype, t.id) texsubimage(t, newvalue, indexes) glBindTexture(t.texturetype, 0) end -function gpu_setindex!(t::Texture{T, N}, newvalue::Array{T, N}, indexes::Union{UnitRange,Integer}...) where {T, N} +function gpu_setindex!(t::Texture{T,N}, newvalue::Array{T,N}, indexes::Union{UnitRange,Integer}...) where {T,N} glBindTexture(t.texturetype, t.id) texsubimage(t, newvalue, indexes...) glBindTexture(t.texturetype, 0) end -function gpu_setindex!(target::Texture{T, 2}, source::Texture{T, 2}, fbo=glGenFramebuffers()) where T - glBindFramebuffer(GL_FRAMEBUFFER, fbo); +function gpu_setindex!(target::Texture{T,2}, source::Texture{T,2}, fbo=glGenFramebuffers()) where {T} + glBindFramebuffer(GL_FRAMEBUFFER, fbo) glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, source.id, 0); + GL_TEXTURE_2D, source.id, 0) glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, - GL_TEXTURE_2D, target.id, 0); - glDrawBuffer(GL_COLOR_ATTACHMENT1); + GL_TEXTURE_2D, target.id, 0) + glDrawBuffer(GL_COLOR_ATTACHMENT1) w, h = map(minimum, zip(size(target), size(source))) glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, - GL_COLOR_BUFFER_BIT, GL_NEAREST) + GL_COLOR_BUFFER_BIT, GL_NEAREST) end # Implementing the GPUArray interface -function gpu_data(t::Texture{T, ND}) where {T, ND} - result = zeros(T, size(t)...) +# To CPU +""" + gpu_data(t) +Create a new CPU array with the size of the texture and copy the data from the gpu to it +""" +function gpu_data(t::Texture{T,ND}) where {T,ND} + result = Array{T}(undef, size(t)...) unsafe_copyto!(result, t) return result end -function Base.unsafe_copyto!(dest::Array{T, N}, source::Texture{T, N}) where {T,N} - bind(source) - glGetTexImage(source.texturetype, 0, source.format, source.pixeltype, dest) - bind(source, 0) +""" + unsafe_copyto!(dest, source, x, y, z) +Copy the 3D data from the texture to the CPU using glGetTextureSubImage. +Allows specifying the upper left corner (Julia: starting at 1). +The size is inferred form dest. +""" +function Base.unsafe_copyto!(dest::Array{T,3}, source::Texture{T,3}, x::Integer=1, y::Integer=1, z::Integer=1) where {T} + width, height, depth = size(dest) + buf_size = width * height * depth * sizeof(T) + glGetTextureSubImage(source.id, 0, x - 1, y - 1, z - 1, width, height, depth, source.format, source.pixeltype, buf_size, dest) nothing end -similar(t::Texture{T, NDim}, newdims::Int...) where {T, NDim} = similar(t, newdims) +""" + unsafe_copyto!(dest, source, x, y) +Copy the 2D data from the texture to the CPU using glGetTextureSubImage. +Allows specifying the upper left corner (Julia: starting at 1). +The size is inferred form dest. +""" +function Base.unsafe_copyto!(dest::Array{T,2}, source::Texture{T,2}, x::Integer=1, y::Integer=1) where {T} + width, height = size(dest) + depth = 1 + buf_size = width * height * depth * sizeof(T) + glGetTextureSubImage(source.id, 0, x - 1, y - 1, 0, width, height, depth, source.format, source.pixeltype, buf_size, dest) + nothing +end -texsubimage(t::Texture{T, 1}, newvalue::Array{T, 1}, xrange::UnitRange, level=0) where {T} = glTexSubImage1D( - t.texturetype, level, first(xrange)-1, length(xrange), t.format, t.pixeltype, newvalue +""" + unsafe_copyto!(dest, source, x) +Copy the 2D data from the texture to the CPU using glGetTextureSubImage. +Allows specifying the upper left corner (Julia: starting at 1). +The size is inferred form dest. +""" +function Base.unsafe_copyto!(dest::Array{T,1}, source::Texture{T,1}, x::Integer=1) where {T} + width, height = size(dest) + depth = height = 1 + buf_size = width * height * depth * sizeof(T) + glGetTextureSubImage(source.id, 0, x - 1, 0, 0, width, height, depth, source.format, source.pixeltype, buf_size, dest) + nothing +end + +similar(t::Texture{T,NDim}, newdims::Int...) where {T,NDim} = similar(t, newdims) + +# To GPU +texsubimage(t::Texture{T,1}, newvalue::Array{T,1}, xrange::UnitRange, level=0) where {T} = glTexSubImage1D( + t.texturetype, level, first(xrange) - 1, length(xrange), t.format, t.pixeltype, newvalue ) -function texsubimage(t::Texture{T, 2}, newvalue::Array{T, 2}, xrange::UnitRange, yrange::UnitRange, level=0) where T +function texsubimage(t::Texture{T,2}, newvalue::Array{T,2}, xrange::UnitRange, yrange::UnitRange, level=0) where {T} glTexSubImage2D( t.texturetype, level, - first(xrange)-1, first(yrange)-1, length(xrange), length(yrange), + first(xrange) - 1, first(yrange) - 1, length(xrange), length(yrange), t.format, t.pixeltype, newvalue ) end -texsubimage(t::Texture{T, 3}, newvalue::Array{T, 3}, xrange::UnitRange, yrange::UnitRange, zrange::UnitRange, level=0) where {T} = glTexSubImage3D( +texsubimage(t::Texture{T,3}, newvalue::Array{T,3}, xrange::UnitRange, yrange::UnitRange, zrange::UnitRange, level=0) where {T} = glTexSubImage3D( t.texturetype, level, - first(xrange)-1, first(yrange)-1, first(zrange)-1, length(xrange), length(yrange), length(zrange), + first(xrange) - 1, first(yrange) - 1, first(zrange) - 1, length(xrange), length(yrange), length(zrange), t.format, t.pixeltype, newvalue ) -function similar(t::Texture{T, NDim}, newdims::NTuple{NDim, Int}) where {T, NDim} +function similar(t::Texture{T,NDim}, newdims::NTuple{NDim,Int}) where {T,NDim} Texture( Ptr{T}(C_NULL), newdims, t.texturetype, @@ -444,89 +486,3 @@ function similar(t::Texture{T, NDim}, newdims::NTuple{NDim, Int}) where {T, NDim t.parameters ) end - -# for bufferSampler, aka Texture Buffer -mutable struct TextureBuffer{T} <: OpenglTexture{T, 1} - texture::Texture{T, 1} - buffer::Buffer{T} -end -function TextureBuffer(buffer::Buffer{T}) where T - glasserteltype(T) - texture_type = GL_TEXTURE_BUFFER - id = glGenTextures() - glBindTexture(texture_type, id) - internalformat = default_internalcolorformat(T) - glTexBuffer(texture_type, internalformat, buffer.id) - tex = Texture{T, 1}( - id, texture_type, julia2glenum(T), internalformat, - default_colorformat(T), TextureParameters(T, 1), - size(buffer) - ) - TextureBuffer(tex, buffer) -end -function TextureBuffer(buffer::Vector{T}) where T - glasserteltype(T) - buff = Buffer(buffer, buffertype = GL_TEXTURE_BUFFER, usage = GL_DYNAMIC_DRAW) - TextureBuffer(buff) -end -Base.size(t::TextureBuffer) = size(t.buffer) -Base.size(t::TextureBuffer, i::Integer) = size(t.buffer, i) -Base.length(t::TextureBuffer) = length(t.buffer) - -# GPUArray interface: -function Base.unsafe_copyto!(a::Vector{T}, readoffset::Int, b::TextureBuffer{T}, writeoffset::Int, len::Int) where T - copy!(a, readoffset, b.buffer, writeoffset, len) - glBindTexture(b.texture.texturetype, b.texture.id) - glTexBuffer(b.texture.texturetype, b.texture.internalformat, b.buffer.id) # update texture -end - -function Base.unsafe_copyto!(a::TextureBuffer{T}, readoffset::Int, b::Vector{T}, writeoffset::Int, len::Int) where T - copy!(a.buffer, readoffset, b, writeoffset, len) - glBindTexture(a.texture.texturetype, a.texture.id) - glTexBuffer(a.texture.texturetype, a.texture.internalformat, a.buffer.id) # update texture -end -function Base.unsafe_copyto!(a::TextureBuffer{T}, readoffset::Int, b::TextureBuffer{T}, writeoffset::Int, len::Int) where T - unsafe_copy!(a.buffer, readoffset, b.buffer, writeoffset, len) - - glBindTexture(a.texture.texturetype, a.texture.id) - glTexBuffer(a.texture.texturetype, a.texture.internalformat, a.buffer.id) # update texture - - glBindTexture(b.texture.texturetype, btexture..id) - glTexBuffer(b.texture.texturetype, b.texture.internalformat, b.buffer.id) # update texture - glBindTexture(t.texture.texturetype, 0) -end -function gpu_setindex!(t::TextureBuffer{T}, newvalue::Vector{T}, indexes::UnitRange{I}) where {T, I <: Integer} - glBindTexture(t.texture.texturetype, t.texture.id) - t.buffer[indexes] = newvalue # set buffer indexes - glTexBuffer(t.texture.texturetype, t.texture.internalformat, t.buffer.id) # update texture - glBindTexture(t.texture.texturetype, 0) -end - -gpu_data(t::TextureBuffer{T}) where {T} = gpu_data(t.buffer) -gpu_getindex(t::TextureBuffer{T}, i::UnitRange{Int64}) where {T} = t.buffer[i] - -function similar(t::TextureBuffer{T}, newdims::NTuple{1, Int}) where T - buff = similar(t.buffer, newdims...) - return TextureBuffer(buff) -end - -# Resize Texture -function gpu_resize!(t::TextureBuffer{T}, newdims::NTuple{1, Int}) where T - resize!(t.buffer, newdims) - glBindTexture(t.texture.texturetype, t.texture.id) - glTexBuffer(t.texture.texturetype, t.texture.internalformat, t.buffer.id) #update data in texture - t.texture.size = newdims - glBindTexture(t.texture.texturetype, 0) - t -end - -# next(t::TextureBuffer{T}, state::Tuple{Ptr{T}, Int}) where {T} = next(t.buffer, state) -# function done(t::TextureBuffer{T}, state::Tuple{Ptr{T}, Int}) where T -# isdone = done(t.buffer, state) -# if isdone -# glBindTexture(t.texturetype, t.id) -# glTexBuffer(t.texturetype, t.internalformat, t.buffer.id) -# glBindTexture(t.texturetype, 0) -# end -# isdone -# end diff --git a/src/uniformbuffer.jl b/src/uniformbuffer.jl deleted file mode 100644 index 542efb3..0000000 --- a/src/uniformbuffer.jl +++ /dev/null @@ -1,169 +0,0 @@ -const GLSLScalarTypes = Union{Float32, Int32, UInt32} - -""" -Statically sized uniform buffer. -Supports push!, but with fixed memory, so it will error after reaching -it's preallocated length. -""" -struct UniformBuffer{T, N} - buffer::Buffer{T} - offsets::NTuple{N, Int} - elementsize::Int - length::Int -end - -""" - Pre allocates an empty buffer with `max_batch_size` size - which can be used to store multiple uniform blocks of type T -""" -function UniformBuffer(::Type{T}, max_batch_size = 1024, mode = GL_STATIC_DRAW) where T - offsets, elementsize = std140_offsets(T) - buffer = Buffer{T}( - max_batch_size, - elementsize * max_batch_size, - GL_UNIFORM_BUFFER, mode - ) - UniformBuffer(buffer, offsets, elementsize, 0) -end -""" - Creates an Uniform buffer with the contents of `data` -""" -function UniformBuffer{T}(data::T, mode = GL_STATIC_DRAW) where T - buffer = UniformBuffer(T, 1, mode) - push!(buffer, data) - buffer -end - -""" -Returns the alignment of the `Type` of T as assumed in https://khronos.org/registry/OpenGL/specs/gl/glspec45.core.pdf#page=159, -returning a tuple with the first element being the 'base' alignment, and the second the total size inside memory. -""" -function glsl_alignment_size(T) - function ceil4(i) - while i%4 != 0 - i += 1 - end - return i - end - T <: Bool && return sizeof(Int32), sizeof(Int32) - N = sizeof(T) - T <: GLSLScalarTypes && return N, N - T <: Function && return sizeof(Vec4f0), sizeof(Vec4f0) # sizeof(EmptyStruct) padded to Vec4f0 - ET = eltype(T) - N = sizeof(ET) - if T <: Matrix - nrows, ncols = size(T) - ncols = ceil4(ncols) - return div(ncols, 4) * N, ncols * nrows * N - end - if T <: Vector - return ceil4(length(T)) * N, length(T) * N - end - @error "Struct $T not supported yet. Please help by implementing all rules from https://khronos.org/registry/OpenGL/specs/gl/glspec45.core.pdf#page=159" -end - -function std140_offsets(::Type{T}) where T - elementsize = 0 - offsets = if T <: GLSLScalarTypes - elementsize = sizeof(T) - (0,) - else - offset = 0 - offsets = ntuple(nfields(T)) do i - ft = fieldtype(T, i) - alignement, sz = glsl_alignment_size(ft) - if offset % alignement != 0 - offset = (div(offset, alignement) + 1) * alignement - end - of = offset - offset += sz - of - end - elementsize = offset - offsets - end - offsets, elementsize -end - -Base.convert(::Type{UniformBuffer}, x) = UniformBuffer(x) -Base.convert(::Type{UniformBuffer}, x::UniformBuffer) = x -Base.eltype(::UniformBuffer{T}) where T = T - -function Base.setindex!(buffer::UniformBuffer{T}, element::T, idx::Integer) where T - if idx > length(buffer.buffer) - throw(BoundsError(buffer, idx)) - end - buff = buffer.buffer - glBindBuffer(buff.buffertype, buff.id) - dptr = Ptr{UInt8}(glMapBuffer(buff.buffertype, GL_WRITE_ONLY)) - for (offset, ptr, size) in iterate_fields(buffer, element, idx) - unsafe_copy!(dptr + offset, ptr, size) - end - glUnmapBuffer(buff.buffertype) - bind(buff, 0) - element -end - -function Base.push!(buffer::UniformBuffer{T}, element::T) where T - buffer.length += 1 - buffer[buffer.length] = element - buffer -end - -function assert_blocksize(buffer::UniformBuffer, program, blockname::String) - block_index = glGetUniformBlockIndex(program, blockname) - blocksize_ref = Ref{GLint}(0) - glGetActiveUniformBlockiv( - program, block_index, - GL_UNIFORM_BLOCK_DATA_SIZE, blocksize_ref - ) - blocksize = blocksize_ref[] - @assert buffer.elementsize * length(buffer.buffer) == blocksize -end - -_getfield(x::GLSLScalarTypes, i) = x -_getfield(x, i) = getfield(x, i) - -function iterate_fields(buffer::UniformBuffer{T, N}, x, index) where {T, N} - offset = buffer.elementsize * (index - 1) - x_ref = isimmutable(x) ? Ref(x) : x - base_ptr = Ptr{UInt8}(pointer_from_objref(x_ref)) - ntuple(Val{N}) do i - offset + buffer.offsets[i], base_ptr + fieldoffset(T, i), sizeof(fieldtype(T, i)) - end -end - -extract_val(::Val{X}) where X = X - -# function Base.setindex!{T <: Composable, N, TF}(x::UniformBuffer{T, N}, val::TF, field::Type{<: Field}) -# index = extract_val(FieldTraits.fieldindex(T, field)) -# if index === 0 -# throw(BoundsError(x, field)) -# end -# val_conv = convert(fieldtype(T, index), val) -# val_ref = if isbits(val) -# Base.Ref(val) -# elseif isimmutable(val) -# error("Struct $TF contains pointers and can't be transferred to GPU") -# else -# pointer_from_objref(val) -# end -# buff = x.buffer -# bind(buff) do -# BufferSubData(buff.buffertype, x.offsets[index], sizeof(val_conv), val_ref) -# end -# x -# end - -# function Base.getindex{T <: Composable, N}(x::UniformBuffer{T, N}, field::Type{<: Field}) -# index = extract_val(FieldTraits.fieldindex(T, field)[1]) -# if index == 0 -# throw(BoundsError(x, field)) -# end -# ET = fieldtype(T, index) -# val_ref = Ref{ET}() -# bind(x.buffer) do -# glGetBufferSubData(x.buffer.buffertype, x.offsets[index], sizeof(ET), val_ref) -# end -# val_ref[] -# end diff --git a/src/vertexarray.jl b/src/vertexarray.jl index 378b1f1..4d30afd 100644 --- a/src/vertexarray.jl +++ b/src/vertexarray.jl @@ -1,26 +1,31 @@ -@enum VaoKind SIMPLE ELEMENTS ELEMENTS_INSTANCED EMPTY +# VaoKind as Enum crashes VSCode debugger +const VaoKind = Int +const SIMPLE = 1 +const ELEMENTS = 2 +const ELEMENTS_INSTANCED = 3 +const EMPTY = 4 # buffers which are not instanced have divisor = -1 const GEOMETRY_DIVISOR = GLint(-1) const UNIFORM_DIVISOR = GLint(1) struct BufferAttachmentInfo{T} - name ::Symbol - location ::GLint - buffer ::Buffer{T} - divisor ::GLint + name::Symbol + location::GLint + buffer::Buffer{T} + divisor::GLint end -Base.eltype(b::BufferAttachmentInfo{T}) where T = T +Base.eltype(b::BufferAttachmentInfo{T}) where {T} = T function generate_buffers(program::Program, divisor::GLint=GEOMETRY_DIVISOR; name_buffers...) - buflen = 0 + buflen = 0 buffers = BufferAttachmentInfo[] for (name, val) in pairs(name_buffers) loc = attribute_location(program, name) if loc != INVALID_ATTRIBUTE - buflen = buflen == 0 ? length(val) : buflen + buflen = buflen == 0 ? length(val) : buflen vallen = length(val) if vallen == buflen push!(buffers, BufferAttachmentInfo(name, loc, Buffer(val, usage=GL_DYNAMIC_DRAW), divisor)) @@ -28,20 +33,20 @@ function generate_buffers(program::Program, divisor::GLint=GEOMETRY_DIVISOR; nam push!(buffers, BufferAttachmentInfo(name, loc, Buffer(fill(val, buflen), usage=GL_DYNAMIC_DRAW), divisor)) end else - error("Invalid attribute: $name.") + @warn "Invalid attribute: $name." end end return buffers end -mutable struct VertexArray{Vertex, Kind} - id ::GLuint +mutable struct VertexArray{Vertex,Kind} + id::GLuint bufferinfos::Vector{<:BufferAttachmentInfo} - indices ::Union{Buffer, Nothing} - nverts ::GLint #total vertices to be drawn in drawcall - ninst ::GLint - face ::GLenum - context ::Context + indices::Union{Buffer,Nothing} + nverts::GLint #total vertices to be drawn in drawcall + ninst::GLint + face::GLenum + context::Context function VertexArray(kind::VaoKind, bufferinfos::Vector{<:BufferAttachmentInfo}, indices, ninst, face) id = glGenVertexArrays() glBindVertexArray(id) @@ -72,19 +77,19 @@ mutable struct VertexArray{Vertex, Kind} else vert_type = Tuple{eltype.(bufferinfos)...} end - obj = new{vert_type, kind}(id, bufferinfos, indices, nverts, ninst, face, current_context()) + obj = new{vert_type,kind}(id, bufferinfos, indices, nverts, ninst, face, current_context()) finalizer(free!, obj) obj end function VertexArray() - return new{Nothing, EMPTY}(GLuint(0), - Buffer[], - nothing, - GLint(0), - GLint(0), - GL_POINTS, - current_context()) - end + return new{Nothing,EMPTY}(GLuint(0), + Buffer[], + nothing, + GLint(0), + GLint(0), + GL_POINTS, + current_context()) + end end VertexArray(bufferinfos::Vector{<:BufferAttachmentInfo}, face::GLenum=GL_TRIANGLES) = @@ -94,26 +99,26 @@ VertexArray(bufferinfos::Vector{<:BufferAttachmentInfo}, indices::Vector{<:Integ VertexArray(ELEMENTS, bufferinfos, indexbuffer(GLint.(indices)), 1, face) #TODO this is messy -VertexArray(bufferinfos::Vector{<:BufferAttachmentInfo}, indices::Vector{F}; facelength=F) where F = +VertexArray(bufferinfos::Vector{<:BufferAttachmentInfo}, indices::Vector{F}; facelength=F) where {F} = VertexArray(ELEMENTS, bufferinfos, indexbuffer(indices), 1, face2glenum(facelength)) -VertexArray(bufferinfos::Vector{<:BufferAttachmentInfo}, indices::Vector{<:Integer}, facelength::Union{GLenum, Int}, ninst::Int) = +VertexArray(bufferinfos::Vector{<:BufferAttachmentInfo}, indices::Vector{<:Integer}, facelength::Union{GLenum,Int}, ninst::Int) = VertexArray(ELEMENTS_INSTANCED, bufferinfos, indexbuffer(GLint.(indices)), ninst, face2glenum(facelength)) -VertexArray(bufferinfos::Vector{<:BufferAttachmentInfo}, indices::Vector{F}, ninst::Int) where F = +VertexArray(bufferinfos::Vector{<:BufferAttachmentInfo}, indices::Vector{F}, ninst::Int) where {F} = VertexArray(ELEMENTS_INSTANCED, bufferinfos, indexbuffer(indices), ninst, face2glenum(F)) free!(x::VertexArray) = context_command(() -> glDeleteVertexArrays(1, [x.id]), x.context) - -is_null(vao::VertexArray{Nothing, EMPTY}) = true -is_null(vao::VertexArray) = false -bufferinfo(vao::VertexArray, name::Symbol) = (id =findfirst(x->x.name == name, vao.bufferinfos); id !== nothing ? vao.bufferinfos[id] : id) +is_null(vao::VertexArray{Nothing,EMPTY}) = true +is_null(vao::VertexArray) = false + +bufferinfo(vao::VertexArray, name::Symbol) = (id = findfirst(x -> x.name == name, vao.bufferinfos); id !== nothing ? vao.bufferinfos[id] : id) # the instanced ones assume that there is at least one buffer with the vertextype (=has fields, bit whishy washy) and the others are the instanced things # It is assumed that when an attribute is longer than 4 bytes, the rest is stored in consecutive locations -function attach2vao(bufferinfo::BufferAttachmentInfo{T}) where T +function attach2vao(bufferinfo::BufferAttachmentInfo{T}) where {T} function enable_attrib(loc) glEnableVertexAttribArray(loc) @@ -129,26 +134,28 @@ function attach2vao(bufferinfo::BufferAttachmentInfo{T}) where T # TODO this is not tested for i = 1:nfields(T) loc = bufferinfo.location + i - 1 - FT = fieldtype(T, i); ET = eltype(FT) + FT = fieldtype(T, i) + ET = eltype(FT) glVertexAttribPointer(loc, - cardinality(FT), julia2glenum(ET), - GL_FALSE, sizeof(T), Ptr{Nothing}(fieldoffset(T, i))) + cardinality(FT), julia2glenum(ET), + GL_FALSE, sizeof(T), Ptr{Nothing}(fieldoffset(T, i))) enable_attrib(loc) end else # This is for when the buffer holds a single attribute, no need to # calculate fieldoffsets and stuff like that. # TODO Assumes everything larger than vec4 is a matrix, is this ok? - FT = T; ET = eltype(FT) + FT = T + ET = eltype(FT) cardi = cardinality(FT) gltype = julia2glenum(ET) if cardi > 4 s = size(FT) loc_size = s[2] - for li=0:s[1]-1 + for li = 0:s[1]-1 loc = bufferinfo.location + li offset = sizeof(gltype) * loc_size * li - glVertexAttribPointer(loc, loc_size, gltype, GL_FALSE, cardi*sizeof(gltype), Ptr{Nothing}(offset)) + glVertexAttribPointer(loc, loc_size, gltype, GL_FALSE, cardi * sizeof(gltype), Ptr{Nothing}(offset)) enable_attrib(loc) end else @@ -164,37 +171,37 @@ Base.convert(::Type{VertexArray}, x::VertexArray) = x function face2glenum(face) facelength = typeof(face) <: Integer ? face : (face <: Integer ? 1 : length(face)) - facelength == 1 && return GL_POINTS - facelength == 2 && return GL_LINES - facelength == 3 && return GL_TRIANGLES - facelength == 4 && return GL_QUADS - facelength == 5 && return GL_TRIANGLE_STRIP + facelength == 1 && return GL_POINTS + facelength == 2 && return GL_LINES + facelength == 3 && return GL_TRIANGLES + facelength == 4 && return GL_QUADS + facelength == 5 && return GL_TRIANGLE_STRIP facelength == 10 && return GL_LINES_ADJACENCY facelength == 11 && return GL_LINE_STRIP_ADJACENCY return GL_TRIANGLES end function glenum2face(glenum) - glenum == GL_POINTS && return 1 - glenum == GL_LINES && return 2 - glenum == GL_TRIANGLES && return 3 - glenum == GL_QUADS && return 4 - glenum == GL_TRIANGLE_STRIP && return 5 - glenum == GL_LINES_ADJACENCY && return 10 + glenum == GL_POINTS && return 1 + glenum == GL_LINES && return 2 + glenum == GL_TRIANGLES && return 3 + glenum == GL_QUADS && return 4 + glenum == GL_TRIANGLE_STRIP && return 5 + glenum == GL_LINES_ADJACENCY && return 10 glenum == GL_LINE_STRIP_ADJACENCY && return 11 return 1 end -is_struct(::Type{T}) where T = !(sizeof(T) != 0 && nfields(T) == 0) +is_struct(::Type{T}) where {T} = !(sizeof(T) != 0 && nfields(T) == 0) # is_glsl_primitive{T <: StaticVector}(::Type{T}) = true -is_glsl_primitive(::Type{T}) where {T <: Union{Float32, Int32}}= true +is_glsl_primitive(::Type{T}) where {T<:Union{Float32,Int32}} = true function is_glsl_primitive(T) glasserteltype(T) true end -_typeof(::Type{T}) where T = Type{T} -_typeof(::T) where T = T +_typeof(::Type{T}) where {T} = Type{T} +_typeof(::T) where {T} = T glitype(vao::VertexArray) = julia2glenum(eltype(vao.indices)) @@ -205,21 +212,21 @@ bind(vao::VertexArray) = glBindVertexArray(vao.id) unbind(vao::VertexArray) = glBindVertexArray(0) #does this ever work with anything aside from an unsigned int?? -draw(vao::VertexArray{V, ELEMENTS} where V) = glDrawElements(vao.face, vao.nverts, GL_UNSIGNED_INT, C_NULL) +draw(vao::VertexArray{V,ELEMENTS} where {V}) = glDrawElements(vao.face, vao.nverts, GL_UNSIGNED_INT, C_NULL) -draw(vao::VertexArray{V, ELEMENTS_INSTANCED} where V) = glDrawElementsInstanced(vao.face, vao.nverts, GL_UNSIGNED_INT, C_NULL, vao.ninst) +draw(vao::VertexArray{V,ELEMENTS_INSTANCED} where {V}) = glDrawElementsInstanced(vao.face, vao.nverts, GL_UNSIGNED_INT, C_NULL, vao.ninst) -draw(vao::VertexArray{V, SIMPLE} where V) = glDrawArrays(vao.face, 0, vao.nverts) +draw(vao::VertexArray{V,SIMPLE} where {V}) = glDrawArrays(vao.face, 0, vao.nverts) -function Base.show(io::IO, vao::T) where T<:VertexArray - fields = filter(x->x != :buffers && x!=:indices, [fieldnames(T)...]) +function Base.show(io::IO, vao::T) where {T<:VertexArray} + fields = filter(x -> x != :buffers && x != :indices, [fieldnames(T)...]) for field in fields show(io, getfield(vao, field)) - println(io,"") + println(io, "") end end -Base.eltype(::Type{VertexArray{ElTypes, Kind}}) where {ElTypes, Kind} = (ElTypes, Kind) +Base.eltype(::Type{VertexArray{ElTypes,Kind}}) where {ElTypes,Kind} = (ElTypes, Kind) #This could also be done just with the symbols, not needing new bufferattachment infos function upload!(vao::VertexArray; name_buffers...)