faiface / pixel

A hand-crafted 2D game library in Go
MIT License
4.46k stars 246 forks source link

NewCanvas requires NewWindow to be called first #257

Closed uberswe closed 4 years ago

uberswe commented 4 years ago

I know this might be an unusual use of pixel but I am trying to use pixel to make some basic videos as a hobby project. With this project I do not need a window and I would therefore like to only use a canvas to draw on. I would still like to use all of the methods available in pixel to generate the content for my video. Here is my full code which works:

package main

import (
    "bytes"
    "fmt"
    "github.com/faiface/pixel"
    "github.com/faiface/pixel/pixelgl"
    "github.com/faiface/pixel/text"
    "github.com/icza/mjpeg"
    "golang.org/x/image/colornames"
    "golang.org/x/image/font/basicfont"
    "image/jpeg"
)

var (
    resX = 720
    resY = 480
)

func run() {
    cfg := pixelgl.WindowConfig{
        Title:  "Window",
        Bounds: pixel.R(0, 0, float64(resX), float64(resY)),
    }
    _, err := pixelgl.NewWindow(cfg)
    if err != nil {
        panic(err)
    }
    canvas := pixelgl.NewCanvas(pixel.R(0, 0, float64(resX), float64(resY)))

    basicAtlas := text.NewAtlas(basicfont.Face7x13, text.ASCII)
    basicTxt := text.New(pixel.V(50, float64(resY-50)), basicAtlas)

    basicTxt.LineHeight = basicAtlas.LineHeight() * 1.5

    fmt.Fprintln(basicTxt, "This is an example text")
    fmt.Fprintln(basicTxt, "This text supports multiple lines")

    var (
        i           = 1
        totalFrames = 600
    )

    aw, err := mjpeg.New("test.avi", int32(resX), int32(resY), 60)
    if err != nil {
        panic(err)
    }

    fmt.Printf("Generating frames\n")
    for i <= totalFrames {

        canvas.Clear(colornames.Black)

        fmt.Fprintf(basicTxt, "%d ", i)
        if i%30 == 0 && i > 1 {
            fmt.Fprint(basicTxt, "\n")
        }
        basicTxt.Draw(canvas, pixel.IM.Scaled(basicTxt.Orig, 1))

        img := pixel.PictureDataFromPicture(canvas)
        buf := &bytes.Buffer{}
        err = jpeg.Encode(buf, img.Image(), nil)
        if err != nil {
            panic(err)
        }
        err = aw.AddFrame(buf.Bytes())
        if err != nil {
            panic(err)
        }

        i++
    }
    fmt.Printf("Saving video\n")
    err = aw.Close()
    if err != nil {
        panic(err)
    }
}

func main() {
    pixelgl.Run(run)
}

However if I remove the first lines in the run function, specifically these lines

cfg := pixelgl.WindowConfig{
        Title:  "Window",
        Bounds: pixel.R(0, 0, float64(resX), float64(resY)),
    }
    _, err := pixelgl.NewWindow(cfg)

Then I get the following error:

fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x0]

runtime stack:
runtime.throw(0x414e282, 0x2a)
        /usr/local/Cellar/go/1.14.2_1/libexec/src/runtime/panic.go:1116 +0x72
runtime.sigpanic()
        /usr/local/Cellar/go/1.14.2_1/libexec/src/runtime/signal_unix.go:679 +0x46a
runtime.asmcgocall(0x7ffeefbff728, 0x405ca83)
        /usr/local/Cellar/go/1.14.2_1/libexec/src/runtime/asm_amd64.s:659 +0x70

goroutine 1 [syscall, locked to thread]:
runtime.cgocall(0x40f3f50, 0xc00005dd08, 0x425bc01)
        /usr/local/Cellar/go/1.14.2_1/libexec/src/runtime/cgocall.go:133 +0x5b fp=0xc00005dcd8 sp=0xc00005dca0 pc=0x40058db
github.com/go-gl/gl/v3.3-core/gl._Cfunc_glowGenTextures(0x0, 0xc000000001, 0xc00008e060)
        _cgo_gotypes.go:7583 +0x45 fp=0xc00005dd08 sp=0xc00005dcd8 pc=0x40b8025
github.com/go-gl/gl/v3.3-core/gl.GenTextures(...)
        /Users/uberswe/go/pkg/mod/github.com/go-gl/gl@v0.0.0-20190320180904-bf2b1f2f34d7/v3.3-core/gl/package.go:9607
github.com/faiface/glhf.NewTexture(0x2d0, 0x1e0, 0x151800, 0xc0001ac000, 0x151800, 0x151800, 0x0)
        /Users/uberswe/go/pkg/mod/github.com/faiface/glhf@v0.0.0-20181018222622-82a6317ac380/texture.go:32 +0x98 fp=0xc00005dd60 sp=0xc00005dd08 pc=0x40c2fc8
github.com/faiface/glhf.NewFrame(0x2d0, 0x1e0, 0x0, 0x0)
        /Users/uberswe/go/pkg/mod/github.com/faiface/glhf@v0.0.0-20181018222622-82a6317ac380/frame.go:37 +0x82 fp=0xc00005ddc0 sp=0xc00005dd60 pc=0x40c0f02
github.com/faiface/pixel/pixelgl.(*GLFrame).SetBounds.func1()
        /Users/uberswe/go/pkg/mod/github.com/faiface/pixel@v0.10.0-beta.0.20200524070125-585f7c1f14eb/pixelgl/glframe.go:41 +0xfd fp=0xc00005de50 sp=0xc00005ddc0 pc=0x40cd4ed
github.com/faiface/mainthread.Call.func1()
        /Users/uberswe/go/pkg/mod/github.com/faiface/mainthread@v0.0.0-20171120011319-8b78f0a41ae3/mainthread.go:63 +0x2f fp=0xc00005de80 sp=0xc00005de50 pc=0x40b5def
github.com/faiface/mainthread.Run(0x41503d0)
        /Users/uberswe/go/pkg/mod/github.com/faiface/mainthread@v0.0.0-20171120011319-8b78f0a41ae3/mainthread.go:44 +0xbd fp=0xc00005df20 sp=0xc00005de80 pc=0x40b5b6d
github.com/faiface/pixel/pixelgl.Run(0x41503d0)
        /Users/uberswe/go/pkg/mod/github.com/faiface/pixel@v0.10.0-beta.0.20200524070125-585f7c1f14eb/pixelgl/run.go:32 +0x64 fp=0xc00005df70 sp=0xc00005df20 pc=0x40ccd94
main.main()
        /Users/uberswe/Dropbox (Personal)/go/src/github.com/markustenghamn/hls/main.go:73 +0x2d fp=0xc00005df88 sp=0xc00005df70 pc=0x40dd26d
runtime.main()
        /usr/local/Cellar/go/1.14.2_1/libexec/src/runtime/proc.go:203 +0x212 fp=0xc00005dfe0 sp=0xc00005df88 pc=0x4034992
runtime.goexit()
        /usr/local/Cellar/go/1.14.2_1/libexec/src/runtime/asm_amd64.s:1373 +0x1 fp=0xc00005dfe8 sp=0xc00005dfe0 pc=0x4060751

goroutine 6 [chan receive]:
github.com/faiface/mainthread.Call(0xc000090000)
        /Users/uberswe/go/pkg/mod/github.com/faiface/mainthread@v0.0.0-20171120011319-8b78f0a41ae3/mainthread.go:66 +0xc2
github.com/faiface/pixel/pixelgl.(*GLFrame).SetBounds(0xc00008e000, 0x0, 0x0, 0x4086800000000000, 0x407e000000000000)
        /Users/uberswe/go/pkg/mod/github.com/faiface/pixel@v0.10.0-beta.0.20200524070125-585f7c1f14eb/pixelgl/glframe.go:31 +0xe0
github.com/faiface/pixel/pixelgl.NewGLFrame(...)
        /Users/uberswe/go/pkg/mod/github.com/faiface/pixel@v0.10.0-beta.0.20200524070125-585f7c1f14eb/pixelgl/glframe.go:21
github.com/faiface/pixel/pixelgl.NewCanvas(0x0, 0x0, 0x4086800000000000, 0x407e000000000000, 0x0)
        /Users/uberswe/go/pkg/mod/github.com/faiface/pixel@v0.10.0-beta.0.20200524070125-585f7c1f14eb/pixelgl/canvas.go:35 +0x7a
main.run()
        /Users/uberswe/Dropbox (Personal)/go/src/github.com/markustenghamn/hls/main.go:21 +0x6f
github.com/faiface/mainthread.Run.func1(0x41503d0, 0xc00001c0c0)
        /Users/uberswe/go/pkg/mod/github.com/faiface/mainthread@v0.0.0-20171120011319-8b78f0a41ae3/mainthread.go:37 +0x27
created by github.com/faiface/mainthread.Run
        /Users/uberswe/go/pkg/mod/github.com/faiface/mainthread@v0.0.0-20171120011319-8b78f0a41ae3/mainthread.go:36 +0xb1
exit status 2

I was wondering if this might be a bug or if it is expected? If it is expected I would appreciate some hints as to what I might be doing wrong as I can not find anything about this in other issues or in the documentation.

dusk125 commented 4 years ago

So it looks like pixel is trying to create a glhf texture, which is in turn trying to create a GL texture, but because you don't have a window, OpenGL hasn't been initialized which I believe is causing the error you're seeing.

You could try creating the window with the 'Invisible' config option; though I'm not sure if that'll keep the update loop going (some will pause the input polling and drawing when the window is hidden, don't know about pixel).

If that doesn't work, you could try making a TransparentFramebuffer and Undecorated window; I think that'll result in a completely invisible (but still active) window.

uberswe commented 4 years ago

Thanka @dusk125 the invisible flag worked like this

cfg := pixelgl.WindowConfig{
        Title:  "Window",
        Bounds: pixel.R(0, 0, float64(resX), float64(resY)),
        Invisible: true,
    }