Adding modding folder with a hacked build.
This commit is contained in:
@@ -0,0 +1,420 @@
|
||||
package gui
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/inkyblackness/imgui-go/v3"
|
||||
|
||||
"github.com/inkyblackness/hacked/ui/opengl"
|
||||
)
|
||||
|
||||
type fontFileError struct {
|
||||
Filename string
|
||||
}
|
||||
|
||||
func (err fontFileError) Error() string {
|
||||
return fmt.Sprintf("could not load font '%s'", err.Filename)
|
||||
}
|
||||
|
||||
// ContextParameters describes how to create the context.
|
||||
type ContextParameters struct {
|
||||
// ConfigDir is used to store the UI state in.
|
||||
ConfigDir string
|
||||
// FontFile is the filename of a .TTF file to load instead of using default.
|
||||
FontFile string
|
||||
// FontSize is the requested size of the font. Defaults to 12.
|
||||
FontSize float32
|
||||
}
|
||||
|
||||
// BitmapTextureQuery resolves the texture and the palette to be used for a bitmap.
|
||||
type BitmapTextureQuery func(id imgui.TextureID) (palette uint32, texture uint32)
|
||||
|
||||
// Context describes a scope for a graphical user interface.
|
||||
// It is based on ImGui.
|
||||
type Context struct {
|
||||
imguiContext *imgui.Context
|
||||
window opengl.Window
|
||||
|
||||
lastRenderTime time.Time
|
||||
|
||||
mouseButtonWasDown [3]bool
|
||||
mouseButtonIsDown [3]bool
|
||||
|
||||
fontTexture uint32
|
||||
shaderHandle uint32
|
||||
attribLocationType int32
|
||||
attribLocationTex int32
|
||||
attribLocationPal int32
|
||||
attribLocationProjMtx int32
|
||||
attribLocationPosition int32
|
||||
attribLocationUV int32
|
||||
attribLocationColor int32
|
||||
vboHandle uint32
|
||||
elementsHandle uint32
|
||||
}
|
||||
|
||||
// NewContext initializes a new UI context based on the provided OpenGL window.
|
||||
func NewContext(window opengl.Window, param ContextParameters) (context *Context, err error) {
|
||||
imgui.SetAssertHandler(nil)
|
||||
context = &Context{
|
||||
imguiContext: imgui.CreateContext(nil),
|
||||
window: window,
|
||||
}
|
||||
|
||||
imgui.CurrentIO().SetIniFilename(filepath.Join(param.ConfigDir, "imgui.ini"))
|
||||
|
||||
err = context.createDeviceObjects(param)
|
||||
if err != nil {
|
||||
context.Destroy()
|
||||
context = nil
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Destroy cleans up the resources of the graphical user interface.
|
||||
func (context *Context) Destroy() {
|
||||
context.destroyDeviceObjects(context.window.OpenGL())
|
||||
context.imguiContext.Destroy()
|
||||
}
|
||||
|
||||
// MouseButtonChanged is called when the state of a button has changed.
|
||||
func (context *Context) MouseButtonChanged(buttonIndex int, down bool) {
|
||||
if (buttonIndex >= 0) && (buttonIndex < len(context.mouseButtonIsDown)) {
|
||||
context.mouseButtonIsDown[buttonIndex] = down
|
||||
if down {
|
||||
context.mouseButtonWasDown[buttonIndex] = down
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IsUsingMouse returns true if the UI is using the mouse.
|
||||
// The application should not process mouse events in this case.
|
||||
func (context Context) IsUsingMouse() bool {
|
||||
return imgui.CurrentIO().WantCaptureMouse()
|
||||
}
|
||||
|
||||
// IsUsingKeyboard returns true if the UI is currently capturing keyboard input.
|
||||
// The application should not process keyboard input events in this case.
|
||||
func (context Context) IsUsingKeyboard() bool {
|
||||
return imgui.CurrentIO().WantTextInput()
|
||||
}
|
||||
|
||||
// NewFrame must be called at the start of rendering.
|
||||
func (context *Context) NewFrame() {
|
||||
io := imgui.CurrentIO()
|
||||
|
||||
windowWidth, windowHeight := context.window.Size()
|
||||
io.SetDisplaySize(imgui.Vec2{X: float32(windowWidth), Y: float32(windowHeight)})
|
||||
|
||||
now := time.Now()
|
||||
if !context.lastRenderTime.IsZero() {
|
||||
elapsed := now.Sub(context.lastRenderTime)
|
||||
io.SetDeltaTime(float32(elapsed.Seconds()))
|
||||
}
|
||||
context.lastRenderTime = now
|
||||
|
||||
for i := 0; i < len(context.mouseButtonWasDown); i++ {
|
||||
down := context.mouseButtonWasDown[i] || context.mouseButtonIsDown[i]
|
||||
io.SetMouseButtonDown(i, down)
|
||||
context.mouseButtonWasDown[i] = false
|
||||
}
|
||||
|
||||
imgui.NewFrame()
|
||||
}
|
||||
|
||||
// Render must be called at the end of rendering.
|
||||
func (context *Context) Render(bitmapTextureQuery BitmapTextureQuery) {
|
||||
imgui.Render()
|
||||
context.renderDrawData(imgui.RenderedDrawData(), bitmapTextureQuery)
|
||||
}
|
||||
|
||||
func (context *Context) createDeviceObjects(param ContextParameters) (err error) {
|
||||
gl := context.window.OpenGL()
|
||||
glslVersion := "#version 150"
|
||||
|
||||
vertexShaderSource := glslVersion + `
|
||||
uniform mat4 ProjMtx;
|
||||
in vec2 Position;
|
||||
in vec2 UV;
|
||||
in vec4 Color;
|
||||
out vec2 Frag_UV;
|
||||
out vec4 Frag_Color;
|
||||
void main()
|
||||
{
|
||||
Frag_UV = UV;
|
||||
Frag_Color = Color;
|
||||
gl_Position = ProjMtx * vec4(Position.xy,0,1);
|
||||
}
|
||||
`
|
||||
fragmentShaderSource := glslVersion + `
|
||||
uniform int ImageType;
|
||||
uniform sampler2D Texture;
|
||||
uniform sampler2D Palette;
|
||||
in vec2 Frag_UV;
|
||||
in vec4 Frag_Color;
|
||||
out vec4 Out_Color;
|
||||
void main()
|
||||
{
|
||||
if (ImageType == 1)
|
||||
{
|
||||
vec4 pixel = texture(Texture, Frag_UV.st);
|
||||
Out_Color = Frag_Color * texture(Palette, vec2(pixel.r, 0.5));
|
||||
}
|
||||
else if (ImageType == 2)
|
||||
{
|
||||
Out_Color = texture(Texture, Frag_UV.st) * Frag_Color;
|
||||
}
|
||||
else
|
||||
{
|
||||
Out_Color = vec4(Frag_Color.rgb, Frag_Color.a * texture( Texture, Frag_UV.st).r);
|
||||
}
|
||||
}
|
||||
`
|
||||
context.shaderHandle, err = opengl.LinkNewStandardProgram(gl, vertexShaderSource, fragmentShaderSource)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
context.attribLocationType = gl.GetUniformLocation(context.shaderHandle, "ImageType")
|
||||
context.attribLocationTex = gl.GetUniformLocation(context.shaderHandle, "Texture")
|
||||
context.attribLocationPal = gl.GetUniformLocation(context.shaderHandle, "Palette")
|
||||
context.attribLocationProjMtx = gl.GetUniformLocation(context.shaderHandle, "ProjMtx")
|
||||
context.attribLocationPosition = gl.GetAttribLocation(context.shaderHandle, "Position")
|
||||
context.attribLocationUV = gl.GetAttribLocation(context.shaderHandle, "UV")
|
||||
context.attribLocationColor = gl.GetAttribLocation(context.shaderHandle, "Color")
|
||||
|
||||
buffers := gl.GenBuffers(2)
|
||||
context.vboHandle = buffers[0]
|
||||
context.elementsHandle = buffers[1]
|
||||
|
||||
return context.createFontsTexture(gl, param)
|
||||
}
|
||||
|
||||
func (context *Context) createFontsTexture(gl opengl.OpenGL, param ContextParameters) error {
|
||||
io := imgui.CurrentIO()
|
||||
fontAtlas := io.Fonts()
|
||||
if len(param.FontFile) > 0 {
|
||||
fontSize := float32(16.0)
|
||||
if param.FontSize > 0.0 {
|
||||
fontSize = param.FontSize
|
||||
}
|
||||
font := fontAtlas.AddFontFromFileTTF(param.FontFile, fontSize)
|
||||
if font == imgui.DefaultFont {
|
||||
return fontFileError{Filename: param.FontFile}
|
||||
}
|
||||
}
|
||||
image := fontAtlas.TextureDataAlpha8()
|
||||
|
||||
context.fontTexture = gl.GenTextures(1)[0]
|
||||
gl.BindTexture(opengl.TEXTURE_2D, context.fontTexture)
|
||||
gl.TexParameteri(opengl.TEXTURE_2D, opengl.TEXTURE_MIN_FILTER, opengl.LINEAR)
|
||||
gl.TexParameteri(opengl.TEXTURE_2D, opengl.TEXTURE_MAG_FILTER, opengl.LINEAR)
|
||||
gl.PixelStorei(opengl.UNPACK_ROW_LENGTH, 0)
|
||||
gl.TexImage2D(opengl.TEXTURE_2D, 0, opengl.RED, int32(image.Width), int32(image.Height),
|
||||
0, opengl.RED, opengl.UNSIGNED_BYTE, image.Pixels)
|
||||
|
||||
io.Fonts().SetTextureID(TextureIDForSimpleTexture(context.fontTexture))
|
||||
|
||||
gl.BindTexture(opengl.TEXTURE_2D, 0)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (context *Context) destroyDeviceObjects(gl opengl.OpenGL) {
|
||||
if context.vboHandle != 0 {
|
||||
gl.DeleteBuffers([]uint32{context.vboHandle})
|
||||
}
|
||||
context.vboHandle = 0
|
||||
if context.elementsHandle != 0 {
|
||||
gl.DeleteBuffers([]uint32{context.elementsHandle})
|
||||
}
|
||||
context.elementsHandle = 0
|
||||
|
||||
if context.shaderHandle != 0 {
|
||||
gl.DeleteProgram(context.shaderHandle)
|
||||
}
|
||||
context.shaderHandle = 0
|
||||
|
||||
if context.fontTexture != 0 {
|
||||
gl.DeleteTextures([]uint32{context.fontTexture})
|
||||
imgui.CurrentIO().Fonts().SetTextureID(0)
|
||||
context.fontTexture = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (context *Context) renderDrawData(drawData imgui.DrawData, bitmapTextureQuery BitmapTextureQuery) {
|
||||
gl := context.window.OpenGL()
|
||||
|
||||
displayWidth, displayHeight := context.window.Size()
|
||||
|
||||
// Backup GL state
|
||||
var lastActiveTexture int32
|
||||
gl.GetIntegerv(opengl.ACTIVE_TEXTURE, &lastActiveTexture)
|
||||
gl.ActiveTexture(opengl.TEXTURE0)
|
||||
var lastProgram int32
|
||||
gl.GetIntegerv(opengl.CURRENT_PROGRAM, &lastProgram)
|
||||
var lastTexture int32
|
||||
gl.GetIntegerv(opengl.TEXTURE_BINDING_2D, &lastTexture)
|
||||
var lastSampler int32
|
||||
gl.GetIntegerv(opengl.SAMPLER_BINDING, &lastSampler)
|
||||
var lastArrayBuffer int32
|
||||
gl.GetIntegerv(opengl.ARRAY_BUFFER_BINDING, &lastArrayBuffer)
|
||||
var lastElementArrayBuffer int32
|
||||
gl.GetIntegerv(opengl.ELEMENT_ARRAY_BUFFER_BINDING, &lastElementArrayBuffer)
|
||||
var lastVertexArray int32
|
||||
gl.GetIntegerv(opengl.VERTEX_ARRAY_BINDING, &lastVertexArray)
|
||||
var lastPolygonMode [2]int32
|
||||
gl.GetIntegerv(opengl.POLYGON_MODE, &lastPolygonMode[0])
|
||||
var lastViewport [4]int32
|
||||
gl.GetIntegerv(opengl.VIEWPORT, &lastViewport[0])
|
||||
var lastScissorBox [4]int32
|
||||
gl.GetIntegerv(opengl.SCISSOR_BOX, &lastScissorBox[0])
|
||||
var lastBlendSrcRgb int32
|
||||
gl.GetIntegerv(opengl.BLEND_SRC_RGB, &lastBlendSrcRgb)
|
||||
var lastBlendDstRgb int32
|
||||
gl.GetIntegerv(opengl.BLEND_DST_RGB, &lastBlendDstRgb)
|
||||
var lastBlendSrcAlpha int32
|
||||
gl.GetIntegerv(opengl.BLEND_SRC_ALPHA, &lastBlendSrcAlpha)
|
||||
var lastBlendDstAlpha int32
|
||||
gl.GetIntegerv(opengl.BLEND_DST_ALPHA, &lastBlendDstAlpha)
|
||||
var lastBlendEquationRgb int32
|
||||
gl.GetIntegerv(opengl.BLEND_EQUATION_RGB, &lastBlendEquationRgb)
|
||||
var lastBlendEquationAlpha int32
|
||||
gl.GetIntegerv(opengl.BLEND_EQUATION_ALPHA, &lastBlendEquationAlpha)
|
||||
lastEnableBlend := gl.IsEnabled(opengl.BLEND)
|
||||
lastEnableCullFace := gl.IsEnabled(opengl.CULL_FACE)
|
||||
lastEnableDepthTest := gl.IsEnabled(opengl.DEPTH_TEST)
|
||||
lastEnableScissorTest := gl.IsEnabled(opengl.SCISSOR_TEST)
|
||||
|
||||
// Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled, polygon fill
|
||||
gl.Enable(opengl.BLEND)
|
||||
gl.BlendEquation(opengl.FUNC_ADD)
|
||||
gl.BlendFunc(opengl.SRC_ALPHA, opengl.ONE_MINUS_SRC_ALPHA)
|
||||
gl.Disable(opengl.CULL_FACE)
|
||||
gl.Disable(opengl.DEPTH_TEST)
|
||||
gl.Enable(opengl.SCISSOR_TEST)
|
||||
gl.PolygonMode(opengl.FRONT_AND_BACK, opengl.FILL)
|
||||
|
||||
// Setup viewport, orthographic projection matrix
|
||||
gl.Viewport(0, 0, int32(displayWidth), int32(displayHeight))
|
||||
orthoProjection := [16]float32{
|
||||
2.0 / float32(displayWidth), 0.0, 0.0, 0.0,
|
||||
0.0, 2.0 / float32(-displayHeight), 0.0, 0.0,
|
||||
0.0, 0.0, -1.0, 0.0,
|
||||
-1.0, 1.0, 0.0, 1.0,
|
||||
}
|
||||
gl.UseProgram(context.shaderHandle)
|
||||
gl.Uniform1i(context.attribLocationTex, 0)
|
||||
gl.Uniform1i(context.attribLocationPal, 1)
|
||||
gl.UniformMatrix4fv(context.attribLocationProjMtx, false, &orthoProjection)
|
||||
gl.BindSampler(0, 0) // Rely on combined texture/sampler state.
|
||||
|
||||
vaoHandle := gl.GenVertexArrays(1)[0]
|
||||
gl.BindVertexArray(vaoHandle)
|
||||
gl.BindBuffer(opengl.ARRAY_BUFFER, context.vboHandle)
|
||||
gl.EnableVertexAttribArray(uint32(context.attribLocationPosition))
|
||||
gl.EnableVertexAttribArray(uint32(context.attribLocationUV))
|
||||
gl.EnableVertexAttribArray(uint32(context.attribLocationColor))
|
||||
vertexSize, vertexOffsetPos, vertexOffsetUv, vertexOffsetCol := imgui.VertexBufferLayout()
|
||||
gl.VertexAttribOffset(uint32(context.attribLocationPosition), 2, opengl.FLOAT, false, int32(vertexSize), vertexOffsetPos)
|
||||
gl.VertexAttribOffset(uint32(context.attribLocationUV), 2, opengl.FLOAT, false, int32(vertexSize), vertexOffsetUv)
|
||||
gl.VertexAttribOffset(uint32(context.attribLocationColor), 4, opengl.UNSIGNED_BYTE, true, int32(vertexSize), vertexOffsetCol)
|
||||
indexSize := imgui.IndexBufferLayout()
|
||||
drawType := opengl.UNSIGNED_SHORT
|
||||
if indexSize == 4 {
|
||||
drawType = opengl.UNSIGNED_INT
|
||||
}
|
||||
|
||||
// Draw
|
||||
for _, list := range drawData.CommandLists() {
|
||||
var indexBufferOffset uintptr
|
||||
|
||||
vertexBuffer, vertexBufferSize := list.VertexBuffer()
|
||||
gl.BindBuffer(opengl.ARRAY_BUFFER, context.vboHandle)
|
||||
gl.BufferData(opengl.ARRAY_BUFFER, vertexBufferSize, vertexBuffer, opengl.STREAM_DRAW)
|
||||
|
||||
indexBuffer, indexBufferSize := list.IndexBuffer()
|
||||
gl.BindBuffer(opengl.ELEMENT_ARRAY_BUFFER, context.elementsHandle)
|
||||
gl.BufferData(opengl.ELEMENT_ARRAY_BUFFER, indexBufferSize, indexBuffer, opengl.STREAM_DRAW)
|
||||
|
||||
for _, cmd := range list.Commands() {
|
||||
if cmd.HasUserCallback() {
|
||||
cmd.CallUserCallback(list)
|
||||
} else {
|
||||
textureID := cmd.TextureID()
|
||||
imageType := ImageTypeFromID(textureID)
|
||||
gl.Uniform1i(context.attribLocationType, int32(imageType))
|
||||
switch imageType {
|
||||
case ImageTypeSimpleTexture:
|
||||
gl.ActiveTexture(opengl.TEXTURE0 + uint32(0))
|
||||
gl.BindTexture(opengl.TEXTURE_2D, uint32(textureID))
|
||||
case ImageTypeColorTexture:
|
||||
gl.ActiveTexture(opengl.TEXTURE0 + uint32(0))
|
||||
gl.BindTexture(opengl.TEXTURE_2D, uint32(textureID))
|
||||
case ImageTypeBitmapTexture:
|
||||
palette, bitmap := bitmapTextureQuery(textureID)
|
||||
gl.ActiveTexture(opengl.TEXTURE0 + uint32(0))
|
||||
gl.BindTexture(opengl.TEXTURE_2D, bitmap)
|
||||
gl.ActiveTexture(opengl.TEXTURE0 + uint32(1))
|
||||
gl.BindTexture(opengl.TEXTURE_2D, palette)
|
||||
default:
|
||||
gl.ActiveTexture(opengl.TEXTURE0 + uint32(0))
|
||||
gl.BindTexture(opengl.TEXTURE_2D, 0)
|
||||
gl.ActiveTexture(opengl.TEXTURE0 + uint32(1))
|
||||
gl.BindTexture(opengl.TEXTURE_2D, 0)
|
||||
}
|
||||
clipRect := cmd.ClipRect()
|
||||
gl.Scissor(int32(clipRect.X), int32(displayHeight)-int32(clipRect.W), int32(clipRect.Z-clipRect.X), int32(clipRect.W-clipRect.Y))
|
||||
gl.DrawElements(opengl.TRIANGLES, int32(cmd.ElementCount()), uint32(drawType), indexBufferOffset)
|
||||
}
|
||||
indexBufferOffset += uintptr(cmd.ElementCount() * indexSize)
|
||||
}
|
||||
}
|
||||
gl.DeleteVertexArrays([]uint32{vaoHandle})
|
||||
|
||||
// Restore modified GL state
|
||||
gl.UseProgram(uint32(lastProgram))
|
||||
gl.BindTexture(opengl.TEXTURE_2D, uint32(lastTexture))
|
||||
gl.BindSampler(0, uint32(lastSampler))
|
||||
gl.ActiveTexture(uint32(lastActiveTexture))
|
||||
gl.BindVertexArray(uint32(lastVertexArray))
|
||||
gl.BindBuffer(opengl.ARRAY_BUFFER, uint32(lastArrayBuffer))
|
||||
gl.BindBuffer(opengl.ELEMENT_ARRAY_BUFFER, uint32(lastElementArrayBuffer))
|
||||
gl.BlendEquationSeparate(uint32(lastBlendEquationRgb), uint32(lastBlendEquationAlpha))
|
||||
gl.BlendFuncSeparate(uint32(lastBlendSrcRgb), uint32(lastBlendDstRgb), uint32(lastBlendSrcAlpha), uint32(lastBlendDstAlpha))
|
||||
if lastEnableBlend {
|
||||
gl.Enable(opengl.BLEND)
|
||||
} else {
|
||||
gl.Disable(opengl.BLEND)
|
||||
}
|
||||
if lastEnableCullFace {
|
||||
gl.Enable(opengl.CULL_FACE)
|
||||
} else {
|
||||
gl.Disable(opengl.CULL_FACE)
|
||||
}
|
||||
if lastEnableDepthTest {
|
||||
gl.Enable(opengl.DEPTH_TEST)
|
||||
} else {
|
||||
gl.Disable(opengl.DEPTH_TEST)
|
||||
}
|
||||
if lastEnableScissorTest {
|
||||
gl.Enable(opengl.SCISSOR_TEST)
|
||||
} else {
|
||||
gl.Disable(opengl.SCISSOR_TEST)
|
||||
}
|
||||
gl.PolygonMode(opengl.FRONT_AND_BACK, uint32(lastPolygonMode[0]))
|
||||
gl.Viewport(lastViewport[0], lastViewport[1], lastViewport[2], lastViewport[3])
|
||||
gl.Scissor(lastScissorBox[0], lastScissorBox[1], lastScissorBox[2], lastScissorBox[3])
|
||||
}
|
||||
|
||||
// SetMousePosition must be called to report the current mouse position.
|
||||
func (context *Context) SetMousePosition(x, y float32) {
|
||||
imgui.CurrentIO().SetMousePosition(imgui.Vec2{X: x, Y: y})
|
||||
}
|
||||
|
||||
// MouseScroll must be called to report the current scroll delta.
|
||||
func (context *Context) MouseScroll(dx, dy float32) {
|
||||
imgui.CurrentIO().AddMouseWheelDelta(dx, dy)
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package gui
|
||||
|
||||
import "github.com/inkyblackness/imgui-go/v3"
|
||||
|
||||
// ImageType is an identifier how an image is to be rendered.
|
||||
type ImageType byte
|
||||
|
||||
const (
|
||||
// ImageTypeSimpleTexture identifies textures that use the image key as OpenGL texture handle.
|
||||
ImageTypeSimpleTexture ImageType = 0
|
||||
// ImageTypeBitmapTexture identifies bitmap textures.
|
||||
ImageTypeBitmapTexture ImageType = 1
|
||||
// ImageTypeColorTexture identifies textures with own color information.
|
||||
ImageTypeColorTexture ImageType = 2
|
||||
)
|
||||
|
||||
// TextureIDForSimpleTexture returns a TextureID with ImageTypeSimpleTexture.
|
||||
func TextureIDForSimpleTexture(handle uint32) imgui.TextureID {
|
||||
return imgui.TextureID(ImageTypeSimpleTexture)<<56 | imgui.TextureID(handle)
|
||||
}
|
||||
|
||||
// TextureIDForColorTexture returns a TextureID with ImageTypeSimpleTexture.
|
||||
func TextureIDForColorTexture(handle uint32) imgui.TextureID {
|
||||
return imgui.TextureID(ImageTypeColorTexture)<<56 | imgui.TextureID(handle)
|
||||
}
|
||||
|
||||
// ImageTypeFromID returns the image type the given texture ID specifies.
|
||||
func ImageTypeFromID(id imgui.TextureID) ImageType {
|
||||
return ImageType(id >> 56)
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package gui
|
||||
|
||||
// ModalState represents a modal dialog.
|
||||
type ModalState interface {
|
||||
// Render renders the dialog.
|
||||
Render()
|
||||
}
|
||||
|
||||
// FileHandler is accepting filenames.
|
||||
type FileHandler interface {
|
||||
// HandleFiles is called for any dropped files.
|
||||
HandleFiles(names []string)
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package gui
|
||||
|
||||
// ModalStateMachine allows to set a new state.
|
||||
type ModalStateMachine interface {
|
||||
SetState(state ModalState)
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package gui
|
||||
|
||||
// ModalStateWrapper is a wrapper over a series of modal popup states.
|
||||
// It implements both ModalState and ModalStateMachine to allow nested states, if necessary.
|
||||
type ModalStateWrapper struct {
|
||||
State ModalState
|
||||
}
|
||||
|
||||
// SetState sets the new state.
|
||||
func (machine *ModalStateWrapper) SetState(state ModalState) {
|
||||
machine.State = state
|
||||
}
|
||||
|
||||
// Render renders the current state.
|
||||
func (machine *ModalStateWrapper) Render() {
|
||||
if machine.State != nil {
|
||||
machine.State.Render()
|
||||
}
|
||||
}
|
||||
|
||||
// HandleFiles forwards the given filenames to the current state.
|
||||
func (machine *ModalStateWrapper) HandleFiles(filenames []string) {
|
||||
handler, isHandler := machine.State.(FileHandler)
|
||||
if !isHandler {
|
||||
return
|
||||
}
|
||||
handler.HandleFiles(filenames)
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package gui
|
||||
|
||||
import (
|
||||
"github.com/inkyblackness/imgui-go/v3"
|
||||
)
|
||||
|
||||
// StepSliderIntV creates a SliderInt with additional buttons to make single digit steps.
|
||||
// min and max parameters are inclusive. Returns true on change.
|
||||
func StepSliderIntV(label string, value *int, min, max int, format string) bool {
|
||||
imgui.PushID(label)
|
||||
changed := false
|
||||
if imgui.Button("-") && (*value > min) {
|
||||
*value--
|
||||
changed = true
|
||||
}
|
||||
innerSpacing := imgui.CurrentStyle().ItemInnerSpacing()
|
||||
imgui.SameLineV(0, innerSpacing.X)
|
||||
if imgui.Button("+") && (*value < max) {
|
||||
*value++
|
||||
changed = true
|
||||
}
|
||||
imgui.SameLineV(0, innerSpacing.X)
|
||||
value32 := int32(*value)
|
||||
if imgui.SliderIntV(label, &value32, int32(min), int32(max), format, imgui.SlidersFlagsNone) {
|
||||
switch {
|
||||
case int(value32) < min:
|
||||
*value = min
|
||||
case int(value32) > max:
|
||||
*value = max
|
||||
default:
|
||||
*value = int(value32)
|
||||
}
|
||||
changed = true
|
||||
}
|
||||
imgui.PopID()
|
||||
return changed
|
||||
}
|
||||
|
||||
// StepSliderInt calls StepSliderIntV(label, value, min, max, "%d").
|
||||
func StepSliderInt(label string, value *int, min, max int) bool {
|
||||
return StepSliderIntV(label, value, min, max, "%d")
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package input
|
||||
|
||||
// Key describes a named key on the keyboard. These are keys which are
|
||||
// unspecific to layout or language, or are universal.
|
||||
// Or, described in another way: keys that don't end up as printable characters.
|
||||
type Key int
|
||||
|
||||
// Constants for commonly known named keys.
|
||||
const (
|
||||
KeyEnter = Key(300)
|
||||
KeyEscape = Key(301)
|
||||
KeyBackspace = Key(302)
|
||||
KeyTab = Key(303)
|
||||
|
||||
KeyDown = Key(310)
|
||||
KeyLeft = Key(311)
|
||||
KeyRight = Key(312)
|
||||
KeyUp = Key(313)
|
||||
|
||||
KeyDelete = Key(320)
|
||||
KeyEnd = Key(321)
|
||||
KeyHome = Key(322)
|
||||
KeyInsert = Key(323)
|
||||
KeyPageDown = Key(324)
|
||||
KeyPageUp = Key(325)
|
||||
|
||||
KeyAlt = Key(330)
|
||||
KeyControl = Key(331)
|
||||
KeyShift = Key(332)
|
||||
KeySuper = Key(333)
|
||||
|
||||
KeyPause = Key(340)
|
||||
KeyPrintScreen = Key(341)
|
||||
KeyCapsLock = Key(342)
|
||||
KeyScrollLock = Key(343)
|
||||
|
||||
KeyF1 = Key(351)
|
||||
KeyF10 = Key(360)
|
||||
KeyF11 = Key(361)
|
||||
KeyF12 = Key(362)
|
||||
KeyF13 = Key(363)
|
||||
KeyF14 = Key(364)
|
||||
KeyF15 = Key(365)
|
||||
KeyF16 = Key(366)
|
||||
KeyF17 = Key(367)
|
||||
KeyF18 = Key(368)
|
||||
KeyF19 = Key(369)
|
||||
KeyF2 = Key(352)
|
||||
KeyF20 = Key(370)
|
||||
KeyF21 = Key(371)
|
||||
KeyF22 = Key(372)
|
||||
KeyF23 = Key(373)
|
||||
KeyF24 = Key(374)
|
||||
KeyF25 = Key(375)
|
||||
KeyF3 = Key(353)
|
||||
KeyF4 = Key(354)
|
||||
KeyF5 = Key(355)
|
||||
KeyF6 = Key(356)
|
||||
KeyF7 = Key(357)
|
||||
KeyF8 = Key(358)
|
||||
KeyF9 = Key(359)
|
||||
|
||||
KeyCopy = Key(380)
|
||||
KeyCut = Key(381)
|
||||
KeyPaste = Key(382)
|
||||
|
||||
KeyUndo = Key(390)
|
||||
KeyRedo = Key(391)
|
||||
|
||||
KeySave = Key(400)
|
||||
KeyNew = Key(401)
|
||||
|
||||
KeyA = Key(410)
|
||||
KeyC = Key(411)
|
||||
KeyV = Key(412)
|
||||
KeyX = Key(413)
|
||||
)
|
||||
|
||||
var keyToModifier = map[Key]Modifier{
|
||||
KeyShift: ModShift,
|
||||
KeyControl: ModControl,
|
||||
KeyAlt: ModAlt,
|
||||
KeySuper: ModSuper,
|
||||
}
|
||||
|
||||
// AsModifier returns the modifier equivalent for the key - if applicable.
|
||||
func (key Key) AsModifier() Modifier {
|
||||
mod, isModifier := keyToModifier[key]
|
||||
|
||||
if !isModifier {
|
||||
mod = ModNone
|
||||
}
|
||||
|
||||
return mod
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package input
|
||||
|
||||
// Modifier is a collection of currently pressed modifier keys.
|
||||
type Modifier uint32
|
||||
|
||||
// Constants for common modifier.
|
||||
const (
|
||||
ModNone = Modifier(0x00000000)
|
||||
ModShift = Modifier(0x00000001)
|
||||
ModControl = Modifier(0x00000002)
|
||||
ModAlt = Modifier(0x00000004)
|
||||
ModSuper = Modifier(0x00000008)
|
||||
)
|
||||
|
||||
// IsClear returns true if nothing is set.
|
||||
func (mod Modifier) IsClear() bool {
|
||||
return mod == ModNone
|
||||
}
|
||||
|
||||
// With returns a combination of this modifier and the given one.
|
||||
func (mod Modifier) With(other Modifier) Modifier {
|
||||
return Modifier(uint32(mod) | uint32(other))
|
||||
}
|
||||
|
||||
// Without returns the result of this modifier without the given one.
|
||||
func (mod Modifier) Without(other Modifier) Modifier {
|
||||
return Modifier(uint32(mod) & ^uint32(other))
|
||||
}
|
||||
|
||||
// Has returns true if the given modifier is included in this set.
|
||||
// This modifier can have more keys set than the requested and still return true.
|
||||
func (mod Modifier) Has(other Modifier) bool {
|
||||
return (uint32(mod) | uint32(other)) == uint32(mod)
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package input_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/inkyblackness/hacked/ui/input"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestHasReturnsTrueForThemselves(t *testing.T) {
|
||||
mods := []input.Modifier{input.ModShift, input.ModControl, input.ModAlt, input.ModSuper}
|
||||
|
||||
for _, mod := range mods {
|
||||
assert.True(t, mod.Has(mod))
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasReturnsFalseForDifferentModifiers(t *testing.T) {
|
||||
mods := []input.Modifier{input.ModShift, input.ModControl, input.ModAlt, input.ModSuper}
|
||||
|
||||
for index, mod := range mods {
|
||||
nextMod := mods[(index+1)%len(mods)]
|
||||
assert.False(t, mod.Has(nextMod))
|
||||
}
|
||||
}
|
||||
|
||||
func TestHasReturnsFalseForSetsIncludingOthers(t *testing.T) {
|
||||
mods := []input.Modifier{input.ModShift, input.ModControl, input.ModAlt, input.ModSuper}
|
||||
|
||||
for index, mod := range mods {
|
||||
nextMod := mods[(index+1)%len(mods)]
|
||||
assert.False(t, mod.Has(mod.With(nextMod)))
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithoutReturnsReduction(t *testing.T) {
|
||||
mod := input.ModShift.With(input.ModAlt).Without(input.ModShift)
|
||||
|
||||
assert.Equal(t, input.ModAlt, mod)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package input
|
||||
|
||||
import "strings"
|
||||
|
||||
type shortcut struct {
|
||||
keyName string
|
||||
modifier Modifier
|
||||
key Key
|
||||
}
|
||||
|
||||
var shortcuts = []shortcut{
|
||||
{keyName: "c", modifier: ModControl, key: KeyCopy},
|
||||
{keyName: "x", modifier: ModControl, key: KeyCut},
|
||||
{keyName: "v", modifier: ModControl, key: KeyPaste},
|
||||
{keyName: "z", modifier: ModControl, key: KeyUndo},
|
||||
{keyName: "z", modifier: ModControl.With(ModShift), key: KeyRedo},
|
||||
{keyName: "y", modifier: ModControl, key: KeyRedo},
|
||||
{keyName: "s", modifier: ModControl, key: KeySave},
|
||||
{keyName: "n", modifier: ModControl, key: KeyNew},
|
||||
}
|
||||
|
||||
// ResolveShortcut tries to map the given name and modifier combination to a
|
||||
// known (common) shortcut key. For instance, Ctrl+C is KeyCopy.
|
||||
func ResolveShortcut(keyName string, modifier Modifier) (key Key, knownKey bool) {
|
||||
lowercaseName := strings.ToLower(keyName)
|
||||
for _, entry := range shortcuts {
|
||||
if (entry.keyName == lowercaseName) && (entry.modifier == modifier) {
|
||||
knownKey = true
|
||||
key = entry.key
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package input_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/inkyblackness/hacked/ui/input"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestResolveShortcutReturnsValuesOfKnownCombo(t *testing.T) {
|
||||
key, knownKey := input.ResolveShortcut("c", input.ModControl)
|
||||
|
||||
assert.True(t, knownKey)
|
||||
assert.Equal(t, input.KeyCopy, key)
|
||||
}
|
||||
|
||||
func TestResolveShortcutReturnsFalseForUnknownCombo(t *testing.T) {
|
||||
_, knownKey := input.ResolveShortcut("l", input.ModControl.With(input.ModShift))
|
||||
|
||||
assert.False(t, knownKey)
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package input
|
||||
|
||||
// StickyKeyListener is the listener interface for receiving key events.
|
||||
type StickyKeyListener interface {
|
||||
// KeyPress is called for a pressed key.
|
||||
KeyPress(key Key, modifier Modifier)
|
||||
// KeyRelease is called for a released key.
|
||||
KeyRelease(key Key, modifier Modifier)
|
||||
// Modifier is called when the currently active modifier changed.
|
||||
Modifier(modifier Modifier)
|
||||
}
|
||||
|
||||
// StickyKeyBuffer is a buffer to keep track of several identically named keys.
|
||||
// Keys can be reported being pressed or released. Their state will be forwarded
|
||||
// to a StickyKeyListener instance. If a specific key is reported to be pressed
|
||||
// more than once, the listener will have received the down state only once.
|
||||
type StickyKeyBuffer struct {
|
||||
pressedKeys map[Key]int
|
||||
pressedModifier map[Modifier]int
|
||||
activeModifier Modifier
|
||||
listener StickyKeyListener
|
||||
}
|
||||
|
||||
// NewStickyKeyBuffer returns a new instance of a sticky key buffer.
|
||||
func NewStickyKeyBuffer(listener StickyKeyListener) *StickyKeyBuffer {
|
||||
buffer := &StickyKeyBuffer{
|
||||
pressedKeys: make(map[Key]int),
|
||||
pressedModifier: make(map[Modifier]int),
|
||||
activeModifier: ModNone,
|
||||
listener: listener,
|
||||
}
|
||||
|
||||
return buffer
|
||||
}
|
||||
|
||||
// ActiveModifier returns the currently pressed modifier set.
|
||||
func (buffer *StickyKeyBuffer) ActiveModifier() Modifier {
|
||||
return buffer.activeModifier
|
||||
}
|
||||
|
||||
// KeyDown registers a pressed key state. Multiple down states can be
|
||||
// registered for the same key and result in only one key event.
|
||||
func (buffer *StickyKeyBuffer) KeyDown(key Key, modifier Modifier) {
|
||||
keyAsModifier := key.AsModifier()
|
||||
updatedModifier := modifier.With(keyAsModifier)
|
||||
|
||||
oldCount := buffer.pressedKeys[key]
|
||||
buffer.pressedKeys[key] = oldCount + 1
|
||||
if oldCount == 0 {
|
||||
buffer.listener.KeyPress(key, updatedModifier)
|
||||
}
|
||||
|
||||
buffer.setActiveModifier(updatedModifier)
|
||||
if keyAsModifier != ModNone {
|
||||
buffer.pressedModifier[keyAsModifier]++
|
||||
}
|
||||
}
|
||||
|
||||
// KeyUp registers a released key state. Multiple up states can be registered
|
||||
// for the same key, as long as enough down states were reported.
|
||||
func (buffer *StickyKeyBuffer) KeyUp(key Key, modifier Modifier) {
|
||||
updatedModifier := modifier
|
||||
keyAsModifier := key.AsModifier()
|
||||
if keyAsModifier != ModNone {
|
||||
oldCount := buffer.pressedModifier[keyAsModifier]
|
||||
if oldCount > 0 {
|
||||
buffer.pressedModifier[keyAsModifier] = oldCount - 1
|
||||
if oldCount == 1 {
|
||||
updatedModifier = updatedModifier.Without(keyAsModifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
oldCount := buffer.pressedKeys[key]
|
||||
if oldCount > 0 {
|
||||
buffer.pressedKeys[key] = oldCount - 1
|
||||
if oldCount == 1 {
|
||||
buffer.listener.KeyRelease(key, updatedModifier)
|
||||
}
|
||||
}
|
||||
buffer.setActiveModifier(updatedModifier)
|
||||
}
|
||||
|
||||
// ReleaseAll notifies the listener of the reset of all modifiers.
|
||||
// Key states are reset to accept new down states.
|
||||
func (buffer *StickyKeyBuffer) ReleaseAll() {
|
||||
buffer.pressedKeys = make(map[Key]int)
|
||||
buffer.setActiveModifier(ModNone)
|
||||
}
|
||||
|
||||
func (buffer *StickyKeyBuffer) setActiveModifier(modifier Modifier) {
|
||||
if buffer.activeModifier != modifier {
|
||||
for mod := range buffer.pressedModifier {
|
||||
if !modifier.Has(mod) {
|
||||
buffer.pressedModifier[mod] = 0
|
||||
}
|
||||
}
|
||||
buffer.activeModifier = modifier
|
||||
buffer.listener.Modifier(buffer.activeModifier)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,261 @@
|
||||
package input_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/inkyblackness/hacked/ui/input"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type keyEvent struct {
|
||||
event string
|
||||
key input.Key
|
||||
mod input.Modifier
|
||||
}
|
||||
|
||||
type testingStickyKeysListener struct {
|
||||
eventMap map[input.Key][]keyEvent
|
||||
events []keyEvent
|
||||
}
|
||||
|
||||
func (listener *testingStickyKeysListener) KeyPress(key input.Key, modifier input.Modifier) {
|
||||
listener.addEvent(keyEvent{event: "P", key: key, mod: modifier})
|
||||
}
|
||||
|
||||
func (listener *testingStickyKeysListener) KeyRelease(key input.Key, modifier input.Modifier) {
|
||||
listener.addEvent(keyEvent{event: "R", key: key, mod: modifier})
|
||||
}
|
||||
|
||||
func (listener *testingStickyKeysListener) Modifier(modifier input.Modifier) {
|
||||
listener.addEvent(keyEvent{event: "M", key: 0, mod: modifier})
|
||||
}
|
||||
|
||||
func (listener *testingStickyKeysListener) addEvent(event keyEvent) {
|
||||
listener.eventMap[event.key] = append(listener.eventMap[event.key], event)
|
||||
listener.events = append(listener.events, event)
|
||||
}
|
||||
|
||||
type StickyKeyBufferSuite struct {
|
||||
suite.Suite
|
||||
buffer *input.StickyKeyBuffer
|
||||
listener *testingStickyKeysListener
|
||||
}
|
||||
|
||||
func TestProviderBackedStoreSuite(t *testing.T) {
|
||||
suite.Run(t, new(StickyKeyBufferSuite))
|
||||
}
|
||||
|
||||
func (suite *StickyKeyBufferSuite) SetupTest() {
|
||||
suite.listener = &testingStickyKeysListener{
|
||||
eventMap: make(map[input.Key][]keyEvent)}
|
||||
suite.buffer = input.NewStickyKeyBuffer(suite.listener)
|
||||
}
|
||||
|
||||
func (suite *StickyKeyBufferSuite) TestRegularEventsAreForwarded_A() {
|
||||
suite.buffer.KeyDown(input.KeyF1, input.ModNone)
|
||||
suite.buffer.KeyUp(input.KeyF1, input.ModNone)
|
||||
suite.buffer.KeyDown(input.KeyF2, input.ModNone)
|
||||
suite.buffer.KeyUp(input.KeyF2, input.ModNone)
|
||||
|
||||
assert.Equal(suite.T(), []keyEvent{
|
||||
{event: "P", key: input.KeyF1, mod: input.ModNone},
|
||||
{event: "R", key: input.KeyF1, mod: input.ModNone},
|
||||
}, suite.listener.eventMap[input.KeyF1])
|
||||
assert.Equal(suite.T(), []keyEvent{
|
||||
{event: "P", key: input.KeyF2, mod: input.ModNone},
|
||||
{event: "R", key: input.KeyF2, mod: input.ModNone},
|
||||
}, suite.listener.eventMap[input.KeyF2])
|
||||
}
|
||||
|
||||
func (suite *StickyKeyBufferSuite) TestRegularEventsAreForwarded_B() {
|
||||
suite.buffer.KeyDown(input.KeyF1, input.ModNone)
|
||||
suite.buffer.KeyDown(input.KeyF2, input.ModNone)
|
||||
suite.buffer.KeyUp(input.KeyF2, input.ModNone)
|
||||
suite.buffer.KeyUp(input.KeyF1, input.ModNone)
|
||||
|
||||
assert.Equal(suite.T(), []keyEvent{
|
||||
{event: "P", key: input.KeyF1, mod: input.ModNone},
|
||||
{event: "R", key: input.KeyF1, mod: input.ModNone},
|
||||
}, suite.listener.eventMap[input.KeyF1])
|
||||
assert.Equal(suite.T(), []keyEvent{
|
||||
{event: "P", key: input.KeyF2, mod: input.ModNone},
|
||||
{event: "R", key: input.KeyF2, mod: input.ModNone},
|
||||
}, suite.listener.eventMap[input.KeyF2])
|
||||
assert.Equal(suite.T(), []keyEvent{
|
||||
{event: "P", key: input.KeyF1, mod: input.ModNone},
|
||||
{event: "P", key: input.KeyF2, mod: input.ModNone},
|
||||
{event: "R", key: input.KeyF2, mod: input.ModNone},
|
||||
{event: "R", key: input.KeyF1, mod: input.ModNone},
|
||||
}, suite.listener.events)
|
||||
}
|
||||
|
||||
func (suite *StickyKeyBufferSuite) TestIdenticalKeysAreReportedOnlyOnce() {
|
||||
suite.buffer.KeyDown(input.KeyF1, input.ModNone)
|
||||
suite.buffer.KeyDown(input.KeyF1, input.ModNone)
|
||||
suite.buffer.KeyDown(input.KeyF1, input.ModNone)
|
||||
suite.buffer.KeyUp(input.KeyF1, input.ModNone)
|
||||
suite.buffer.KeyUp(input.KeyF1, input.ModNone)
|
||||
suite.buffer.KeyUp(input.KeyF1, input.ModNone)
|
||||
|
||||
assert.Equal(suite.T(), []keyEvent{
|
||||
{event: "P", key: input.KeyF1, mod: input.ModNone},
|
||||
{event: "R", key: input.KeyF1, mod: input.ModNone},
|
||||
}, suite.listener.eventMap[input.KeyF1])
|
||||
assert.Equal(suite.T(), []keyEvent{
|
||||
{event: "P", key: input.KeyF1, mod: input.ModNone},
|
||||
{event: "R", key: input.KeyF1, mod: input.ModNone},
|
||||
}, suite.listener.events)
|
||||
}
|
||||
|
||||
func (suite *StickyKeyBufferSuite) TestSuperfluousReleasesAreIgnored() {
|
||||
suite.buffer.KeyDown(input.KeyF1, input.ModNone)
|
||||
suite.buffer.KeyUp(input.KeyF1, input.ModNone)
|
||||
suite.buffer.KeyUp(input.KeyF1, input.ModNone)
|
||||
suite.buffer.KeyUp(input.KeyF1, input.ModNone)
|
||||
suite.buffer.KeyDown(input.KeyF2, input.ModNone)
|
||||
suite.buffer.KeyDown(input.KeyF1, input.ModNone)
|
||||
suite.buffer.KeyUp(input.KeyF1, input.ModNone)
|
||||
|
||||
assert.Equal(suite.T(), []keyEvent{
|
||||
{event: "P", key: input.KeyF1, mod: input.ModNone},
|
||||
{event: "R", key: input.KeyF1, mod: input.ModNone},
|
||||
{event: "P", key: input.KeyF1, mod: input.ModNone},
|
||||
{event: "R", key: input.KeyF1, mod: input.ModNone},
|
||||
}, suite.listener.eventMap[input.KeyF1])
|
||||
assert.Equal(suite.T(), []keyEvent{
|
||||
{event: "P", key: input.KeyF1, mod: input.ModNone},
|
||||
{event: "R", key: input.KeyF1, mod: input.ModNone},
|
||||
{event: "P", key: input.KeyF2, mod: input.ModNone},
|
||||
{event: "P", key: input.KeyF1, mod: input.ModNone},
|
||||
{event: "R", key: input.KeyF1, mod: input.ModNone},
|
||||
}, suite.listener.events)
|
||||
}
|
||||
|
||||
func (suite *StickyKeyBufferSuite) TestReleaseAllResetsRegularKeys() {
|
||||
suite.buffer.KeyDown(input.KeyEnter, input.ModNone)
|
||||
suite.buffer.KeyDown(input.KeyEnter, input.ModNone)
|
||||
suite.buffer.KeyDown(input.KeyTab, input.ModNone)
|
||||
suite.buffer.ReleaseAll()
|
||||
suite.buffer.KeyDown(input.KeyTab, input.ModNone)
|
||||
|
||||
assert.Equal(suite.T(), []keyEvent{
|
||||
{event: "P", key: input.KeyEnter, mod: input.ModNone},
|
||||
}, suite.listener.eventMap[input.KeyEnter])
|
||||
assert.Equal(suite.T(), []keyEvent{
|
||||
{event: "P", key: input.KeyTab, mod: input.ModNone},
|
||||
{event: "P", key: input.KeyTab, mod: input.ModNone},
|
||||
}, suite.listener.eventMap[input.KeyTab])
|
||||
}
|
||||
|
||||
func (suite *StickyKeyBufferSuite) TestModifierEventsAreConvertedToModifierStates_DownAugmented() {
|
||||
suite.buffer.KeyDown(input.KeyShift, input.ModShift)
|
||||
suite.buffer.KeyDown(input.KeyAlt, input.ModShift.With(input.ModAlt))
|
||||
suite.buffer.KeyUp(input.KeyAlt, input.ModShift)
|
||||
suite.buffer.KeyUp(input.KeyShift, input.ModNone)
|
||||
|
||||
assert.Equal(suite.T(), 2, len(suite.listener.eventMap[input.KeyShift]))
|
||||
assert.Equal(suite.T(), 2, len(suite.listener.eventMap[input.KeyAlt]))
|
||||
assert.Equal(suite.T(),
|
||||
[]keyEvent{
|
||||
{event: "P", key: input.KeyShift, mod: input.ModShift},
|
||||
{event: "M", key: 0, mod: input.ModShift},
|
||||
{event: "P", key: input.KeyAlt, mod: input.ModShift.With(input.ModAlt)},
|
||||
{event: "M", key: 0, mod: input.ModShift.With(input.ModAlt)},
|
||||
{event: "R", key: input.KeyAlt, mod: input.ModShift},
|
||||
{event: "M", key: 0, mod: input.ModShift},
|
||||
{event: "R", key: input.KeyShift, mod: input.ModNone},
|
||||
{event: "M", key: 0, mod: input.ModNone},
|
||||
},
|
||||
suite.listener.events)
|
||||
}
|
||||
|
||||
func (suite *StickyKeyBufferSuite) TestModifierEventsAreConvertedToModifierStates_UpAugmented() {
|
||||
suite.buffer.KeyDown(input.KeyShift, input.ModNone)
|
||||
suite.buffer.KeyDown(input.KeyAlt, input.ModShift)
|
||||
suite.buffer.KeyUp(input.KeyAlt, input.ModShift.With(input.ModAlt))
|
||||
suite.buffer.KeyUp(input.KeyShift, input.ModShift)
|
||||
|
||||
assert.Equal(suite.T(), 2, len(suite.listener.eventMap[input.KeyShift]))
|
||||
assert.Equal(suite.T(), 2, len(suite.listener.eventMap[input.KeyAlt]))
|
||||
assert.Equal(suite.T(),
|
||||
[]keyEvent{
|
||||
{event: "P", key: input.KeyShift, mod: input.ModShift},
|
||||
{event: "M", key: 0, mod: input.ModShift},
|
||||
{event: "P", key: input.KeyAlt, mod: input.ModShift.With(input.ModAlt)},
|
||||
{event: "M", key: 0, mod: input.ModShift.With(input.ModAlt)},
|
||||
{event: "R", key: input.KeyAlt, mod: input.ModShift},
|
||||
{event: "M", key: 0, mod: input.ModShift},
|
||||
{event: "R", key: input.KeyShift, mod: input.ModNone},
|
||||
{event: "M", key: 0, mod: input.ModNone},
|
||||
},
|
||||
suite.listener.events)
|
||||
}
|
||||
|
||||
func (suite *StickyKeyBufferSuite) TestReleaseAllReleasesModifiers() {
|
||||
suite.buffer.KeyDown(input.KeyShift, input.ModNone)
|
||||
suite.buffer.KeyDown(input.KeyShift, input.ModNone)
|
||||
suite.buffer.KeyDown(input.KeyAlt, input.ModShift)
|
||||
suite.buffer.ReleaseAll()
|
||||
|
||||
assert.Equal(suite.T(),
|
||||
[]keyEvent{
|
||||
{event: "P", key: input.KeyShift, mod: input.ModShift},
|
||||
{event: "M", key: 0, mod: input.ModShift},
|
||||
{event: "P", key: input.KeyAlt, mod: input.ModShift.With(input.ModAlt)},
|
||||
{event: "M", key: 0, mod: input.ModShift.With(input.ModAlt)},
|
||||
{event: "M", key: 0, mod: input.ModNone},
|
||||
},
|
||||
suite.listener.events)
|
||||
}
|
||||
|
||||
func (suite *StickyKeyBufferSuite) TestActiveModifierReturnsCurrentModifier() {
|
||||
suite.buffer.KeyDown(input.KeyShift, input.ModNone)
|
||||
suite.buffer.KeyDown(input.KeyControl, input.ModShift)
|
||||
suite.buffer.KeyDown(input.KeyAlt, input.ModShift.With(input.ModControl))
|
||||
suite.buffer.KeyUp(input.KeyControl, input.ModShift.With(input.ModControl).With(input.ModAlt))
|
||||
|
||||
assert.Equal(suite.T(), input.ModShift.With(input.ModAlt), suite.buffer.ActiveModifier())
|
||||
}
|
||||
|
||||
func (suite *StickyKeyBufferSuite) TestModifierAreUpdatedOnOtherKeys_A() {
|
||||
suite.buffer.KeyDown(input.KeyShift, input.ModShift)
|
||||
suite.buffer.KeyDown(input.KeyTab, input.ModNone)
|
||||
|
||||
assert.Equal(suite.T(),
|
||||
[]keyEvent{
|
||||
{event: "P", key: input.KeyShift, mod: input.ModShift},
|
||||
{event: "M", key: 0, mod: input.ModShift},
|
||||
{event: "P", key: input.KeyTab, mod: input.ModNone},
|
||||
{event: "M", key: 0, mod: input.ModNone},
|
||||
},
|
||||
suite.listener.events)
|
||||
}
|
||||
|
||||
func (suite *StickyKeyBufferSuite) TestModifierAreUpdatedOnOtherKeys_B() {
|
||||
suite.buffer.KeyDown(input.KeyTab, input.ModNone)
|
||||
suite.buffer.KeyDown(input.KeyShift, input.ModShift)
|
||||
suite.buffer.KeyUp(input.KeyTab, input.ModNone)
|
||||
|
||||
assert.Equal(suite.T(),
|
||||
[]keyEvent{
|
||||
{event: "P", key: input.KeyTab, mod: input.ModNone},
|
||||
{event: "P", key: input.KeyShift, mod: input.ModShift},
|
||||
{event: "M", key: 0, mod: input.ModShift},
|
||||
{event: "R", key: input.KeyTab, mod: input.ModNone},
|
||||
{event: "M", key: 0, mod: input.ModNone},
|
||||
},
|
||||
suite.listener.events)
|
||||
}
|
||||
|
||||
func (suite *StickyKeyBufferSuite) TestModifierAreUpdatedOnOtherKeysWithoutThemselves() {
|
||||
suite.buffer.KeyDown(input.KeyShift, input.ModShift)
|
||||
suite.buffer.KeyDown(input.KeyShift, input.ModShift)
|
||||
suite.buffer.KeyUp(input.KeyShift, input.ModShift)
|
||||
|
||||
assert.Equal(suite.T(), []keyEvent{
|
||||
{event: "P", key: input.KeyShift, mod: input.ModShift},
|
||||
{event: "M", key: 0, mod: input.ModShift},
|
||||
}, suite.listener.events)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package input
|
||||
|
||||
const (
|
||||
// MousePrimary specifies the primary mouse button (by default, the left one).
|
||||
MousePrimary = uint32(1)
|
||||
// MouseSecondary specifies the secondary mouse button (by default, the right one).
|
||||
MouseSecondary = uint32(2)
|
||||
)
|
||||
@@ -0,0 +1,73 @@
|
||||
package native
|
||||
|
||||
import (
|
||||
"github.com/go-gl/glfw/v3.2/glfw"
|
||||
|
||||
"github.com/inkyblackness/hacked/ui/input"
|
||||
)
|
||||
|
||||
var keyMap = map[glfw.Key]input.Key{
|
||||
glfw.KeyEnter: input.KeyEnter,
|
||||
glfw.KeyKPEnter: input.KeyEnter,
|
||||
glfw.KeyEscape: input.KeyEscape,
|
||||
glfw.KeyBackspace: input.KeyBackspace,
|
||||
glfw.KeyTab: input.KeyTab,
|
||||
|
||||
glfw.KeyDown: input.KeyDown,
|
||||
glfw.KeyLeft: input.KeyLeft,
|
||||
glfw.KeyRight: input.KeyRight,
|
||||
glfw.KeyUp: input.KeyUp,
|
||||
|
||||
glfw.KeyDelete: input.KeyDelete,
|
||||
glfw.KeyEnd: input.KeyEnd,
|
||||
glfw.KeyHome: input.KeyHome,
|
||||
glfw.KeyInsert: input.KeyInsert,
|
||||
glfw.KeyPageDown: input.KeyPageDown,
|
||||
glfw.KeyPageUp: input.KeyPageUp,
|
||||
|
||||
glfw.KeyLeftAlt: input.KeyAlt,
|
||||
glfw.KeyLeftControl: input.KeyControl,
|
||||
glfw.KeyLeftShift: input.KeyShift,
|
||||
glfw.KeyLeftSuper: input.KeySuper,
|
||||
glfw.KeyRightAlt: input.KeyAlt,
|
||||
glfw.KeyRightControl: input.KeyControl,
|
||||
glfw.KeyRightShift: input.KeyShift,
|
||||
glfw.KeyRightSuper: input.KeySuper,
|
||||
|
||||
glfw.KeyPause: input.KeyPause,
|
||||
glfw.KeyPrintScreen: input.KeyPrintScreen,
|
||||
|
||||
glfw.KeyCapsLock: input.KeyCapsLock,
|
||||
glfw.KeyScrollLock: input.KeyScrollLock,
|
||||
|
||||
glfw.KeyF1: input.KeyF1,
|
||||
glfw.KeyF10: input.KeyF10,
|
||||
glfw.KeyF11: input.KeyF11,
|
||||
glfw.KeyF12: input.KeyF12,
|
||||
glfw.KeyF13: input.KeyF13,
|
||||
glfw.KeyF14: input.KeyF14,
|
||||
glfw.KeyF15: input.KeyF15,
|
||||
glfw.KeyF16: input.KeyF16,
|
||||
glfw.KeyF17: input.KeyF17,
|
||||
glfw.KeyF18: input.KeyF18,
|
||||
glfw.KeyF19: input.KeyF19,
|
||||
glfw.KeyF2: input.KeyF2,
|
||||
glfw.KeyF20: input.KeyF20,
|
||||
glfw.KeyF21: input.KeyF21,
|
||||
glfw.KeyF22: input.KeyF22,
|
||||
glfw.KeyF23: input.KeyF23,
|
||||
glfw.KeyF24: input.KeyF24,
|
||||
glfw.KeyF25: input.KeyF25,
|
||||
glfw.KeyF3: input.KeyF3,
|
||||
glfw.KeyF4: input.KeyF4,
|
||||
glfw.KeyF5: input.KeyF5,
|
||||
glfw.KeyF6: input.KeyF6,
|
||||
glfw.KeyF7: input.KeyF7,
|
||||
glfw.KeyF8: input.KeyF8,
|
||||
glfw.KeyF9: input.KeyF9,
|
||||
|
||||
glfw.KeyA: input.KeyA,
|
||||
glfw.KeyC: input.KeyC,
|
||||
glfw.KeyV: input.KeyV,
|
||||
glfw.KeyX: input.KeyX,
|
||||
}
|
||||
@@ -0,0 +1,378 @@
|
||||
package native
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"github.com/go-gl/gl/v3.2-core/gl"
|
||||
)
|
||||
|
||||
// OpenGL wraps the native GL API into a common interface.
|
||||
type OpenGL struct {
|
||||
}
|
||||
|
||||
// NewOpenGL initializes the Gl bindings and returns an OpenGL instance.
|
||||
func NewOpenGL() *OpenGL {
|
||||
opengl := &OpenGL{}
|
||||
|
||||
if err := gl.Init(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return opengl
|
||||
}
|
||||
|
||||
// ActiveTexture implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) ActiveTexture(texture uint32) {
|
||||
gl.ActiveTexture(texture)
|
||||
}
|
||||
|
||||
// AttachShader implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) AttachShader(program uint32, shader uint32) {
|
||||
gl.AttachShader(program, shader)
|
||||
}
|
||||
|
||||
// BindAttribLocation implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) BindAttribLocation(program uint32, index uint32, name string) {
|
||||
gl.BindAttribLocation(program, index, gl.Str(name+"\x00"))
|
||||
}
|
||||
|
||||
// BindBuffer implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) BindBuffer(target uint32, buffer uint32) {
|
||||
gl.BindBuffer(target, buffer)
|
||||
}
|
||||
|
||||
// BindFramebuffer implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) BindFramebuffer(target uint32, buffer uint32) {
|
||||
gl.BindFramebuffer(target, buffer)
|
||||
}
|
||||
|
||||
// BindRenderbuffer implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) BindRenderbuffer(target uint32, buffer uint32) {
|
||||
gl.BindRenderbuffer(target, buffer)
|
||||
}
|
||||
|
||||
// BindSampler implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) BindSampler(unit uint32, sampler uint32) {
|
||||
gl.BindSampler(unit, sampler)
|
||||
}
|
||||
|
||||
// BindTexture implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) BindTexture(target uint32, texture uint32) {
|
||||
gl.BindTexture(target, texture)
|
||||
}
|
||||
|
||||
// BindVertexArray implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) BindVertexArray(array uint32) {
|
||||
gl.BindVertexArray(array)
|
||||
}
|
||||
|
||||
// BlendEquation implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) BlendEquation(mode uint32) {
|
||||
gl.BlendEquation(mode)
|
||||
}
|
||||
|
||||
// BlendEquationSeparate implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) BlendEquationSeparate(modeRGB uint32, modeAlpha uint32) {
|
||||
gl.BlendEquationSeparate(modeRGB, modeAlpha)
|
||||
}
|
||||
|
||||
// BlendFunc implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) BlendFunc(sfactor uint32, dfactor uint32) {
|
||||
gl.BlendFunc(sfactor, dfactor)
|
||||
}
|
||||
|
||||
// BlendFuncSeparate implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) BlendFuncSeparate(srcRGB uint32, dstRGB uint32, srcAlpha uint32, dstAlpha uint32) {
|
||||
gl.BlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha)
|
||||
}
|
||||
|
||||
// BufferData implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) BufferData(target uint32, size int, data interface{}, usage uint32) {
|
||||
dataPtr, isPtr := data.(unsafe.Pointer)
|
||||
if isPtr {
|
||||
gl.BufferData(target, size, dataPtr, usage)
|
||||
} else {
|
||||
gl.BufferData(target, size, gl.Ptr(data), usage)
|
||||
}
|
||||
}
|
||||
|
||||
// CheckFramebufferStatus implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) CheckFramebufferStatus(target uint32) uint32 {
|
||||
return gl.CheckFramebufferStatus(target)
|
||||
}
|
||||
|
||||
// Clear implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) Clear(mask uint32) {
|
||||
gl.Clear(mask)
|
||||
}
|
||||
|
||||
// ClearColor implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) ClearColor(red float32, green float32, blue float32, alpha float32) {
|
||||
gl.ClearColor(red, green, blue, alpha)
|
||||
}
|
||||
|
||||
// CompileShader implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) CompileShader(shader uint32) {
|
||||
gl.CompileShader(shader)
|
||||
}
|
||||
|
||||
// CreateProgram implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) CreateProgram() uint32 {
|
||||
return gl.CreateProgram()
|
||||
}
|
||||
|
||||
// CreateShader implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) CreateShader(shaderType uint32) uint32 {
|
||||
return gl.CreateShader(shaderType)
|
||||
}
|
||||
|
||||
// DeleteBuffers implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) DeleteBuffers(buffers []uint32) {
|
||||
gl.DeleteBuffers(int32(len(buffers)), &buffers[0])
|
||||
}
|
||||
|
||||
// DeleteFramebuffers implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) DeleteFramebuffers(buffers []uint32) {
|
||||
gl.DeleteFramebuffers(int32(len(buffers)), &buffers[0])
|
||||
}
|
||||
|
||||
// DeleteProgram implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) DeleteProgram(program uint32) {
|
||||
gl.DeleteProgram(program)
|
||||
}
|
||||
|
||||
// DeleteShader implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) DeleteShader(shader uint32) {
|
||||
gl.DeleteShader(shader)
|
||||
}
|
||||
|
||||
// DeleteTextures implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) DeleteTextures(textures []uint32) {
|
||||
gl.DeleteTextures(int32(len(textures)), &textures[0])
|
||||
}
|
||||
|
||||
// DeleteVertexArrays implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) DeleteVertexArrays(arrays []uint32) {
|
||||
gl.DeleteVertexArrays(int32(len(arrays)), &arrays[0])
|
||||
}
|
||||
|
||||
// Disable implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) Disable(capability uint32) {
|
||||
gl.Disable(capability)
|
||||
}
|
||||
|
||||
// DrawArrays implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) DrawArrays(mode uint32, first int32, count int32) {
|
||||
gl.DrawArrays(mode, first, count)
|
||||
}
|
||||
|
||||
// DrawBuffers implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) DrawBuffers(buffers []uint32) {
|
||||
gl.DrawBuffers(int32(len(buffers)), &buffers[0])
|
||||
}
|
||||
|
||||
// DrawElements implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) DrawElements(mode uint32, count int32, elementType uint32, indices uintptr) {
|
||||
gl.DrawElements(mode, count, elementType, unsafe.Pointer(indices)) // nolint: govet,gas
|
||||
}
|
||||
|
||||
// Enable implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) Enable(capability uint32) {
|
||||
gl.Enable(capability)
|
||||
}
|
||||
|
||||
// EnableVertexAttribArray implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) EnableVertexAttribArray(index uint32) {
|
||||
gl.EnableVertexAttribArray(index)
|
||||
}
|
||||
|
||||
// FramebufferRenderbuffer implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) FramebufferRenderbuffer(target uint32, attachment uint32, renderbuffertarget uint32, renderbuffer uint32) {
|
||||
gl.FramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer)
|
||||
}
|
||||
|
||||
// FramebufferTexture implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) FramebufferTexture(target uint32, attachment uint32, texture uint32, level int32) {
|
||||
gl.FramebufferTexture(target, attachment, texture, level)
|
||||
}
|
||||
|
||||
// GenerateMipmap implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) GenerateMipmap(target uint32) {
|
||||
gl.GenerateMipmap(target)
|
||||
}
|
||||
|
||||
// GenBuffers implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) GenBuffers(n int32) []uint32 {
|
||||
buffers := make([]uint32, n)
|
||||
gl.GenBuffers(n, &buffers[0])
|
||||
return buffers
|
||||
}
|
||||
|
||||
// GenFramebuffers implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) GenFramebuffers(n int32) []uint32 {
|
||||
buffers := make([]uint32, n)
|
||||
gl.GenFramebuffers(n, &buffers[0])
|
||||
return buffers
|
||||
}
|
||||
|
||||
// GenRenderbuffers implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) GenRenderbuffers(n int32) []uint32 {
|
||||
buffers := make([]uint32, n)
|
||||
gl.GenRenderbuffers(n, &buffers[0])
|
||||
return buffers
|
||||
}
|
||||
|
||||
// GenTextures implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) GenTextures(n int32) []uint32 {
|
||||
ids := make([]uint32, n)
|
||||
gl.GenTextures(n, &ids[0])
|
||||
return ids
|
||||
}
|
||||
|
||||
// GenVertexArrays implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) GenVertexArrays(n int32) []uint32 {
|
||||
ids := make([]uint32, n)
|
||||
gl.GenVertexArrays(n, &ids[0])
|
||||
return ids
|
||||
}
|
||||
|
||||
// GetAttribLocation implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) GetAttribLocation(program uint32, name string) int32 {
|
||||
return gl.GetAttribLocation(program, gl.Str(name+"\x00"))
|
||||
}
|
||||
|
||||
// GetError implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) GetError() uint32 {
|
||||
return gl.GetError()
|
||||
}
|
||||
|
||||
// GetIntegerv implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) GetIntegerv(name uint32, data *int32) {
|
||||
gl.GetIntegerv(name, data)
|
||||
}
|
||||
|
||||
// GetProgramInfoLog implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) GetProgramInfoLog(program uint32) string {
|
||||
logLength := native.GetProgramParameter(program, gl.INFO_LOG_LENGTH)
|
||||
log := strings.Repeat("\x00", int(logLength+1))
|
||||
gl.GetProgramInfoLog(program, logLength, nil, gl.Str(log))
|
||||
return log
|
||||
}
|
||||
|
||||
// GetProgramParameter implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) GetProgramParameter(program uint32, param uint32) int32 {
|
||||
result := int32(0)
|
||||
gl.GetProgramiv(program, param, &result)
|
||||
return result
|
||||
}
|
||||
|
||||
// GetShaderInfoLog implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) GetShaderInfoLog(shader uint32) string {
|
||||
logLength := native.GetShaderParameter(shader, gl.INFO_LOG_LENGTH)
|
||||
log := strings.Repeat("\x00", int(logLength+1))
|
||||
gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log))
|
||||
return log
|
||||
}
|
||||
|
||||
// GetShaderParameter implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) GetShaderParameter(shader uint32, param uint32) int32 {
|
||||
result := int32(0)
|
||||
gl.GetShaderiv(shader, param, &result)
|
||||
return result
|
||||
}
|
||||
|
||||
// GetUniformLocation implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) GetUniformLocation(program uint32, name string) int32 {
|
||||
return gl.GetUniformLocation(program, gl.Str(name+"\x00"))
|
||||
}
|
||||
|
||||
// IsEnabled implements the OpenGL interface.
|
||||
func (native *OpenGL) IsEnabled(capability uint32) bool {
|
||||
return gl.IsEnabled(capability)
|
||||
}
|
||||
|
||||
// LinkProgram implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) LinkProgram(program uint32) {
|
||||
gl.LinkProgram(program)
|
||||
}
|
||||
|
||||
// PixelStorei implements the OpenGL interface.
|
||||
func (native *OpenGL) PixelStorei(name uint32, param int32) {
|
||||
gl.PixelStorei(name, param)
|
||||
}
|
||||
|
||||
// PolygonMode implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) PolygonMode(face uint32, mode uint32) {
|
||||
gl.PolygonMode(face, mode)
|
||||
}
|
||||
|
||||
// ReadPixels implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) ReadPixels(x int32, y int32, width int32, height int32, format uint32, pixelType uint32, pixels interface{}) {
|
||||
gl.ReadPixels(x, y, width, height, format, pixelType, gl.Ptr(pixels))
|
||||
}
|
||||
|
||||
// RenderbufferStorage implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) RenderbufferStorage(target uint32, internalFormat uint32, width int32, height int32) {
|
||||
gl.RenderbufferStorage(target, internalFormat, width, height)
|
||||
}
|
||||
|
||||
// Scissor implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) Scissor(x, y int32, width, height int32) {
|
||||
gl.Scissor(x, y, width, height)
|
||||
}
|
||||
|
||||
// ShaderSource implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) ShaderSource(shader uint32, source string) {
|
||||
csources, free := gl.Strs(source + "\x00")
|
||||
defer free()
|
||||
|
||||
gl.ShaderSource(shader, 1, csources, nil)
|
||||
}
|
||||
|
||||
// TexImage2D implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) TexImage2D(target uint32, level int32, internalFormat uint32, width int32, height int32,
|
||||
border int32, format uint32, xtype uint32, pixels interface{}) {
|
||||
ptr, isPointer := pixels.(unsafe.Pointer)
|
||||
if isPointer {
|
||||
gl.TexImage2D(target, level, int32(internalFormat), width, height, border, format, xtype, ptr)
|
||||
} else {
|
||||
gl.TexImage2D(target, level, int32(internalFormat), width, height, border, format, xtype, gl.Ptr(pixels))
|
||||
}
|
||||
}
|
||||
|
||||
// TexParameteri implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) TexParameteri(target uint32, pname uint32, param int32) {
|
||||
gl.TexParameteri(target, pname, param)
|
||||
}
|
||||
|
||||
// Uniform1i implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) Uniform1i(location int32, value int32) {
|
||||
gl.Uniform1i(location, value)
|
||||
}
|
||||
|
||||
// Uniform4fv implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) Uniform4fv(location int32, value *[4]float32) {
|
||||
gl.Uniform4fv(location, 1, &value[0])
|
||||
}
|
||||
|
||||
// UniformMatrix4fv implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) UniformMatrix4fv(location int32, transpose bool, value *[16]float32) {
|
||||
count := int32(1)
|
||||
gl.UniformMatrix4fv(location, count, transpose, &value[0])
|
||||
}
|
||||
|
||||
// UseProgram implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) UseProgram(program uint32) {
|
||||
gl.UseProgram(program)
|
||||
}
|
||||
|
||||
// VertexAttribOffset implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) VertexAttribOffset(index uint32, size int32, attribType uint32, normalized bool, stride int32, offset int) {
|
||||
gl.VertexAttribPointer(index, size, attribType, normalized, stride, gl.PtrOffset(offset))
|
||||
}
|
||||
|
||||
// Viewport implements the opengl.OpenGL interface.
|
||||
func (native *OpenGL) Viewport(x int32, y int32, width int32, height int32) {
|
||||
gl.Viewport(x, y, width, height)
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
package native
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/go-gl/glfw/v3.2/glfw"
|
||||
|
||||
"github.com/inkyblackness/hacked/ui/input"
|
||||
"github.com/inkyblackness/hacked/ui/opengl"
|
||||
)
|
||||
|
||||
var buttonsByIndex = map[glfw.MouseButton]uint32{
|
||||
glfw.MouseButton1: input.MousePrimary,
|
||||
glfw.MouseButton2: input.MouseSecondary}
|
||||
|
||||
// OpenGLWindow represents a native OpenGL surface.
|
||||
type OpenGLWindow struct {
|
||||
opengl.WindowEventDispatcher
|
||||
|
||||
keyBuffer *input.StickyKeyBuffer
|
||||
|
||||
glfwWindow *glfw.Window
|
||||
glWrapper *OpenGL
|
||||
|
||||
titleBase string
|
||||
titleSuffix string
|
||||
projectModified bool
|
||||
|
||||
framesPerSecond float64
|
||||
frameTime time.Duration
|
||||
nextRenderTick time.Time
|
||||
}
|
||||
|
||||
// NewOpenGLWindow tries to initialize the OpenGL environment and returns a
|
||||
// new window instance.
|
||||
func NewOpenGLWindow(title string, framesPerSecond float64) (*OpenGLWindow, error) {
|
||||
err := glfw.Init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
glfw.WindowHint(glfw.Resizable, 1)
|
||||
glfw.WindowHint(glfw.Decorated, 1)
|
||||
glfw.WindowHint(glfw.ClientAPI, glfw.OpenGLAPI)
|
||||
glfw.WindowHint(glfw.ContextVersionMajor, 3)
|
||||
glfw.WindowHint(glfw.ContextVersionMinor, 2)
|
||||
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
|
||||
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
|
||||
glfw.WindowHint(glfw.DoubleBuffer, glfw.True)
|
||||
glfwWindow, err := glfw.CreateWindow(1280, 720, title, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
glfwWindow.MakeContextCurrent()
|
||||
glfw.SwapInterval(0)
|
||||
|
||||
window := &OpenGLWindow{
|
||||
WindowEventDispatcher: opengl.NullWindowEventDispatcher(),
|
||||
glfwWindow: glfwWindow,
|
||||
glWrapper: NewOpenGL(),
|
||||
titleBase: title,
|
||||
framesPerSecond: framesPerSecond,
|
||||
frameTime: time.Duration(int64(float64(time.Second) / framesPerSecond)),
|
||||
nextRenderTick: time.Now()}
|
||||
|
||||
window.keyBuffer = input.NewStickyKeyBuffer(window.StickyKeyListener())
|
||||
|
||||
glfwWindow.SetCursorPosCallback(window.onCursorPos)
|
||||
glfwWindow.SetMouseButtonCallback(window.onMouseButton)
|
||||
glfwWindow.SetScrollCallback(window.onMouseScroll)
|
||||
glfwWindow.SetFramebufferSizeCallback(window.onFramebufferResize)
|
||||
glfwWindow.SetKeyCallback(window.onKey)
|
||||
glfwWindow.SetCharCallback(window.onChar)
|
||||
glfwWindow.SetDropCallback(window.onDrop)
|
||||
glfwWindow.SetCloseCallback(window.onClosing)
|
||||
|
||||
return window, nil
|
||||
}
|
||||
|
||||
// ShouldClose returns true if the user requested the window to close.
|
||||
func (window *OpenGLWindow) ShouldClose() bool {
|
||||
return window.glfwWindow.ShouldClose()
|
||||
}
|
||||
|
||||
// Close closes the window and releases its resources.
|
||||
func (window *OpenGLWindow) Close() {
|
||||
window.CallClosed()
|
||||
window.glfwWindow.Destroy()
|
||||
glfw.Terminate()
|
||||
}
|
||||
|
||||
// StateSnapshot returns the current state of the window.
|
||||
func (window OpenGLWindow) StateSnapshot() opengl.WindowState {
|
||||
var state opengl.WindowState
|
||||
if window.glfwWindow.GetAttrib(glfw.Maximized) != 0 {
|
||||
state.Maximized = true
|
||||
// restore window to retrieve restored details, otherwise the maximized details will be read.
|
||||
_ = window.glfwWindow.Restore()
|
||||
}
|
||||
state.Left, state.Top = window.glfwWindow.GetPos()
|
||||
state.Width, state.Height = window.glfwWindow.GetSize()
|
||||
if state.Maximized {
|
||||
_ = window.glfwWindow.Maximize()
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
// RestoreState puts the window into the same state when StateSnapshot() was called.
|
||||
func (window OpenGLWindow) RestoreState(state opengl.WindowState) {
|
||||
_ = window.glfwWindow.Restore()
|
||||
window.glfwWindow.SetPos(state.Left, state.Top)
|
||||
window.glfwWindow.SetSize(state.Width, state.Height)
|
||||
if state.Maximized {
|
||||
_ = window.glfwWindow.Maximize()
|
||||
}
|
||||
}
|
||||
|
||||
// ClipboardString returns the current value of the clipboard, if it is compatible with UTF-8.
|
||||
func (window OpenGLWindow) ClipboardString() (string, error) {
|
||||
return window.glfwWindow.GetClipboardString()
|
||||
}
|
||||
|
||||
// SetClipboardString sets the current value of the clipboard as UTF-8 string.
|
||||
func (window OpenGLWindow) SetClipboardString(value string) {
|
||||
window.glfwWindow.SetClipboardString(value)
|
||||
}
|
||||
|
||||
// Update must be called from within the main thread as often as possible.
|
||||
func (window *OpenGLWindow) Update() {
|
||||
glfw.PollEvents()
|
||||
|
||||
now := time.Now()
|
||||
delta := now.Sub(window.nextRenderTick)
|
||||
if delta.Nanoseconds() < 0 {
|
||||
// detected a change of wallclock time into the past; realign
|
||||
delta = window.frameTime
|
||||
window.nextRenderTick = now
|
||||
}
|
||||
|
||||
if delta.Nanoseconds() >= window.frameTime.Nanoseconds() {
|
||||
window.glfwWindow.MakeContextCurrent()
|
||||
window.CallRender()
|
||||
window.glfwWindow.SwapBuffers()
|
||||
framesCovered := delta.Nanoseconds() / window.frameTime.Nanoseconds()
|
||||
window.nextRenderTick = window.nextRenderTick.Add(time.Duration(framesCovered * window.frameTime.Nanoseconds()))
|
||||
}
|
||||
}
|
||||
|
||||
// OpenGL returns the OpenGL API.
|
||||
func (window *OpenGLWindow) OpenGL() opengl.OpenGL {
|
||||
return window.glWrapper
|
||||
}
|
||||
|
||||
// Size returns the dimension of the frame buffer of this window.
|
||||
func (window *OpenGLWindow) Size() (width int, height int) {
|
||||
return window.glfwWindow.GetFramebufferSize()
|
||||
}
|
||||
|
||||
// SetCursorVisible toggles the visibility of the cursor.
|
||||
func (window *OpenGLWindow) SetCursorVisible(visible bool) {
|
||||
if visible {
|
||||
window.glfwWindow.SetInputMode(glfw.CursorMode, glfw.CursorNormal)
|
||||
} else {
|
||||
window.glfwWindow.SetInputMode(glfw.CursorMode, glfw.CursorHidden)
|
||||
}
|
||||
}
|
||||
|
||||
// SetFullScreen toggles the windowed mode.
|
||||
func (window *OpenGLWindow) SetFullScreen(on bool) {
|
||||
if on {
|
||||
monitor := glfw.GetPrimaryMonitor()
|
||||
videoMode := monitor.GetVideoMode()
|
||||
window.glfwWindow.SetMonitor(monitor, 0, 0, videoMode.Width, videoMode.Height, glfw.DontCare)
|
||||
} else {
|
||||
window.glfwWindow.SetMonitor(nil, 0, 0, 1280, 720, glfw.DontCare)
|
||||
}
|
||||
}
|
||||
|
||||
// SetTitleSuffix appends a text to the current window title.
|
||||
func (window *OpenGLWindow) SetTitleSuffix(value string) {
|
||||
window.titleSuffix = value
|
||||
window.updateTitle()
|
||||
}
|
||||
|
||||
// SetProjectModified sets an indicator in the window frame that the project has not been saved.
|
||||
func (window *OpenGLWindow) SetProjectModified(modified bool) {
|
||||
window.projectModified = modified
|
||||
window.updateTitle()
|
||||
}
|
||||
|
||||
func (window *OpenGLWindow) updateTitle() {
|
||||
title := window.titleBase
|
||||
if len(window.titleSuffix) > 0 {
|
||||
title += " - " + window.titleSuffix
|
||||
}
|
||||
if window.projectModified {
|
||||
title += " (unsaved changes)"
|
||||
}
|
||||
window.glfwWindow.SetTitle(title)
|
||||
}
|
||||
|
||||
// SetCloseRequest sets the should-close property of the window.
|
||||
func (window *OpenGLWindow) SetCloseRequest(shouldClose bool) {
|
||||
window.glfwWindow.SetShouldClose(shouldClose)
|
||||
}
|
||||
|
||||
func (window *OpenGLWindow) onClosing(rawWindow *glfw.Window) {
|
||||
window.CallClosing()
|
||||
}
|
||||
|
||||
func (window *OpenGLWindow) onFramebufferResize(rawWindow *glfw.Window, width int, height int) {
|
||||
window.CallResize(width, height)
|
||||
}
|
||||
|
||||
func (window *OpenGLWindow) onCursorPos(rawWindow *glfw.Window, x float64, y float64) {
|
||||
window.CallOnMouseMove(float32(x), float32(y))
|
||||
}
|
||||
|
||||
func (window *OpenGLWindow) onMouseButton(rawWindow *glfw.Window, rawButton glfw.MouseButton, action glfw.Action, mods glfw.ModifierKey) {
|
||||
button, knownButton := buttonsByIndex[rawButton]
|
||||
|
||||
if knownButton {
|
||||
modifier := window.mapModifier(mods)
|
||||
|
||||
if action == glfw.Press {
|
||||
window.CallOnMouseButtonDown(button, modifier)
|
||||
} else if action == glfw.Release {
|
||||
window.CallOnMouseButtonUp(button, modifier)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (window *OpenGLWindow) onMouseScroll(rawWindow *glfw.Window, dx float64, dy float64) {
|
||||
window.CallOnMouseScroll(float32(dx), float32(dy))
|
||||
}
|
||||
|
||||
func (window *OpenGLWindow) onKey(rawWindow *glfw.Window, glfwKey glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
|
||||
modifier := window.mapModifier(mods)
|
||||
key, knownKey := keyMap[glfwKey]
|
||||
if knownKey {
|
||||
window.reportKey(action, key, modifier)
|
||||
}
|
||||
|
||||
keyName := glfw.GetKeyName(glfwKey, scancode)
|
||||
key, knownKey = input.ResolveShortcut(keyName, modifier)
|
||||
if knownKey {
|
||||
window.reportKey(action, key, modifier)
|
||||
}
|
||||
}
|
||||
|
||||
func (window *OpenGLWindow) reportKey(action glfw.Action, key input.Key, modifier input.Modifier) {
|
||||
switch action {
|
||||
case glfw.Press:
|
||||
window.keyBuffer.KeyDown(key, modifier)
|
||||
case glfw.Repeat:
|
||||
window.keyBuffer.KeyUp(key, modifier)
|
||||
window.keyBuffer.KeyDown(key, modifier)
|
||||
case glfw.Release:
|
||||
window.keyBuffer.KeyUp(key, modifier)
|
||||
}
|
||||
}
|
||||
|
||||
func (window *OpenGLWindow) onChar(rawWindow *glfw.Window, char rune) {
|
||||
window.CallCharCallback(char)
|
||||
}
|
||||
|
||||
func (window *OpenGLWindow) mapModifier(mods glfw.ModifierKey) input.Modifier {
|
||||
modifier := input.ModNone
|
||||
|
||||
if (mods & glfw.ModControl) != 0 {
|
||||
modifier = modifier.With(input.ModControl)
|
||||
}
|
||||
if (mods & glfw.ModShift) != 0 {
|
||||
modifier = modifier.With(input.ModShift)
|
||||
}
|
||||
if (mods & glfw.ModAlt) != 0 {
|
||||
modifier = modifier.With(input.ModAlt)
|
||||
}
|
||||
if (mods & glfw.ModSuper) != 0 {
|
||||
modifier = modifier.With(input.ModSuper)
|
||||
}
|
||||
|
||||
return modifier
|
||||
}
|
||||
|
||||
func (window *OpenGLWindow) onDrop(rawWindow *glfw.Window, filePaths []string) {
|
||||
window.CallFileDropCallback(filePaths)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package native
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/inkyblackness/hacked/ui/opengl"
|
||||
)
|
||||
|
||||
// Run creates a native OpenGL window, initializes it with the given function and
|
||||
// then runs the event loop until the window shall be closed.
|
||||
func Run(initializer func(opengl.Window) error, title string, framesPerSecond float64) error {
|
||||
runtime.LockOSThread()
|
||||
|
||||
window, err := NewOpenGLWindow(title, framesPerSecond)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer window.Close()
|
||||
|
||||
err = initializer(window)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ticker := time.NewTicker(time.Millisecond)
|
||||
for !window.ShouldClose() {
|
||||
<-ticker.C
|
||||
window.Update()
|
||||
}
|
||||
ticker.Stop()
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package opengl
|
||||
|
||||
// CompileNewShader creates a shader of given type and compiles the provided source.
|
||||
func CompileNewShader(gl OpenGL, shaderType uint32, source string) (shader uint32, err error) {
|
||||
shader = gl.CreateShader(shaderType)
|
||||
|
||||
gl.ShaderSource(shader, source)
|
||||
gl.CompileShader(shader)
|
||||
|
||||
compileStatus := gl.GetShaderParameter(shader, COMPILE_STATUS)
|
||||
if compileStatus == 0 {
|
||||
err = ShaderError{Log: gl.GetShaderInfoLog(shader)}
|
||||
gl.DeleteShader(shader)
|
||||
shader = 0
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package opengl
|
||||
|
||||
// DebuggingEntryFunc is a function to be called on function entry.
|
||||
type DebuggingEntryFunc func(name string, param ...interface{})
|
||||
|
||||
// DebuggingExitFunc is a function to be called after an OpenGL function has returned.
|
||||
// result may be several parameters for functions with multiple return values.
|
||||
type DebuggingExitFunc func(name string, result ...interface{})
|
||||
|
||||
// DebuggingErrorFunc is a function which is called if a previous OpenGL call caused an error state.
|
||||
type DebuggingErrorFunc func(name string, errorCodes []uint32)
|
||||
|
||||
// DebugBuilder is a builder for an OpenGL implementation for debugging.
|
||||
type DebugBuilder struct {
|
||||
wrapped OpenGL
|
||||
|
||||
onEntry DebuggingEntryFunc
|
||||
onExit DebuggingExitFunc
|
||||
onError DebuggingErrorFunc
|
||||
}
|
||||
|
||||
// NewDebugBuilder wraps the provided OpenGL instance and returns a new builder
|
||||
// instance.
|
||||
func NewDebugBuilder(wrapped OpenGL) *DebugBuilder {
|
||||
builder := &DebugBuilder{
|
||||
wrapped: wrapped,
|
||||
onEntry: func(string, ...interface{}) {},
|
||||
onExit: func(string, ...interface{}) {},
|
||||
onError: func(string, []uint32) {}}
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
// Build creates a new instance of the debugging OpenGL implementation.
|
||||
// The builder can be reused to create another instance with different parameters.
|
||||
func (builder *DebugBuilder) Build() OpenGL {
|
||||
opengl := &debuggingOpenGL{
|
||||
gl: builder.wrapped,
|
||||
|
||||
onEntry: builder.onEntry,
|
||||
onExit: builder.onExit,
|
||||
onError: builder.onError}
|
||||
|
||||
return opengl
|
||||
}
|
||||
|
||||
// OnEntry registers a callback function to be called before an OpenGL function is called.
|
||||
func (builder *DebugBuilder) OnEntry(callback DebuggingEntryFunc) *DebugBuilder {
|
||||
builder.onEntry = callback
|
||||
return builder
|
||||
}
|
||||
|
||||
// OnExit registers a callback function to be called after an OpenGL function returned.
|
||||
func (builder *DebugBuilder) OnExit(callback DebuggingExitFunc) *DebugBuilder {
|
||||
builder.onExit = callback
|
||||
return builder
|
||||
}
|
||||
|
||||
// OnError registers a callback function to be called when an OpenGL function set an error state.
|
||||
func (builder *DebugBuilder) OnError(callback DebuggingErrorFunc) *DebugBuilder {
|
||||
builder.onError = callback
|
||||
return builder
|
||||
}
|
||||
@@ -0,0 +1,490 @@
|
||||
package opengl
|
||||
|
||||
type debuggingOpenGL struct {
|
||||
gl OpenGL
|
||||
|
||||
onEntry DebuggingEntryFunc
|
||||
onExit DebuggingExitFunc
|
||||
onError DebuggingErrorFunc
|
||||
}
|
||||
|
||||
func (debugging *debuggingOpenGL) recordEntry(name string, param ...interface{}) {
|
||||
debugging.onEntry(name, param...)
|
||||
}
|
||||
|
||||
func (debugging *debuggingOpenGL) recordExit(name string, result ...interface{}) {
|
||||
var errorCodes []uint32
|
||||
|
||||
for errorCode := debugging.gl.GetError(); errorCode != NO_ERROR; errorCode = debugging.gl.GetError() {
|
||||
errorCodes = append(errorCodes, errorCode)
|
||||
}
|
||||
debugging.onExit(name, result...)
|
||||
if len(errorCodes) > 0 {
|
||||
debugging.onError(name, errorCodes)
|
||||
}
|
||||
}
|
||||
|
||||
// ActiveTexture implements the opengl.OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) ActiveTexture(texture uint32) {
|
||||
debugging.recordEntry("ActiveTexture", texture)
|
||||
debugging.gl.ActiveTexture(texture)
|
||||
debugging.recordExit("ActiveTexture")
|
||||
}
|
||||
|
||||
// AttachShader implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) AttachShader(program uint32, shader uint32) {
|
||||
debugging.recordEntry("AttachShader", program, shader)
|
||||
debugging.gl.AttachShader(program, shader)
|
||||
debugging.recordExit("AttachShader")
|
||||
}
|
||||
|
||||
// BindAttribLocation implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) BindAttribLocation(program uint32, index uint32, name string) {
|
||||
debugging.recordEntry("BindAttribLocation", program, index, name)
|
||||
debugging.gl.BindAttribLocation(program, index, name)
|
||||
debugging.recordExit("BindAttribLocation")
|
||||
}
|
||||
|
||||
// BindBuffer implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) BindBuffer(target uint32, buffer uint32) {
|
||||
debugging.recordEntry("BindBuffer", target, buffer)
|
||||
debugging.gl.BindBuffer(target, buffer)
|
||||
debugging.recordExit("BindBuffer")
|
||||
}
|
||||
|
||||
// BindFramebuffer implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) BindFramebuffer(target uint32, buffer uint32) {
|
||||
debugging.recordEntry("BindFramebuffer", target, buffer)
|
||||
debugging.gl.BindFramebuffer(target, buffer)
|
||||
debugging.recordExit("BindFramebuffer")
|
||||
}
|
||||
|
||||
// BindRenderbuffer implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) BindRenderbuffer(target uint32, buffer uint32) {
|
||||
debugging.recordEntry("BindRenderbuffer", target, buffer)
|
||||
debugging.gl.BindRenderbuffer(target, buffer)
|
||||
debugging.recordExit("BindRenderbuffer")
|
||||
}
|
||||
|
||||
// BindSampler implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) BindSampler(unit uint32, sampler uint32) {
|
||||
debugging.recordEntry("BindSampler", unit, sampler)
|
||||
debugging.gl.BindSampler(unit, sampler)
|
||||
debugging.recordExit("BindSampler")
|
||||
}
|
||||
|
||||
// BindTexture implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) BindTexture(target uint32, texture uint32) {
|
||||
debugging.recordEntry("BindTexture", target, texture)
|
||||
debugging.gl.BindTexture(target, texture)
|
||||
debugging.recordExit("BindTexture")
|
||||
}
|
||||
|
||||
// BindVertexArray implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) BindVertexArray(array uint32) {
|
||||
debugging.recordEntry("BindVertexArray", array)
|
||||
debugging.gl.BindVertexArray(array)
|
||||
debugging.recordExit("BindVertexArray")
|
||||
}
|
||||
|
||||
// BlendEquation implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) BlendEquation(mode uint32) {
|
||||
debugging.recordEntry("BlendEquation", mode)
|
||||
debugging.gl.BlendEquation(mode)
|
||||
debugging.recordExit("BlendEquation")
|
||||
}
|
||||
|
||||
// BlendEquationSeparate implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) BlendEquationSeparate(modeRGB uint32, modeAlpha uint32) {
|
||||
debugging.recordEntry("BlendEquationSeparate", modeRGB, modeAlpha)
|
||||
debugging.gl.BlendEquationSeparate(modeRGB, modeAlpha)
|
||||
debugging.recordExit("BlendEquationSeparate")
|
||||
}
|
||||
|
||||
// BlendFunc implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) BlendFunc(sfactor uint32, dfactor uint32) {
|
||||
debugging.recordEntry("BlendFunc", sfactor, dfactor)
|
||||
debugging.gl.BlendFunc(sfactor, dfactor)
|
||||
debugging.recordExit("BlendFunc")
|
||||
}
|
||||
|
||||
// BlendFuncSeparate implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) BlendFuncSeparate(srcRGB uint32, dstRGB uint32, srcAlpha uint32, dstAlpha uint32) {
|
||||
debugging.recordEntry("BlendFuncSeparate", srcRGB, dstRGB, srcAlpha, dstAlpha)
|
||||
debugging.gl.BlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha)
|
||||
debugging.recordExit("BlendFuncSeparate")
|
||||
}
|
||||
|
||||
// BufferData implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) BufferData(target uint32, size int, data interface{}, usage uint32) {
|
||||
debugging.recordEntry("BufferData", target, size, data, usage)
|
||||
debugging.gl.BufferData(target, size, data, usage)
|
||||
debugging.recordExit("BufferData")
|
||||
}
|
||||
|
||||
// CheckFramebufferStatus implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) CheckFramebufferStatus(target uint32) uint32 {
|
||||
debugging.recordEntry("CheckFramebufferStatus", target)
|
||||
result := debugging.gl.CheckFramebufferStatus(target)
|
||||
debugging.recordExit("CheckFramebufferStatus")
|
||||
return result
|
||||
}
|
||||
|
||||
// Clear implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) Clear(mask uint32) {
|
||||
debugging.recordEntry("Clear", mask)
|
||||
debugging.gl.Clear(mask)
|
||||
debugging.recordExit("Clear")
|
||||
}
|
||||
|
||||
// ClearColor implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) ClearColor(red float32, green float32, blue float32, alpha float32) {
|
||||
debugging.recordEntry("ClearColor", red, green, blue, alpha)
|
||||
debugging.gl.ClearColor(red, green, blue, alpha)
|
||||
debugging.recordExit("ClearColor")
|
||||
}
|
||||
|
||||
// CompileShader implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) CompileShader(shader uint32) {
|
||||
debugging.recordEntry("CompileShader", shader)
|
||||
debugging.gl.CompileShader(shader)
|
||||
debugging.recordExit("CompileShader")
|
||||
}
|
||||
|
||||
// CreateProgram implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) CreateProgram() uint32 {
|
||||
debugging.recordEntry("CreateProgram")
|
||||
result := debugging.gl.CreateProgram()
|
||||
debugging.recordExit("CreateProgram", result)
|
||||
return result
|
||||
}
|
||||
|
||||
// CreateShader implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) CreateShader(shaderType uint32) uint32 {
|
||||
debugging.recordEntry("CreateShader", shaderType)
|
||||
result := debugging.gl.CreateShader(shaderType)
|
||||
debugging.recordExit("CreateShader", result)
|
||||
return result
|
||||
}
|
||||
|
||||
// DeleteBuffers implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) DeleteBuffers(buffers []uint32) {
|
||||
debugging.recordEntry("DeleteBuffers", buffers)
|
||||
debugging.gl.DeleteBuffers(buffers)
|
||||
debugging.recordExit("DeleteBuffers")
|
||||
}
|
||||
|
||||
// DeleteFramebuffers implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) DeleteFramebuffers(buffers []uint32) {
|
||||
debugging.recordEntry("DeleteFramebuffers", buffers)
|
||||
debugging.gl.DeleteFramebuffers(buffers)
|
||||
debugging.recordExit("DeleteFramebuffers")
|
||||
}
|
||||
|
||||
// DeleteProgram implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) DeleteProgram(program uint32) {
|
||||
debugging.recordEntry("DeleteProgram", program)
|
||||
debugging.gl.DeleteProgram(program)
|
||||
debugging.recordExit("DeleteProgram")
|
||||
}
|
||||
|
||||
// DeleteShader implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) DeleteShader(shader uint32) {
|
||||
debugging.recordEntry("DeleteShader", shader)
|
||||
debugging.gl.DeleteShader(shader)
|
||||
debugging.recordExit("DeleteShader")
|
||||
}
|
||||
|
||||
// DeleteTextures implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) DeleteTextures(textures []uint32) {
|
||||
debugging.recordEntry("DeleteTextures", textures)
|
||||
debugging.gl.DeleteTextures(textures)
|
||||
debugging.recordExit("DeleteTextures")
|
||||
}
|
||||
|
||||
// DeleteVertexArrays implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) DeleteVertexArrays(arrays []uint32) {
|
||||
debugging.recordEntry("DeleteVertexArrays", arrays)
|
||||
debugging.gl.DeleteVertexArrays(arrays)
|
||||
debugging.recordExit("DeleteVertexArrays")
|
||||
}
|
||||
|
||||
// Disable implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) Disable(capability uint32) {
|
||||
debugging.recordEntry("Disable", capability)
|
||||
debugging.gl.Disable(capability)
|
||||
debugging.recordExit("Disable")
|
||||
}
|
||||
|
||||
// DrawArrays implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) DrawArrays(mode uint32, first int32, count int32) {
|
||||
debugging.recordEntry("DrawArrays", first, count)
|
||||
debugging.gl.DrawArrays(mode, first, count)
|
||||
debugging.recordExit("DrawArrays")
|
||||
}
|
||||
|
||||
// DrawBuffers implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) DrawBuffers(buffers []uint32) {
|
||||
debugging.recordEntry("DrawBuffers", buffers)
|
||||
debugging.gl.DrawBuffers(buffers)
|
||||
debugging.recordExit("DrawBuffers")
|
||||
}
|
||||
|
||||
// DrawElements implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) DrawElements(mode uint32, count int32, elementType uint32, indices uintptr) {
|
||||
debugging.recordEntry("DrawElements", mode, count, elementType, indices)
|
||||
debugging.gl.DrawElements(mode, count, elementType, indices)
|
||||
debugging.recordExit("DrawElements")
|
||||
}
|
||||
|
||||
// Enable implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) Enable(capability uint32) {
|
||||
debugging.recordEntry("Enable", capability)
|
||||
debugging.gl.Enable(capability)
|
||||
debugging.recordExit("Enable")
|
||||
}
|
||||
|
||||
// EnableVertexAttribArray implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) EnableVertexAttribArray(index uint32) {
|
||||
debugging.recordEntry("EnableVertexAttribArray", index)
|
||||
debugging.gl.EnableVertexAttribArray(index)
|
||||
debugging.recordExit("EnableVertexAttribArray")
|
||||
}
|
||||
|
||||
// FramebufferRenderbuffer implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) FramebufferRenderbuffer(target uint32, attachment uint32, renderbuffertarget uint32, renderbuffer uint32) {
|
||||
debugging.recordEntry("FramebufferRenderbuffer", target, attachment, renderbuffertarget, renderbuffer)
|
||||
debugging.gl.FramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer)
|
||||
debugging.recordExit("FramebufferRenderbuffer")
|
||||
}
|
||||
|
||||
// FramebufferTexture implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) FramebufferTexture(target uint32, attachment uint32, texture uint32, level int32) {
|
||||
debugging.recordEntry("FramebufferTexture", target, attachment, texture, level)
|
||||
debugging.gl.FramebufferTexture(target, attachment, texture, level)
|
||||
debugging.recordExit("FramebufferTexture")
|
||||
}
|
||||
|
||||
// GenerateMipmap implements the opengl.OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) GenerateMipmap(target uint32) {
|
||||
debugging.recordEntry("GenerateMipmap", target)
|
||||
debugging.gl.GenerateMipmap(target)
|
||||
debugging.recordExit("GenerateMipmap")
|
||||
}
|
||||
|
||||
// GenBuffers implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) GenBuffers(n int32) []uint32 {
|
||||
debugging.recordEntry("GenBuffers", n)
|
||||
result := debugging.gl.GenBuffers(n)
|
||||
debugging.recordExit("GenBuffers", result)
|
||||
return result
|
||||
}
|
||||
|
||||
// GenFramebuffers implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) GenFramebuffers(n int32) []uint32 {
|
||||
debugging.recordEntry("GenFramebuffers", n)
|
||||
result := debugging.gl.GenFramebuffers(n)
|
||||
debugging.recordExit("GenFramebuffers", result)
|
||||
return result
|
||||
}
|
||||
|
||||
// GenRenderbuffers implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) GenRenderbuffers(n int32) []uint32 {
|
||||
debugging.recordEntry("GenRenderbuffers", n)
|
||||
result := debugging.gl.GenRenderbuffers(n)
|
||||
debugging.recordExit("GenRenderbuffers", result)
|
||||
return result
|
||||
}
|
||||
|
||||
// GenTextures implements the opengl.OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) GenTextures(n int32) []uint32 {
|
||||
debugging.recordEntry("GenTextures", n)
|
||||
result := debugging.gl.GenTextures(n)
|
||||
debugging.recordExit("GenTextures", result)
|
||||
return result
|
||||
}
|
||||
|
||||
// GenVertexArrays implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) GenVertexArrays(n int32) []uint32 {
|
||||
debugging.recordEntry("GenVertexArrays", n)
|
||||
result := debugging.gl.GenVertexArrays(n)
|
||||
debugging.recordExit("GenVertexArrays", result)
|
||||
return result
|
||||
}
|
||||
|
||||
// GetAttribLocation implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) GetAttribLocation(program uint32, name string) int32 {
|
||||
debugging.recordEntry("GetAttribLocation", program, name)
|
||||
result := debugging.gl.GetAttribLocation(program, name)
|
||||
debugging.recordExit("GetAttribLocation", result)
|
||||
return result
|
||||
}
|
||||
|
||||
// GetError implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) GetError() uint32 {
|
||||
debugging.recordEntry("GetError")
|
||||
result := debugging.gl.GetError()
|
||||
debugging.recordExit("GetError", result)
|
||||
return result
|
||||
}
|
||||
|
||||
// GetIntegerv implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) GetIntegerv(name uint32, data *int32) {
|
||||
debugging.recordEntry("GetIntegerv", name, data)
|
||||
debugging.gl.GetIntegerv(name, data)
|
||||
debugging.recordExit("GetIntegerv")
|
||||
}
|
||||
|
||||
// GetProgramInfoLog implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) GetProgramInfoLog(program uint32) string {
|
||||
debugging.recordEntry("GetProgramInfoLog", program)
|
||||
result := debugging.gl.GetProgramInfoLog(program)
|
||||
debugging.recordExit("GetProgramInfoLog", result)
|
||||
return result
|
||||
}
|
||||
|
||||
// GetProgramParameter implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) GetProgramParameter(program uint32, param uint32) int32 {
|
||||
debugging.recordEntry("GetProgramParameter", program, param)
|
||||
result := debugging.gl.GetProgramParameter(program, param)
|
||||
debugging.recordExit("GetProgramParameter", result)
|
||||
return result
|
||||
}
|
||||
|
||||
// GetShaderInfoLog implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) GetShaderInfoLog(shader uint32) string {
|
||||
debugging.recordEntry("GetShaderInfoLog", shader)
|
||||
result := debugging.gl.GetShaderInfoLog(shader)
|
||||
debugging.recordExit("GetShaderInfoLog", result)
|
||||
return result
|
||||
}
|
||||
|
||||
// GetShaderParameter implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) GetShaderParameter(shader uint32, param uint32) int32 {
|
||||
debugging.recordEntry("GetShaderParameter", shader, param)
|
||||
result := debugging.gl.GetShaderParameter(shader, param)
|
||||
debugging.recordExit("GetShaderParameter", result)
|
||||
return result
|
||||
}
|
||||
|
||||
// GetUniformLocation implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) GetUniformLocation(program uint32, name string) int32 {
|
||||
debugging.recordEntry("GetUniformLocation", program, name)
|
||||
result := debugging.gl.GetUniformLocation(program, name)
|
||||
debugging.recordExit("GetUniformLocation", result)
|
||||
return result
|
||||
}
|
||||
|
||||
// IsEnabled implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) IsEnabled(capability uint32) bool {
|
||||
debugging.recordEntry("IsEnabled", capability)
|
||||
result := debugging.gl.IsEnabled(capability)
|
||||
debugging.recordExit("IsEnabled", result)
|
||||
return result
|
||||
}
|
||||
|
||||
// LinkProgram implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) LinkProgram(program uint32) {
|
||||
debugging.recordEntry("LinkProgram", program)
|
||||
debugging.gl.LinkProgram(program)
|
||||
debugging.recordExit("LinkProgram")
|
||||
}
|
||||
|
||||
// PixelStorei implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) PixelStorei(name uint32, param int32) {
|
||||
debugging.recordEntry("PixelStorei", name, param)
|
||||
debugging.gl.PixelStorei(name, param)
|
||||
debugging.recordExit("PixelStorei")
|
||||
}
|
||||
|
||||
// PolygonMode implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) PolygonMode(face uint32, mode uint32) {
|
||||
debugging.recordEntry("PolygonMode", face, mode)
|
||||
debugging.gl.PolygonMode(face, mode)
|
||||
debugging.recordExit("PolygonMode")
|
||||
}
|
||||
|
||||
// ReadPixels implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) ReadPixels(x int32, y int32, width int32, height int32, format uint32, pixelType uint32, pixels interface{}) {
|
||||
debugging.recordEntry("ReadPixels", x, y, width, height, format, pixelType, pixels)
|
||||
debugging.gl.ReadPixels(x, y, width, height, format, pixelType, pixels)
|
||||
debugging.recordExit("ReadPixels")
|
||||
}
|
||||
|
||||
// RenderbufferStorage implements the opengl.OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) RenderbufferStorage(target uint32, internalFormat uint32, width int32, height int32) {
|
||||
debugging.recordEntry("RenderbufferStorage", target, internalFormat, width, height)
|
||||
debugging.gl.RenderbufferStorage(target, internalFormat, width, height)
|
||||
debugging.recordExit("RenderbufferStorage")
|
||||
}
|
||||
|
||||
// Scissor implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) Scissor(x, y int32, width, height int32) {
|
||||
debugging.recordEntry("Scissor", x, y, width, height)
|
||||
debugging.gl.Scissor(x, y, width, height)
|
||||
debugging.recordExit("Scissor")
|
||||
}
|
||||
|
||||
// ShaderSource implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) ShaderSource(shader uint32, source string) {
|
||||
debugging.recordEntry("ShaderSource", shader, source)
|
||||
debugging.gl.ShaderSource(shader, source)
|
||||
debugging.recordExit("ShaderSource")
|
||||
}
|
||||
|
||||
// TexImage2D implements the opengl.OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) TexImage2D(target uint32, level int32, internalFormat uint32, width int32, height int32,
|
||||
border int32, format uint32, xtype uint32, pixels interface{}) {
|
||||
debugging.recordEntry("TexImage2D", target, level, internalFormat, width, height, border, format, xtype, pixels)
|
||||
debugging.gl.TexImage2D(target, level, internalFormat, width, height, border, format, xtype, pixels)
|
||||
debugging.recordExit("TexImage2D")
|
||||
}
|
||||
|
||||
// TexParameteri implements the opengl.OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) TexParameteri(target uint32, pname uint32, param int32) {
|
||||
debugging.recordEntry("TexParameteri", target, pname, param)
|
||||
debugging.gl.TexParameteri(target, pname, param)
|
||||
debugging.recordExit("TexParameteri")
|
||||
}
|
||||
|
||||
// Uniform1i implements the opengl.OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) Uniform1i(location int32, value int32) {
|
||||
debugging.recordEntry("Uniform1i", location, value)
|
||||
debugging.gl.Uniform1i(location, value)
|
||||
debugging.recordExit("Uniform1i")
|
||||
}
|
||||
|
||||
// Uniform4fv implements the opengl.OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) Uniform4fv(location int32, value *[4]float32) {
|
||||
debugging.recordEntry("Uniform4fv", location, value)
|
||||
debugging.gl.Uniform4fv(location, value)
|
||||
debugging.recordExit("Uniform4fv")
|
||||
}
|
||||
|
||||
// UniformMatrix4fv implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) UniformMatrix4fv(location int32, transpose bool, value *[16]float32) {
|
||||
debugging.recordEntry("UniformMatrix4fv", location, transpose, value)
|
||||
debugging.gl.UniformMatrix4fv(location, transpose, value)
|
||||
debugging.recordExit("UniformMatrix4fv")
|
||||
}
|
||||
|
||||
// UseProgram implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) UseProgram(program uint32) {
|
||||
debugging.recordEntry("UseProgram", program)
|
||||
debugging.gl.UseProgram(program)
|
||||
debugging.recordExit("UseProgram")
|
||||
}
|
||||
|
||||
// VertexAttribOffset implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) VertexAttribOffset(index uint32, size int32, attribType uint32, normalized bool, stride int32, offset int) {
|
||||
debugging.recordEntry("VertexAttribOffset", index, size, attribType, normalized, stride, offset)
|
||||
debugging.gl.VertexAttribOffset(index, size, attribType, normalized, stride, offset)
|
||||
debugging.recordExit("VertexAttribOffset")
|
||||
}
|
||||
|
||||
// Viewport implements the OpenGL interface.
|
||||
func (debugging *debuggingOpenGL) Viewport(x int32, y int32, width int32, height int32) {
|
||||
debugging.recordEntry("Viewport", x, y, width, height)
|
||||
debugging.gl.Viewport(x, y, width, height)
|
||||
debugging.recordExit("Viewport")
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package opengl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var errorStrings = map[uint32]string{
|
||||
NO_ERROR: "NO_ERROR",
|
||||
INVALID_ENUM: "INVALID_ENUM",
|
||||
INVALID_VALUE: "INVALID_VALUE",
|
||||
INVALID_OPERATION: "INVALID_OPERATION",
|
||||
STACK_OVERFLOW: "STACK_OVERFLOW",
|
||||
STACK_UNDERFLOW: "STACK_UNDERFLOW",
|
||||
OUT_OF_MEMORY: "OUT_OF_MEMORY",
|
||||
INVALID_FRAMEBUFFER_OPERATION: "INVALID_FRAMEBUFFER_OPERATION"}
|
||||
|
||||
// ErrorString returns a readable version of the provided error code. If the
|
||||
// code is unknown, the textual representation of the hexadecimal value is
|
||||
// returned.
|
||||
func ErrorString(errorCode uint32) string {
|
||||
value, exists := errorStrings[errorCode]
|
||||
|
||||
if !exists {
|
||||
value = fmt.Sprintf("0x%04X", errorCode)
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
// ShaderError describes a problem with a log.
|
||||
type ShaderError struct {
|
||||
Log string
|
||||
}
|
||||
|
||||
// Error returns the log.
|
||||
func (err ShaderError) Error() string {
|
||||
return err.Log
|
||||
}
|
||||
|
||||
// NamedShaderError is an error with a name.
|
||||
type NamedShaderError struct {
|
||||
Name string
|
||||
Nested error
|
||||
}
|
||||
|
||||
// Error returns the name with the nested error information.
|
||||
func (err NamedShaderError) Error() string {
|
||||
return fmt.Sprintf("%s failed: %v", err.Name, err.Nested)
|
||||
}
|
||||
|
||||
// Unwrap returns the nested error.
|
||||
func (err NamedShaderError) Unwrap() error {
|
||||
return err.Nested
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package opengl
|
||||
|
||||
// OpenGL describes an Open GL interface usable for all environments of this
|
||||
// application.
|
||||
type OpenGL interface {
|
||||
ActiveTexture(texture uint32)
|
||||
AttachShader(program uint32, shader uint32)
|
||||
|
||||
BindAttribLocation(program uint32, index uint32, name string)
|
||||
BindBuffer(target uint32, buffer uint32)
|
||||
BindFramebuffer(target uint32, buffer uint32)
|
||||
BindRenderbuffer(target uint32, buffer uint32)
|
||||
BindSampler(unit uint32, sampler uint32)
|
||||
BindTexture(target uint32, texture uint32)
|
||||
BindVertexArray(array uint32)
|
||||
BlendEquation(mode uint32)
|
||||
BlendEquationSeparate(modeRGB uint32, modeAlpha uint32)
|
||||
BlendFunc(sfactor uint32, dfactor uint32)
|
||||
BlendFuncSeparate(srcRGB uint32, dstRGB uint32, srcAlpha uint32, dstAlpha uint32)
|
||||
BufferData(target uint32, size int, data interface{}, usage uint32)
|
||||
|
||||
CheckFramebufferStatus(target uint32) uint32
|
||||
|
||||
Clear(mask uint32)
|
||||
ClearColor(red float32, green float32, blue float32, alpha float32)
|
||||
|
||||
CompileShader(shader uint32)
|
||||
|
||||
CreateProgram() uint32
|
||||
CreateShader(shaderType uint32) uint32
|
||||
|
||||
DeleteBuffers(buffers []uint32)
|
||||
DeleteFramebuffers(buffers []uint32)
|
||||
DeleteProgram(program uint32)
|
||||
DeleteShader(shader uint32)
|
||||
DeleteTextures(textures []uint32)
|
||||
DeleteVertexArrays(arrays []uint32)
|
||||
Disable(capability uint32)
|
||||
|
||||
DrawArrays(mode uint32, first int32, count int32)
|
||||
DrawBuffers(buffers []uint32)
|
||||
DrawElements(mode uint32, count int32, elementType uint32, indices uintptr)
|
||||
|
||||
Enable(capability uint32)
|
||||
EnableVertexAttribArray(index uint32)
|
||||
|
||||
FramebufferRenderbuffer(target uint32, attachment uint32, renderbuffertarget uint32, renderbuffer uint32)
|
||||
FramebufferTexture(target uint32, attachment uint32, texture uint32, level int32)
|
||||
|
||||
GenerateMipmap(target uint32)
|
||||
GenBuffers(n int32) []uint32
|
||||
GenFramebuffers(n int32) []uint32
|
||||
GenRenderbuffers(n int32) []uint32
|
||||
GenTextures(n int32) []uint32
|
||||
GenVertexArrays(n int32) []uint32
|
||||
|
||||
GetAttribLocation(program uint32, name string) int32
|
||||
GetError() uint32
|
||||
GetIntegerv(name uint32, data *int32)
|
||||
GetShaderInfoLog(shader uint32) string
|
||||
GetShaderParameter(shader uint32, param uint32) int32
|
||||
GetProgramInfoLog(program uint32) string
|
||||
GetProgramParameter(program uint32, param uint32) int32
|
||||
GetUniformLocation(program uint32, name string) int32
|
||||
|
||||
IsEnabled(capability uint32) bool
|
||||
|
||||
LinkProgram(program uint32)
|
||||
|
||||
PixelStorei(name uint32, param int32)
|
||||
PolygonMode(face uint32, mode uint32)
|
||||
|
||||
ReadPixels(x int32, y int32, width int32, height int32, format uint32, pixelType uint32, pixels interface{})
|
||||
RenderbufferStorage(target uint32, internalFormat uint32, width int32, height int32)
|
||||
|
||||
Scissor(x, y int32, width, height int32)
|
||||
ShaderSource(shader uint32, source string)
|
||||
|
||||
TexImage2D(target uint32, level int32, internalFormat uint32, width int32, height int32,
|
||||
border int32, format uint32, xtype uint32, pixels interface{})
|
||||
TexParameteri(target uint32, pname uint32, param int32)
|
||||
|
||||
Uniform1i(location int32, value int32)
|
||||
Uniform4fv(location int32, value *[4]float32)
|
||||
UniformMatrix4fv(location int32, transpose bool, value *[16]float32)
|
||||
UseProgram(program uint32)
|
||||
|
||||
VertexAttribOffset(index uint32, size int32, attribType uint32, normalized bool, stride int32, offset int)
|
||||
Viewport(x int32, y int32, width int32, height int32)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package opengl
|
||||
|
||||
// LinkNewProgram creates a new shader program based on the provided shaders.
|
||||
func LinkNewProgram(gl OpenGL, shaders ...uint32) (program uint32, err error) {
|
||||
program = gl.CreateProgram()
|
||||
|
||||
for _, shader := range shaders {
|
||||
gl.AttachShader(program, shader)
|
||||
}
|
||||
gl.LinkProgram(program)
|
||||
|
||||
if gl.GetProgramParameter(program, LINK_STATUS) == 0 {
|
||||
err = ShaderError{Log: gl.GetProgramInfoLog(program)}
|
||||
gl.DeleteProgram(program)
|
||||
program = 0
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// LinkNewStandardProgram creates a new shader based on two shader sources.
|
||||
func LinkNewStandardProgram(gl OpenGL, vertexShaderSource, fragmentShaderSource string) (program uint32, err error) {
|
||||
vertexShader, vertexErr := CompileNewShader(gl, VERTEX_SHADER, vertexShaderSource)
|
||||
if vertexErr != nil {
|
||||
return 0, NamedShaderError{Name: "vertexShader", Nested: vertexErr}
|
||||
}
|
||||
defer gl.DeleteShader(vertexShader)
|
||||
fragmentShader, fragmentErr := CompileNewShader(gl, FRAGMENT_SHADER, fragmentShaderSource)
|
||||
if fragmentErr != nil {
|
||||
return 0, NamedShaderError{Name: "fragmentShader", Nested: fragmentErr}
|
||||
}
|
||||
defer gl.DeleteShader(fragmentShader)
|
||||
|
||||
return LinkNewProgram(gl, vertexShader, fragmentShader)
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package opengl
|
||||
|
||||
import (
|
||||
mgl "github.com/go-gl/mathgl/mgl32"
|
||||
)
|
||||
|
||||
// UniformLocation represents a uniform parameter for a shader program.
|
||||
type UniformLocation int32
|
||||
|
||||
// Matrix4Uniform represents one uniform parameter for a 4x4 matrix.
|
||||
type Matrix4Uniform UniformLocation
|
||||
|
||||
// Set stores the provided matrix as the current uniform value.
|
||||
func (location Matrix4Uniform) Set(gl OpenGL, matrix *mgl.Mat4) {
|
||||
matrixArray := (*[16]float32)(matrix)
|
||||
gl.UniformMatrix4fv(int32(location), false, matrixArray)
|
||||
}
|
||||
|
||||
// Vector4Uniform represents one uniform parameter for a 4-dimensional vector.
|
||||
type Vector4Uniform UniformLocation
|
||||
|
||||
// Set stores the provided 4-dimensional vector as the current uniform value.
|
||||
func (location Vector4Uniform) Set(gl OpenGL, value *[4]float32) {
|
||||
gl.Uniform4fv(int32(location), value)
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package opengl
|
||||
|
||||
// AttributeSetter is a callback function for a VertexArrayObject.
|
||||
type AttributeSetter func(OpenGL)
|
||||
|
||||
// VertexArrayObject registers common vertex properties which are pre-set
|
||||
// before regular rendering loops.
|
||||
// Depending on the supported level of the Open GL API, these settings are
|
||||
// either buffered (using a VAO - vertex array object), or replayed for
|
||||
// every render call.
|
||||
type VertexArrayObject struct {
|
||||
gl OpenGL
|
||||
program uint32
|
||||
handle uint32
|
||||
setter AttributeSetter
|
||||
}
|
||||
|
||||
// NewVertexArrayObject returns a new instance.
|
||||
func NewVertexArrayObject(gl OpenGL, program uint32) *VertexArrayObject {
|
||||
vao := &VertexArrayObject{
|
||||
gl: gl,
|
||||
program: program,
|
||||
handle: gl.GenVertexArrays(1)[0],
|
||||
setter: func(OpenGL) {}}
|
||||
|
||||
return vao
|
||||
}
|
||||
|
||||
// Dispose drops any associated resources.
|
||||
func (vao *VertexArrayObject) Dispose() {
|
||||
vao.gl.DeleteVertexArrays([]uint32{vao.handle})
|
||||
vao.handle = 0
|
||||
}
|
||||
|
||||
// WithSetter registers the setter function for this object.
|
||||
// Depending on the support of the OpenGL API, this setter may be called
|
||||
// once immediately, or for each render call.
|
||||
func (vao *VertexArrayObject) WithSetter(setter AttributeSetter) {
|
||||
if vao.handle != 0 {
|
||||
vao.OnShader(func() { setter(vao.gl) })
|
||||
}
|
||||
vao.setter = setter
|
||||
}
|
||||
|
||||
// OnShader executes the provided task with an activated shader program
|
||||
// and the vertex array object initialized.
|
||||
func (vao *VertexArrayObject) OnShader(task func()) {
|
||||
gl := vao.gl
|
||||
|
||||
gl.UseProgram(vao.program)
|
||||
gl.BindVertexArray(vao.handle)
|
||||
|
||||
defer func() {
|
||||
gl.BindVertexArray(0)
|
||||
gl.UseProgram(0)
|
||||
}()
|
||||
|
||||
if vao.handle == 0 {
|
||||
vao.setter(gl)
|
||||
}
|
||||
task()
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
package opengl
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/inkyblackness/hacked/ui/input"
|
||||
)
|
||||
|
||||
// ClosingCallback is the function to handle close requests by the user.
|
||||
type ClosingCallback func()
|
||||
|
||||
// ClosedCallback is the function to clean up resources when the window is being closed.
|
||||
type ClosedCallback func()
|
||||
|
||||
// RenderCallback is the function to receive render events. When the callback
|
||||
// returns, the window will swap the internal buffer.
|
||||
type RenderCallback func()
|
||||
|
||||
// MouseMoveCallback is the function to receive the current mouse coordinate while moving.
|
||||
// Movement is reported while the cursor is within the client area of the window, and
|
||||
// beyond the window as long as at least one captured button is pressed.
|
||||
// Reported values are with sub-pixel precision, if possible.
|
||||
type MouseMoveCallback func(x float32, y float32)
|
||||
|
||||
// MouseButtonCallback is the function to receive button up/down events.
|
||||
// An Up event is sent for every reported Down event, even if the mouse cursor is outside
|
||||
// the client area.
|
||||
type MouseButtonCallback func(buttonMask uint32, modifier input.Modifier)
|
||||
|
||||
// MouseScrollCallback is the function to receive scroll events.
|
||||
// Delta values are right-hand oriented: positive values go right/down/far.
|
||||
type MouseScrollCallback func(dx float32, dy float32)
|
||||
|
||||
// ResizeCallback is called for a change of window dimensions.
|
||||
type ResizeCallback func(width int, height int)
|
||||
|
||||
// CharCallback is called for typing a character.
|
||||
type CharCallback func(char rune)
|
||||
|
||||
// KeyCallback is called for pressing or releasing a key on the keyboard.
|
||||
type KeyCallback func(key input.Key, modifier input.Modifier)
|
||||
|
||||
// ModifierCallback is called when the currently active modifier changed.
|
||||
type ModifierCallback func(modifier input.Modifier)
|
||||
|
||||
// FileDropCallback is called when one or more files were dropped into the window.
|
||||
type FileDropCallback func(filePaths []string)
|
||||
|
||||
// WindowState describes how the window is currently presented to the user.
|
||||
type WindowState struct {
|
||||
// Maximized is set to true if the window is currently resized to fill the screen.
|
||||
Maximized bool
|
||||
// Top marks the screen position of the upper border of the window.
|
||||
Top int
|
||||
// Left marks the screen position of the left border of the window.
|
||||
Left int
|
||||
// Width marks the width of the non-maximized window.
|
||||
Width int
|
||||
// Height marks the height of the non-maximized window.
|
||||
Height int
|
||||
}
|
||||
|
||||
// WindowStateFromFile attempts to load the state from a file with given name.
|
||||
// If this does not work, the given default state will be returned.
|
||||
func WindowStateFromFile(filename string, defaultState WindowState) WindowState {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return defaultState
|
||||
}
|
||||
var state WindowState
|
||||
err = json.Unmarshal(data, &state)
|
||||
if err != nil {
|
||||
return defaultState
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
// SaveTo stores the state in a file with given filename.
|
||||
func (state WindowState) SaveTo(filename string) error {
|
||||
bytes, err := json.MarshalIndent(state, "", " ")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ioutil.WriteFile(filename, bytes, 0640)
|
||||
}
|
||||
|
||||
// Window represents an OpenGL render surface.
|
||||
type Window interface {
|
||||
// StateSnapshot returns the current state of the window.
|
||||
StateSnapshot() WindowState
|
||||
// RestoreState puts the window into the same state when StateSnapshot() was called.
|
||||
RestoreState(state WindowState)
|
||||
|
||||
// ClipboardString returns the current value of the clipboard, if it is compatible with UTF-8.
|
||||
ClipboardString() (string, error)
|
||||
// SetClipboardString sets the current value of the clipboard as UTF-8 string.
|
||||
SetClipboardString(value string)
|
||||
|
||||
// OnClosing registers a callback function which shall be called when the user requests to close the window.
|
||||
OnClosing(callback ClosingCallback)
|
||||
// OnClosed registers a callback function which shall be called when the window is being closed.
|
||||
OnClosed(callback ClosedCallback)
|
||||
// SetCloseRequest notifies the window system whether the window shall be closed.
|
||||
// It can be called during the callback of OnClosing() to abort a close request by the user.
|
||||
SetCloseRequest(shouldClose bool)
|
||||
|
||||
// OpenGL returns the OpenGL API wrapper for this window.
|
||||
OpenGL() OpenGL
|
||||
// OnRender registers a callback function which shall be called to update the scene.
|
||||
OnRender(callback RenderCallback)
|
||||
|
||||
// OnResize registers a callback function for sizing events.
|
||||
OnResize(callback ResizeCallback)
|
||||
// Size returns the dimensions of the window display area in pixel.
|
||||
Size() (width int, height int)
|
||||
// SetFullScreen sets the full screen state of the window.
|
||||
SetFullScreen(on bool)
|
||||
// SetTitleSuffix appends a text to the current window title.
|
||||
SetTitleSuffix(value string)
|
||||
// SetProjectModified sets an indicator in the window frame that the project has not been saved.
|
||||
SetProjectModified(modified bool)
|
||||
|
||||
// SetCursorVisible controls whether the mouse cursor is currently visible.
|
||||
SetCursorVisible(visible bool)
|
||||
|
||||
// OnMouseMove registers a callback function for mouse move events.
|
||||
OnMouseMove(callback MouseMoveCallback)
|
||||
// OnMouseButtonDown registers a callback function for mouse button down events.
|
||||
OnMouseButtonDown(callback MouseButtonCallback)
|
||||
// OnMouseButtonUp registers a callback function for mouse button up events.
|
||||
OnMouseButtonUp(callback MouseButtonCallback)
|
||||
// OnMouseScroll registers a callback function for mouse scroll events.
|
||||
OnMouseScroll(callback MouseScrollCallback)
|
||||
|
||||
// OnKeyPress registers a callback function for key events.
|
||||
OnKeyPress(callback KeyCallback)
|
||||
// OnKeyRelease registers a callback function for key events.
|
||||
OnKeyRelease(callback KeyCallback)
|
||||
// OnModifier registers a callback function for change of modifier events.
|
||||
OnModifier(callback ModifierCallback)
|
||||
// OnCharCallback registers a callback function for typed characters.
|
||||
OnCharCallback(callback CharCallback)
|
||||
|
||||
// OnFileDropCallback registers a callback function for dropped files.
|
||||
OnFileDropCallback(callback FileDropCallback)
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package opengl
|
||||
|
||||
import (
|
||||
"github.com/inkyblackness/hacked/ui/input"
|
||||
)
|
||||
|
||||
type keyDeferrer struct {
|
||||
window *WindowEventDispatcher
|
||||
}
|
||||
|
||||
func (def *keyDeferrer) KeyPress(key input.Key, modifier input.Modifier) {
|
||||
def.window.CallKeyPress(key, modifier)
|
||||
}
|
||||
|
||||
func (def *keyDeferrer) KeyRelease(key input.Key, modifier input.Modifier) {
|
||||
def.window.CallKeyRelease(key, modifier)
|
||||
}
|
||||
|
||||
func (def *keyDeferrer) Modifier(modifier input.Modifier) {
|
||||
def.window.CallModifier(modifier)
|
||||
}
|
||||
|
||||
// WindowEventDispatcher implements the common, basic functionality of Window.
|
||||
type WindowEventDispatcher struct {
|
||||
CallClosing ClosingCallback
|
||||
CallClosed ClosedCallback
|
||||
CallRender RenderCallback
|
||||
CallResize ResizeCallback
|
||||
CallOnMouseMove MouseMoveCallback
|
||||
CallOnMouseButtonUp MouseButtonCallback
|
||||
CallOnMouseButtonDown MouseButtonCallback
|
||||
CallOnMouseScroll MouseScrollCallback
|
||||
CallModifier ModifierCallback
|
||||
CallKeyPress KeyCallback
|
||||
CallKeyRelease KeyCallback
|
||||
CallCharCallback CharCallback
|
||||
CallFileDropCallback FileDropCallback
|
||||
}
|
||||
|
||||
// NullWindowEventDispatcher returns an initialized instance with empty callbacks.
|
||||
func NullWindowEventDispatcher() WindowEventDispatcher {
|
||||
return WindowEventDispatcher{
|
||||
CallClosing: func() {},
|
||||
CallClosed: func() {},
|
||||
CallRender: func() {},
|
||||
CallResize: func(int, int) {},
|
||||
CallOnMouseMove: func(float32, float32) {},
|
||||
CallOnMouseButtonUp: func(uint32, input.Modifier) {},
|
||||
CallOnMouseButtonDown: func(uint32, input.Modifier) {},
|
||||
CallOnMouseScroll: func(float32, float32) {},
|
||||
CallKeyPress: func(input.Key, input.Modifier) {},
|
||||
CallKeyRelease: func(input.Key, input.Modifier) {},
|
||||
CallModifier: func(input.Modifier) {},
|
||||
CallCharCallback: func(rune) {},
|
||||
CallFileDropCallback: func([]string) {},
|
||||
}
|
||||
}
|
||||
|
||||
// StickyKeyListener returns an instance of a listener acting as an adapter
|
||||
// for the key-down/-up callbacks.
|
||||
func (window *WindowEventDispatcher) StickyKeyListener() input.StickyKeyListener {
|
||||
return &keyDeferrer{window: window}
|
||||
}
|
||||
|
||||
// OnClosing implements the Window interface.
|
||||
func (window *WindowEventDispatcher) OnClosing(callback ClosingCallback) {
|
||||
window.CallClosing = callback
|
||||
}
|
||||
|
||||
// OnClosed implements the Window interface.
|
||||
func (window *WindowEventDispatcher) OnClosed(callback ClosedCallback) {
|
||||
window.CallClosed = callback
|
||||
}
|
||||
|
||||
// OnRender implements the Window interface.
|
||||
func (window *WindowEventDispatcher) OnRender(callback RenderCallback) {
|
||||
window.CallRender = callback
|
||||
}
|
||||
|
||||
// OnResize implements the Window interface.
|
||||
func (window *WindowEventDispatcher) OnResize(callback ResizeCallback) {
|
||||
window.CallResize = callback
|
||||
}
|
||||
|
||||
// OnMouseMove implements the Window interface.
|
||||
func (window *WindowEventDispatcher) OnMouseMove(callback MouseMoveCallback) {
|
||||
window.CallOnMouseMove = callback
|
||||
}
|
||||
|
||||
// OnMouseButtonDown implements the Window interface.
|
||||
func (window *WindowEventDispatcher) OnMouseButtonDown(callback MouseButtonCallback) {
|
||||
window.CallOnMouseButtonDown = callback
|
||||
}
|
||||
|
||||
// OnMouseButtonUp implements the Window interface.
|
||||
func (window *WindowEventDispatcher) OnMouseButtonUp(callback MouseButtonCallback) {
|
||||
window.CallOnMouseButtonUp = callback
|
||||
}
|
||||
|
||||
// OnMouseScroll implements the Window interface.
|
||||
func (window *WindowEventDispatcher) OnMouseScroll(callback MouseScrollCallback) {
|
||||
window.CallOnMouseScroll = callback
|
||||
}
|
||||
|
||||
// OnKeyPress implements the Window interface.
|
||||
func (window *WindowEventDispatcher) OnKeyPress(callback KeyCallback) {
|
||||
window.CallKeyPress = callback
|
||||
}
|
||||
|
||||
// OnKeyRelease implements the Window interface.
|
||||
func (window *WindowEventDispatcher) OnKeyRelease(callback KeyCallback) {
|
||||
window.CallKeyRelease = callback
|
||||
}
|
||||
|
||||
// OnModifier implements the WindowEventDispatcher interface.
|
||||
func (window *WindowEventDispatcher) OnModifier(callback ModifierCallback) {
|
||||
window.CallModifier = callback
|
||||
}
|
||||
|
||||
// OnCharCallback implements the Window interface.
|
||||
func (window *WindowEventDispatcher) OnCharCallback(callback CharCallback) {
|
||||
window.CallCharCallback = callback
|
||||
}
|
||||
|
||||
// OnFileDropCallback implements the Window interface.
|
||||
func (window *WindowEventDispatcher) OnFileDropCallback(callback FileDropCallback) {
|
||||
window.CallFileDropCallback = callback
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
package opengl
|
||||
|
||||
// Buffer Bits
|
||||
// nolint: golint,megacheck
|
||||
const (
|
||||
DEPTH_BUFFER_BIT uint32 = 0x00000100
|
||||
STENCIL_BUFFER_BIT = 0x00000400
|
||||
COLOR_BUFFER_BIT = 0x00004000
|
||||
)
|
||||
|
||||
// Draw Types
|
||||
// nolint: golint,megacheck
|
||||
const (
|
||||
POINTS uint32 = 0x0000
|
||||
LINES = 0x0001
|
||||
LINE_LOOP = 0x0002
|
||||
LINE_STRIP = 0x0003
|
||||
TRIANGLES = 0x0004
|
||||
TRIANGLE_STRIP = 0x0005
|
||||
TRIANGLE_FAN = 0x0006
|
||||
)
|
||||
|
||||
// Shader Types
|
||||
// nolint: golint,megacheck
|
||||
const (
|
||||
FRAGMENT_SHADER uint32 = 0x8B30
|
||||
VERTEX_SHADER = 0x8B31
|
||||
)
|
||||
|
||||
// Status Values
|
||||
// nolint: golint,megacheck
|
||||
const (
|
||||
COMPILE_STATUS uint32 = 0x8B81
|
||||
LINK_STATUS = 0x8B82
|
||||
)
|
||||
|
||||
// Buffer Types
|
||||
// nolint: golint,megacheck
|
||||
const (
|
||||
ARRAY_BUFFER uint32 = 0x8892
|
||||
ELEMENT_ARRAY_BUFFER = 0x8893
|
||||
)
|
||||
|
||||
// Framebuffer Types
|
||||
// nolint: golint,megacheck
|
||||
const (
|
||||
FRAMEBUFFER = 0x8D40
|
||||
RENDERBUFFER = 0x8D41
|
||||
|
||||
DEPTH_COMPONENT24 = 0x81A6
|
||||
|
||||
COLOR_ATTACHMENT0 = 0x8CE0
|
||||
DEPTH_ATTACHMENT = 0x8D00
|
||||
)
|
||||
|
||||
// Draw Types
|
||||
// nolint: golint,megacheck
|
||||
const (
|
||||
STREAM_DRAW uint32 = 0x88E0
|
||||
STATIC_DRAW = 0x88E4
|
||||
DYNAMIC_DRAW = 0x88E8
|
||||
)
|
||||
|
||||
// Features
|
||||
// nolint: golint,megacheck
|
||||
const (
|
||||
BLEND uint32 = 0x0BE2
|
||||
DEPTH_TEST = 0x0B71
|
||||
CULL_FACE = 0x0B44
|
||||
SCISSOR_TEST = 0x0C11
|
||||
|
||||
NICEST = 0x1102
|
||||
LINE_SMOOTH = 0x0B20
|
||||
LINE_SMOOTH_HINT = 0x0C52
|
||||
|
||||
ACTIVE_TEXTURE = 0x84E0
|
||||
CURRENT_PROGRAM = 0x8B8D
|
||||
TEXTURE_BINDING_2D = 0x8069
|
||||
SAMPLER_BINDING = 0x8919
|
||||
ARRAY_BUFFER_BINDING = 0x8894
|
||||
ELEMENT_ARRAY_BUFFER_BINDING = 0x8895
|
||||
VERTEX_ARRAY_BINDING = 0x85B5
|
||||
POLYGON_MODE = 0x0B40
|
||||
VIEWPORT = 0x0BA2
|
||||
SCISSOR_BOX = 0x0C10
|
||||
BLEND_SRC_RGB = 0x80C9
|
||||
BLEND_DST_RGB = 0x80C8
|
||||
BLEND_SRC_ALPHA = 0x80CB
|
||||
BLEND_DST_ALPHA = 0x80CA
|
||||
BLEND_EQUATION_RGB = 0x8009
|
||||
BLEND_EQUATION_ALPHA = 0x883D
|
||||
FRONT_AND_BACK = 0x0408
|
||||
FILL = 0x1B02
|
||||
)
|
||||
|
||||
// Alpha constants
|
||||
// nolint: golint,megacheck
|
||||
const (
|
||||
SRC_ALPHA uint32 = 0x0302
|
||||
ONE_MINUS_SRC_ALPHA = 0x0303
|
||||
ONE_MINUS_SRC_COLOR = 0x0301
|
||||
|
||||
FUNC_ADD = 0x8006
|
||||
)
|
||||
|
||||
// Data Types
|
||||
// nolint: golint,megacheck
|
||||
const (
|
||||
BYTE uint32 = 0x1400
|
||||
UNSIGNED_BYTE = 0x1401
|
||||
SHORT = 0x1402
|
||||
UNSIGNED_SHORT = 0x1403
|
||||
INT = 0x1404
|
||||
UNSIGNED_INT = 0x1405
|
||||
FLOAT = 0x1406
|
||||
)
|
||||
|
||||
// Texture Constants
|
||||
// nolint: golint,megacheck
|
||||
const (
|
||||
TEXTURE_2D uint32 = 0x0DE1
|
||||
|
||||
TEXTURE0 = 0x84C0
|
||||
|
||||
NEAREST = 0x2600
|
||||
TEXTURE_MAG_FILTER = 0x2800
|
||||
TEXTURE_MIN_FILTER = 0x2801
|
||||
|
||||
UNPACK_ROW_LENGTH = 0x0CF2
|
||||
|
||||
LINEAR = 0x2601
|
||||
)
|
||||
|
||||
// Errors
|
||||
// nolint: golint,megacheck
|
||||
const (
|
||||
NO_ERROR uint32 = 0
|
||||
INVALID_ENUM = 0x0500
|
||||
INVALID_VALUE = 0x0501
|
||||
INVALID_OPERATION = 0x0502
|
||||
STACK_OVERFLOW = 0x0503
|
||||
STACK_UNDERFLOW = 0x0504
|
||||
OUT_OF_MEMORY = 0x0505
|
||||
INVALID_FRAMEBUFFER_OPERATION = 0x0506
|
||||
)
|
||||
|
||||
// Color Types
|
||||
// nolint: golint,megacheck
|
||||
const (
|
||||
ALPHA uint32 = 0x1906
|
||||
RGBA = 0x1908
|
||||
RED = 0x1903
|
||||
|
||||
RGBA8 = 0x8058
|
||||
R8 = 0x8229
|
||||
)
|
||||
Reference in New Issue
Block a user