Beispiel #1
0
func (f *Font) setupTextRendering(color [3]byte, txt string) (gl.GLuint, *sdl.Surface, *sdl.Surface, *sdl.Surface, int, int) {

	//
	var texture gl.GLuint

	/* Use SDL_TTF to render our text */
	var col sdl.Color
	col.R = color[0]
	col.G = color[1]
	col.B = color[2]

	// get surface with text
	initial := ttf.RenderText_Blended(f.font, txt, col)

	/* Convert the rendered text to a known format */
	w := next_p2(int(initial.W))
	h := next_p2(int(initial.H))

	intermediarya := sdl.CreateRGBSurface(0, w, h, 32,
		0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000)

	var rr *sdl.Rect = nil
	intermediarya.Blit(rr, initial, rr)

	intermediary := intermediarya.DisplayFormatAlpha()

	/* Tell GL about our new texture */
	gl.GenTextures(1, &texture)
	gl.BindTexture(gl.TEXTURE_2D, texture)
	gl.TexImage2D(gl.TEXTURE_2D, 0, 4, gl.GLsizei(w), gl.GLsizei(h), 0, gl.BGRA,
		gl.UNSIGNED_BYTE, unsafe.Pointer(intermediary.Pixels))

	gl.TexEnvi(gl.TEXTURE_ENV, gl.TEXTURE_ENV_MODE, gl.MODULATE)

	/* GL_NEAREST looks horrible, if scaled... */
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)

	/* prepare to render our texture */
	gl.Enable(gl.TEXTURE_2D)

	gl.BindTexture(gl.TEXTURE_2D, texture)
	gl.Color4f(1.0, 1.0, 1.0, 1.0)

	gl.Enable(gl.BLEND)
	//	gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
	gl.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_COLOR) // TODO : MAke real alpha work!

	return texture, initial, intermediarya, intermediary, w, h
}
Beispiel #2
0
func (self *Font) Draw(x, y int, text string) {
	gl.BindTexture(gl.TEXTURE_2D, uint(self.Texture))
	for _, rune := range text {
		index, ok := self.EncodingMap[rune]
		if !ok {
			continue
		}

		g := &self.Glyphs[index-1]
		drawGlyph(x, y, g)
		x += int(g.XAdvance)
	}
	gl.BindTexture(gl.TEXTURE_2D, 0)
}
// Load bitmap from path as GL texture
func LoadGLTexture(path string) {
	image := sdl.Load(path)
	if image == nil {
		panic(sdl.GetError())
	}

	// Check that the image's width is a power of 2
	if image.W&(image.W-1) != 0 {
		fmt.Println("warning:", path, "has a width that is not a power of 2")
	}

	// Also check if the height is a power of 2
	if image.H&(image.H-1) != 0 {
		fmt.Println("warning:", path, "has an height that is not a power of 2")
	}

	// get the number of channels in the SDL surface
	nOfColors := image.Format.BytesPerPixel
	var textureFormat gl.GLenum

	if nOfColors == 4 { // contains alpha channel
		if image.Format.Rmask == 0x000000ff {
			textureFormat = gl.RGBA
		} else {
			textureFormat = gl.BGRA
		}
	} else if nOfColors == 3 { // no alpha channel
		if image.Format.Rmask == 0x000000ff {
			textureFormat = gl.RGB
		} else {
			textureFormat = gl.BGR
		}
	} else {
		fmt.Println("warning:", path, "is not truecolor, this will probably break")
	}

	texture = gl.GenTexture()

	// Typical texture generation using data from the bitmap
	gl.BindTexture(gl.TEXTURE_2D, uint(texture))

	// Generate the texture
	gl.TexImage2D(gl.TEXTURE_2D, 0, int(image.Format.BytesPerPixel),
		int(image.W), int(image.H),
		0, textureFormat, gl.UNSIGNED_BYTE, image.Pixels,
	)

	// linear filtering
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)

	// free up memory we have used.
	image.Free()
}
// Here goes our drawing code
func drawGLScene(sector Sector) {
	xtrans := gl.GLfloat(-xpos)
	ztrans := gl.GLfloat(-zpos)
	ytrans := gl.GLfloat(-walkbias - 0.25)
	scenroty := gl.GLfloat(360.0 - yrot)

	// Clear the screen and depth buffer
	gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

	// reset the view
	gl.LoadIdentity()

	// Rotate up and down to look up and down
	gl.Rotatef(float32(lookupdown), 1.0, 0.0, 0.0)
	// Rotate depending on direction player is facing
	gl.Rotatef(float32(scenroty), 0.0, 1.0, 0.0)
	// translate the scene based on player position
	gl.Translatef(float32(xtrans), float32(ytrans), float32(ztrans))

	gl.BindTexture(gl.TEXTURE_2D, uint(textures[filter]))

	for _, vertices := range sector {
		gl.Begin(gl.TRIANGLES)
		for _, triangle := range *vertices {
			gl.Normal3f(0.0, 0.0, 1.0)
			gl.TexCoord2f(float32(triangle.u), float32(triangle.v))
			gl.Vertex3f(float32(triangle.x), float32(triangle.y), float32(triangle.z))
		}
		gl.End()
	}

	// Draw to the screen
	sdl.GL_SwapBuffers()

	// Gather our frames per second
	frames++
	t := sdl.GetTicks()
	if t-t0 >= 5000 {
		seconds := (t - t0) / 1000.0
		fps := frames / seconds
		fmt.Println(frames, "frames in", seconds, "seconds =", fps, "FPS")
		t0 = t
		frames = 0
	}
}
Beispiel #5
0
func uploadTexture_RGBA32(w, h int, data []byte) gl.GLuint {
	var id gl.GLuint

	gl.GenTextures(1, &id)
	gl.BindTexture(gl.TEXTURE_2D, id)
	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, gl.GLsizei(w), gl.GLsizei(h), 0, gl.RGBA,
		gl.UNSIGNED_BYTE, unsafe.Pointer(&data[0]))

	if gl.GetError() != gl.NO_ERROR {
		gl.DeleteTextures(1, &id)
		panic("Failed to load a texture")
		return 0
	}
	return id
}
Beispiel #6
0
func main() {
	runtime.LockOSThread()
	flag.Parse()
	buildPalette()
	sdl.Init(sdl.INIT_VIDEO)
	defer sdl.Quit()

	sdl.GL_SetAttribute(sdl.GL_SWAP_CONTROL, 1)

	if sdl.SetVideoMode(512, 512, 32, sdl.OPENGL) == nil {
		panic("sdl error")
	}

	if gl.Init() != 0 {
		panic("gl error")
	}

	sdl.WM_SetCaption("Gomandel", "Gomandel")

	gl.Enable(gl.TEXTURE_2D)
	gl.Viewport(0, 0, 512, 512)
	gl.MatrixMode(gl.PROJECTION)
	gl.LoadIdentity()
	gl.Ortho(0, 512, 512, 0, -1, 1)

	gl.ClearColor(0, 0, 0, 0)

	//-----------------------------------------------------------------------------
	var dndDragging bool = false
	var dndStart Point
	var dndEnd Point
	var tex gl.Texture
	var tc TexCoords
	var lastProgress int
	initialRect := Rect{-1.5, -1.5, 3, 3}
	rect := initialRect

	rc := new(MandelbrotRequest)
	rc.MakeRequest(512, 512, rect)
	rc.WaitFor(Small, &tex, &tc)

	running := true
	e := new(sdl.Event)
	for running {
		for e.Poll() {
			switch e.Type {
			case sdl.QUIT:
				running = false
			case sdl.MOUSEBUTTONDOWN:
				dndDragging = true
				sdl.GetMouseState(&dndStart.X, &dndStart.Y)
				dndEnd = dndStart
			case sdl.MOUSEBUTTONUP:
				dndDragging = false
				sdl.GetMouseState(&dndEnd.X, &dndEnd.Y)
				if e.MouseButton().Button == 3 {
					rect = initialRect
				} else {
					rect = rectFromSelection(dndStart, dndEnd, 512, 512, rect)
					tc = texCoordsFromSelection(dndStart, dndEnd, 512, 512, tc)
				}

				// make request
				rc.MakeRequest(512, 512, rect)
			case sdl.MOUSEMOTION:
				if dndDragging {
					sdl.GetMouseState(&dndEnd.X, &dndEnd.Y)
				}
			}
		}

		// if we're waiting for a result, check if it's ready
		p := rc.Update(&tex, &tc)
		if p != -1 {
			lastProgress = p
		}

		gl.Clear(gl.COLOR_BUFFER_BIT)
		tex.Bind(gl.TEXTURE_2D)
		drawQuad(0, 0, 512, 512, tc.TX, tc.TY, tc.TX2, tc.TY2)
		gl.BindTexture(gl.TEXTURE_2D, 0)
		if dndDragging {
			drawSelection(dndStart, dndEnd)
		}
		drawProgress(512, 512, lastProgress, rc.Pending)
		sdl.GL_SwapBuffers()
	}
}
Beispiel #7
0
// Here goes our drawing code
func drawGLScene() {
	// Clear the screen and depth buffer
	gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

	// Move left 1.5 units and into the screen 6.0 units.
	gl.LoadIdentity()
	gl.Translatef(0.0, 0.0, -7.0)

	gl.Rotatef(float32(xrot), 1.0, 0.0, 0.0) /* Rotate On The X Axis */
	gl.Rotatef(float32(yrot), 0.0, 1.0, 0.0) /* Rotate On The Y Axis */
	gl.Rotatef(float32(zrot), 0.0, 0.0, 1.0) /* Rotate On The Z Axis */

	/* Select Our Texture */
	gl.BindTexture(gl.TEXTURE_2D, uint(texture))

	gl.Begin(gl.QUADS) // Draw a quad
	/* Front Face */
	gl.TexCoord2f(0.0, 1.0)
	gl.Vertex3f(-1.0, -1.0, 1.0) // Bottom left
	gl.TexCoord2f(1.0, 1.0)
	gl.Vertex3f(1.0, -1.0, 1.0) // Bottom right
	gl.TexCoord2f(1.0, 0.0)
	gl.Vertex3f(1.0, 1.0, 1.0) // Top right
	gl.TexCoord2f(0.0, 0.0)
	gl.Vertex3f(-1.0, 1.0, 1.0) // Top left

	/* Back Face */
	gl.TexCoord2f(0.0, 0.0)
	gl.Vertex3f(-1.0, -1.0, -1.0) // Bottom right
	gl.TexCoord2f(0.0, 1.0)
	gl.Vertex3f(-1.0, 1.0, -1.0) // Top right
	gl.TexCoord2f(1.0, 1.0)
	gl.Vertex3f(1.0, 1.0, -1.0) // Top left
	gl.TexCoord2f(1.0, 0.0)
	gl.Vertex3f(1.0, -1.0, -1.0) // Bottom left

	/* Top Face */
	gl.TexCoord2f(1.0, 1.0)
	gl.Vertex3f(-1.0, 1.0, -1.0) // Top left
	gl.TexCoord2f(1.0, 0.0)
	gl.Vertex3f(-1.0, 1.0, 1.0) // Bottom left
	gl.TexCoord2f(0.0, 0.0)
	gl.Vertex3f(1.0, 1.0, 1.0) // Bottom right
	gl.TexCoord2f(0.0, 1.0)
	gl.Vertex3f(1.0, 1.0, -1.0) // Top right

	/* Bottom Face */
	gl.TexCoord2f(0.0, 1.0)
	gl.Vertex3f(-1.0, -1.0, -1.0) // Top right
	gl.TexCoord2f(1.0, 1.0)
	gl.Vertex3f(1.0, -1.0, -1.0) // Top left
	gl.TexCoord2f(1.0, 0.0)
	gl.Vertex3f(1.0, -1.0, 1.0) // Bottom left
	gl.TexCoord2f(0.0, 0.0)
	gl.Vertex3f(-1.0, -1.0, 1.0) // Bottom right

	/* Right face */
	gl.TexCoord2f(0.0, 0.0)
	gl.Vertex3f(1.0, -1.0, -1.0) // Bottom right
	gl.TexCoord2f(0.0, 1.0)
	gl.Vertex3f(1.0, 1.0, -1.0) // Top right
	gl.TexCoord2f(1.0, 1.0)
	gl.Vertex3f(1.0, 1.0, 1.0) // Top left
	gl.TexCoord2f(1.0, 0.0)
	gl.Vertex3f(1.0, -1.0, 1.0) // Bottom left

	/* Left Face */
	gl.TexCoord2f(1.0, 0.0)
	gl.Vertex3f(-1.0, -1.0, -1.0) // Bottom left
	gl.TexCoord2f(0.0, 0.0)
	gl.Vertex3f(-1.0, -1.0, 1.0) // Bottom right
	gl.TexCoord2f(0.0, 1.0)
	gl.Vertex3f(-1.0, 1.0, 1.0) // Top right
	gl.TexCoord2f(1.0, 1.0)
	gl.Vertex3f(-1.0, 1.0, -1.0) // Top left
	gl.End()                     // done drawing the quad

	// Draw to the screen
	sdl.GL_SwapBuffers()

	xrot += 0.3 /* X Axis Rotation */
	yrot += 0.2 /* Y Axis Rotation */
	zrot += 0.4 /* Z Axis Rotation */

	// Gather our frames per second
	frames++
	t := sdl.GetTicks()
	if t-t0 >= 5000 {
		seconds := (t - t0) / 1000.0
		fps := frames / seconds
		fmt.Println(frames, "frames in", seconds, "seconds =", fps, "FPS")
		t0 = t
		frames = 0
	}
}
Beispiel #8
0
// Here goes our drawing code
func drawGLScene() {
  // Clear the screen and depth buffer
  gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

  // Move left 1.5 units and into the screen 6.0 units.
  gl.LoadIdentity()
  gl.Translatef(0.0, 0.0, float32(z)) // translate by z

  gl.Rotatef(float32(xrot), 1.0, 0.0, 0.0) /* Rotate On The X Axis */
  gl.Rotatef(float32(yrot), 0.0, 1.0, 0.0) /* Rotate On The Y Axis */

  /* Select Our Texture */
  gl.BindTexture(gl.TEXTURE_2D, uint(textures[filter])) // based on filter

  gl.Begin(gl.QUADS)

  // Front face
  gl.Normal3f(0.0, 0.0, 1.0) // Normal Pointing Towards Viewer
  gl.TexCoord2f(0.0, 1.0); gl.Vertex3f(-1.0, -1.0, 1.0) // Bottom left
  gl.TexCoord2f(1.0, 1.0); gl.Vertex3f( 1.0, -1.0, 1.0) // Bottom right
  gl.TexCoord2f(1.0, 0.0); gl.Vertex3f( 1.0,  1.0, 1.0) // Top right
  gl.TexCoord2f(0.0, 0.0); gl.Vertex3f(-1.0,  1.0, 1.0) // Top left

  // Back Face
  gl.Normal3f(0.0, 0.0, -1.0) // Normal Pointing Away From Viewer
  gl.TexCoord2f(0.0, 0.0); gl.Vertex3f(-1.0, -1.0, -1.0) // Bottom right
  gl.TexCoord2f(0.0, 1.0); gl.Vertex3f(-1.0,  1.0, -1.0) // Top right
  gl.TexCoord2f(1.0, 1.0); gl.Vertex3f( 1.0,  1.0, -1.0) // Top left
  gl.TexCoord2f(1.0, 0.0); gl.Vertex3f( 1.0, -1.0, -1.0) // Bottom left

  // Top Face
  gl.Normal3f(0.0, 1.0, 0.0) // Normal Pointing Up
  gl.TexCoord2f(1.0, 1.0); gl.Vertex3f(-1.0,  1.0, -1.0) // Top left
  gl.TexCoord2f(1.0, 0.0); gl.Vertex3f(-1.0,  1.0,  1.0) // Bottom left
  gl.TexCoord2f(0.0, 0.0); gl.Vertex3f( 1.0,  1.0,  1.0) // Bottom right
  gl.TexCoord2f(0.0, 1.0); gl.Vertex3f( 1.0,  1.0, -1.0) // Top right

  // Bottom Face
  gl.Normal3f(0.0, -1.0, 0.0) // Normal Pointing Down
  gl.TexCoord2f(0.0, 1.0); gl.Vertex3f(-1.0, -1.0, -1.0) // Top right
  gl.TexCoord2f(1.0, 1.0); gl.Vertex3f( 1.0, -1.0, -1.0) // Top left
  gl.TexCoord2f(1.0, 0.0); gl.Vertex3f( 1.0, -1.0,  1.0) // Bottom left
  gl.TexCoord2f(0.0, 0.0); gl.Vertex3f(-1.0, -1.0,  1.0) // Bottom right

  // Right face
  gl.Normal3f(1.0, 0.0, 0.0) // Normal Pointing Right
  gl.TexCoord2f(0.0, 0.0); gl.Vertex3f(1.0, -1.0, -1.0) // Bottom right
  gl.TexCoord2f(0.0, 1.0); gl.Vertex3f(1.0,  1.0, -1.0) // Top right
  gl.TexCoord2f(1.0, 1.0); gl.Vertex3f(1.0,  1.0,  1.0) // Top left
  gl.TexCoord2f(1.0, 0.0); gl.Vertex3f(1.0, -1.0,  1.0) // Bottom left

  // Left Face
  gl.Normal3f(-1.0, 0.0, 0.0) // Normal Pointing Left
  gl.TexCoord2f(1.0, 0.0); gl.Vertex3f(-1.0, -1.0, -1.0) // Bottom left
  gl.TexCoord2f(0.0, 0.0); gl.Vertex3f(-1.0, -1.0,  1.0) // Bottom right
  gl.TexCoord2f(0.0, 1.0); gl.Vertex3f(-1.0,  1.0,  1.0) // Top right
  gl.TexCoord2f(1.0, 1.0); gl.Vertex3f(-1.0,  1.0, -1.0) // Top left

  gl.End()

  sdl.GL_SwapBuffers()

  xrot += xspeed
  yrot += yspeed

  // Gather our frames per second
  frames++
  t := sdl.GetTicks()
  if t-t0 >= 5000 {
    seconds := (t - t0) / 1000.0
    fps := frames / seconds
    fmt.Println(frames, "frames in", seconds, "seconds =", fps, "FPS")
    t0 = t
    frames = 0
  }
}
Beispiel #9
0
// load in bitmap as a GL texture
func LoadGLTextures(path string) {
  image := sdl.Load(path)
  if image == nil { panic(sdl.GetError()) }

  // Check that the image's width is a power of 2
  if image.W & (image.W - 1) != 0 {
    fmt.Println("warning:", path, "has a width that is not a power of 2")
  }

  // Also check if the height is a power of 2
  if image.H & (image.H - 1) != 0 {
    fmt.Println("warning:", path, "has an height that is not a power of 2")
  }

  // get the number of channels in the SDL surface
  nOfColors := image.Format.BytesPerPixel
  var textureFormat gl.GLenum

  if nOfColors == 4 { // contains alpha channel
    if image.Format.Rmask == 0x000000ff {
      textureFormat = gl.RGBA
    } else {
      textureFormat = gl.BGRA
    }
  } else if nOfColors == 3 { // no alpha channel
    if image.Format.Rmask == 0x000000ff {
      textureFormat = gl.RGB
    } else {
      textureFormat = gl.BGR
    }
  } else {
    fmt.Println("warning:", path, "is not truecolor, this will probably break")
  }

  // Create the textures
  gl.GenTextures(textures[:])

  // First texture
  gl.BindTexture(gl.TEXTURE_2D, uint(textures[0]))
  gl.TexImage2D(
    gl.TEXTURE_2D,
    0,
    3,
    int(image.W),
    int(image.H),
    0,
    textureFormat,
    gl.UNSIGNED_BYTE,
    image.Pixels,
  )

  // linear filtering
  gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
  gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)


  // Second texture
  gl.BindTexture(gl.TEXTURE_2D, uint(textures[1]))
  gl.TexImage2D(gl.TEXTURE_2D, 0,
    3,
    int(image.W),
    int(image.H),
    0, textureFormat, gl.UNSIGNED_BYTE,
    image.Pixels,
  )

  // Mipmapped filtering
  gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
  gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)


  // Third texture
  gl.BindTexture(gl.TEXTURE_2D, uint(textures[2]))
  gl.TexImage2D(gl.TEXTURE_2D, 0,
    3,
    int(image.W),
    int(image.H),
    0, textureFormat, gl.UNSIGNED_BYTE,
    image.Pixels,
  )

  // Mipmapped filtering
  gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST)
  gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)

  glu.Build2DMipmaps(
    gl.TEXTURE_2D,
    3,
    int(image.W),
    int(image.H),
    textureFormat,
    image.Pixels,
  )
}
func genTexture(into gl.Texture, from *sdl.Surface, format gl.GLenum) {
	gl.BindTexture(gl.TEXTURE_2D, uint(into))
	gl.TexImage2D(gl.TEXTURE_2D, 0, 3, int(from.W), int(from.H),
		0, format, gl.UNSIGNED_BYTE, from.Pixels,
	)
}
// Here goes our drawing code
func drawGLScene() {
	// Clear the screen and depth buffer
	gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
	gl.BindTexture(gl.TEXTURE_2D, uint(texture))

	for loop, star := range stars {
		gl.LoadIdentity()
		gl.Translatef(0.0, 0.0, float32(zoom))
		gl.Rotatef(float32(tilt), 1.0, 0.0, 0.0)
		gl.Rotatef(float32(star.angle), 0.0, 1.0, 0.0)
		gl.Translatef(float32(star.dist), 0.0, 0.0)
		gl.Rotatef(float32(-star.angle), 0.0, 1.0, 0.0)
		gl.Rotatef(float32(-tilt), 1.0, 0.0, 0.0)

		if twinkle {
			other := stars[(num-loop)-1]
			gl.Color4ub(uint8(other.r), uint8(other.g), uint8(other.b), 255)
			gl.Begin(gl.QUADS)
			gl.TexCoord2f(0.0, 0.0)
			gl.Vertex3f(-1.0, -1.0, 0.0)
			gl.TexCoord2f(1.0, 0.0)
			gl.Vertex3f(1.0, -1.0, 0.0)
			gl.TexCoord2f(1.0, 1.0)
			gl.Vertex3f(1.0, 1.0, 0.0)
			gl.TexCoord2f(0.0, 1.0)
			gl.Vertex3f(-1.0, 1.0, 0.0)
			gl.End()
		}

		gl.Rotatef(float32(spin), 0.0, 0.0, 1.0)
		gl.Color4ub(uint8(star.r), uint8(star.g), uint8(star.b), 255)
		gl.Begin(gl.QUADS)
		gl.TexCoord2f(0.0, 0.0)
		gl.Vertex3f(-1.0, -1.0, 0.0)
		gl.TexCoord2f(1.0, 0.0)
		gl.Vertex3f(1.0, -1.0, 0.0)
		gl.TexCoord2f(1.0, 1.0)
		gl.Vertex3f(1.0, 1.0, 0.0)
		gl.TexCoord2f(0.0, 1.0)
		gl.Vertex3f(-1.0, 1.0, 0.0)
		gl.End()

		spin += 0.01
		star.angle += gl.GLfloat(loop) / gl.GLfloat(num)
		star.dist -= 0.01

		if star.dist < 0.0 {
			star.dist += 5.0
			star.r = gl.GLubyte(rand.Float32() * 255)
			star.g = gl.GLubyte(rand.Float32() * 255)
			star.b = gl.GLubyte(rand.Float32() * 255)
		}
	}

	// Draw to the screen
	sdl.GL_SwapBuffers()

	// Gather our frames per second
	frames++
	t := sdl.GetTicks()
	if t-t0 >= 5000 {
		seconds := (t - t0) / 1000.0
		fps := frames / seconds
		fmt.Println(frames, "frames in", seconds, "seconds =", fps, "FPS")
		t0 = t
		frames = 0
	}
}