Exemple #1
0
Fichier : 09.go Projet : nzlov/gogl
func initGL() (err error) {

	goph, err := os.Open(texturefiles[0])
	if err != nil {
		panic(err)
	}
	defer goph.Close()

	texture, err = createTexture(goph)

	gl.ShadeModel(gl.SMOOTH)
	gl.ClearColor(0, 0, 0, 0.5)
	gl.ClearDepth(1)
	gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST)
	gl.BlendFunc(gl.SRC_ALPHA, gl.ONE) // 设置混色函数取得半透明效果
	gl.Enable(gl.BLEND)
	gl.Enable(gl.TEXTURE_2D)

	rand.Seed(time.Now().Unix())
	for loop = 0; loop < num; loop++ {
		star[loop].angle = 0.0
		star[loop].dist = float32(loop) / num * 5
		//fmt.Println(loop, star[loop].dist)
		star[loop].r = uint8(rand.Int() % 256)
		star[loop].g = uint8(rand.Int() % 256)
		star[loop].b = uint8(rand.Int() % 256)
	}

	return
}
Exemple #2
0
func initGL() (err error) {
	if err = loadTextures(); err != nil {
		return
	}

	gl.ShadeModel(gl.SMOOTH) /// 启用阴影平滑,设置平滑着色,阴影平滑通过多边形精细的混合色彩,并对外部光进行平滑

	/*
	  色彩值的范围从0.0f到1.0f。0.0f代表最黑的情况,1.0f就是最亮的情况。
	  glClearColor 后的第一个参数是Red Intensity(红色分量),第二个是绿色,第三个是蓝色。最大值也是1.0f,代表特定颜色分量的最亮情况。
	  最后一个参数是Alpha值。当它用来清除屏幕的时候,我们不用关心第四个数字。现在让它为0.0f.
	*/
	gl.ClearColor(0, 0, 0, 0) ///设置清除屏幕时所用的颜色,黑色背景

	/*
	  接下来的三行必须做的是关于depth buffer(深度缓存)的。将深度缓存设想为屏幕后面的层。
	  深度缓存不断的对物体进入屏幕内部有多深进行跟踪。
	  本程序其实没有真正使用深度缓存,但几乎所有在屏幕上显示3D场景OpenGL程序都使用深度缓存。
	  它的排序决定那个物体先画。这样您就不会将一个圆形后面的正方形画到圆形上来。深度缓存是OpenGL十分重要的部分。
	*/
	gl.ClearDepth(1)                                   ///设置深度缓存
	gl.DepthFunc(gl.LEQUAL)                            ///所作深度测试的类型
	gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST) ///告诉系统对透视进行修正,这会十分轻微的影响性能。但使得透视图看起来好一点

	gl.Enable(gl.DEPTH_TEST) ///启用深度测试
	gl.Enable(gl.TEXTURE_2D) ///启用纹理映射
	return
}
Exemple #3
0
func initGL() (err error) {
	if err = loadTextures(); err != nil {
		return
	}

	gl.ShadeModel(gl.SMOOTH)
	gl.ClearColor(0, 0, 0, 0)
	gl.ClearDepth(1)
	gl.DepthFunc(gl.LEQUAL)
	gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST)
	gl.Enable(gl.TEXTURE_2D)
	gl.Enable(gl.DEPTH_TEST)

	//alpha通道的值为 0.0意味着物体材质是完全透明的。1.0 则意味着完全不透明
	//以全亮度绘制此物体,并对其进行50%的alpha混合(半透明)。
	//当混合选项打开时,此物体将会产生50%的透明效果
	gl.Color4f(1, 1, 1, 0.5)           //全亮度, 50% Alpha 混合
	gl.BlendFunc(gl.SRC_ALPHA, gl.ONE) //基于源象素alpha通道值的半透明混合函数

	gl.Lightfv(gl.LIGHT1, gl.AMBIENT, ambient)
	gl.Lightfv(gl.LIGHT1, gl.AMBIENT, diffuse)
	gl.Lightfv(gl.LIGHT1, gl.POSITION, lightpos)
	gl.Enable(gl.LIGHT1)
	return
}
Exemple #4
0
Fichier : 04.go Projet : nzlov/gogl
// program & OpenGL initialization
func Init() {
	gl.ShadeModel(gl.SMOOTH)                           // 启用阴影平滑
	gl.ClearColor(0.0, 0.0, 0.0, 0.0)                  // 黑色背景
	gl.ClearDepth(1.0)                                 // 设置深度缓存
	gl.Enable(gl.DEPTH_TEST)                           // 启用深度测试
	gl.DepthFunc(gl.LEQUAL)                            // 所作深度测试的类型
	gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST) // 告诉系统对透视进行修正
}
Exemple #5
0
func initGL() {
	gl.ShadeModel(gl.SMOOTH)
	gl.ClearColor(0, 0, 0, 0)
	gl.ClearDepth(1)
	gl.Enable(gl.DEPTH_TEST)
	gl.DepthFunc(gl.LEQUAL)
	gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST)
}
Exemple #6
0
func initGL() {
	gl.ShadeModel(gl.SMOOTH) /// 设置平滑着色?(是默认的)
	//gl.ShadeModel(gl.FLAT); /// 即单色,使用最后一个点所用的颜色
	gl.ClearColor(0, 0, 0, 0)
	gl.ClearDepth(1)
	gl.Enable(gl.DEPTH_TEST)
	gl.DepthFunc(gl.LEQUAL)
	gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST)
}
Exemple #7
0
func copiedInit() {
	gl.ClearColor(0, 0, 0, 0)
	gl.ShadeModel(gl.FLAT)
	gl.Enable(gl.CULL_FACE)
	gl.Viewport(320, 240, 640, 480)
	gl.MatrixMode(gl.PROJECTION)
	gl.LoadIdentity()
	gl.Frustum(-1, 1, -1, 1, 1.5, 20)
	gl.MatrixMode(gl.MODELVIEW)
}
Exemple #8
0
func setupGL(w, h int) {
	gl.Viewport(0, 0, w, h)
	gl.MatrixMode(gl.PROJECTION)
	gl.LoadIdentity()
	gl.Ortho(0, float64(w), float64(h), 0, 0, 1)

	gl.ShadeModel(gl.SMOOTH)
	gl.ClearColor(1, 1, 1, 0)
	gl.Enable(gl.BLEND)
	gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
	gl.Disable(gl.DEPTH_TEST)
	gl.Hint(gl.LINE_SMOOTH_HINT|gl.LINE_SMOOTH_HINT, gl.NICEST)
}
Exemple #9
0
func initGL() (err error) {
	if err = loadTextures(); err != nil {
		return
	}

	gl.ShadeModel(gl.SMOOTH)
	gl.ClearColor(0, 0, 0, 0)
	gl.ClearDepth(1)
	gl.DepthFunc(gl.LEQUAL)
	gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST)
	gl.Enable(gl.DEPTH_TEST)
	gl.Enable(gl.TEXTURE_2D)
	return
}
Exemple #10
0
func initGL() (err error) {
	gl.Init()
	gl.ShadeModel(gl.SMOOTH)
	gl.ClearColor(0, 0, 0, 0)
	gl.ClearDepth(1)
	gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
	gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST)
	gl.DepthFunc(gl.NEVER)
	gl.Enable(gl.BLEND)
	gl.DepthMask(true)

	//loadShader()

	return
}
Exemple #11
0
func InitGL(width, height int) {
	//enable vertical sync if the card supports it
	glfw.SetSwapInterval(1)

	gl.ShadeModel(gl.SMOOTH)

	gl.ClearColor(0.1, 0.1, 0.1, 1.0)

	gl.Enable(gl.TEXTURE_2D)
	gl.Enable(gl.CULL_FACE)
	gl.Enable(gl.DEPTH_TEST)
	gl.DepthFunc(gl.LEQUAL)

	gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST)

	SetViewport(width, height)
	glfw.SetWindowSizeCallback(SetViewport)
	glfw.SetKeyCallback(OnKey)
}
Exemple #12
0
Fichier : 06.go Projet : nzlov/gogl
func initGL() (err error) {

	goph, err := os.Open(texturefiles[0])
	if err != nil {
		panic(err)
	}
	defer goph.Close()

	texture, err = createTexture(goph)

	gl.ShadeModel(gl.SMOOTH)
	gl.ClearColor(0, 0, 0, 0)
	gl.ClearDepth(1)
	gl.DepthFunc(gl.LEQUAL)
	gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST)
	gl.Enable(gl.DEPTH_TEST)
	gl.Enable(gl.TEXTURE_2D)
	return
}
Exemple #13
0
func initGL() (err error) {
	if err = loadTextures(); err != nil {
		return
	}

	gl.ShadeModel(gl.SMOOTH)
	gl.ClearColor(0, 0, 0, 0)
	gl.ClearDepth(1)
	gl.DepthFunc(gl.LEQUAL)
	gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST)
	gl.Enable(gl.DEPTH_TEST)
	gl.Enable(gl.TEXTURE_2D)

	gl.Lightfv(gl.LIGHT1, gl.AMBIENT, ambient)
	gl.Lightfv(gl.LIGHT1, gl.AMBIENT, diffuse)
	gl.Lightfv(gl.LIGHT1, gl.POSITION, lightpos)
	gl.Enable(gl.LIGHT1)
	return
}
Exemple #14
0
// initGL initializes GLFW and OpenGL.
func initGL() error {
	err := glfw.Init()
	if err != nil {
		return err
	}

	glfw.OpenWindowHint(glfw.FsaaSamples, 4)
	glfw.OpenWindowHint(glfw.WindowNoResize, gl.TRUE)

	err = glfw.OpenWindow(512, 512, 8, 8, 8, 8, 32, 0, glfw.Windowed)
	if err != nil {
		glfw.Terminate()
		return err
	}

	glfw.SetWindowTitle("Meshbuffer 3D example")
	glfw.SetSwapInterval(1)
	glfw.SetWindowSizeCallback(onResize)
	glfw.SetKeyCallback(onKey)

	gl.Init()
	if err = glh.CheckGLError(); err != nil {
		return err
	}

	gl.Enable(gl.DEPTH_TEST)
	gl.Enable(gl.MULTISAMPLE)
	gl.Disable(gl.LIGHTING)

	//gl.ClearColor(0.2, 0.2, 0.23, 1.0)
	gl.ClearColor(0, 0, 0, 1.0)
	gl.ShadeModel(gl.SMOOTH)
	gl.LineWidth(2)
	gl.ClearDepth(1)
	gl.DepthFunc(gl.LEQUAL)
	gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST)
	gl.ColorMaterial(gl.FRONT_AND_BACK, gl.AMBIENT_AND_DIFFUSE)
	return nil
}
Exemple #15
0
Fichier : 10.go Projet : nzlov/gogl
func initGL() (err error) {

	goph, err := os.Open(texturefiles)
	if err != nil {
		panic(err)
	}
	defer goph.Close()

	texture, err = createTexture(goph)

	gl.Enable(gl.TEXTURE_2D)
	gl.BlendFunc(gl.SRC_ALPHA, gl.ONE) // 设置混色函数取得半透明效果
	gl.ClearColor(0, 0, 0, 0.0)
	gl.ClearDepth(1)
	gl.DepthFunc(gl.LESS)
	gl.Enable(gl.DEPTH_TEST)
	gl.ShadeModel(gl.SMOOTH)
	gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST)

	SetupWorld()

	return
}
Exemple #16
0
func initGL() (err error) {
	if err = loadTextures(); err != nil {
		return
	}

	gl.ShadeModel(gl.SMOOTH)  ///阴影模式设为平滑阴影
	gl.ClearColor(0, 0, 0, 0) ///背景色设为黑色
	gl.ClearDepth(1)
	gl.DepthFunc(gl.LEQUAL)
	gl.Hint(gl.PERSPECTIVE_CORRECTION_HINT, gl.NICEST) ///启用优化透视计算
	gl.Enable(gl.DEPTH_TEST)                           ///启用深度测试
	gl.Enable(gl.TEXTURE_2D)                           ///启用2D纹理映射

	/*
	   创建光源的数组。我们将使用两种不同的光。
	   第一种称为环境光。环境光来自于四面八方。所有场景中的对象都处于环境光的照射中。
	   第二种类型的光源叫做漫射光。漫射光由特定的光源产生,并在您的场景中的对象表面上产生反射。
	   处于漫射光直接照射下的任何对象表面都变得很亮,而几乎未被照射到的区域就显得要暗一些。
	   这样在我们所创建的木板箱的棱边上就会产生的很不错的阴影效果。
	   创建光源的过程和颜色的创建完全一致。前三个参数分别是RGB三色分量,最后一个是alpha通道参数。
	   因此,下面的代码我们得到的是半亮(0.5f)的白色环境光。如果没有环境光,未被漫射光照到的地方会变得十分黑暗。
	*/
	gl.Lightfv(gl.LIGHT1, gl.AMBIENT, ambient) //设置环境光(半亮度环境光)
	//gl.Lightfv(gl.LIGHT1, gl.AMBIENT, diffuse); //设置漫射光
	gl.Lightfv(gl.LIGHT1, gl.DIFFUSE, diffuse)   //设置漫射光(全亮度白光)
	gl.Lightfv(gl.LIGHT1, gl.POSITION, lightpos) //设置光源位置
	gl.Enable(gl.LIGHT1)                         //启用一号光源
	/*
	   光源的位置。前三个参数和glTranslate中的一样。依次分别是XYZ轴上的位移。
	   由于我们想要光线直接照射在木箱的正面,所以XY轴上的位移都是0.0f。
	   第三个值是Z轴上的位移。为了保证光线总在木箱的前面,所以我们将光源的位置朝着观察者(就是您哪。)挪出屏幕。
	   我们通常将屏幕也就是显示器的屏幕玻璃所处的位置称作Z轴的0.0f点。所以Z轴上的位移最后定为2.0f。
	   假如您能够看见光源的话,它就浮在您显示器的前方。当然,如果木箱不在显示器的屏幕玻璃后面的话,您也无法看见箱子。
	*/
	return
}
Exemple #17
0
func gear(inner_radius, outer_radius, width float64, teeth int, tooth_depth float64) {
	var i int
	var r0, r1, r2 float64
	var angle, da float64
	var u, v, len float64

	r0 = inner_radius
	r1 = outer_radius - tooth_depth/2.0
	r2 = outer_radius + tooth_depth/2.0

	da = 2.0 * math.Pi / float64(teeth) / 4.0

	gl.ShadeModel(gl.FLAT)

	gl.Normal3d(0.0, 0.0, 1.0)

	/* draw front face */
	gl.Begin(gl.QUAD_STRIP)
	for i = 0; i <= teeth; i++ {
		angle = float64(i) * 2.0 * math.Pi / float64(teeth)
		gl.Vertex3d(r0*math.Cos(angle), r0*math.Sin(angle), width*0.5)
		gl.Vertex3d(r1*math.Cos(angle), r1*math.Sin(angle), width*0.5)
		if i < teeth {
			gl.Vertex3d(r0*math.Cos(angle), r0*math.Sin(angle), width*0.5)
			gl.Vertex3d(r1*math.Cos(angle+3*da), r1*math.Sin(angle+3*da), width*0.5)
		}
	}
	gl.End()

	/* draw front sides of teeth */
	gl.Begin(gl.QUADS)
	da = 2.0 * math.Pi / float64(teeth) / 4.0
	for i = 0; i < teeth; i++ {
		angle = float64(i) * 2.0 * math.Pi / float64(teeth)

		gl.Vertex3d(r1*math.Cos(angle), r1*math.Sin(angle), width*0.5)
		gl.Vertex3d(r2*math.Cos(angle+da), r2*math.Sin(angle+da), width*0.5)
		gl.Vertex3d(r2*math.Cos(angle+2*da), r2*math.Sin(angle+2*da), width*0.5)
		gl.Vertex3d(r1*math.Cos(angle+3*da), r1*math.Sin(angle+3*da), width*0.5)
	}
	gl.End()

	gl.Normal3d(0.0, 0.0, -1.0)

	/* draw back face */
	gl.Begin(gl.QUAD_STRIP)
	for i = 0; i <= teeth; i++ {
		angle = float64(i) * 2.0 * math.Pi / float64(teeth)
		gl.Vertex3d(r1*math.Cos(angle), r1*math.Sin(angle), -width*0.5)
		gl.Vertex3d(r0*math.Cos(angle), r0*math.Sin(angle), -width*0.5)
		if i < teeth {
			gl.Vertex3d(r1*math.Cos(angle+3*da), r1*math.Sin(angle+3*da), -width*0.5)
			gl.Vertex3d(r0*math.Cos(angle), r0*math.Sin(angle), -width*0.5)
		}
	}
	gl.End()

	/* draw back sides of teeth */
	gl.Begin(gl.QUADS)
	da = 2.0 * math.Pi / float64(teeth) / 4.0
	for i = 0; i < teeth; i++ {
		angle = float64(i) * 2.0 * math.Pi / float64(teeth)

		gl.Vertex3d(r1*math.Cos(angle+3*da), r1*math.Sin(angle+3*da), -width*0.5)
		gl.Vertex3d(r2*math.Cos(angle+2*da), r2*math.Sin(angle+2*da), -width*0.5)
		gl.Vertex3d(r2*math.Cos(angle+da), r2*math.Sin(angle+da), -width*0.5)
		gl.Vertex3d(r1*math.Cos(angle), r1*math.Sin(angle), -width*0.5)
	}
	gl.End()

	/* draw outward faces of teeth */
	gl.Begin(gl.QUAD_STRIP)
	for i = 0; i < teeth; i++ {
		angle = float64(i) * 2.0 * math.Pi / float64(teeth)

		gl.Vertex3d(r1*math.Cos(angle), r1*math.Sin(angle), width*0.5)
		gl.Vertex3d(r1*math.Cos(angle), r1*math.Sin(angle), -width*0.5)
		u = r2*math.Cos(angle+da) - r1*math.Cos(angle)
		v = r2*math.Sin(angle+da) - r1*math.Sin(angle)
		len = math.Sqrt(u*u + v*v)
		u /= len
		v /= len
		gl.Normal3d(v, -u, 0.0)
		gl.Vertex3d(r2*math.Cos(angle+da), r2*math.Sin(angle+da), width*0.5)
		gl.Vertex3d(r2*math.Cos(angle+da), r2*math.Sin(angle+da), -width*0.5)
		gl.Normal3d(math.Cos(angle), math.Sin(angle), 0.0)
		gl.Vertex3d(r2*math.Cos(angle+2*da), r2*math.Sin(angle+2*da), width*0.5)
		gl.Vertex3d(r2*math.Cos(angle+2*da), r2*math.Sin(angle+2*da), -width*0.5)
		u = r1*math.Cos(angle+3*da) - r2*math.Cos(angle+2*da)
		v = r1*math.Sin(angle+3*da) - r2*math.Sin(angle+2*da)
		gl.Normal3d(v, -u, 0.0)
		gl.Vertex3d(r1*math.Cos(angle+3*da), r1*math.Sin(angle+3*da), width*0.5)
		gl.Vertex3d(r1*math.Cos(angle+3*da), r1*math.Sin(angle+3*da), -width*0.5)
		gl.Normal3d(math.Cos(angle), math.Sin(angle), 0.0)
	}

	gl.Vertex3d(r1*math.Cos(0), r1*math.Sin(0), width*0.5)
	gl.Vertex3d(r1*math.Cos(0), r1*math.Sin(0), -width*0.5)

	gl.End()

	gl.ShadeModel(gl.SMOOTH)

	/* draw inside radius cylinder */
	gl.Begin(gl.QUAD_STRIP)
	for i = 0; i <= teeth; i++ {
		angle = float64(i) * 2.0 * math.Pi / float64(teeth)
		gl.Normal3d(-math.Cos(angle), -math.Sin(angle), 0.0)
		gl.Vertex3d(r0*math.Cos(angle), r0*math.Sin(angle), -width*0.5)
		gl.Vertex3d(r0*math.Cos(angle), r0*math.Sin(angle), width*0.5)
	}
	gl.End()

}
Exemple #18
0
func main() {

	if err := glfw.Init(); err != nil {
		log.Fatal(err.Error())
	}

	if err := glfw.OpenWindow(800, 600, 8, 8, 8, 8, 32, 0, glfw.Windowed); err != nil {
		glfw.Terminate()
		log.Fatal(err.Error())
	}

	glfw.SetWindowTitle("Landscapes")
	glfw.SetSwapInterval(1)

	m := GenerateMap(160, 160, 16)
	m.BuildVertices()

	gl.Enable(gl.LIGHT0)
	gl.Enable(gl.LIGHTING)
	gl.Lightfv(gl.LIGHT0, gl.POSITION, []float32{0, 1, 0.2, 0})
	gl.Lightfv(gl.LIGHT0, gl.AMBIENT, []float32{0.0, 0.0, 0.0, 1})
	gl.Lightfv(gl.LIGHT0, gl.DIFFUSE, []float32{0.75, 0.75, 0.75, 1})
	gl.Lightfv(gl.LIGHT0, gl.SPECULAR, []float32{1, 1, 1, 1})

	gl.ShadeModel(gl.SMOOTH)
	gl.ClearColor(0.1, 0.05, 0.0, 1.0)

	far := 4096.0
	fov := 60.0

	gl.MatrixMode(gl.PROJECTION)
	gl.LoadIdentity()
	glu.Perspective(fov, 800.0/600, 1.0, far)
	gl.MatrixMode(gl.MODELVIEW)

	rot := float32(0.0)

	for glfw.WindowParam(glfw.Opened) == 1 {

		rot += 0.125

		gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

		gl.LoadIdentity()

		gl.Enable(gl.DEPTH_TEST)
		gl.DepthFunc(gl.LEQUAL)

		cx := float32(m.width*m.gridSize) * 0.5
		cy := float32(m.maxHeight) * 0.15
		cz := float32(m.depth*m.gridSize) * 0.5

		gl.Translatef(0, 0, -2000)
		gl.Rotatef(30, 1, 0, 0)
		gl.Rotatef(rot, 0, 1, 0)
		gl.Translatef(-cx, -cy, -cz)

		m.Draw()
		glfw.SwapBuffers()
	}

	glfw.Terminate()

}
Exemple #19
0
func main() {
	var err error
	if err = glfw.Init(); err != nil {
		fmt.Fprintf(os.Stderr, "[e] %v\n", err)
		return
	}

	defer glfw.Terminate()

	w, h := 1980, 1080
	// w, h := 1280, 768
	if err = glfw.OpenWindow(w, h, 8, 8, 8, 16, 0, 32, glfw.Fullscreen); err != nil {
		fmt.Fprintf(os.Stderr, "[e] %v\n", err)
		return
	}

	defer glfw.CloseWindow()

	glfw.SetSwapInterval(1)
	glfw.SetWindowTitle("Debris")

	quadric = glu.NewQuadric()

	gl.Enable(gl.CULL_FACE)

	gl.Enable(gl.DEPTH_TEST)
	gl.DepthFunc(gl.LEQUAL)

	gl.Enable(gl.NORMALIZE)

	gl.Enable(gl.BLEND)
	gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)

	gl.ShadeModel(gl.SMOOTH)
	gl.Enable(gl.LIGHTING)

	var (
		ambient        = []float32{0.1, 0.3, 0.6, 1}
		diffuse        = []float32{1, 1, 0.5, 1}
		specular       = []float32{0.4, 0.4, 0.4, 1}
		light_position = []float32{1, 0, 0, 0}

		// mat_specular  []float32 = []float32{1, 1, 0.5, 1}
		mat_specular  = []float32{1, 1, 0.75, 1}
		mat_shininess = float32(120)
		// light_position []float32 = []float32{0.0, 0.0, 1.0, 0.0}
	)

	const (
		fov               = 1.1 // degrees
		znear             = 145
		zfar              = 155
		camera_z_offset   = -150
		camera_x_rotation = 0 // degrees
		// camera_x_rotation = 20 // degrees

		starfield_fov = 45

		faces        = 1000
		earth_radius = 1
	)

	gl.Lightfv(gl.LIGHT1, gl.AMBIENT, ambient)
	gl.Lightfv(gl.LIGHT1, gl.DIFFUSE, diffuse)
	gl.Lightfv(gl.LIGHT1, gl.SPECULAR, specular)
	gl.Lightfv(gl.LIGHT1, gl.POSITION, light_position)
	gl.Enable(gl.LIGHT1)

	mat_emission := []float32{0, 0, 0.1, 1}
	gl.Materialfv(gl.FRONT_AND_BACK, gl.EMISSION, mat_emission)
	gl.Materialfv(gl.FRONT_AND_BACK, gl.SPECULAR, mat_specular)
	gl.Materialf(gl.FRONT_AND_BACK, gl.SHININESS, mat_shininess)

	gl.ClearColor(0.02, 0.02, 0.02, 1)
	gl.ClearDepth(1)
	gl.ClearStencil(0)
	gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

	b := createBuffer()

	planetoids := []*Planetoid{}
	for i := 0; i < 1000; i++ {
		p := &Planetoid{
			apogee:  1.2 + rand.Float64()*0.7,
			perigee: 1.5,
			// inclination: 45,
			inclination: rand.Float64()*20 - 10,
			// inclination: 0,
			phase0:      rand.Float64() * 360,
			rising_node: rand.Float64() * 10,
			phase:       0,
			// radius:      rand.Float32()*0.05 + 0.01, //float32(r),
			radius: rand.Float32()*0.0125 + 0.005, //float32(r),
			// quadric:     glu.NewQuadric(),
			circle: b,
		}
		planetoids = append(planetoids, p)
	}

	// Initial projection matrix:

	var aspect float64

	glfw.SetWindowSizeCallback(func(w, h int) {
		gl.Viewport(0, 0, w, h)

		gl.MatrixMode(gl.PROJECTION)
		gl.LoadIdentity()
		aspect = float64(w) / float64(h)
		glu.Perspective(fov, aspect, znear, zfar)
	})

	d := float64(0)

	wireframe := false
	atmosphere := false
	polar := false
	rotating := false
	front := false
	earth := true
	cone := true
	shadowing := true
	tilt := false
	running := true

	glfw.SetKeyCallback(func(key, state int) {
		if state != glfw.KeyPress {
			// Don't act on key coming up
			return
		}

		switch key {
		case 'A':
			atmosphere = !atmosphere
		case 'C':
			cone = !cone
		case 'E':
			earth = !earth
		case 'R':
			rotating = !rotating
		case 'F':
			front = !front
			if front {
				gl.FrontFace(gl.CW)
			} else {
				gl.FrontFace(gl.CCW)
			}
		case 'S':
			shadowing = !shadowing
		case 'T':
			tilt = !tilt
		case 'W':
			wireframe = !wireframe
			method := gl.GLenum(gl.FILL)
			if wireframe {
				method = gl.LINE
			}
			gl.PolygonMode(gl.FRONT_AND_BACK, method)

		case glfw.KeyF2:
			println("Screenshot captured")
			// glh.CaptureToPng("screenshot.png")

			w, h := glh.GetViewportWH()
			im := image.NewRGBA(image.Rect(0, 0, w, h))
			glh.ClearAlpha(1)
			gl.Flush()
			glh.CaptureRGBA(im)

			go func() {
				fd, err := os.Create("screenshot.png")
				if err != nil {
					panic("Unable to open file")
				}
				defer fd.Close()

				png.Encode(fd, im)
			}()

		case 'Q', glfw.KeyEsc:
			running = !running

		case glfw.KeySpace:
			polar = !polar
		}
	})

	_ = rand.Float64

	stars := glh.NewMeshBuffer(
		glh.RenderArrays,
		glh.NewPositionAttr(3, gl.DOUBLE, gl.STATIC_DRAW),
		glh.NewColorAttr(3, gl.DOUBLE, gl.STATIC_DRAW))

	const Nstars = 50000
	points := make([]float64, 3*Nstars)
	colors := make([]float64, 3*Nstars)

	for i := 0; i < Nstars; i++ {
		const R = 1

		phi := rand.Float64() * 2 * math.Pi
		z := R * (2*rand.Float64() - 1)
		theta := math.Asin(z / R)

		points[i*3+0] = R * math.Cos(theta) * math.Cos(phi)
		points[i*3+1] = R * math.Cos(theta) * math.Sin(phi)
		points[i*3+2] = z

		const r = 0.8
		v := rand.Float64()*r + (1 - r)
		colors[i*3+0] = v
		colors[i*3+1] = v
		colors[i*3+2] = v
	}

	stars.Add(points, colors)

	render_stars := func() {
		glh.With(glh.Attrib{gl.DEPTH_BUFFER_BIT | gl.ENABLE_BIT}, func() {
			gl.Disable(gl.LIGHTING)
			gl.PointSize(1)
			gl.Color4f(1, 1, 1, 1)

			gl.Disable(gl.DEPTH_TEST)
			gl.DepthMask(false)

			stars.Render(gl.POINTS)
		})
	}

	render_scene := func() {

		// Update light position (sensitive to current modelview matrix)
		gl.Lightfv(gl.LIGHT1, gl.POSITION, light_position)
		gl.Lightfv(gl.LIGHT2, gl.POSITION, light_position)

		if earth {
			Sphere(earth_radius, faces)
		}

		unlit_points := glh.Compound(glh.Disable(gl.LIGHTING), glh.Primitive{gl.POINTS})
		glh.With(unlit_points, func() {
			gl.Vertex3d(1, 0, 0)
		})

		for _, p := range planetoids {
			const dt = 0.1 // TODO: Frame update
			p.Render(dt)
		}

		glh.With(glh.Disable(gl.LIGHTING), func() {
			// Atmosphere
			gl.Color4f(0.25, 0.25, 1, 0.1)

			if atmosphere && earth {
				Sphere(earth_radius*1.025, 100)
			}

			gl.PointSize(10)

			glh.With(glh.Primitive{gl.POINTS}, func() {
				gl.Color4f(1.75, 0.75, 0.75, 1)
				gl.Vertex3d(-1.04, 0, 0)
			})
		})

	}

	render_shadow_volume := func() {

		glh.With(glh.Attrib{
			gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.ENABLE_BIT |
				gl.POLYGON_BIT | gl.STENCIL_BUFFER_BIT,
		}, func() {

			gl.Disable(gl.LIGHTING)

			if shadowing {
				// gl.Disable(gl.DEPTH_TEST)
				gl.DepthMask(false)
				gl.DepthFunc(gl.LEQUAL)

				gl.Enable(gl.STENCIL_TEST)
				gl.ColorMask(false, false, false, false)
				gl.StencilFunc(gl.ALWAYS, 1, 0xffffffff)
			}

			shadow_volume := func() {
				const sv_length = 2
				const sv_granularity = 100
				const sv_radius = earth_radius * 1.001

				// Shadow cone
				glh.With(glh.Matrix{gl.MODELVIEW}, func() {
					gl.Rotatef(90, 1, 0, 0)
					gl.Rotatef(90, 0, -1, 0)
					gl.Color4f(0.5, 0.5, 0.5, 1)
					glu.Cylinder(quadric, sv_radius, sv_radius*1.05,
						sv_length, sv_granularity, 1)

					glu.Disk(quadric, 0, sv_radius, sv_granularity, 1)

					glh.With(glh.Matrix{gl.MODELVIEW}, func() {
						gl.Translated(0, 0, sv_length)
						glu.Disk(quadric, 0, sv_radius*1.05, sv_granularity, 1)
					})
				})

				for _, p := range planetoids {
					p.RenderShadowVolume()
				}

			}

			if cone {
				gl.FrontFace(gl.CCW)
				gl.StencilOp(gl.KEEP, gl.KEEP, gl.INCR)

				shadow_volume()

				gl.FrontFace(gl.CW)
				gl.StencilOp(gl.KEEP, gl.KEEP, gl.DECR)

				shadow_volume()
			}

			if shadowing {
				gl.StencilFunc(gl.NOTEQUAL, 0, 0xffffffff)
				gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP)

				gl.ColorMask(true, true, true, true)
				// gl.Disable(gl.STENCIL_TEST)

				gl.Disable(gl.DEPTH_TEST)

				gl.FrontFace(gl.CCW)
				// gl.Color4f(1, 0, 0, 0.75)
				gl.Color4f(0, 0, 0, 0.75)
				// gl.Color4f(1, 1, 1, 0.75)

				gl.LoadIdentity()
				gl.Translated(0, 0, camera_z_offset)
				// TODO: Figure out why this doesn't draw over the whole screen
				glh.With(glh.Disable(gl.LIGHTING), func() {
					glh.DrawQuadd(-10, -10, 20, 20)
				})

				// gl.FrontFace(gl.CW)
				// gl.Enable(gl.LIGHTING)
				// gl.Disable(gl.LIGHT1)
				// render_scene()
				// gl.Enable(gl.LIGHT1)
			}
		})
	}
	_ = render_stars

	for running {
		running = glfw.WindowParam(glfw.Opened) == 1

		glfw.SwapBuffers()

		gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)

		rotation := func() {
			if tilt {
				gl.Rotated(20, 1, 0, 0)
			}

			if polar {
				gl.Rotated(90, 1, 0, 0)
			}

			gl.Rotated(d, 0, -1, 0)
		}

		// Star field

		glh.With(glh.Matrix{gl.PROJECTION}, func() {
			gl.LoadIdentity()
			glu.Perspective(starfield_fov, aspect, 0, 1)

			glh.With(glh.Matrix{gl.MODELVIEW}, func() {
				gl.LoadIdentity()
				rotation()
				render_stars()
			})
		})

		gl.MatrixMode(gl.MODELVIEW)
		gl.LoadIdentity()
		gl.Translated(0, 0, camera_z_offset)

		rotation()
		if rotating {
			d += 0.2
		}

		_ = render_scene
		render_scene()

		_ = render_shadow_volume
		render_shadow_volume()
	}
}