func (m *Manager) LoadFromPath(path string) *Data { setupTextureList() m.mutex.RLock() var data *Data var ok bool if data, ok = m.registry[path]; ok { m.mutex.RUnlock() m.mutex.Lock() data.accessed = generation m.mutex.Unlock() return data } m.mutex.RUnlock() m.mutex.Lock() if data, ok = m.deleted[path]; ok { delete(m.deleted, path) } else { data = &Data{} } data.accessed = generation m.registry[path] = data m.mutex.Unlock() f, err := os.Open(path) if err != nil { base.Error().Printf("Unable to open %s: %v", path, err) return data } config, _, err := image.DecodeConfig(f) f.Close() data.dx = config.Width data.dy = config.Height load_requests <- loadRequest{path, data} return data }
func handleLoadRequest(req loadRequest) { f, _ := os.Open(req.path) im, _, err := image.Decode(f) f.Close() if err != nil { base.Error().Printf("Unable to open %s: %v", req.path, err) 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 base.Log().Printf("Is Gray: %t", gray) 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) gl.GenTextures(1, (*gl.Uint)(&req.data.texture)) gl.BindTexture(gl.TEXTURE_2D, req.data.texture) gl.PixelStorei(gl.UNPACK_ALIGNMENT, 1) gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.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 { gl.TexImage2D( gl.TEXTURE_2D, 0, gl.ALPHA, gl.Sizei(req.data.dx), gl.Sizei(req.data.dy), 0, gl.ALPHA, gl.UNSIGNED_BYTE, gl.Pointer(&pix[0])) } else { gl.TexImage2D( gl.TEXTURE_2D, 0, gl.RGBA, gl.Sizei(req.data.dx), gl.Sizei(req.data.dy), 0, gl.RGBA, gl.UNSIGNED_BYTE, gl.Pointer(&pix[0])) // gl.TexImage2D(target, level, internalformat, width, height, border, format, type_, pixels) // 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() } }) }