// loadFont loads the given font data. This does not deal with font scaling. // Scaling should be handled by the independent Bitmap/Truetype loaders. // We therefore expect the supplied image and charset to already be adjusted // to the correct font scale. // // The image should hold a sprite sheet, defining the graphical layout for // every glyph. The config describes font metadata. func loadFont(img *image.RGBA, config *FontConfig) (f *Font, err error) { f = new(Font) f.Config = config // Resize image to next power-of-two. img = glh.Pow2Image(img).(*image.RGBA) ib := img.Bounds() f.Width = ib.Dx() f.Height = ib.Dy() // Create the texture itself. It will contain all glyphs. // Individual glyph-quads display a subset of this texture. f.Texture = gl.GenTexture() f.Texture.Bind(gl.TEXTURE_2D) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, ib.Dx(), ib.Dy(), 0, gl.RGBA, gl.UNSIGNED_BYTE, img.Pix) // file, err := os.Create("font.png") // if err != nil { // log.Fatal(err) // } // err = png.Encode(file, img) // if err != nil { // log.Fatal(err) // } return }
func (v *Video) Init(w int, h int) { var err error if err = glfw.Init(); err != nil { log.Fatal(err) } glfw.OpenWindowHint(glfw.WindowNoResize, gl.TRUE) if err = glfw.OpenWindow(w, h, 8, 8, 8, 0, 24, 0, glfw.Windowed); err != nil { log.Fatal(err) } if gl.Init() != 0 { log.Fatal("ummm... hmmm") } glfw.SetWindowSizeCallback(resize) gl.Enable(gl.TEXTURE_2D) resize(w, h) v.Texture = gl.GenTexture() }
// Creates a new Framebuffer. func NewFramebuffer(w int, h int) (fb *Framebuffer, err error) { var ( buffer gl.Framebuffer texture gl.Texture ) buffer = gl.GenFramebuffer() buffer.Bind() texture = gl.GenTexture() texture.Bind(gl.TEXTURE_2D) gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, w, h, 0, gl.RGBA, gl.UNSIGNED_BYTE, nil) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) gl.FramebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0) gl.DrawBuffer(gl.COLOR_ATTACHMENT0) if gl.CheckFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE { err = fmt.Errorf("Framebuffer could not be set up") return } fb = &Framebuffer{ Buffer: buffer, Texture: texture, Width: w, Height: h, } return }
func createTexture(r io.Reader) (gl.Texture, error) { img, err := png.Decode(r) if err != nil { return gl.Texture(0), err } rgbaImg, ok := img.(*image.NRGBA) if !ok { return gl.Texture(0), errors.New("texture must be an NRGBA image") } textureId := gl.GenTexture() textureId.Bind(gl.TEXTURE_2D) gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) // flip image: first pixel is lower left corner imgWidth, imgHeight := img.Bounds().Dx(), img.Bounds().Dy() data := make([]byte, imgWidth*imgHeight*4) lineLen := imgWidth * 4 dest := len(data) - lineLen for src := 0; src < len(rgbaImg.Pix); src += rgbaImg.Stride { copy(data[dest:dest+lineLen], rgbaImg.Pix[src:src+rgbaImg.Stride]) dest -= lineLen } gl.TexImage2D(gl.TEXTURE_2D, 0, 4, imgWidth, imgHeight, 0, gl.RGBA, gl.UNSIGNED_BYTE, data) return textureId, nil }
func imageAlpha(pix []byte, width, height int) (*Sampler2D, error) { s := &Sampler2D{ tex: gl.GenTexture(), } s.bind() gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) gl.TexImage2D(gl.TEXTURE_2D, 0, gl.R8, width, height, 0, gl.RED, gl.UNSIGNED_BYTE, pix) return s, nil }
// Create a new texture, initialize it to have a `gl.LINEAR` filter and use // `gl.CLAMP_TO_EDGE`. func NewTexture(w, h int) *Texture { texture := &Texture{gl.GenTexture(), w, h} With(texture, func() { gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) 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_WRAP_R, gl.CLAMP_TO_EDGE) }) return texture }
func (rm *ResourceManager) loadTile(name string) (*Bitmap, bool) { fname, _ := filepath.Abs(path.Join("resources", name)) var tex gl.Texture allegro.RunInThread(func() { tex = gl.GenTexture() tex.Bind(gl.TEXTURE_2D) glfw.LoadTexture2D(fname, 0) }) bmp := Bitmap{tex, 0, 0, DEFAULT_TILE_WIDTH, DEFAULT_TILE_HEIGHT} rm.tileBmps[name] = bmp return &bmp, true }
func getGLTexture(img image.Image, smoothing int) (gltexture gl.Texture, err error) { var data *bytes.Buffer if data, err = encodeTGA("texture", img); err != nil { return } gltexture = gl.GenTexture() gltexture.Bind(gl.TEXTURE_2D) if !glfw.LoadMemoryTexture2D(data.Bytes(), 0) { err = fmt.Errorf("Failed to load texture") return } gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, smoothing) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, smoothing) return }
func MakeTextureFromTGA(fname string) gl.Texture { tex := gl.GenTexture() tex.Bind(gl.TEXTURE_2D) glfw.LoadTexture2D(fname, 0) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR) gl.GenerateMipmap(gl.TEXTURE_2D) // glh.OpenGLSentinel() // check for errors return tex }
func (self *OpenGLRenderer) LoadTexture(texture *render.Texture) gl.Texture { glTexture := gl.GenTexture() glTexture.Bind(gl.TEXTURE_2D) defer glTexture.Unbind(gl.TEXTURE_2D) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR) self.glTexImage2D(gl.TEXTURE_2D, texture) gl.GenerateMipmap(gl.TEXTURE_2D) return glTexture }
func initTexture2(filename string) gl.Texture { img, err := glfw.ReadImage(filename+".tga", glfw.NoRescaleBit) if err != nil { panic(err) } rt := gl.GenTexture() gl.Enable(gl.TEXTURE_2D) rt.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.NEAREST) gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) // gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT) // gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT) gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, img.Width(), img.Height(), 0, gl.RGBA, gl.UNSIGNED_BYTE, img.Data()) fmt.Println(filename, img.Width(), img.Height()) return rt }
func (v *Video) Init(t <-chan []uint32, ft chan bool, n string) chan [2]int { v.tick = t v.frametick = ft v.resize = make(chan [2]int) if sdl.Init(sdl.INIT_VIDEO|sdl.INIT_JOYSTICK|sdl.INIT_AUDIO) != 0 { log.Fatal(sdl.GetError()) } v.screen = sdl.SetVideoMode(512, 480, 32, sdl.OPENGL|sdl.RESIZABLE) if v.screen == nil { log.Fatal(sdl.GetError()) } sdl.WM_SetCaption(fmt.Sprintf("Fergulator - %s", n), "") if gl.Init() != 0 { panic(sdl.GetError()) } gl.Enable(gl.TEXTURE_2D) v.Reshape(int(v.screen.W), int(v.screen.H)) v.tex = gl.GenTexture() joy = make([]*sdl.Joystick, sdl.NumJoysticks()) for i := 0; i < sdl.NumJoysticks(); i++ { joy[i] = sdl.JoystickOpen(i) fmt.Println("-----------------") if joy[i] != nil { fmt.Printf("Joystick %d\n", i) fmt.Println(" Name: ", sdl.JoystickName(0)) fmt.Println(" Number of Axes: ", joy[i].NumAxes()) fmt.Println(" Number of Buttons: ", joy[i].NumButtons()) fmt.Println(" Number of Balls: ", joy[i].NumBalls()) } else { fmt.Println(" Couldn't open Joystick!") } } return v.resize }
func uploadTexture_RGBA32(w, h int, data []byte) gl.Texture { id := gl.GenTexture() id.Bind(gl.TEXTURE_2D) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) 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_WRAP_R, gl.CLAMP_TO_EDGE) gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int(w), int(h), 0, gl.RGBA, gl.UNSIGNED_BYTE, data) if gl.GetError() != gl.NO_ERROR { id.Delete() panic("Failed to load a texture") return 0 } return id }
func CreateTexture(img image.Image) (*Texture, error) { imgW, imgH := img.Bounds().Dx(), img.Bounds().Dy() imgDim := Vector2{float32(imgW), float32(imgH)} rgbaImg, ok := img.(*image.NRGBA) if !ok { return nil, errors.New("texture must be an NRGBA image") } textureId := gl.GenTexture() textureId.Bind(gl.TEXTURE_2D) gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) gl.TexImage2D(gl.TEXTURE_2D, 0, 4, imgW, imgH, 0, gl.RGBA, gl.UNSIGNED_BYTE, rgbaImg.Pix) return &Texture{textureId, imgDim, false, false, false, nextTextureCacheId()}, nil }
func NewTextureEmpty(width int, height int, model color.Model) *Texture { internalFormat, typ, format, target, e := ColorModelToGLTypes(model) if e != nil { return nil } a := gl.GenTexture() a.Bind(target) gl.TexImage2D(target, 0, internalFormat, width, height, 0, typ, format, nil) t := &Texture{a, false, nil, format, typ, internalFormat, target, width, height} t.SetWraping(WrapS, ClampToEdge) t.SetWraping(WrapT, ClampToEdge) t.SetFiltering(Nearest, Nearest) ResourceManager.Add(t) return t }
// NewAtlas creates a new texture atlas. // // The given width, height and depth determine the size and depth of // the underlying texture. // // depth should be 1, 3 or 4 and it will specify if the texture is // created with Alpha, RGB or RGBA channels. // The image data supplied through Atlas.Set() should be of the same format. func NewTextureAtlas(width, height, depth int) *TextureAtlas { switch depth { case 1, 3, 4: default: panic("Invalid depth value") } a := new(TextureAtlas) a.width = width a.height = height a.depth = depth a.used = 0 a.data = make([]byte, width*height*depth) // We want a one pixel border around the whole atlas to avoid // any artefacts when sampling our texture. a.nodes = append(a.nodes, atlasNode{1, 1, width - 2}) a.texture = gl.GenTexture() return a }
func initTexture(filename string, width, height int) gl.Texture { file, err := os.Open(filename + ".png") if err != nil { panic(err) } defer file.Close() img, _, err := image.Decode(file) if err != nil { panic(err) } t := reflect.ValueOf(img) fmt.Println(t.Elem().Type().Name()) canvas := image.NewRGBA(image.Rect(0, 0, width, height)) for y := 0; y < height; y++ { for x := 0; x < width; x++ { r, g, b, a := img.At(x, y).RGBA() if (filename == "hex4v" || filename == "hexstar2" || filename == "hexborder") && r == 0 && g == 0 && b == 0 { a = 0 } // if filename == "hex5k" { // fmt.Println(r, g, b, a) // } base := 4*x + canvas.Stride*y canvas.Pix[base] = uint8(r) canvas.Pix[base+1] = uint8(g) canvas.Pix[base+2] = uint8(b) canvas.Pix[base+3] = uint8(a) } } rt := gl.GenTexture() gl.Enable(gl.TEXTURE_2D) rt.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.NEAREST) gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) // gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT) // gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT) gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, canvas.Pix) return rt }
func (self *OpenGLRenderer) loadCubeMap(material *render.Material) gl.Texture { glTexture := gl.GenTexture() glTexture.Bind(gl.TEXTURE_CUBE_MAP) defer glTexture.Unbind(gl.TEXTURE_CUBE_MAP) gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.NEAREST) gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST) gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE) gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE) self.glTexImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X, material.CubeMap[render.CubeFace_Right]) self.glTexImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_X, material.CubeMap[render.CubeFace_Left]) self.glTexImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Y, material.CubeMap[render.CubeFace_Top]) self.glTexImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, material.CubeMap[render.CubeFace_Bottom]) self.glTexImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_Z, material.CubeMap[render.CubeFace_Front]) self.glTexImage2D(gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, material.CubeMap[render.CubeFace_Back]) return glTexture }
// Packs image into a texture of size * size dimensions func (i *ImagePacker) pack(size int) (SpriteSheet, error) { rootNode := newNode(size, size) for v, img := range i.images { err := rootNode.recInsert(img.w, img.h, v) if err != nil { return SpriteSheet{}, err } } nodeImage := image.NewRGBA(image.Rect(0, 0, size, size)) traverseNodes(rootNode, func(nd node) { draw.Draw(nodeImage, image.Rect(nd.rc.left, nd.rc.top, nd.rc.right, nd.rc.bottom), i.images[nd.id].image, image.ZP, draw.Src) i.sprites[nd.id].left = float32(nd.rc.left) / float32(size) i.sprites[nd.id].top = float32(nd.rc.bottom) / float32(size) i.sprites[nd.id].right = float32(nd.rc.right) / float32(size) i.sprites[nd.id].bottom = float32(nd.rc.top) / float32(size) i.sprites[nd.id].W = float32(nd.rc.right - nd.rc.left) i.sprites[nd.id].H = float32(nd.rc.bottom - nd.rc.top) }) texture := gl.GenTexture() texture.Bind(gl.TEXTURE_2D) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) 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.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, nodeImage.Pix) texture.Unbind(gl.TEXTURE_2D) spriteSheet := NewSpriteSheet(texture, size, size) return spriteSheet, nil }
// bind the given atlas to the current GL context // // the current implementation is very stupid, since it will // upload the texture every single call. // // later, improve this to upload only if there is a real need for it func (a *Atlas) bind() error { // discard any possible error if err := checkGlError(); err != nil { return err } if gl.Object(a.gltex).IsTexture() { a.gltex = gl.GenTexture() } a.gltex.Bind(gl.TEXTURE_2D) gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, a.data.Bounds().Dx(), a.data.Bounds().Dy(), 0, gl.RGBA, gl.UNSIGNED_BYTE, a.data.Pix) if err := checkGlError(gl.OUT_OF_MEMORY, gl.INVALID_OPERATION); err != nil { return err } gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR) gl.GenerateMipmap(gl.TEXTURE_2D) panicGlError() return nil }
func (video *SDLVideo) initGL() { if gl.Init() != 0 { panic(sdl.GetError()) } gl.ClearColor(0.0, 0.0, 0.0, 1.0) gl.Enable(gl.CULL_FACE) gl.Enable(gl.DEPTH_TEST) video.prog = createProgram(vertShaderSrcDef, fragShaderSrcDef) posAttrib := video.prog.GetAttribLocation("vPosition") texCoordAttr := video.prog.GetAttribLocation("vTexCoord") video.textureUni = video.prog.GetAttribLocation("texture") video.texture = gl.GenTexture() gl.ActiveTexture(gl.TEXTURE0) video.texture.Bind(gl.TEXTURE_2D) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) video.prog.Use() posAttrib.EnableArray() texCoordAttr.EnableArray() vertVBO := gl.GenBuffer() vertVBO.Bind(gl.ARRAY_BUFFER) verts := []float32{-1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0} gl.BufferData(gl.ARRAY_BUFFER, len(verts)*int(unsafe.Sizeof(verts[0])), &verts[0], gl.STATIC_DRAW) textCoorBuf := gl.GenBuffer() textCoorBuf.Bind(gl.ARRAY_BUFFER) texVerts := []float32{0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0} gl.BufferData(gl.ARRAY_BUFFER, len(texVerts)*int(unsafe.Sizeof(texVerts[0])), &texVerts[0], gl.STATIC_DRAW) posAttrib.AttribPointer(2, gl.FLOAT, false, 0, uintptr(0)) texCoordAttr.AttribPointer(2, gl.FLOAT, false, 0, uintptr(0)) }
func LoadTexture(filename string) gl.Texture { r, err := os.Open(filename) if err != nil { fmt.Fprintf(os.Stderr, "[e] %v\n", err) return 0 } defer r.Close() img, _, err := image.Decode(r) if err != nil { fmt.Fprintf(os.Stderr, "[e] %v\n", err) return 0 } // lazy way to ensure we have the correct image format for opengl rgbaImg := image.NewNRGBA(img.Bounds()) draw.Draw(rgbaImg, img.Bounds(), img, image.ZP, draw.Src) tex := gl.GenTexture() tex.Bind(gl.TEXTURE_2D) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) 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) // flip image: first pixel is lower left corner w, h := img.Bounds().Dx(), img.Bounds().Dy() data := make([]byte, w*h*4) lineLen := w * 4 dest := len(data) - lineLen for src := 0; src < len(rgbaImg.Pix); src += rgbaImg.Stride { copy(data[dest:dest+lineLen], rgbaImg.Pix[src:src+rgbaImg.Stride]) dest -= lineLen } gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, w, h, 0, gl.RGBA, gl.UNSIGNED_BYTE, data) return tex }
func NewTexture2(data interface{}, width int, height int, target gl.GLenum, internalFormat int, typ gl.GLenum, format gl.GLenum) *Texture { a := gl.GenTexture() a.Bind(target) gl.TexImage2D(target, 0, internalFormat, width, height, 0, typ, format, data) t := &Texture{a, false, data, format, typ, internalFormat, target, width, height} t.SetWraping(WrapS, ClampToEdge) t.SetWraping(WrapT, ClampToEdge) t.SetFiltering(Nearest, Nearest) //ansi := []float32{0} //gl.GetFloatv(gl.MAX_TEXTURE_MAX_ANISOTROPY_EXT, ansi) //gl.TexParameterf(target, gl.TEXTURE_MAX_ANISOTROPY_EXT, ansi[0]) t.PreloadRender() //Forcing texture to go to VRAM and prevent shuttering t.data = nil data = nil ResourceManager.Add(t) return t }
func main() { b, _ := ioutil.ReadFile("./roboto/roboto-light.ttf") font, ferr := tt.Parse(b) if ferr != nil { fmt.Println("can't parse font %v , len %v", ferr.Error(), len(b)) } fc := ft.NewContext() fc.SetFont(font) glfw.SetErrorCallback(errorCallback) if !glfw.Init() { panic("Can't init glfw!") } defer glfw.Terminate() window, err := glfw.CreateWindow(800, 600, "Testing", nil, nil) if err != nil { panic(err) } window.MakeContextCurrent() gl.Init() program := gl.CreateProgram() vertexShader := gl.CreateShader(gl.VERTEX_SHADER) vertexShader.Source(` attribute vec4 a_position; attribute vec2 a_coord; varying vec2 v_coord; void main() { gl_Position = a_position; v_coord = a_coord; } `) vertexShader.Compile() fmt.Printf("vertex: %v\n", vertexShader.GetInfoLog()) fragmentShader := gl.CreateShader(gl.FRAGMENT_SHADER) fragmentShader.Source(` varying vec2 v_coord; uniform sampler2D s_picture; uniform vec4 color; uniform bool has_picture; void main() { if(has_picture) { gl_FragColor = texture2D(s_picture, v_coord); } else { gl_FragColor = color; } } `) fragmentShader.Compile() fmt.Printf("fragment %v \n", fragmentShader.GetInfoLog()) program.AttachShader(vertexShader) program.AttachShader(fragmentShader) program.Link() // ini //gl.MatrixMode(gl.PROJECTION) //gl.Ortho(0, 640, 0, 480, 0, 1) gl.ClearColor(0.5, 0.5, 0.5, 0.0) root := widget.Widget{ Name: "Red", Rect: image.Rect(0, 0, 800, 600), Background: color.RGBA{255, 128, 128, 126}, OnClick: widget.ClickInner, OnDrag: widget.DragInner, OnHover: widget.HoverInner, OnResize: widget.ResizeItself, } blue := root.AddWidget(&widget.Widget{ Name: "Blue", Rect: image.Rect(100, 100, 200, 200), Image: LoadImage("./test.png"), Background: color.RGBA{128, 128, 255, 126}, OnClick: func(w *widget.Widget, p image.Point) { root.SetTop(w) fmt.Println("Clicked blue box") widget.ClickInner(w, p) }, OnDrag: func(w *widget.Widget, p image.Point, d image.Point) bool { widget.DragInner(w, p, d) widget.DragItself(w, p, d) return true }, OnResize: widget.ResizeItself, }) blue.AddWidget(&widget.Widget{ Name: "White", Rect: image.Rect(90, 90, 100, 100), Background: color.RGBA{250, 250, 250, 250}, OnDrag: func(w *widget.Widget, p image.Point, d image.Point) bool { widget.DragItself(w, p, d) blue.Resize(d) return true }, }) root.AddWidget(&widget.Widget{ Name: "Green", Rect: image.Rect(100, 300, 200, 400), Background: color.RGBA{128, 255, 128, 126}, OnClick: func(w *widget.Widget, p image.Point) { root.SetTop(w) w.Image = LoadImage("./test2.png") }, OnDrag: widget.DragItself, }) root.AddWidget(&widget.Widget{ Name: "Black", Rect: image.Rect(100, 400, 150, 450), Background: color.RGBA{0, 0, 0, 126}, OnHover: func(w *widget.Widget, p0 image.Point, p1 image.Point) { if p1.In(w.Rect) { w.Background = color.RGBA{255, 255, 255, 126} } else { w.Background = color.RGBA{0, 0, 0, 126} } }, }) white := root.AddWidget(&widget.Widget{ Name: "White", Text: "Меня зовут Светлана, я из города Иваново. «Единая Россия» очень много сделала достижений: они подняли экономик… экономику, мы стали более лучшие… одеваться, и не было того что щас — это очень большие достижения! В сельском хозяйстве очень хорошо. (Гладин: Что именно в сельском хозяйстве они сделали?) Стало больше… земель за-а… много, ну… я не знаю даже как сказать… засеивать больше земель… а-а-а вот, овощи там, рожь — вот это всё. Что еще сказать… Так как у нас страна многонациональная, у нас в Москве очень много людей, которые очень помогают нам… с других городов… (вопрос Гладина: Вы считаете это достижение «Единой России»?) Да, это большое достижение! Очень хорошее даже! Видите ну… да… Видите ну у нас в Иванове очень хорошая стала медицина… а…что ещё… благоустройство в городах хорошее… с жильём… никаких проблем. Люди подмогают очень хорошо", Rect: image.Rect(400, 200, 700, 500), Foreground: color.RGBA{0, 0, 0, 0}, Background: color.RGBA{255, 255, 255, 126}, OnDrag: func(w *widget.Widget, p image.Point, d image.Point) bool { root.SetTop(w) widget.DragInner(w, p, d) widget.DragItself(w, p, d) return true }, OnResize: widget.ResizeItself, Padding: image.Rect(20, 20, 20, 20), }) white.AddWidget(&widget.Widget{ Name: "White", Rect: image.Rect(290, 290, 300, 300), Background: color.RGBA{0, 0, 0, 250}, OnDrag: func(w *widget.Widget, p image.Point, d image.Point) bool { widget.DragItself(w, p, d) white.Resize(d) return true }, }) x0 := 0.0 y0 := 0.0 window.SetMouseButtonCallback(func(w *glfw.Window, but glfw.MouseButton, act glfw.Action, key glfw.ModifierKey) { xpos, ypos := w.GetCursorPosition() if act == glfw.Press { root.Click(image.Point{X: int(xpos), Y: int(ypos)}) x0, y0 = xpos, ypos } }) window.SetCursorPositionCallback(func(w *glfw.Window, xpos float64, ypos float64) { root.Hover(image.Point{X: int(x0), Y: int(y0)}, image.Point{X: int(xpos), Y: int(ypos)}) if w.GetMouseButton(glfw.MouseButtonLeft) == glfw.Press { root.Drag(image.Point{X: int(x0), Y: int(y0)}, image.Point{X: int(xpos - x0), Y: int(ypos - y0)}) x0, y0 = xpos, ypos } x0, y0 = xpos, ypos }) width0, height0 := window.GetSize() window.SetSizeCallback(func(w *glfw.Window, width int, height int) { gl.Viewport(0, 0, width, height) root.Rect.Max = image.Point{width, height} width0, height0 = width, height }) /*switch(color_type){ case PNG_COLOR_TYPE_GRAY: return GL_LUMINANCE; case PNG_COLOR_TYPE_GRAY_ALPHA: return GL_LUMINANCE_ALPHA; case PNG_COLOR_TYPE_RGB: return GL_RGB; case PNG_COLOR_TYPE_RGB_ALPHA: return GL_RGBA; */ /* here init texture pool texturePool := make([widget.Widget]texture) */ for !window.ShouldClose() { //Do OpenGL stuff program.Use() gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) root.DrawBy(image.Point{}, func(w *widget.Widget, corner image.Point) { var texture gl.Texture if w.Image != nil { texture = gl.GenTexture() texture.Bind(gl.TEXTURE_2D) gl.ActiveTexture(gl.TEXTURE0) gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, w.Image.Rect.Dx(), w.Image.Rect.Dy(), 0, gl.RGBA, gl.UNSIGNED_BYTE, w.Image.Pix) } leftX := 2.0*float32(corner.X+w.Rect.Min.X)/float32(root.Rect.Dx()) - 1.0 leftY := 1.0 - 2.0*float32(corner.Y+w.Rect.Min.Y)/float32(root.Rect.Dy()) rightX := 2.0*float32(corner.X+w.Rect.Min.X)/float32(root.Rect.Dx()) - 1.0 rightY := 1.0 - 2.0*float32(corner.Y+w.Rect.Max.Y)/float32(root.Rect.Dy()) bottomX := 2.0*float32(corner.X+w.Rect.Max.X)/float32(root.Rect.Dx()) - 1.0 bottomY := 1.0 - 2.0*float32(corner.Y+w.Rect.Min.Y)/float32(root.Rect.Dy()) topX := 2.0*float32(corner.X+w.Rect.Max.X)/float32(root.Rect.Dx()) - 1.0 topY := 1.0 - 2.0*float32(corner.Y+w.Rect.Max.Y)/float32(root.Rect.Dy()) vertices := []float32{ leftX, leftY, rightX, rightY, bottomX, bottomY, topX, topY, } texturePoints := []float32{ 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, } s_picture := program.GetUniformLocation("s_picture") s_picture.Uniform1i(0) has_picture := program.GetUniformLocation("has_picture") if w.Image != nil { has_picture.Uniform1i(1) } else { has_picture.Uniform1i(0) } col := program.GetUniformLocation("color") r, g, b, a := w.Background.RGBA() col.Uniform4f(float32(r)/float32(0xFFFF), float32(g)/float32(0xFFFF), float32(b)/float32(0xFFFF), float32(a)/float32(0xFFFF)) gl.PixelStorei(gl.UNPACK_ALIGNMENT, gl.UNSIGNED_BYTE) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) a_position := program.GetAttribLocation("a_position") a_position.AttribPointer(2, gl.FLOAT, false, 0, vertices) a_position.EnableArray() a_coord := program.GetAttribLocation("a_coord") a_coord.AttribPointer(2, gl.FLOAT, false, 0, texturePoints) a_coord.EnableArray() gl.DrawArrays(gl.TRIANGLE_STRIP, 0, 4) gl.Flush() texture.Delete() if len(w.Text) > 0 { rct := w.Rect rct.Max = rct.Max.Sub(w.Rect.Min) rct.Min = rct.Min.Sub(w.Rect.Min) fg := image.NewRGBA(rct) fgu := image.NewUniform(color.RGBA{0, 16, 32, 255}) draw.Draw(fg, fg.Bounds(), fgu, image.ZP, draw.Src) bg := image.NewRGBA(rct) bgu := image.NewUniform(color.RGBA{255, 255, 255, 255}) draw.Draw(bg, bg.Bounds(), bgu, image.ZP, draw.Src) lineHeight := 20.0 fc.SetDPI(100.0) fc.SetFont(font) fc.SetFontSize(12.0) fc.SetClip(bg.Bounds()) fc.SetDst(bg) fc.SetSrc(fg) p0 := ft.Pt(w.Padding.Min.X, w.Padding.Min.Y) p := p0 for _, s := range w.Text { p, _ = fc.DrawString(string(s), p) if int(p.X>>8) > rct.Max.X-w.Padding.Max.X-w.Padding.Min.X { p.X = p0.X p.Y += raster.Fix32(lineHeight * 256) } } var texture gl.Texture if bg != nil { texture = gl.GenTexture() texture.Bind(gl.TEXTURE_2D) gl.ActiveTexture(gl.TEXTURE0) gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, bg.Rect.Dx(), bg.Rect.Dy(), 0, gl.RGBA, gl.UNSIGNED_BYTE, bg.Pix) } leftX := 2.0*float32(corner.X+w.Rect.Min.X)/float32(root.Rect.Dx()) - 1.0 leftY := 1.0 - 2.0*float32(corner.Y+w.Rect.Min.Y)/float32(root.Rect.Dy()) rightX := 2.0*float32(corner.X+w.Rect.Min.X)/float32(root.Rect.Dx()) - 1.0 rightY := 1.0 - 2.0*float32(corner.Y+w.Rect.Max.Y)/float32(root.Rect.Dy()) bottomX := 2.0*float32(corner.X+w.Rect.Max.X)/float32(root.Rect.Dx()) - 1.0 bottomY := 1.0 - 2.0*float32(corner.Y+w.Rect.Min.Y)/float32(root.Rect.Dy()) topX := 2.0*float32(corner.X+w.Rect.Max.X)/float32(root.Rect.Dx()) - 1.0 topY := 1.0 - 2.0*float32(corner.Y+w.Rect.Max.Y)/float32(root.Rect.Dy()) vertices := []float32{ leftX, leftY, rightX, rightY, bottomX, bottomY, topX, topY, } texturePoints := []float32{ 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, } s_picture := program.GetUniformLocation("s_picture") s_picture.Uniform1i(0) has_picture := program.GetUniformLocation("has_picture") if bg != nil { has_picture.Uniform1i(1) } else { has_picture.Uniform1i(0) } col := program.GetUniformLocation("color") r, g, b, a := w.Background.RGBA() col.Uniform4f(float32(r)/float32(0xFFFF), float32(g)/float32(0xFFFF), float32(b)/float32(0xFFFF), float32(a)/float32(0xFFFF)) gl.PixelStorei(gl.UNPACK_ALIGNMENT, gl.UNSIGNED_BYTE) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST) a_position := program.GetAttribLocation("a_position") a_position.AttribPointer(2, gl.FLOAT, false, 0, vertices) a_position.EnableArray() a_coord := program.GetAttribLocation("a_coord") a_coord.AttribPointer(2, gl.FLOAT, false, 0, texturePoints) a_coord.EnableArray() gl.DrawArrays(gl.TRIANGLE_STRIP, 0, 4) gl.Flush() texture.Delete() } }) window.SwapBuffers() glfw.PollEvents() } }
func LoadSkybox() { gl.ActiveTexture(gl.TEXTURE0) if err := CheckGlError(); err != nil { panic(err) } t := gl.GenTexture() if err := CheckGlError(); err != nil { panic(err) } t.Bind(gl.TEXTURE_CUBE_MAP) if err := CheckGlError(); err != nil { panic(err) } const filename = "Skybox_tut13_384x256.png" img, err := LoadImage(filename) if err != nil { panic(err) } size := img.Bounds().Size() w := size.X h := size.Y if w/3 != h/2 { panic("incorrect aspect ratio") } s := h / 2 // Size of one face of the cube. targets := [...]gl.GLenum{ gl.TEXTURE_CUBE_MAP_NEGATIVE_X, gl.TEXTURE_CUBE_MAP_POSITIVE_X, gl.TEXTURE_CUBE_MAP_NEGATIVE_Y, gl.TEXTURE_CUBE_MAP_POSITIVE_Y, gl.TEXTURE_CUBE_MAP_NEGATIVE_Z, gl.TEXTURE_CUBE_MAP_POSITIVE_Z, } rs := []image.Rectangle{ image.Rect(0*s, 0*s, 1*s, 1*s), // 0 side. image.Rect(1*s, 0*s, 2*s, 1*s), // 1 side. image.Rect(2*s, 0*s, 3*s, 1*s), // 2 side. image.Rect(0*s, 1*s, 1*s, 2*s), // 3 bottom. image.Rect(1*s, 1*s, 2*s, 2*s), // 4 top. image.Rect(2*s, 1*s, 3*s, 2*s), // 5 side. } // redirect must end with 3 and 4. This places the floor at -z and the // sky at +z. // All the sides look properly oriented (grass down) on the +y side. // Considering that the sky is properly oriented the way it is, then // rectangle 5 contains the picture that matches it on the +y side. // Therefore, redirect must end with 5, 3, 4. // Problem now: all the other sides, and maybe the floor too, need to be // rotated in order to line up, that is having their sky on top. redirect := [...]int{0, 2, 1, 5, 3, 4} ID := matrix23{1, 0, 0, 1, 0, 0} ms := [...]matrix23{ matrix23{0, -1, 1, 0, 0, s - 1}, matrix23{0, 1, -1, 0, s - 1, 0}, matrix23{-1, 0, 0, -1, s - 1, s - 1}, ID, matrix23{-1, 0, 0, -1, s - 1, s - 1}, ID, } rgba := forceRGBA(img) for i, target := range targets { subimage := rgba.SubImage(rs[redirect[i]]) data := GlRgba(subimage, ms[i]) gl.TexImage2D( target, 0, // Mipmap level. gl.SRGB8_ALPHA8, // Format inside OpenGL. s, // Width. s, // Height. 0, // Border. Doc says it must be 0. gl.RGBA, // Format of the data that... gl.UNSIGNED_BYTE, // ... I give to OpenGL. data, // And the data itself. ) if err := CheckGlError(); err != nil { panic(err) } } const target = gl.TEXTURE_CUBE_MAP gl.GenerateMipmap(target) if err := CheckGlError(); err != nil { panic(err) } gl.TexParameteri(target, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR) if err := CheckGlError(); err != nil { panic(err) } gl.TexParameteri(target, gl.TEXTURE_MAG_FILTER, gl.LINEAR) if err := CheckGlError(); err != nil { panic(err) } gl.TexParameteri(target, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE) if err := CheckGlError(); err != nil { panic(err) } gl.TexParameteri(target, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE) if err := CheckGlError(); err != nil { panic(err) } gl.TexParameteri(target, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) if err := CheckGlError(); err != nil { panic(err) } t.Unbind(target) globaltexture = t }
func LoadTexture() { gl.ActiveTexture(gl.TEXTURE0) if err := CheckGlError(); err != nil { panic(err) } t := gl.GenTexture() if err := CheckGlError(); err != nil { panic(err) } const target = gl.TEXTURE_2D t.Bind(target) if err := CheckGlError(); err != nil { panic(err) } img, err := LoadImage("test.jpg") if err != nil { panic(err) } data := GlRgba(img, matrix23{1, 0, 0, 1, 0, 0}) size := img.Bounds().Size() gl.TexImage2D( target, 0, // Mipmap level. gl.SRGB8_ALPHA8, // Format inside OpenGL. size.X, // Width. size.Y, // Height. 0, // Border. Doc says it must be 0. gl.RGBA, // Format of the data that... gl.UNSIGNED_BYTE, // ... I give to OpenGL. data, // And the data itself. ) if err := CheckGlError(); err != nil { panic(err) } gl.GenerateMipmap(target) if err := CheckGlError(); err != nil { panic(err) } gl.TexParameteri(target, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR) if err := CheckGlError(); err != nil { panic(err) } gl.TexParameteri(target, gl.TEXTURE_MAG_FILTER, gl.LINEAR) if err := CheckGlError(); err != nil { panic(err) } gl.TexParameteri(target, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE) if err := CheckGlError(); err != nil { panic(err) } gl.TexParameteri(target, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE) if err := CheckGlError(); err != nil { panic(err) } t.Unbind(target) globaltexture = t }
func TextureFromDDS(fname string) (gl.Texture, error) { file, err := os.Open(fname) if err != nil { return gl.Texture(0), fmt.Errorf("Cannot open DDS file: %v", err) } defer file.Close() var filecode [4]byte binary.Read(file, binary.LittleEndian, &filecode) // DDS is always Little Endian encoded if string(filecode[:]) != "DDS " { return gl.Texture(0), fmt.Errorf("File code is not DDS, instead got %v.", string(filecode[:])) } header := ddsHeader{} err = binary.Read(file, binary.LittleEndian, &header) if err != nil { return gl.Texture(0), fmt.Errorf("Couldn't read DDS header: %v", err) } stat, err := file.Stat() if err != nil { return gl.Texture(0), fmt.Errorf("Couldn't get size of file: %v", err) } // All of the file after the header and file identifier "DDS " // is images. 4 byte identifier + 124 byte header = 128 bytes // to take off the file size. bufSize := stat.Size() - 128 buffer := make([]byte, bufSize) err = binary.Read(file, binary.LittleEndian, buffer) if err != nil { return gl.Texture(0), fmt.Errorf("Couldn't read all mipmaps into buffer: %v", err) } //var components uint32 var blockSize uint32 var format gl.GLenum switch header.PixelFormat.FourCC { case fourCC_DXT1: format = gl.COMPRESSED_RGBA_S3TC_DXT1_EXT //components = 3 blockSize = 8 case fourCC_DXT3: format = gl.COMPRESSED_RGBA_S3TC_DXT3_EXT //components = 4 blockSize = 16 case fourCC_DXT5: format = gl.COMPRESSED_RGBA_S3TC_DXT5_EXT //components = 4 blockSize = 16 default: return gl.Texture(0), fmt.Errorf("Invalid four CC in DDS header. Got: %x; Expected %x; %x; or %x", header.PixelFormat.FourCC, fourCC_DXT1, fourCC_DXT3, fourCC_DXT5) } offset := 0 tex := gl.GenTexture() tex.Bind(gl.TEXTURE_2D) gl.PixelStorei(gl.UNPACK_ALIGNMENT, 1) for level, width, height := 0, header.Width, header.Height; level < int(header.MipMapCount) && (width > 0 || height > 0); level, width, height = level+1, width/2, height/2 { size := int(((width + 3) / 4) * ((height + 3) / 4) * blockSize) gl.CompressedTexImage2D(gl.TEXTURE_2D, level, format, int(width), int(height), 0, size, &buffer[offset]) offset += size } return tex, nil }
// loadFont loads the given font data. This does not deal with font scaling. // Scaling should be handled by the independent Bitmap/Truetype loaders. // We therefore expect the supplied image and charset to already be adjusted // to the correct font scale. // // The image should hold a sprite sheet, defining the graphical layout for // every glyph. The config describes font metadata. func loadFont(img *image.RGBA, config *FontConfig) (f *Font, err error) { f = new(Font) f.config = config // Resize image to next power-of-two. img = glh.Pow2Image(img).(*image.RGBA) ib := img.Bounds() // Create the texture itself. It will contain all glyphs. // Individual glyph-quads display a subset of this texture. f.texture = gl.GenTexture() f.texture.Bind(gl.TEXTURE_2D) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, ib.Dx(), ib.Dy(), 0, gl.RGBA, gl.UNSIGNED_BYTE, img.Pix) // Create display lists for each glyph. f.listbase = gl.GenLists(len(config.Glyphs)) texWidth := float32(ib.Dx()) texHeight := float32(ib.Dy()) for index, glyph := range config.Glyphs { // Update max glyph bounds. if glyph.Width > f.maxGlyphWidth { f.maxGlyphWidth = glyph.Width } if glyph.Height > f.maxGlyphHeight { f.maxGlyphHeight = glyph.Height } // Quad width/height vw := float32(glyph.Width) vh := float32(glyph.Height) // Texture coordinate offsets. tx1 := float32(glyph.X) / texWidth ty1 := float32(glyph.Y) / texHeight tx2 := (float32(glyph.X) + vw) / texWidth ty2 := (float32(glyph.Y) + vh) / texHeight // Advance width (or height if we render top-to-bottom) adv := float32(glyph.Advance) gl.NewList(f.listbase+uint(index), gl.COMPILE) { gl.Begin(gl.QUADS) { gl.TexCoord2f(tx1, ty2) gl.Vertex2f(0, 0) gl.TexCoord2f(tx2, ty2) gl.Vertex2f(vw, 0) gl.TexCoord2f(tx2, ty1) gl.Vertex2f(vw, vh) gl.TexCoord2f(tx1, ty1) gl.Vertex2f(0, vh) } gl.End() switch config.Dir { case LeftToRight: gl.Translatef(adv, 0, 0) case RightToLeft: gl.Translatef(-adv, 0, 0) case TopToBottom: gl.Translatef(0, -adv, 0) } } gl.EndList() } err = glh.CheckGLError() return }