package render import ( "image/color" "unsafe" "edgaru089.ml/go/gl01/internal/asset" "edgaru089.ml/go/gl01/internal/util/itype" "github.com/go-gl/gl/all-core/gl" "github.com/go-gl/mathgl/mgl32" ) // framewire vertex type frvertex struct { pos itype.Vec3f color itype.Vec4f } // FramewireRenderer is a renderer drawing framewires. // // It is mainly for debugging uses. type FramewireRenderer struct { shader *Shader vao, vbo uint32 vertex []frvertex } // Framewire is a global FramewireRenderer managed by game logic, for debugging. var Framewire = &FramewireRenderer{} func (f *FramewireRenderer) Init() (err error) { f.shader, err = NewShader(asset.FramewireShaderVert, asset.FramewireShaderFrag) if err != nil { return err } f.shader.SetUniformMat4("model", mgl32.Ident4()) gl.BindFragDataLocation(f.shader.Handle(), 0, gl.Str("outputColor\x00")) gl.GenVertexArrays(1, &f.vao) gl.BindVertexArray(f.vao) gl.GenBuffers(1, &f.vbo) gl.BindBuffer(gl.ARRAY_BUFFER, f.vbo) vertAttrib := uint32(gl.GetAttribLocation(f.shader.Handle(), gl.Str("vert\x00"))) gl.VertexAttribPointer(vertAttrib, 3, gl.FLOAT, false, int32(unsafe.Sizeof(frvertex{})), gl.PtrOffset(int(unsafe.Offsetof(frvertex{}.pos)))) colorAttrib := uint32(gl.GetAttribLocation(f.shader.Handle(), gl.Str("vertColor\x00"))) gl.VertexAttribPointer(colorAttrib, 4, gl.FLOAT, false, int32(unsafe.Sizeof(frvertex{})), gl.PtrOffset(int(unsafe.Offsetof(frvertex{}.color)))) gl.EnableVertexAttribArray(vertAttrib) gl.EnableVertexAttribArray(colorAttrib) return nil } func colorToVec4f(color color.Color) itype.Vec4f { r, g, b, a := color.RGBA() return itype.Vec4f{float32(r) / 0xffff, float32(g) / 0xffff, float32(b) / 0xffff, float32(a) / 0xffff} } // PushLine pushes a line from p0 to p1 into the vertex array. func (f *FramewireRenderer) PushLine(p0, p1 itype.Vec3f, color0, color1 color.Color) { f.vertex = append(f.vertex, frvertex{ pos: p0, color: colorToVec4f(color0), }, frvertex{ pos: p1, color: colorToVec4f(color1), }, ) } const FramewireSizeShrink = 1e-2 // PushBox pushes a 3D box into the vertex array. // // The size of the box is shrunk by a little bit so that it is not obstructed by the world. func (f *FramewireRenderer) PushBox(box itype.Boxf, color color.Color) { box = itype.Boxf{ OffX: box.OffX + FramewireSizeShrink, OffY: box.OffY + 5*FramewireSizeShrink, OffZ: box.OffZ + FramewireSizeShrink, SizeX: box.SizeX - 2*FramewireSizeShrink, SizeY: box.SizeY - 10*FramewireSizeShrink, SizeZ: box.SizeZ - 2*FramewireSizeShrink, } base := box.MinPoint() f.PushLine(base, base.Addv(box.SizeX, 0, 0), color, color) f.PushLine(base, base.Addv(0, 0, box.SizeZ), color, color) f.PushLine(base.Addv(box.SizeX, 0, box.SizeZ), base.Addv(box.SizeX, 0, 0), color, color) f.PushLine(base.Addv(box.SizeX, 0, box.SizeZ), base.Addv(0, 0, box.SizeZ), color, color) f.PushLine(base, base.Addv(0, box.SizeY, 0), color, color) f.PushLine(base.Addv(box.SizeX, 0, 0), base.Addv(box.SizeX, box.SizeY, 0), color, color) f.PushLine(base.Addv(0, 0, box.SizeZ), base.Addv(0, box.SizeY, box.SizeZ), color, color) f.PushLine(base.Addv(box.SizeX, 0, box.SizeZ), base.Addv(box.SizeX, box.SizeY, box.SizeZ), color, color) f.PushLine(base.Addv(0, box.SizeY, 0), base.Addv(box.SizeX, box.SizeY, 0), color, color) f.PushLine(base.Addv(0, box.SizeY, 0), base.Addv(0, box.SizeY, box.SizeZ), color, color) f.PushLine(base.Addv(box.SizeX, box.SizeY, box.SizeZ), base.Addv(box.SizeX, box.SizeY, 0), color, color) f.PushLine(base.Addv(box.SizeX, box.SizeY, box.SizeZ), base.Addv(0, box.SizeY, box.SizeZ), color, color) } // Render renders the framewire into the current OpenGL context and clears it. func (f *FramewireRenderer) Render(view *View) { if len(f.vertex) == 0 { return } f.shader.UseProgram() f.shader.SetUniformMat4("view", view.View()) f.shader.SetUniformMat4("projection", view.Perspective()) gl.BindVertexArray(f.vao) gl.BindBuffer(gl.ARRAY_BUFFER, f.vbo) gl.BufferData(gl.ARRAY_BUFFER, len(f.vertex)*int(unsafe.Sizeof(frvertex{})), gl.Ptr(f.vertex), gl.STREAM_DRAW) gl.DrawArrays(gl.LINES, 0, int32(len(f.vertex))) f.vertex = f.vertex[0:0] }