在Golang中,绘制像素缓冲区到帧的跨平台方法是什么?

huangapple go评论91阅读模式
英文:

Cross-platform way to draw buffer of pixels to frame in Golang?

问题

假设我有一个内存中的位图/像素网格,并且我想将它们全部写入屏幕上的某个窗口中。例如:

[
 [255,0,0],[200,100,100]...
 [255,0,100],[155,200,100]...
 ...
]

有没有一种简单而高效的方法来实现这个?我可以使用OpenGL或Vulkan,但它们在这里似乎有点过度。如果还能够捕获鼠标/键盘输入,那就更好了,但如果这会复杂化问题,我可以自己处理这部分。我个人在Linux上工作,如果不能在Windows上使用,我也可以接受,但如果可以跨平台,那就更好了。

编辑:根据Ben Hoyt的评论,我想提供刷新的帧,可以将其想象为编写一个GIF播放器。给定一组这些帧,我希望按顺序显示它们,并且它们之间的显示间隔相对较低。

英文:

Say I have an in memory bitmap/grid of pixels and I want to write them all out to the screen in some sort of window. For example:

[
 [255,0,0],[200,100,100]...
 [255,0,100],[155,200,100]...
 ...
]

Is there a simple and performant way of doing this? I am happy to use OpenGL or Vulkan, but they seem a bit overkill here. Bonus points for anything that would still allow me to capture mouse/keyboard input, but I'm happy to manage that part on my own if it complicates things. I am personally working on Linux and am ok if it is not portable to Windows, but that would be nice.

Edit: Just an update on this as per Ben Hoyt's comments - my goal is to provide refreshing frames, imagine the use case as writing a GIF player. Given a set of these frames, I would like to display them sequentially and with a reasonably low display between them.

答案1

得分: 1

如果您的目标只是将图像加载到屏幕上,那么可以使用OpenGL和GLFW直接实现。您可以使用类似Fyne的库来完成这个任务,但它已经在内部使用了OpenGL和GLFW(以及许多其他依赖项),所以您可以直接省略中间环节。

以下是一个使用OpenGL纹理和帧缓冲将图像绘制到屏幕上的样板程序。

package main

import (
	"image"
	"runtime"

	"github.com/go-gl/gl/all-core/gl"
	"github.com/go-gl/glfw/v3.3/glfw"
)

func init() {
	// GLFW:这是为了确保main()函数在主线程上运行。
	// 请参阅只允许从主线程调用的函数的文档。
	runtime.LockOSThread()
}

func main() {
	err := glfw.Init()
	if err != nil {
		panic(err)
	}
	defer glfw.Terminate()

	window, err := glfw.CreateWindow(640, 480, "My Window", nil, nil)
	if err != nil {
		panic(err)
	}

	window.MakeContextCurrent()

	err = gl.Init()
	if err != nil {
		panic(err)
	}

	var texture uint32
	{
		gl.GenTextures(1, &texture)

		gl.BindTexture(gl.TEXTURE_2D, texture)
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)

		gl.BindImageTexture(0, texture, 0, false, 0, gl.WRITE_ONLY, gl.RGBA8)
	}

	var framebuffer uint32
	{
		gl.GenFramebuffers(1, &framebuffer)
		gl.BindFramebuffer(gl.FRAMEBUFFER, framebuffer)
		gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0)

		gl.BindFramebuffer(gl.READ_FRAMEBUFFER, framebuffer)
		gl.BindFramebuffer(gl.DRAW_FRAMEBUFFER, 0)
	}

	for !window.ShouldClose() {

		var w, h = window.GetSize()

		var img = image.NewRGBA(image.Rect(0, 0, w, h))

		// -------------------------
		// 在这里修改或加载图像
		// -------------------------

		gl.BindTexture(gl.TEXTURE_2D, texture)
		gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, int32(w), int32(h), 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(img.Pix))

		gl.BlitFramebuffer(0, 0, int32(w), int32(h), 0, 0, int32(w), int32(h), gl.COLOR_BUFFER_BIT, gl.LINEAR)

		window.SwapBuffers()
		glfw.PollEvents()
	}
}

希望对您有所帮助!

英文:

If your goal is only to load the image to the screen, here's a direct way to do it with OpenGL and GLFW. You can use a library like Fyne to do this, but it already uses OpenGL and GLFW internally (along with lots of other dependencies), so you might as well cut out the middle man.

Here's my boilerplate program that blits an image to the screen with an OpenGL texture and framebuffer.

package main

import (
	"image"
	"runtime"

	"github.com/go-gl/gl/all-core/gl"
	"github.com/go-gl/glfw/v3.3/glfw"
)

func init() {
	// GLFW: This is needed to arrange that main() runs on main thread.
	// See documentation for functions that are only allowed to be called from the main thread.
	runtime.LockOSThread()
}

func main() {
	err := glfw.Init()
	if err != nil {
		panic(err)
	}
	defer glfw.Terminate()

	window, err := glfw.CreateWindow(640, 480, "My Window", nil, nil)
	if err != nil {
		panic(err)
	}

	window.MakeContextCurrent()

	err = gl.Init()
	if err != nil {
		panic(err)
	}

	var texture uint32
	{
		gl.GenTextures(1, &texture)

		gl.BindTexture(gl.TEXTURE_2D, texture)
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)

		gl.BindImageTexture(0, texture, 0, false, 0, gl.WRITE_ONLY, gl.RGBA8)
	}

	var framebuffer uint32
	{
		gl.GenFramebuffers(1, &framebuffer)
		gl.BindFramebuffer(gl.FRAMEBUFFER, framebuffer)
		gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0)

		gl.BindFramebuffer(gl.READ_FRAMEBUFFER, framebuffer)
		gl.BindFramebuffer(gl.DRAW_FRAMEBUFFER, 0)
	}

	for !window.ShouldClose() {

		var w, h = window.GetSize()

		var img = image.NewRGBA(image.Rect(0, 0, w, h))

		// -------------------------
		// MODIFY OR LOAD IMAGE HERE
		// -------------------------

		gl.BindTexture(gl.TEXTURE_2D, texture)
		gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, int32(w), int32(h), 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(img.Pix))

		gl.BlitFramebuffer(0, 0, int32(w), int32(h), 0, 0, int32(w), int32(h), gl.COLOR_BUFFER_BIT, gl.LINEAR)

		window.SwapBuffers()
		glfw.PollEvents()
	}
}

答案2

得分: 0

我最终选择了Fyne来实现这个目标,以支持跨平台和快速刷新。如果有人知道一种本地的方法来将像素缓冲区放在屏幕上,请随时在这里评论,但这似乎相当轻量级并且在Go中本地工作。关于如何正确实现这一点的指南可以在这里看到:https://github.com/fyne-io/fyne/issues/3052

以60 FPS播放大量连续的光栅帧:
在Golang中,绘制像素缓冲区到帧的跨平台方法是什么?

英文:

I ended up using Fyne for this, to support the goal of going cross-platform and supporting fast refresh. If anyone knows of a native way to put a buffer of pixels on the screen, feel free to comment it here, but this seems pretty lightweight and natively works for Go. My GHI on how to do this correctly can be seen here: https://github.com/fyne-io/fyne/issues/3052

Playing a lot of sequential raster frames at 60 FPS:
在Golang中,绘制像素缓冲区到帧的跨平台方法是什么?

huangapple
  • 本文由 发表于 2022年6月9日 04:38:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/72551944.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定