package levels import ( mgl "github.com/go-gl/mathgl/mgl32" "github.com/inkyblackness/hacked/editor/graphics" "github.com/inkyblackness/hacked/editor/render" "github.com/inkyblackness/hacked/ui/opengl" ) var mapIconsVertexShaderSource = ` #version 150 precision mediump float; in vec3 vertexPosition; in vec3 uvPosition; uniform mat4 modelMatrix; uniform mat4 viewMatrix; uniform mat4 projectionMatrix; uniform vec4 uvLimit; out vec2 uv; void main(void) { gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(vertexPosition, 1.0); uv = vec2(uvPosition.x * uvLimit.x, uvPosition.y * uvLimit.y); } ` var mapIconsFragmentShaderSource = ` #version 150 precision mediump float; uniform sampler2D palette; uniform sampler2D bitmap; in vec2 uv; out vec4 fragColor; void main(void) { vec4 pixel = texture(bitmap, uv); if (pixel.r > 0.0) { fragColor = texture(palette, vec2(pixel.r, 0.5)); } else { discard; } } ` // MapIcons is a renderable for simple bitmaps. type MapIcons struct { context *render.Context program uint32 vao *opengl.VertexArrayObject vertexPositionBuffer uint32 vertexPositionAttrib int32 uvPositionBuffer uint32 uvPositionAttrib int32 modelMatrixUniform opengl.Matrix4Uniform viewMatrixUniform opengl.Matrix4Uniform projectionMatrixUniform opengl.Matrix4Uniform uvLimitUniform opengl.Vector4Uniform paletteUniform int32 bitmapUniform int32 } type iconData struct { pos MapPosition texture *graphics.BitmapTexture } // NewMapIcons returns a new instance. func NewMapIcons(context *render.Context) *MapIcons { gl := context.OpenGL program, programErr := opengl.LinkNewStandardProgram(gl, mapIconsVertexShaderSource, mapIconsFragmentShaderSource) if programErr != nil { panic(opengl.NamedShaderError{Name: "MapIconsShader", Nested: programErr}) } renderable := &MapIcons{ context: context, program: program, vao: opengl.NewVertexArrayObject(gl, program), vertexPositionBuffer: gl.GenBuffers(1)[0], vertexPositionAttrib: gl.GetAttribLocation(program, "vertexPosition"), uvPositionBuffer: gl.GenBuffers(1)[0], uvPositionAttrib: gl.GetAttribLocation(program, "uvPosition"), modelMatrixUniform: opengl.Matrix4Uniform(gl.GetUniformLocation(program, "modelMatrix")), viewMatrixUniform: opengl.Matrix4Uniform(gl.GetUniformLocation(program, "viewMatrix")), projectionMatrixUniform: opengl.Matrix4Uniform(gl.GetUniformLocation(program, "projectionMatrix")), uvLimitUniform: opengl.Vector4Uniform(gl.GetUniformLocation(program, "uvLimit")), paletteUniform: gl.GetUniformLocation(program, "palette"), bitmapUniform: gl.GetUniformLocation(program, "bitmap")} { half := float32(0.5) var vertices = []float32{ -half, half, 0.0, half, half, 0.0, half, -half, 0.0, half, -half, 0.0, -half, -half, 0.0, -half, half, 0.0, } gl.BindBuffer(opengl.ARRAY_BUFFER, renderable.vertexPositionBuffer) gl.BufferData(opengl.ARRAY_BUFFER, len(vertices)*4, vertices, opengl.STATIC_DRAW) gl.BindBuffer(opengl.ARRAY_BUFFER, 0) } { var uv = []float32{ 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, } gl.BindBuffer(opengl.ARRAY_BUFFER, renderable.uvPositionBuffer) gl.BufferData(opengl.ARRAY_BUFFER, len(uv)*4, uv, opengl.STATIC_DRAW) gl.BindBuffer(opengl.ARRAY_BUFFER, 0) } renderable.vao.WithSetter(func(gl opengl.OpenGL) { gl.EnableVertexAttribArray(uint32(renderable.vertexPositionAttrib)) gl.BindBuffer(opengl.ARRAY_BUFFER, renderable.vertexPositionBuffer) gl.VertexAttribOffset(uint32(renderable.vertexPositionAttrib), 3, opengl.FLOAT, false, 0, 0) gl.EnableVertexAttribArray(uint32(renderable.uvPositionAttrib)) gl.BindBuffer(opengl.ARRAY_BUFFER, renderable.uvPositionBuffer) gl.VertexAttribOffset(uint32(renderable.uvPositionAttrib), 3, opengl.FLOAT, false, 0, 0) gl.BindBuffer(opengl.ARRAY_BUFFER, 0) }) return renderable } // Render renders the icons with their center at given position. func (renderable *MapIcons) Render(paletteTexture *graphics.PaletteTexture, iconSize float32, icons []iconData) { gl := renderable.context.OpenGL renderable.vao.OnShader(func() { renderable.viewMatrixUniform.Set(gl, renderable.context.ViewMatrix) renderable.projectionMatrixUniform.Set(gl, &renderable.context.ProjectionMatrix) textureUnit := int32(0) gl.ActiveTexture(opengl.TEXTURE0 + uint32(textureUnit)) gl.BindTexture(opengl.TEXTURE_2D, paletteTexture.Handle()) gl.Uniform1i(renderable.paletteUniform, textureUnit) textureUnit = 1 gl.ActiveTexture(opengl.TEXTURE0 + uint32(textureUnit)) gl.Uniform1i(renderable.bitmapUniform, textureUnit) for _, icon := range icons { x, y := float32(icon.pos.X), float32(icon.pos.Y) u, v := icon.texture.UV() width, height := renderable.limitedSize(iconSize, icon.texture) modelMatrix := mgl.Ident4(). Mul4(mgl.Translate3D(x, y, 0.0)). Mul4(mgl.Scale3D(width, height, 1.0)) renderable.modelMatrixUniform.Set(gl, &modelMatrix) uvLimit := [4]float32{u, v, 0, 0} renderable.uvLimitUniform.Set(gl, &uvLimit) gl.BindTexture(opengl.TEXTURE_2D, icon.texture.Handle()) gl.DrawArrays(opengl.TRIANGLES, 0, 6) } gl.BindTexture(opengl.TEXTURE_2D, 0) }) } func (renderable *MapIcons) limitedSize(iconSize float32, texture *graphics.BitmapTexture) (width, height float32) { width, height = texture.Size() referenceSize := float32(16.0) larger := width if larger < height { larger = height } if larger > referenceSize { ratio := referenceSize / larger width *= ratio height *= ratio } factor := iconSize / referenceSize width *= factor height *= factor return }