Esempio n. 1
0
func OpenWindow(width, height int, caption string) *glfw.Window {
	// OpenGL haluaa että sitä käytetään aina samasta threadista
	// muuten tulee satunnaisia segfaultteja
	runtime.LockOSThread()

	glfw.Init()

	// luodaan ikkuna
	w, err := glfw.CreateWindow(width, height, caption, nil, nil)
	if err != nil {
		log.Fatal(err)
	}
	w.MakeContextCurrent()

	gl.Init()

	// Jotta painalluksista kerrottaisiin vaikka ne olisivat jo päättyneet
	w.SetInputMode(glfw.StickyKeys, glfw.True)
	w.SetInputMode(glfw.StickyMouseButtons, glfw.True)

	// läpinäkyvyys päälle (non-premultiplied alpha)
	gl.Enable(gl.BLEND)
	gl.BlendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD)
	gl.BlendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ZERO)

	return w
}
func (ps *ParticleSystem) DoStep(gs *gamestate.GameState) {
	ps.TransformProg.Use()
	ps.VaoTff1.Bind()

	gl.Enable(gl.RASTERIZER_DISCARD)
	defer gl.Disable(gl.RASTERIZER_DISCARD)

	// ps.Data1.Bind(gl.ARRAY_BUFFER)
	// SetAttribPointers(&ps.TransformLoc, &ParticleVertex{}, false)

	//var orientation mgl.Quat = gs.Player.Camera.Orientation
	var model mgl.Mat4 = gs.Camera.Model()
	pPos := model.Mul4x1(mgl.Vec4{1, -1, 0, 1})
	ps.TransformLoc.Origin.Uniform3f(pPos[0], pPos[1], pPos[2])
	dir := model.Mul4x1(mgl.Vec4{0, 0, 100, 0})
	ps.TransformLoc.Dir.Uniform3f(dir[0], dir[1], dir[2])

	ps.Data2.BindBufferBase(gl.TRANSFORM_FEEDBACK_BUFFER, 0)

	gl.BeginTransformFeedback(gl.POINTS)
	gl.DrawArrays(gl.POINTS, 0, ps.NumParticles)
	gl.EndTransformFeedback()

	ps.Data1, ps.Data2 = ps.Data2, ps.Data1
	ps.VaoRender1, ps.VaoRender2 = ps.VaoRender2, ps.VaoRender1
	ps.VaoTff1, ps.VaoTff2 = ps.VaoTff2, ps.VaoTff1
}
Esempio n. 3
0
func NewGameState(window *sdl.Window, world *World) (gamestate *GameState) {
	gl.ClearColor(0., 0., 0.4, 0.0)

	gl.Enable(gl.DEPTH_TEST)

	bar := tw.NewBar("TweakBar")

	gamestate = &GameState{
		Window:  window,
		Camera:  nil,
		Bar:     bar,
		World:   world,
		Fps:     0,
		Options: settings.BoolOptions{},
	}

	opt := &gamestate.Options
	opt.Load()
	gamestate.Camera = gamestate.World.Player.GetCamera()

	tw.Define(" GLOBAL help='This example shows how to integrate AntTweakBar with SDL2 and OpenGL.' ")
	bar.AddVarRO("fps", tw.TYPE_FLOAT, unsafe.Pointer(&gamestate.Fps), "")
	opt.CreateGui(bar)

	for i, portal := range gamestate.World.KdTree {
		ptr := &(portal.(*Portal).Orientation)
		bar.AddVarRW(fmt.Sprintf("Rotation %d", i), tw.TYPE_QUAT4F, unsafe.Pointer(ptr), "")
	}

	//window.GetSize(w, h)
	w, h := window.GetSize()
	tw.WindowSize(w, h)

	return
}
Esempio n. 4
0
func (v *Video) 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)

	v.prog = createProgram(vertShaderSrcDef, fragShaderSrcDef)
	posAttrib := v.prog.GetAttribLocation("vPosition")
	texCoordAttr := v.prog.GetAttribLocation("vTexCoord")
	v.textureUni = v.prog.GetAttribLocation("texture")

	v.texture = gl.GenTexture()
	gl.ActiveTexture(gl.TEXTURE0)
	v.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)

	v.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))
}
Esempio n. 5
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
}
func (this *WorldRenderer) render(ww *gamestate.World, options *settings.BoolOptions, viewport Viewport, recursion int, srcPortal *gamestate.Portal) {

	this.Framebuffer[recursion].Bind()
	defer this.Framebuffer[recursion].Unbind()

	gl.Clear(gl.DEPTH_BUFFER_BIT)

	camera := gamestate.NewCameraFromMat4(this.View)
	Rot2D := camera.Rotation2D()

	gl.CullFace(gl.BACK)

	time := float64(sdl.GetTicks()) / 1000

	if options.Wireframe {
		gl.PolygonMode(gl.FRONT_AND_BACK, gl.LINE)
	} else {
		gl.PolygonMode(gl.FRONT_AND_BACK, gl.FILL)
	}

	if options.Skybox {
		gl.Disable(gl.DEPTH_TEST)
		this.SkyboxRenderer.Render(this.Skybox, this.Proj, this.View, this.ClippingPlane_ws, nil)
		gl.Enable(gl.DEPTH_TEST)
	}

	gl.Enable(gl.CULL_FACE)

	if recursion != 0 {
		gl.Enable(gl.CLIP_DISTANCE0)
		defer gl.Disable(gl.CLIP_DISTANCE0)
	}

	for _, entity := range ww.ExampleObjects {
		this.MeshRenderer.Render(entity, this.Proj, this.View, this.ClippingPlane_ws, nil)
	}

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

	gl.Disable(gl.CULL_FACE)

	if options.WorldRender {
		this.HeightMapRenderer.Render(ww.HeightMap, this.Proj, this.View, this.ClippingPlane_ws, nil)
	}
	PlayerPos := ww.Player.Position()
	ww.Water.Height = PlayerPos[2] - 15
	if options.WaterRender {
		this.WaterRendererA.Render(ww.Water, this.Proj, this.View, this.ClippingPlane_ws, WaterRenderUniforms{time, PlayerPos})
	}
	if options.WaterNormals {
		this.WaterRendererB.Render(ww.Water, this.Proj, this.View, this.ClippingPlane_ws, WaterRenderUniforms{time, PlayerPos})
	}

	gl.Disable(gl.CULL_FACE)

	gl.Disable(gl.BLEND)
	if options.TreeRender {
		this.TreeRenderer.Render(ww.Trees, this.Proj, this.View, this.ClippingPlane_ws, Rot2D)
	}

	gl.Enable(gl.BLEND)
	gl.BlendFunc(gl.SRC_ALPHA, gl.ONE)
	if options.ParticleRender {
		this.ParticleSystem.Render(this.Proj, this.View, this.ClippingPlane_ws)
	}

	gl.Disable(gl.BLEND)

	boxVertices := (*gamestate.TriangleMesh)(gamestate.QuadMesh()).MakeBoxVertices()

	pv := this.Proj.Mul4(this.View)

	// calculating nearest portal
	pos4f := this.View.Inv().Mul4x1(mgl.Vec4{0, 0, 0, 1})
	nearestPortal := ww.NearestPortal(pos4f)

	// draw  all portals except the nearest and the portal that we are looking throug
	for _, portal := range ww.Portals {
		// do not draw the nearest portal or the portal behind the source portal if available
		if (nearestPortal != portal) && (srcPortal == nil || srcPortal.Target != portal) {
			gl.Enable(gl.DEPTH_CLAMP)
			additionalUniforms := map[string]int{"Image": 7}
			this.PortalRenderer.Render(portal, this.Proj, this.View, this.ClippingPlane_ws, additionalUniforms)
		}
	}

	gl.Disable(gl.BLEND)
	gl.Disable(gl.CULL_FACE)

	if options.DebugLines {

		if options.DepthTestDebugLines {
			gl.Disable(gl.DEPTH_TEST)
		}
		this.DebugRenderer.Render(this.Proj, this.View)
		gl.Enable(gl.DEPTH_TEST)
	}

	// draw
	if recursion < this.MaxRecursion {
		portal := nearestPortal
		pos := portal.Position
		rotation := portal.Orientation.Mat4()
		Model := mgl.Translate3D(pos[0], pos[1], pos[2]).Mul4(rotation)

		pvm := pv.Mul4(Model)
		meshMin := mgl.Vec4{math.MaxFloat32, math.MaxFloat32, math.MaxFloat32, math.MaxFloat32}
		meshMax := mgl.Vec4{-math.MaxFloat32, -math.MaxFloat32, -math.MaxFloat32, -math.MaxFloat32}
		for _, v := range boxVertices {
			v = pvm.Mul4x1(v)
			v = v.Mul(1 / v[3])
			meshMin = gamestate.Min(meshMin, v)
			meshMax = gamestate.Max(meshMax, v)
		}

		// at least partially visible
		if -1 < meshMax[0] && meshMin[0] < 1 &&
			-1 < meshMax[1] && meshMin[1] < 1 &&
			-1 < meshMax[2] && meshMin[2] < 1 {

			p1x, p1y := viewport.ToPixel(meshMin.Vec2())
			p2x, p2y := viewport.ToPixel(meshMax.Vec2())
			pw, ph := p2x-p1x, p2y-p1y

			// do scissoring only when all vertices are in front of the camera
			scissor := meshMax[2] < 1
			scissor = scissor && (p1x != 0 || p1y != 0 || pw != viewport.W-1 || ph != viewport.H-1)

			if scissor {
				gl.Enable(gl.SCISSOR_TEST)
				gl.Scissor(p1x, p1y, pw, ph)
			}

			// omit rendering when portal is not in frustum at all
			// calculation View matrix that shows the target portal from the same angle as view shows the source portal

			//pos2 := portal.Target.Position
			Model2 := portal.Target.Model()
			// model matrix, so that portal 1 in camera 1 looks identical to portal 2 in camera
			oldView := this.View
			this.View = this.View.Mul4(Model).Mul4(Model2.Inv())

			normal_os := portal.Target.Normal
			normal_ws := Model.Mul4x1(normal_os)
			view_dir := helpers.HomogenDiff(portal.Position, camera.Position)
			sign := view_dir.Dot(normal_ws)

			oldClippingPlane := this.ClippingPlane_ws
			this.ClippingPlane_ws = portal.Target.ClippingPlane(sign > 0)

			this.render(ww, options, viewport, recursion+1, nearestPortal)
			this.ClippingPlane_ws = oldClippingPlane
			this.View = oldView

			gl.ActiveTexture(gl.TEXTURE0)
			this.Framebuffer[recursion+1].RenderTexture.Bind(gl.TEXTURE_RECTANGLE)

			if scissor {
				//gl.Scissor(0, 0, w, h)
				gl.Disable(gl.SCISSOR_TEST)
			}
			this.Framebuffer[recursion].Bind()
			gl.Enable(gl.DEPTH_CLAMP)
			additionalUniforms := map[string]int{"Image": 0}
			this.PortalRenderer.Render(nearestPortal, this.Proj, this.View, this.ClippingPlane_ws, additionalUniforms)
		}
	}
}
Esempio n. 7
0
func main() {
	glfw.SetErrorCallback(errorCallback)
	// lock glfw/gl calls to a single thread
	runtime.LockOSThread()
	runtime.GOMAXPROCS(8) // Render, read commands, send input, extra for file loading, etc

	if !glfw.Init() {
		panic("Could not init glfw!")
	}

	defer glfw.Terminate()

	glfw.WindowHint(glfw.ContextVersionMajor, 3)
	glfw.WindowHint(glfw.ContextVersionMinor, 3)
	glfw.WindowHint(glfw.OpenglForwardCompatible, glfw.True)
	glfw.WindowHint(glfw.OpenglProfile, glfw.OpenglCoreProfile)

	window, err := glfw.CreateWindow(800, 600, "Example", nil, nil)
	if err != nil {
		panic(err)
	}

	window.SetFramebufferSizeCallback(func(w *glfw.Window, width, height int) {
		fmt.Printf("Framebuffer size is now %vx%v\n", width, height)
		// Keep aspect ratio from camwidth/camheight
		camRatio := camWidth / camHeight
		bufRatio := float32(width) / float32(height)
		var newWidth, newHeight float32

		switch {
		case camRatio > bufRatio:
			newHeight = float32(width) / camRatio
			newWidth = float32(width)
		case bufRatio > camRatio:
			newWidth = float32(height) * camRatio
			newHeight = float32(height)
		}

		fmt.Printf("Viewport size is now %vx%v; cam ratio is %v; viewport ratio is %v;\n", newWidth, newHeight, camRatio, newWidth/newHeight)

		gl.Viewport((width-int(newWidth))/2, (height-int(newHeight))/2, int(newWidth), int(newHeight))
	})

	defer window.Destroy()

	window.MakeContextCurrent()
	glfw.SwapInterval(1)

	gl.Init()

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

	vao := gl.GenVertexArray()
	vao.Bind()

	vbo := gl.GenBuffer()
	vbo.Bind(gl.ARRAY_BUFFER)

	verticies := []float32{-0.5, 0.5,
		0.5, 0.5,
		0.5, -0.5,
		-0.5, -0.5}

	gl.BufferData(gl.ARRAY_BUFFER, len(verticies)*4, verticies, gl.STATIC_DRAW)

	vertex_shader := gl.CreateShader(gl.VERTEX_SHADER)
	vertex_shader.Source(vertex)
	vertex_shader.Compile()
	fmt.Println(vertex_shader.GetInfoLog())
	defer vertex_shader.Delete()

	fragment_shader := gl.CreateShader(gl.FRAGMENT_SHADER)
	fragment_shader.Source(fragment)
	fragment_shader.Compile()
	fmt.Println(fragment_shader.GetInfoLog())
	defer fragment_shader.Delete()

	program := gl.CreateProgram()
	program.AttachShader(vertex_shader)
	program.AttachShader(fragment_shader)

	program.BindFragDataLocation(0, "outColor")
	program.Link()
	program.Use()
	defer program.Delete()

	positionAttrib := program.GetAttribLocation("position")
	positionAttrib.AttribPointer(2, gl.FLOAT, false, 0, nil)
	positionAttrib.EnableArray()
	defer positionAttrib.DisableArray()

	modelMat := program.GetUniformLocation("modelView")
	projMat := program.GetUniformLocation("projection")
	spriteSize := program.GetUniformLocation("size")

	cmd := exec.Command(os.Args[1], os.Args[2:]...)
	stdoutReader, stdoutWriter := io.Pipe()
	cmd.Stdout = stdoutWriter
	input := bufio.NewReader(stdoutReader)

	stdinReader, stdinWriter := io.Pipe()
	cmd.Stdin = stdinReader

	stderr, err := cmd.StderrPipe()
	chkErr(err)

	go io.Copy(os.Stderr, stderr)

	err = cmd.Start()
	chkErr(err)

	window.SetKeyCallback(handleKey)

	go func() {
		runtime.LockOSThread()
		for !window.ShouldClose() {
			sendInput(stdinWriter)
			//fmt.Fprintf(stdinWriter, "T %v\n", time.Now())
			<-ticks
			readCommands(input)
		}
	}()

	frameCnt := 0
	queueDepth := 0
	then := time.Now()

	for !window.ShouldClose() {
		frameCnt++
		queueDepth += len(commandBus)
		if frameCnt%120 == 0 {
			fmt.Printf("Queue depth: %v. Render time: %v. Decode time: %v.\n", queueDepth/120, time.Since(then)/120, decodeTime/time.Duration(decodes))
			queueDepth = 0
			then = time.Now()
			decodeTime = time.Duration(0)
			decodes = 0
		}

		for len(commandBus) > 0 {
			(<-commandBus)()
		}

		halfwidth := camWidth / 2.0
		halfheight := camHeight / 2.0
		projection := mathgl.Ortho2D(camera.x-halfwidth, camera.x+halfwidth, camera.y+halfheight, camera.y-halfheight)
		projection = mathgl.Scale3D(camera.sx, camera.sy, 1).Mul4(projection)
		projection = mathgl.HomogRotate3DZ(camera.rot).Mul4(projection)

		projMat.UniformMatrix4f(false, (*[16]float32)(&projection))

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

		for _, sprite := range sprites {
			sMat := mathgl.Scale3D(sprite.sx, sprite.sy, 1)
			sMat = mathgl.HomogRotate3DZ(sprite.rot).Mul4(sMat)
			sMat = mathgl.Translate3D(sprite.x, sprite.y, sprite.z).Mul4(sMat)

			// temp hack bank in
			sprite.bank = 1

			sMap := findSMap(sprite.smap)

			spriteSize.Uniform2f(float32(sMap.getWidth()*sprite.cellwidth), float32(sMap.getHeight()*sprite.cellheight))

			modelMat.UniformMatrix4f(false, (*[16]float32)(&sMat))
			gl.DrawArrays(gl.TRIANGLE_FAN, 0, 4)
		}

		window.SwapBuffers()
		glfw.PollEvents()

		if window.GetKey(glfw.KeyEscape) == glfw.Press {
			window.SetShouldClose(true)
		}
	}
}
Esempio n. 8
0
func NewTextures(heightMap *gamestate.HeightMap) *Textures {
	textures := make([]gl.Texture, 10)
	gl.GenTextures(textures)

	gl.ActiveTexture(gl.TEXTURE0 + constants.TextureGround)
	textures[1].Bind(gl.TEXTURE_2D)
	helpers.LoadTexture2DWatched("textures/GravelCobbleS.jpg")
	gl.GenerateMipmap(gl.TEXTURE_2D)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_R, gl.REPEAT)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)

	gl.ActiveTexture(gl.TEXTURE0 + constants.TextureCliffs)
	textures[2].Bind(gl.TEXTURE_2D)
	helpers.LoadTexture2DWatched("textures/Cliffs0149_18_S.png")
	gl.GenerateMipmap(gl.TEXTURE_2D)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_R, gl.REPEAT)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)

	gl.ActiveTexture(gl.TEXTURE0 + constants.TextureColorBand)
	textures[3].Bind(gl.TEXTURE_1D)
	helpers.LoadTexture1DWatched("textures/gradient.png")
	gl.TexParameteri(gl.TEXTURE_1D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
	gl.TexParameteri(gl.TEXTURE_1D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)

	gl.ActiveTexture(gl.TEXTURE0 + constants.TextureHeightMap)
	textures[4].Bind(gl.TEXTURE_2D)
	gl.TexImage2D(gl.TEXTURE_2D, 0, gl.R16, heightMap.W, heightMap.H, 0, gl.RED, gl.FLOAT, heightMap.TexturePixels())
	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.REPEAT)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)

	gl.ActiveTexture(gl.TEXTURE0 + constants.TextureTree)
	textures[5].Bind(gl.TEXTURE_2D)
	helpers.LoadTexture2DWatched("textures/palme.png")
	gl.GenerateMipmap(gl.TEXTURE_2D)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_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.ActiveTexture(gl.TEXTURE0 + constants.TextureFireBall)
	textures[6].Bind(gl.TEXTURE_2D)
	helpers.LoadTexture2DWatched("textures/fireball.png")
	gl.GenerateMipmap(gl.TEXTURE_2D)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_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.ActiveTexture(gl.TEXTURE0 + constants.TextureSkybox)
	textures[7].Bind(gl.TEXTURE_CUBE_MAP)
	helpers.LoadTextureCubeWatched("textures/Above_The_Sea.jpg")
	gl.GenerateMipmap(gl.TEXTURE_CUBE_MAP)
	gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR)
	gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
	//gl.TexParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_R, gl.CLAMP_TO_EDGE)
	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.Enable(gl.TEXTURE_CUBE_MAP_SEAMLESS)

	ttf.Init()
	defer ttf.Quit()
	font, _ := ttf.OpenFont("fonts/Symbola.ttf", 64)
	color := sdl.Color{255, 255, 255, 255}
	surface, _ := font.RenderUTF8_Blended("Bla", color)
	defer surface.Free()
	gl.ActiveTexture(gl.TEXTURE0 + constants.TextureFont)
	textures[8].Bind(gl.TEXTURE_2D)
	gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int(surface.W), int(surface.H), 0, gl.RGBA, gl.UNSIGNED_BYTE, uintptr(surface.Data()))
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)

	gl.ActiveTexture(gl.TEXTURE0)
	return &Textures{textures}
}