Last active
March 14, 2017 11:30
-
-
Save TsurHerman/a2126a640388c3456e9672635e9067ef to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using ModernGL | |
function gen_buffer(f,n::Integer) | |
res = Array{GLuint}(n) | |
f(n,res) | |
if any(res .<= 0) | |
error("invalid id. OpenGL Context active?") | |
end | |
return res | |
end | |
function glGenVertexArrays(n::Integer) | |
f = ModernGL.glGenVertexArrays | |
n == 1 ? begin res = gen_buffer(f,1);res = res[1] end : gen_buffer(f,n) ; | |
end | |
function glGenBuffers(n::Integer) | |
f = ModernGL.glGenBuffers | |
n == 1 ? begin res = gen_buffer(f,1);res = res[1] end : gen_buffer(f,n) ; | |
end | |
###########################shaders.jl | |
#= | |
module glUtils | |
=# | |
function getinfolog(obj::GLuint) | |
# Return the info log for obj, whether it be a shader or a program. | |
isShader = glIsShader(obj) | |
getiv = isShader == GL_TRUE ? glGetShaderiv : glGetProgramiv | |
get_log = isShader == GL_TRUE ? glGetShaderInfoLog : glGetProgramInfoLog | |
# Get the maximum possible length for the descriptive error message | |
maxlength = GLint[0] | |
getiv(obj, GL_INFO_LOG_LENGTH, maxlength) | |
maxlength = first(maxlength) | |
# Return the text of the message if there is any | |
if maxlength > 0 | |
buffer = zeros(GLchar, maxlength+1) | |
sizei = GLsizei[0] | |
get_log(obj, maxlength, sizei, buffer) | |
length = first(sizei) | |
return false,String(buffer) | |
else | |
return true,"success" | |
end | |
end | |
function iscompiled(shader::GLuint) | |
success = GLint[0] | |
glGetShaderiv(shader, GL_COMPILE_STATUS, success) | |
return first(success) == GL_TRUE | |
end | |
function islinked(program::GLuint) | |
success = GLint[0] | |
glGetProgramiv(program, GL_LINK_STATUS, success) | |
return first(success) == GL_TRUE | |
end | |
" loadshaders(path, shadername_type:Array{Tuple{String,GLenum},1})" | |
function loadshaders(path::String, S::Array{Tuple{String,GLenum},1}) | |
prog_id = glCreateProgram(); | |
shader_id = Vector{GLenum}() | |
for s in S | |
sid = compile(joinpath(path,s[1]),s[2]) | |
glAttachShader(prog_id, sid) | |
push!(shader_id,sid) | |
end | |
print("linking...") | |
glLinkProgram(prog_id) | |
info_success,msg = getinfolog(prog_id) | |
success = islinked(prog_id) | |
success ? print("$(msg)\n") : error("[SHADER ERROR]$(msg)") | |
for sid in shader_id | |
glDetachShader(prog_id,sid) | |
glDeleteShader(sid) | |
end | |
glUseProgram(prog_id) | |
return prog_id | |
end | |
""" | |
compile(fname,SHADER_TYPE) | |
""" | |
function compile(fname::String,SHADER_TYPE::GLuint) | |
source = open(fname) do f | |
readstring(f) | |
end | |
shaderid = glCreateShader(SHADER_TYPE) | |
print("Compiling shader $(fname)...") | |
glShaderSource(shaderid, 1, [source,] , C_NULL) | |
glCompileShader(shaderid) | |
info_success,msg = getinfolog(shaderid) | |
success = iscompiled(shaderid) | |
success ? print("$(msg)\n") : | |
begin | |
print("\n $(msg)"); | |
error("[$(GLENUM(SHADER_TYPE).name) ERROR!]") | |
end | |
return shaderid | |
end | |
##################################### | |
###GLProgram############################################### | |
abstract glBuffer | |
type ElementsArrayBuffer <: glBuffer | |
id::GLuint | |
verticesize::Integer | |
nvertices::Integer | |
eltype::GLenum | |
ElementsArrayBuffer() = new(glGenBuffers(1),0,0,GL_UNSIGNED_INT) | |
ElementsArrayBuffer{T<:Integer}(data::Array{T,2}) = begin | |
VA = ElementsArrayBuffer(); | |
update!(VA,data) | |
VA | |
end | |
end | |
export ElementsArrayBuffer | |
type VertexAttrBuffer <: glBuffer | |
id::GLuint | |
verticesize::Integer | |
nvertices::Integer | |
eltype::GLenum | |
VertexAttrBuffer() = new(glGenBuffers(1),0,0,GL_FLOAT) | |
VertexAttrBuffer{T<:Real}(data::Array{T,2}) = begin | |
VA = VertexAttrBuffer(); | |
update!(VA,data) | |
VA | |
end | |
end | |
export VertexAttrBuffer | |
function update!{T<:Real}(va::glBuffer , data::Array{T,2}) | |
isa(va,VertexAttrBuffer) && (data = convert(Array{Float32},data)) | |
isa(va,ElementsArrayBuffer) && (data = convert(Array{UInt32},data)) | |
BufType = isa(va,ElementsArrayBuffer) ? GL_ELEMENT_ARRAY_BUFFER :GL_ARRAY_BUFFER | |
#TODO insert a more elaborate error msg | |
if !(va.verticesize == 0 || va.verticesize == size(data,1)) | |
error("updateing a binded buffer - size mismatch") | |
end | |
va.nvertices = size(data,2) | |
va.verticesize = size(data,1) | |
assert(va.verticesize <= 4) | |
glBindBuffer(BufType, va.id) | |
glBufferData(BufType, sizeof(data), data, GL_STATIC_DRAW) | |
end | |
export update! | |
type ShaderInput | |
inputtype::Symbol | |
location::Int32 | |
size::Int32 | |
GLtype::GLenum | |
GLtype_name::Symbol | |
jeltype::Type | |
_bindedto | |
ShaderInput(int,loc,sz,glt) = | |
new(int,loc,sz,glt,GLENUM(glt).name,gl2jeltype(glt),nothing) | |
end | |
function activeinputs(prog::Integer) | |
inputs = Dict{String,ShaderInput}() | |
buf = zeros(GLchar,81) | |
nchar = GLsizei[0] | |
sz = GLint[0] | |
GLtype = GLenum[0] | |
enumerate(gl_f,enum,loc,sym) = | |
begin | |
num_inputs = Int32[0] | |
glGetProgramiv(prog,enum,num_inputs) | |
num_inputs = first(num_inputs) | |
for i = 0:(num_inputs-1) | |
gl_f(prog,i,80,nchar,sz,GLtype,buf) | |
name = String(buf[1:nchar[1]]) | |
m = match(r"^([^[]*)",name) | |
name = m.captures[1] | |
#print("$(name) $(sym) $(sz[1])\n") | |
inputs[name] = ShaderInput(sym,loc(prog,name),sz[1],GLtype[1]) | |
end | |
end | |
enumerate(glGetActiveAttrib,GL_ACTIVE_ATTRIBUTES,glGetAttribLocation,:VertexAttr) | |
enumerate(glGetActiveUniform,GL_ACTIVE_UNIFORMS,glGetUniformLocation,:Uniform) | |
inputs | |
end | |
type GLprogram | |
id::GLuint | |
indices::ElementsArrayBuffer | |
inputs::Dict{String,ShaderInput} | |
vertices::Int32 | |
GLprogram(path::String, S::Array{Tuple{String,GLenum},1}) = | |
begin | |
id = loadshaders(path,S) | |
glUseProgram(id) | |
inputs = activeinputs(id) | |
new(id,ElementsArrayBuffer(),inputs,0) | |
end | |
end | |
export GLprogram | |
function setvertex_attr(prog::GLprogram,location::Integer,va_array::VertexAttrBuffer) | |
glUseProgram(prog.id); | |
glBindBuffer(GL_ARRAY_BUFFER, va_array.id); | |
glVertexAttribPointer(location, va_array.verticesize ,GL_FLOAT,GL_FALSE,0,C_NULL) | |
glEnableVertexAttribArray(location) | |
end | |
global lastused = -1 | |
function use(P::GLprogram,force::Bool = true) | |
(lastused == P.id && !force) && return; | |
glUseProgram(P.id); | |
lastUsedProg = P.id | |
I = P.inputs; | |
skip_names = ["gl_InstanceID"] | |
foreach(I[key] for key in keys(I) if I[key].inputtype == :VertexAttr && !any(key .== skip_names) ) do I | |
for i=1:I.size | |
setvertex_attr(P,I.location+i-1,I._bindedto[i]); | |
end | |
end | |
end | |
export use | |
function gl2jeltype(typ::GLenum) | |
FLoatTypes = (GL_FLOAT,GL_FLOAT_VEC2,GL_FLOAT_VEC3,GL_FLOAT_VEC4, | |
GL_FLOAT_MAT2,GL_FLOAT_MAT3,GL_FLOAT_MAT4,GL_FLOAT_MAT3x2, | |
GL_FLOAT_MAT2x3 ,GL_FLOAT_MAT4x3 ,GL_FLOAT_MAT3x4); | |
IntTypes = (GL_INT,GL_INT_VEC2,GL_INT_VEC3,GL_INT_VEC4); | |
if any([FLoatTypes...] .== typ) return Float32 end | |
if any([IntTypes...] .== typ) return Int32 end | |
error("[gl2jtype UNMATCHED UNIFORM type please fix!]") | |
end | |
using StaticArrays | |
function setuniform(prog::GLprogram,name::String,offset::Integer,value) | |
value = isa(value,Array) && any([size(value)...] .== 1) ? (value...) : value | |
jeltype = prog.inputs[name].jeltype; | |
location = prog.inputs[name].location + offset | |
suffix = jeltype == Float32 ? "f" : jeltype == Int32 ? "i" : jeltype == UInt32 ? "ui" :"ERROR"; | |
if isa(value,Real) #single value | |
mvalue = convert(jeltype,value) | |
glfunc = eval(Symbol("glProgramUniform1",suffix)) | |
glfunc(prog.id,location,mvalue) | |
elseif isa(value,Tuple) | |
mvalue = convert(NTuple{length(value),jeltype},value) | |
glfunc = eval(Symbol("glProgramUniform",length(mvalue),suffix)) | |
glfunc(prog.id,location,mvalue...) | |
elseif isa(value,Matrix) | |
mvalue = convert(Array{Float32,2},value) | |
(M,N) = size(mvalue) | |
mat_suffix = M == N ? M : string(N,'x',M) | |
glfunc = eval(Symbol("glProgramUniformMatrix",mat_suffix,"fv")) | |
glfunc(prog.id,location,1,false,mvalue) | |
elseif isa(value,StaticArray) | |
if eltype(value) != Float32 | |
value = SMatrix{size(value)...,Float32}(value) | |
end | |
(M,N) = size(value) | |
mat_suffix = M == N ? M : string(N,'x',M) | |
glfunc = eval(Symbol("glProgramUniformMatrix",mat_suffix,"fv")) | |
glfunc(prog.id,location,1,false,pointer_from_objref(value)) | |
end | |
end | |
import Base.setindex! | |
function setindex!(prog::GLprogram,value,param::String,offset=0) | |
param == "_indices" && (return set_indices(prog,value)) | |
if !haskey(prog.inputs,param) | |
warn("[GLProgram] *$(param)* does not exist -- maybe it was optimized out?") | |
return false | |
end | |
# if isa(value,Vector) | |
# for i=0:length(Vector)-1 | |
# setindex!(prog,value[i],(param,offset+i)) | |
# end | |
# end | |
#from here we have a single value lets do some conversions and asserts | |
si = prog.inputs[param] | |
if offset >= si.size | |
error("[GLprogram] **$(param)* size exceeded ") | |
end | |
if si.inputtype == :Uniform | |
setuniform(prog,param,offset,value) | |
elseif si.inputtype == :VertexAttr | |
if si._bindedto == nothing | |
si._bindedto = Vector{VertexAttrBuffer}(si.size) | |
end | |
if isa(value,VertexAttrBuffer) | |
#setvertex_attr(prog,si.location+offset,value) | |
si._bindedto[offset+1] = value | |
prog.vertices = value.nvertices | |
elseif isa(value,Matrix) | |
prog.vertices = size(value,2); | |
if isdefined(si._bindedto,offset+1) #update binded buffer | |
update!(si._bindedto[offset+1] , value) | |
else | |
va = VertexAttrBuffer(value) | |
#setvertex_attr(prog,si.location+offset,va) | |
si._bindedto[offset+1] = va | |
end | |
else | |
error("[GLprogram] unexpected input"); | |
end | |
else | |
error("[GLProgram] unexpected input type") | |
end | |
end | |
function set_indices(prog,value::Matrix) | |
update!(prog.indices,value) | |
end | |
function set_indices(prog,value::ElementsArrayBuffer) | |
glDeleteBuffers(1,[prog.indices]) | |
prog.indices = value | |
end | |
function draw(prog::GLprogram,primitive::GLenum = GL_TRIANGLES,start::Integer = 0,_end::Integer = -1) | |
use(prog) | |
(_end==-1) && (_end = prog.vertices) | |
glDrawArrays(primitive, start, _end); | |
end | |
export draw | |
function drawindexed(prog::GLprogram; start::Integer = 0,_end::Integer = -1, instances = 1) | |
use(prog) | |
(_end==-1) && (_end = prog.indices.nvertices) | |
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, prog.indices.id); | |
nv = prog.indices.nvertices | |
vsz = prog.indices.verticesize | |
primitive = [GL_POINTS GL_LINES GL_TRIANGLES] | |
glDrawElementsInstancedEXT(primitive[vsz] , vsz * _end, prog.indices.eltype , | |
Ptr{Void}(vsz*start*sizeof(prog.indices.eltype)),instances) | |
end | |
export drawindexed | |
function setvar(progs,varname,data) | |
foreach(progs) do prog | |
prog[varname] = data | |
end | |
end | |
function setvar(progs,varname::Tuple,data) | |
foreach(progs) do prog | |
prog[varname...] = data | |
end | |
end | |
function setvar(prog::GLprogram,varname,data) | |
prog[varname] = data | |
end | |
export setvar | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment