func NewSpriteDrawer(window *glfw.Window, layers int) *SpriteDrawer { s := new(SpriteDrawer) vao := gl.GenVertexArray() vao.Bind() s.Camera = vec2.Identity s.Program = CreateProgram("shaders/2d.vert", "shaders/2d.geom", "shaders/texture.frag") s.Use() s.camera_uniform = s.GetUniformLocation("camera") s.Texture = gl.GenTexture() s.Texture.Bind(gl.TEXTURE_2D_ARRAY) gl.TexImage3D(gl.TEXTURE_2D_ARRAY, 0, gl.RGBA, 2048, 2048, layers, 0, gl.RGBA, gl.UNSIGNED_BYTE, nil) gl.TexParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MAG_FILTER, gl.LINEAR) gl.TexParameteri(gl.TEXTURE_2D_ARRAY, gl.TEXTURE_MIN_FILTER, gl.LINEAR) s.Window = window w, h := window.GetSize() s.OnScreenResize(w, h) s.Window.SetSizeCallback(func(window *glfw.Window, w, h int) { s.OnScreenResize(w, h) }) return s }
func NewLineRenderer() *LineRenderer { renderer := LineRenderer{} renderer.Prog = helpers.MakeProgram("Line.vs", "Line.fs") renderer.Prog.Use() renderer.vao = gl.GenVertexArray() renderer.vao.Bind() helpers.BindLocations("line", renderer.Prog, &renderer.RenLoc) renderer.buffer = gl.GenBuffer() renderer.buffer.Bind(gl.ARRAY_BUFFER) helpers.SetAttribPointers(&renderer.RenLoc, &debug.LineVertex{}, false) fmt.Println("Line render location ", renderer.RenLoc) return &renderer }
func MakeProgram(vertFname, fragFname string) gl.Program { vao := gl.GenVertexArray() vao.Bind() vertShader := MakeShader(gl.VERTEX_SHADER, vertFname) defer vertShader.Delete() fragShader := MakeShader(gl.FRAGMENT_SHADER, fragFname) defer fragShader.Delete() program := gl.CreateProgram() program.AttachShader(vertShader) program.AttachShader(fragShader) program.Link() linkstat := program.Get(gl.LINK_STATUS) if linkstat != 1 { // log.Panic("Program link failed, sources=", vertFname, fragFname, "\nstatus=", linkstat, "\nInfo log: ", program.GetInfoLog()) } program.Validate() valstat := program.Get(gl.VALIDATE_STATUS) if valstat != 1 { // log.Panic("Program validation failed: ", valstat) } log := program.GetInfoLog() if log != "" { if program.Get(gl.LINK_STATUS) == gl.FALSE { panic(fmt.Sprint("linking ", vertFname, fragFname, log)) } else { fmt.Print("linking ", vertFname, fragFname, log) } } vao.Delete() return program }
func main() { glfw.SetErrorCallback(errorCallback) // lock glfw/gl calls to a single thread runtime.LockOSThread() runtime.GOMAXPROCS(8) // Render, read commands, send input, extra for file loading, etc if !glfw.Init() { panic("Could not init glfw!") } defer glfw.Terminate() glfw.WindowHint(glfw.ContextVersionMajor, 3) glfw.WindowHint(glfw.ContextVersionMinor, 3) glfw.WindowHint(glfw.OpenglForwardCompatible, glfw.True) glfw.WindowHint(glfw.OpenglProfile, glfw.OpenglCoreProfile) window, err := glfw.CreateWindow(800, 600, "Example", nil, nil) if err != nil { panic(err) } window.SetFramebufferSizeCallback(func(w *glfw.Window, width, height int) { fmt.Printf("Framebuffer size is now %vx%v\n", width, height) // Keep aspect ratio from camwidth/camheight camRatio := camWidth / camHeight bufRatio := float32(width) / float32(height) var newWidth, newHeight float32 switch { case camRatio > bufRatio: newHeight = float32(width) / camRatio newWidth = float32(width) case bufRatio > camRatio: newWidth = float32(height) * camRatio newHeight = float32(height) } fmt.Printf("Viewport size is now %vx%v; cam ratio is %v; viewport ratio is %v;\n", newWidth, newHeight, camRatio, newWidth/newHeight) gl.Viewport((width-int(newWidth))/2, (height-int(newHeight))/2, int(newWidth), int(newHeight)) }) defer window.Destroy() window.MakeContextCurrent() glfw.SwapInterval(1) gl.Init() // Enable blending gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) vao := gl.GenVertexArray() vao.Bind() vbo := gl.GenBuffer() vbo.Bind(gl.ARRAY_BUFFER) verticies := []float32{-0.5, 0.5, 0.5, 0.5, 0.5, -0.5, -0.5, -0.5} gl.BufferData(gl.ARRAY_BUFFER, len(verticies)*4, verticies, gl.STATIC_DRAW) vertex_shader := gl.CreateShader(gl.VERTEX_SHADER) vertex_shader.Source(vertex) vertex_shader.Compile() fmt.Println(vertex_shader.GetInfoLog()) defer vertex_shader.Delete() fragment_shader := gl.CreateShader(gl.FRAGMENT_SHADER) fragment_shader.Source(fragment) fragment_shader.Compile() fmt.Println(fragment_shader.GetInfoLog()) defer fragment_shader.Delete() program := gl.CreateProgram() program.AttachShader(vertex_shader) program.AttachShader(fragment_shader) program.BindFragDataLocation(0, "outColor") program.Link() program.Use() defer program.Delete() positionAttrib := program.GetAttribLocation("position") positionAttrib.AttribPointer(2, gl.FLOAT, false, 0, nil) positionAttrib.EnableArray() defer positionAttrib.DisableArray() modelMat := program.GetUniformLocation("modelView") projMat := program.GetUniformLocation("projection") spriteSize := program.GetUniformLocation("size") cmd := exec.Command(os.Args[1], os.Args[2:]...) stdoutReader, stdoutWriter := io.Pipe() cmd.Stdout = stdoutWriter input := bufio.NewReader(stdoutReader) stdinReader, stdinWriter := io.Pipe() cmd.Stdin = stdinReader stderr, err := cmd.StderrPipe() chkErr(err) go io.Copy(os.Stderr, stderr) err = cmd.Start() chkErr(err) window.SetKeyCallback(handleKey) go func() { runtime.LockOSThread() for !window.ShouldClose() { sendInput(stdinWriter) //fmt.Fprintf(stdinWriter, "T %v\n", time.Now()) <-ticks readCommands(input) } }() frameCnt := 0 queueDepth := 0 then := time.Now() for !window.ShouldClose() { frameCnt++ queueDepth += len(commandBus) if frameCnt%120 == 0 { fmt.Printf("Queue depth: %v. Render time: %v. Decode time: %v.\n", queueDepth/120, time.Since(then)/120, decodeTime/time.Duration(decodes)) queueDepth = 0 then = time.Now() decodeTime = time.Duration(0) decodes = 0 } for len(commandBus) > 0 { (<-commandBus)() } halfwidth := camWidth / 2.0 halfheight := camHeight / 2.0 projection := mathgl.Ortho2D(camera.x-halfwidth, camera.x+halfwidth, camera.y+halfheight, camera.y-halfheight) projection = mathgl.Scale3D(camera.sx, camera.sy, 1).Mul4(projection) projection = mathgl.HomogRotate3DZ(camera.rot).Mul4(projection) projMat.UniformMatrix4f(false, (*[16]float32)(&projection)) gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) for _, sprite := range sprites { sMat := mathgl.Scale3D(sprite.sx, sprite.sy, 1) sMat = mathgl.HomogRotate3DZ(sprite.rot).Mul4(sMat) sMat = mathgl.Translate3D(sprite.x, sprite.y, sprite.z).Mul4(sMat) // temp hack bank in sprite.bank = 1 sMap := findSMap(sprite.smap) spriteSize.Uniform2f(float32(sMap.getWidth()*sprite.cellwidth), float32(sMap.getHeight()*sprite.cellheight)) modelMat.UniformMatrix4f(false, (*[16]float32)(&sMat)) gl.DrawArrays(gl.TRIANGLE_FAN, 0, 4) } window.SwapBuffers() glfw.PollEvents() if window.GetKey(glfw.KeyEscape) == glfw.Press { window.SetShouldClose(true) } } }
func GenVertexArray() VAO { return VAO(gl.GenVertexArray()) }
func NewParticleSystem(w *gamestate.World, numParticles int, Origin mgl.Vec3, initialSpeed, MaxLifetime float32) *ParticleSystem { vertices := make([]ParticleVertex, numParticles) directions := make([]NonTransformBuffer, numParticles) for i := range vertices { dir := mgl.Vec3{rand.Float32()*2 - 1, rand.Float32()*2 - 1, rand.Float32()*2 - 1} for dir.Len() > 1 { dir = mgl.Vec3{rand.Float32()*2 - 1, rand.Float32()*2 - 1, rand.Float32()*2 - 1} } dir = dir.Mul(initialSpeed) vertices[i] = ParticleVertex{ Pos1: Origin, Pos2: Origin.Sub(dir), Lifetime: rand.Float32() * MaxLifetime, } directions[i] = NonTransformBuffer{dir} } buffer1, buffer2, nonTransformBuffer := gl.GenBuffer(), gl.GenBuffer(), gl.GenBuffer() nonTransformBuffer.Bind(gl.ARRAY_BUFFER) gl.BufferData(gl.ARRAY_BUFFER, helpers.ByteSizeOfSlice(directions), directions, gl.STATIC_DRAW) buffer1.Bind(gl.ARRAY_BUFFER) gl.BufferData(gl.ARRAY_BUFFER, helpers.ByteSizeOfSlice(vertices), vertices, gl.STREAM_DRAW) buffer2.Bind(gl.ARRAY_BUFFER) gl.BufferData(gl.ARRAY_BUFFER, helpers.ByteSizeOfSlice(vertices), uintptr(0), gl.STREAM_DRAW) shapeData := CreateShapeDataBuffer() TransformProg := gl.CreateProgram() shader := helpers.MakeShader(gl.VERTEX_SHADER, "ParticleTFF.vs") TransformProg.AttachShader(shader) TransformProg.TransformFeedbackVaryings([]string{"v_Pos1", "v_Pos2", "v_Lifetime"}, gl.INTERLEAVED_ATTRIBS) TransformProg.Link() shader.Delete() TransformProg.Use() TransformLoc := ProgramLocations{} helpers.BindLocations("particle transform", TransformProg, &TransformLoc) renderProgram := helpers.MakeProgram("Particle.vs", "Particle.fs") renderProgram.Use() RenderLoc := RenderProgramLocations{} helpers.BindLocations("particle render", renderProgram, &RenderLoc) vaoTff1 := gl.GenVertexArray() vaoTff2 := gl.GenVertexArray() vaoRender1 := gl.GenVertexArray() vaoRender2 := gl.GenVertexArray() ps := ParticleSystem{ TransformProg: TransformProg, TransformLoc: TransformLoc, RenderProg: renderProgram, RenderLoc: RenderLoc, VaoTff1: vaoTff1, VaoTff2: vaoTff2, VaoRender1: vaoRender1, VaoRender2: vaoRender2, Data1: buffer1, Data2: buffer2, ShapeData: shapeData, NonTransformBuffer: nonTransformBuffer, NumParticles: numParticles, Origin: Origin, Gravity: -9.81 / 200, InitialSpeed: initialSpeed, MaxLifetime: MaxLifetime, } min_h, max_h := w.HeightMap.Bounds() W := float32(w.HeightMap.W) H := float32(w.HeightMap.H) TransformProg.Use() ps.SetUniforms() ps.SetVaos() TransformProg.Use() ps.TransformLoc.HeightMap.Uniform1i(constants.TextureHeightMap) ps.TransformLoc.LowerBound.Uniform3f(0, 0, min_h) ps.TransformLoc.UpperBound.Uniform3f(W, H, max_h) return &ps }
func LoadMeshToGpu(mesh *Mesh, renLoc *RenderLocations) (rd RenderData) { rd.VAO = gl.GenVertexArray() rd.VAO.Bind() { vertices := mesh.Vertices verticesType := reflect.TypeOf(vertices) if verticesType.Kind() != reflect.Slice { panic("Vertices is not a slice") } rd.Vertices = gl.GenBuffer() rd.Vertices.Bind(gl.ARRAY_BUFFER) gl.BufferData(gl.ARRAY_BUFFER, helpers.ByteSizeOfSlice(vertices), vertices, gl.STATIC_DRAW) rd.Numverts = reflect.ValueOf(vertices).Len() helpers.SetAttribPointers(renLoc, reflect.ValueOf(vertices).Index(0).Addr().Interface(), false) switch mesh.Mode { case Points: rd.Mode = gl.POINTS case LineStrip: rd.Mode = gl.LINE_STRIP case LineLoop: rd.Mode = gl.LINE_LOOP case Lines: rd.Mode = gl.LINES case TriangleStrip: rd.Mode = gl.TRIANGLE_STRIP case TriangleFan: rd.Mode = gl.TRIANGLE_FAN case Triangles: rd.Mode = gl.TRIANGLES default: panic("unsupported mode") } } if indices := mesh.Indices; indices != nil { indicesType := reflect.TypeOf(indices) if indicesType.Kind() != reflect.Slice { panic("Indices is not a slice") } rd.Indices = gl.GenBuffer() rd.Indices.Bind(gl.ELEMENT_ARRAY_BUFFER) gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, helpers.ByteSizeOfSlice(indices), indices, gl.STATIC_DRAW) rd.Numverts = reflect.ValueOf(indices).Len() switch indicesType.Elem().Kind() { case reflect.Uint8, reflect.Int8: rd.IndexType = gl.UNSIGNED_BYTE case reflect.Uint16, reflect.Int16: rd.IndexType = gl.UNSIGNED_SHORT case reflect.Uint32, reflect.Int32: rd.IndexType = gl.UNSIGNED_INT default: panic(fmt.Sprint("unsupported index type", indicesType.Elem().Kind())) } } if instanceData := mesh.InstanceData; instanceData != nil { Type := reflect.TypeOf(instanceData) if Type.Kind() != reflect.Slice { panic("InstanceData is not a slice") } rd.InstanceData = gl.GenBuffer() rd.InstanceData.Bind(gl.ARRAY_BUFFER) gl.BufferData(gl.ARRAY_BUFFER, helpers.ByteSizeOfSlice(instanceData), instanceData, gl.STATIC_DRAW) helpers.SetAttribPointers(renLoc, reflect.ValueOf(instanceData).Index(0).Addr().Interface(), true) rd.NumInstances = reflect.ValueOf(instanceData).Len() } return }