之前使用的是SDL,仅支持2D的,从这里开始换成GLFW以支持后续的3D操作,删除之前的所有内容,新建g3d文件夹,如下图:

main.go:

package main

import (
	engine "g3d/engine/game"
	"runtime"
)

func init() {
	runtime.LockOSThread()
}

func main() {
	var game engine.Game
	if game.Initialize() {
		game.RunLoop()
	}
	game.Shutdown()
}

 game.go:

package engine

import (
	"fmt"
	"image"
	"os"

	"github.com/go-gl/gl/v3.3-core/gl"
	"github.com/go-gl/glfw/v3.3/glfw"
	"github.com/mat/besticon/ico"
)

var mIsRunning = false
var mIsFullScreen = false
var mWidth = 1024
var mHeight = 768

type Game struct {
	MWindow *glfw.Window
}

//初始化引擎
func (g *Game) Initialize() bool {
	//获取glfw版本
	fmt.Println(glfw.GetVersionString())
	//初始化glfw
	var err error
	if err = glfw.Init(); err != nil {
		fmt.Printf("Unable to initialize glfw: %v", err)
		return false
	}

	glfw.WindowHint(glfw.RedBits, 8)
	glfw.WindowHint(glfw.GreenBits, 8)
	glfw.WindowHint(glfw.BlueBits, 8)
	glfw.WindowHint(glfw.AlphaBits, 8)
	glfw.WindowHint(glfw.DepthBits, 24)
	glfw.WindowHint(glfw.DoubleBuffer, 1)
	//设置版本
	glfw.WindowHint(glfw.ContextVersionMajor, 3)
	glfw.WindowHint(glfw.ContextVersionMinor, 3)
	glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
	//窗口模式
	if g.MWindow, err = glfw.CreateWindow(mWidth, mHeight, "go glfw", nil, nil); err != nil {
		fmt.Printf("Failed to create window: %v", err)
		return false
	}
	//设置图标
	if ok, _ := PathExists("./app.ico"); ok {
		if f, err := os.Open("./app.ico"); err == nil {
			defer f.Close()
			if img, err := ico.Decode(f); err == nil {
				g.MWindow.SetIcon([]image.Image{img})
			}
		}
	}
	//回调函数
	g.MWindow.SetCloseCallback(CloseCallback)             //关闭回调
	g.MWindow.SetSizeCallback(SizeCallback)               //调整回调
	g.MWindow.SetKeyCallback(KeyCallback)                 //按键回调
	g.MWindow.SetMouseButtonCallback(MouseButtonCallback) //鼠标按键
	g.MWindow.SetCursorPosCallback(CursorPosCallback)     //鼠标位置
	g.MWindow.SetCursorEnterCallback(CursorEnterCallback) //鼠标进入
	g.MWindow.SetScrollCallback(ScrollCallback)           //鼠标滚动
	//上下文
	g.MWindow.MakeContextCurrent()

	//初始化opengl
	if err = gl.Init(); err != nil {
		fmt.Printf("Unable to initialize gl: %v", err)
		return false
	}
	version := gl.GoStr(gl.GetString(gl.VERSION))
	fmt.Println(version)

	//保持运行
	mIsRunning = true
	return true
}

//引擎循环
func (g *Game) RunLoop() {
	for mIsRunning {
		//清屏
		gl.ClearColor(0.86, 0.86, 0.86, 1.0)
		gl.Clear(gl.COLOR_BUFFER_BIT)
		//....
		g.ProcessInput()
		g.UpdateGame()
		g.GenerateOutput()
		//交换缓存
		g.MWindow.SwapBuffers()
		glfw.PollEvents()
	}
}

//引擎销毁
func (g *Game) Shutdown() {
	g.MWindow.Destroy()
	glfw.Terminate()
}

func (g *Game) ProcessInput() {

}

func (g *Game) UpdateGame() {

}

func (g *Game) GenerateOutput() {

}

func CloseCallback(w *glfw.Window) {
	mIsRunning = false
}

func SizeCallback(w *glfw.Window, width int, height int) {
	fmt.Println(width, height)
}

func KeyCallback(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
	switch key {
	case glfw.KeyEscape:
		if action == glfw.Press {
			CloseCallback(w)
		}
	case glfw.KeyF11:
		if action == glfw.Press {
			mIsFullScreen = !mIsFullScreen
			if mIsFullScreen {
				w.SetMonitor(glfw.GetPrimaryMonitor(),
					0,
					0,
					glfw.GetPrimaryMonitor().GetVideoMode().Width,
					glfw.GetPrimaryMonitor().GetVideoMode().Height,
					60)
			} else {
				posX := (glfw.GetPrimaryMonitor().GetVideoMode().Width - mWidth) / 2
				posY := (glfw.GetPrimaryMonitor().GetVideoMode().Height - mHeight) / 2
				w.SetMonitor(nil, posX, posY, mWidth, mHeight, 60)
			}
		}
	}
}

func MouseButtonCallback(w *glfw.Window, button glfw.MouseButton, action glfw.Action, mods glfw.ModifierKey) {
	fmt.Println(button, action)
}

func CursorPosCallback(w *glfw.Window, xpos float64, ypos float64) {
	fmt.Println(xpos, ypos)
}

func CursorEnterCallback(w *glfw.Window, entered bool) {
	fmt.Println(entered)
}

func ScrollCallback(w *glfw.Window, xoff float64, yoff float64) {
	fmt.Println(xoff, yoff)
}

func PathExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}