func (s *sheet) compose(pixer chan<- []byte) { filename := filepath.Join(s.path, s.name) f, err := os.Open(filename) if err == nil { var length int32 err := binary.Read(f, binary.LittleEndian, &length) if err != nil { f.Close() } else { b := memory.GetBlock(int(length)) // b := make([]byte, length) _, err := f.Read(b) f.Close() if err == nil { pixer <- b return } } } rect := image.Rect(0, 0, s.dx, s.dy) canvas := &image.RGBA{memory.GetBlock(4 * s.dx * s.dy), 4 * s.dx, rect} for fid, rect := range s.rects { name := s.anim.Node(fid.node).Line(0) + ".png" file, err := os.Open(filepath.Join(s.path, fmt.Sprintf("%d", fid.facing), name)) // if a file isn't there that's ok if err != nil { continue } im, _, err := image.Decode(file) file.Close() // if a file can't be read that is *not* ok, TODO: Log an error or something if err != nil { continue } draw.Draw(canvas, image.Rect(rect.X, s.dy-rect.Y, rect.X2, s.dy-rect.Y2), im, image.Point{}, draw.Src) } f, err = os.Create(filename) if err == nil { binary.Write(f, binary.LittleEndian, int32(len(canvas.Pix))) _, err := f.Write(canvas.Pix) f.Close() if err != nil { os.Remove(filename) } } pixer <- canvas.Pix }
func NewGrayAlpha(r image.Rectangle) *GrayAlpha { var dx, dy int dx = r.Dx() if dx%2 == 1 { dx++ } dy = r.Dy() return &GrayAlpha{ Pix: memory.GetBlock(dx * dy * 2), Stride: dx * 2, Rect: r, } }
func handleLoadRequest(req loadRequest) { f, _ := os.Open(req.path) im, _, err := image.Decode(f) f.Close() if err != nil { return } gray := true dx := im.Bounds().Dx() dy := im.Bounds().Dy() for i := 0; i < dx; i++ { for j := 0; j < dy; j++ { r, g, b, _ := im.At(i, j).RGBA() if r != g || g != b { gray = false break } } if !gray { break } } var canvas draw.Image var pix []byte if gray { ga := NewGrayAlpha(im.Bounds()) pix = ga.Pix canvas = ga } else { pix = memory.GetBlock(4 * req.data.dx * req.data.dy) canvas = &image.RGBA{pix, 4 * req.data.dx, im.Bounds()} } draw.Draw(canvas, im.Bounds(), im, image.Point{}, draw.Src) load_mutex.Lock() load_count += len(pix) manual_unlock := false // This prevents us from trying to send too much to opengl in a single // frame. If we go over the threshold then we hold the lock until we're // done sending data to opengl, then other requests will be free to // queue up and they will run on the next frame. if load_count < load_threshold { load_mutex.Unlock() } else { manual_unlock = true } render.Queue(func() { { gl.Enable(gl.TEXTURE_2D) req.data.texture = gl.GenTexture() req.data.texture.Bind(gl.TEXTURE_2D) gl.TexEnvf(gl.TEXTURE_ENV, gl.TEXTURE_ENV_MODE, gl.MODULATE) gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR) gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT) gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT) } if gray { glu.Build2DMipmaps(gl.TEXTURE_2D, gl.LUMINANCE_ALPHA, req.data.dx, req.data.dy, gl.LUMINANCE_ALPHA, pix) } else { glu.Build2DMipmaps(gl.TEXTURE_2D, gl.RGBA, req.data.dx, req.data.dy, gl.RGBA, pix) } memory.FreeBlock(pix) if manual_unlock { load_count = 0 load_mutex.Unlock() } }) }