Initial Commit

This commit is contained in:
illyum 2024-10-20 15:48:38 -06:00
commit 429a17cbf5
8 changed files with 534 additions and 0 deletions

8
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/ui.iml" filepath="$PROJECT_DIR$/.idea/ui.iml" />
</modules>
</component>
</project>

9
.idea/ui.iml generated Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

BIN
arial.ttf Normal file

Binary file not shown.

12
go.mod Normal file
View File

@ -0,0 +1,12 @@
module main
go 1.23.0
require (
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 // indirect
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a // indirect
github.com/go-gl/gltext v0.0.0-20170328174336-01a355945a70 // indirect
github.com/go-gl/mathgl v1.1.0 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
golang.org/x/image v0.21.0 // indirect
)

14
go.sum Normal file
View File

@ -0,0 +1,14 @@
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71 h1:5BVwOaUSBTlVZowGO6VZGw2H/zl9nrd3eCZfYV+NfQA=
github.com/go-gl/gl v0.0.0-20231021071112-07e5d0ea2e71/go.mod h1:9YTyiznxEY1fVinfM7RvRcjRHbw2xLBJ3AAGIT0I4Nw=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a h1:vxnBhFDDT+xzxf1jTJKMKZw3H0swfWk9RpWbBbDK5+0=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20240506104042-037f3cc74f2a/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/gltext v0.0.0-20170328174336-01a355945a70 h1:jLHSn7wgzCXTsZoldNrhgFS5fasJxb8Htn+iaYsZt88=
github.com/go-gl/gltext v0.0.0-20170328174336-01a355945a70/go.mod h1:KpCmHMLAPxpCBuDN9Tp7mjJA7lwFZNc2bZ0rCi/X6yc=
github.com/go-gl/mathgl v1.1.0 h1:0lzZ+rntPX3/oGrDzYGdowSLC2ky8Osirvf5uAwfIEA=
github.com/go-gl/mathgl v1.1.0/go.mod h1:yhpkQzEiH9yPyxDUGzkmgScbaBVlhC06qodikEM0ZwQ=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.21.0 h1:c5qV36ajHpdj4Qi0GnE0jUc/yuo33OLFaa0d+crTD5s=
golang.org/x/image v0.21.0/go.mod h1:vUbsLavqK/W303ZroQQVKQ+Af3Yl6Uz1Ppu5J/cLz78=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=

BIN
main.exe Normal file

Binary file not shown.

483
stuff.go Normal file
View File

@ -0,0 +1,483 @@
package main
import (
"fmt"
"os"
"runtime"
"strings"
"github.com/go-gl/gl/v4.1-core/gl"
"github.com/go-gl/glfw/v3.3/glfw"
"github.com/go-gl/gltext"
"github.com/go-gl/mathgl/mgl32"
)
func init() {
// GLFW event handling must run on the main OS thread
runtime.LockOSThread()
}
// Position represents a 2D position
type Position struct {
X, Y float32
}
// Size represents the width and height of a UI element
type Size struct {
Width, Height float32
}
// EventType represents the type of an event
type EventType int
const (
EventTypeClick EventType = iota
EventTypeMouseMove
EventTypeHover
)
// Event represents an input event
type Event struct {
Type EventType
Position Position
}
// UIElement defines the interface for UI elements
type UIElement interface {
Draw()
Update()
HandleEvent(event Event)
}
// Container defines the interface for UI containers
type Container interface {
UIElement
AddChild(UIElement)
RemoveChild(UIElement)
}
// Context manages the OpenGL context and resources
type Context struct {
shaderProgram uint32
font *gltext.Font
windowWidth int
windowHeight int
}
func NewContext(windowWidth, windowHeight int) *Context {
return &Context{
windowWidth: windowWidth,
windowHeight: windowHeight,
}
}
func (c *Context) InitOpenGL() {
if err := gl.Init(); err != nil {
panic(err)
}
version := gl.GoStr(gl.GetString(gl.VERSION))
fmt.Println("OpenGL version", version)
// Initialize shader program
c.shaderProgram = NewShaderProgram(vertexShaderSource, fragmentShaderSource)
// Load font using gltext
fontData, err := os.Open("arial.ttf")
if err != nil {
panic(err)
}
defer fontData.Close()
// Load the truetype font: specify scale, rune range (ASCII), and direction
font, err := gltext.LoadTruetype(fontData, 24, 32, 127, gltext.LeftToRight)
if err != nil {
panic(err)
}
c.font = font
}
func (c *Context) Clear() {
gl.ClearColor(0.0, 0.0, 0.0, 1.0)
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
}
func (c *Context) SwapBuffers(window *glfw.Window) {
window.SwapBuffers()
}
// Window represents the main application window
type Window struct {
width int
height int
title string
transparent bool
panels []*Panel
glContext *Context
glfwWindow *glfw.Window
}
func NewWindow(width, height int, title string) *Window {
if err := glfw.Init(); err != nil {
panic(err)
}
glfw.WindowHint(glfw.ContextVersionMajor, 4)
glfw.WindowHint(glfw.ContextVersionMinor, 1)
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
glfwWindow, err := glfw.CreateWindow(width, height, title, nil, nil)
if err != nil {
panic(err)
}
glfwWindow.MakeContextCurrent()
return &Window{
width: width,
height: height,
title: title,
panels: []*Panel{},
glfwWindow: glfwWindow,
}
}
func (w *Window) SetTransparent(t bool) {
w.transparent = t
// Apply transparency settings if needed
}
func (w *Window) DefineContext() *Context {
w.glContext = NewContext(w.width, w.height)
w.glContext.InitOpenGL()
return w.glContext
}
func (w *Window) CreatePanel() *Panel {
panel := NewPanel()
w.panels = append(w.panels, panel)
return panel
}
func (w *Window) registerCallbacks() {
w.glfwWindow.SetCursorPosCallback(w.cursorPosCallback)
w.glfwWindow.SetMouseButtonCallback(w.mouseButtonCallback)
}
func (w *Window) cursorPosCallback(window *glfw.Window, xpos float64, ypos float64) {
event := Event{
Type: EventTypeMouseMove,
Position: Position{X: float32(xpos), Y: float32(ypos)},
}
w.handleEvent(event)
}
func (w *Window) mouseButtonCallback(window *glfw.Window, button glfw.MouseButton, action glfw.Action, mods glfw.ModifierKey) {
if button == glfw.MouseButtonLeft && action == glfw.Press {
xpos, ypos := window.GetCursorPos()
event := Event{
Type: EventTypeClick,
Position: Position{X: float32(xpos), Y: float32(ypos)},
}
w.handleEvent(event)
}
}
func (w *Window) handleEvent(event Event) {
for _, panel := range w.panels {
panel.HandleEvent(event)
}
}
func (w *Window) update() {
for _, panel := range w.panels {
panel.Update()
}
}
func (w *Window) draw() {
for _, panel := range w.panels {
panel.Draw()
}
}
func (w *Window) Start() {
w.registerCallbacks()
for !w.glfwWindow.ShouldClose() {
glfw.PollEvents()
w.glContext.Clear()
w.update()
w.draw()
w.glContext.SwapBuffers(w.glfwWindow)
}
glfw.Terminate()
}
// Panel is a container for UI elements
type Panel struct {
children []UIElement
}
func NewPanel() *Panel {
return &Panel{
children: []UIElement{},
}
}
func (p *Panel) AddChild(e UIElement) {
p.children = append(p.children, e)
}
func (p *Panel) RemoveChild(e UIElement) {
// Implement child removal logic if needed
}
func (p *Panel) Draw() {
for _, child := range p.children {
child.Draw()
}
}
func (p *Panel) Update() {
for _, child := range p.children {
child.Update()
}
}
func (p *Panel) HandleEvent(event Event) {
for _, child := range p.children {
child.HandleEvent(event)
}
}
// Button is a clickable UI element
type Button struct {
label string
onClick func()
Position
Size
isHovered bool
context *Context
}
func NewButton(label string, onClick func(), context *Context) *Button {
return &Button{
label: label,
onClick: onClick,
context: context,
Position: Position{X: 0, Y: 0},
Size: Size{Width: 100, Height: 50},
isHovered: false,
}
}
func (b *Button) contains(pos Position) bool {
return pos.X >= b.Position.X && pos.X <= b.Position.X+b.Size.Width &&
pos.Y >= b.Position.Y && pos.Y <= b.Position.Y+b.Size.Height
}
func (b *Button) Draw() {
var color [4]float32
if b.isHovered {
color = [4]float32{0.7, 0.7, 0.7, 1.0} // Lighter when hovered
} else {
color = [4]float32{0.5, 0.5, 0.5, 1.0}
}
rect := NewRectangle(b.Position.X, b.Position.Y, b.Size.Width, b.Size.Height, color, b.context)
rect.Draw()
rect.Destroy()
// Draw the label
x := b.Position.X + 10
y := b.Position.Y + b.Size.Height/2 + 8 // Approximate vertical centering
b.context.font.Printf(x, y, b.label)
}
func (b *Button) Update() {
// Update the button if needed
}
func (b *Button) HandleEvent(event Event) {
switch event.Type {
case EventTypeClick:
if b.contains(event.Position) {
b.onClick()
}
case EventTypeMouseMove:
if b.contains(event.Position) {
if !b.isHovered {
b.isHovered = true
}
} else {
if b.isHovered {
b.isHovered = false
}
}
}
}
// Rectangle is used to draw a rectangle using OpenGL
type Rectangle struct {
Position
Size
Color [4]float32
vao uint32
vbo uint32
shaderProgram uint32
context *Context
}
func NewRectangle(x, y, width, height float32, color [4]float32, context *Context) *Rectangle {
rect := &Rectangle{
Position: Position{X: x, Y: y},
Size: Size{Width: width, Height: height},
Color: color,
shaderProgram: context.shaderProgram,
context: context,
}
rect.initOpenGL()
return rect
}
func (r *Rectangle) initOpenGL() {
vertices := []float32{
r.Position.X, r.Position.Y, 0.0,
r.Position.X + r.Size.Width, r.Position.Y, 0.0,
r.Position.X + r.Size.Width, r.Position.Y + r.Size.Height, 0.0,
r.Position.X, r.Position.Y + r.Size.Height, 0.0,
}
indices := []uint32{
0, 1, 2,
2, 3, 0,
}
gl.GenVertexArrays(1, &r.vao)
gl.BindVertexArray(r.vao)
gl.GenBuffers(1, &r.vbo)
gl.BindBuffer(gl.ARRAY_BUFFER, r.vbo)
gl.BufferData(gl.ARRAY_BUFFER, len(vertices)*4, gl.Ptr(vertices), gl.STATIC_DRAW)
var ebo uint32
gl.GenBuffers(1, &ebo)
gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebo)
gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, len(indices)*4, gl.Ptr(indices), gl.STATIC_DRAW)
gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 3*4, gl.PtrOffset(0))
gl.EnableVertexAttribArray(0)
gl.BindVertexArray(0)
}
func (r *Rectangle) Draw() {
gl.UseProgram(r.shaderProgram)
// Set uniforms
model := mgl32.Ident4()
projection := mgl32.Ortho2D(0, float32(r.context.windowWidth), float32(r.context.windowHeight), 0)
modelLoc := gl.GetUniformLocation(r.shaderProgram, gl.Str("model\x00"))
projectionLoc := gl.GetUniformLocation(r.shaderProgram, gl.Str("projection\x00"))
colorLoc := gl.GetUniformLocation(r.shaderProgram, gl.Str("color\x00"))
gl.UniformMatrix4fv(modelLoc, 1, false, &model[0])
gl.UniformMatrix4fv(projectionLoc, 1, false, &projection[0])
gl.Uniform4fv(colorLoc, 1, &r.Color[0])
gl.BindVertexArray(r.vao)
gl.DrawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, gl.PtrOffset(0))
gl.BindVertexArray(0)
}
func (r *Rectangle) Destroy() {
gl.DeleteVertexArrays(1, &r.vao)
gl.DeleteBuffers(1, &r.vbo)
}
// Shader sources
var vertexShaderSource = `
#version 410 core
layout(location = 0) in vec3 position;
uniform mat4 model;
uniform mat4 projection;
void main() {
gl_Position = projection * model * vec4(position, 1.0);
}
` + "\x00"
var fragmentShaderSource = `
#version 410 core
out vec4 fragColor;
uniform vec4 color;
void main() {
fragColor = color;
}
` + "\x00"
// NewShaderProgram compiles and links the vertex and fragment shaders
func NewShaderProgram(vertexShaderSource, fragmentShaderSource string) uint32 {
vertexShader := gl.CreateShader(gl.VERTEX_SHADER)
cvertexShaderSource, freeVertex := gl.Strs(vertexShaderSource)
gl.ShaderSource(vertexShader, 1, cvertexShaderSource, nil)
freeVertex()
gl.CompileShader(vertexShader)
var status int32
gl.GetShaderiv(vertexShader, gl.COMPILE_STATUS, &status)
if status == gl.FALSE {
var logLength int32
gl.GetShaderiv(vertexShader, gl.INFO_LOG_LENGTH, &logLength)
log := strings.Repeat("\x00", int(logLength+1))
gl.GetShaderInfoLog(vertexShader, logLength, nil, gl.Str(log))
panic(fmt.Sprintf("failed to compile vertex shader: %v", log))
}
fragmentShader := gl.CreateShader(gl.FRAGMENT_SHADER)
cfragmentShaderSource, freeFragment := gl.Strs(fragmentShaderSource)
gl.ShaderSource(fragmentShader, 1, cfragmentShaderSource, nil)
freeFragment()
gl.CompileShader(fragmentShader)
gl.GetShaderiv(fragmentShader, gl.COMPILE_STATUS, &status)
if status == gl.FALSE {
var logLength int32
gl.GetShaderiv(fragmentShader, gl.INFO_LOG_LENGTH, &logLength)
log := strings.Repeat("\x00", int(logLength+1))
gl.GetShaderInfoLog(fragmentShader, logLength, nil, gl.Str(log))
panic(fmt.Sprintf("failed to compile fragment shader: %v", log))
}
program := gl.CreateProgram()
gl.AttachShader(program, vertexShader)
gl.AttachShader(program, fragmentShader)
gl.LinkProgram(program)
gl.GetProgramiv(program, gl.LINK_STATUS, &status)
if status == gl.FALSE {
var logLength int32
gl.GetProgramiv(program, gl.INFO_LOG_LENGTH, &logLength)
log := strings.Repeat("\x00", int(logLength+1))
gl.GetProgramInfoLog(program, logLength, nil, gl.Str(log))
panic(fmt.Sprintf("failed to link program: %v", log))
}
gl.DeleteShader(vertexShader)
gl.DeleteShader(fragmentShader)
return program
}
func main() {
window := NewWindow(800, 600, "Demo Window")
window.SetTransparent(true)
context := window.DefineContext()
panel := window.CreatePanel()
button := NewButton("Click me!", func() { fmt.Println("Button pressed!") }, context)
button.Position = Position{X: 100, Y: 100}
button.Size = Size{Width: 200, Height: 50}
panel.AddChild(button)
window.Start()
}