Beispiel #1
0
// Renderer implementation.
// BindTexture makes the texture available on the GPU.
func (gc *opengl) BindTexture(tid *uint32, img image.Image, repeat bool) (err error) {
	if glerr := gl.GetError(); glerr != gl.NO_ERROR {
		log.Printf("opengl:bindTexture need to find and fix prior error %X", glerr)
	}
	if *tid == 0 {
		gl.GenTextures(1, tid)
	}
	gl.BindTexture(gl.TEXTURE_2D, *tid)

	// FUTURE: check if RGBA, or NRGBA are alpha pre-multiplied. The docs say yes
	// for RGBA but the data is from PNG files which are not pre-multiplied
	// and the go png Decode looks like its reading values directly.
	var ptr gl.Pointer
	bounds := img.Bounds()
	width, height := int32(bounds.Dx()), int32(bounds.Dy())
	switch imgType := img.(type) {
	case *image.RGBA:
		i := img.(*image.RGBA)
		ptr = gl.Pointer(&(i.Pix[0]))
	case *image.NRGBA:
		i := img.(*image.NRGBA)
		ptr = gl.Pointer(&(i.Pix[0]))
	default:
		return fmt.Errorf("Unsupported image format %T", imgType)
	}
	gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, ptr)
	gl.GenerateMipmap(gl.TEXTURE_2D)
	gc.setTextureMode(*tid, repeat)
	if glerr := gl.GetError(); glerr != gl.NO_ERROR {
		err = fmt.Errorf("Failed binding texture %d\n", glerr)
	}
	return err
}
Beispiel #2
0
// Render implementation.
// FUTURE: all kinds of possible optimizations that would need to be
//         profiled before implementing.
//           • group by vao to avoid switching vao's.
//           • group by texture to avoid switching textures.
//           • use interleaved vertex data.
//           • uniform buffers http://www.opengl.org/wiki/Uniform_Buffer_Object.
//           • ... lots more possiblities... leave your fav here.
func (gc *opengl) Render(dr Draw) {
	d, ok := dr.(*draw)
	if !ok || d == nil {
		return
	}

	// switch state only if necessary.
	if gc.depthTest != d.depth {
		if d.depth {
			gl.Enable(gl.DEPTH_TEST)
		} else {
			gl.Disable(gl.DEPTH_TEST)
		}
		gc.depthTest = d.depth
	}

	// switch shaders only if necessary.
	if gc.shader != d.shader {
		gl.UseProgram(d.shader)
		gc.shader = d.shader
	}

	// Ask the model to bind its provisioned uniforms.
	// FUTURE: only need to bind uniforms that have changed.
	gc.bindUniforms(d)

	// bind the data buffers and render.
	gl.BindVertexArray(d.vao)
	switch d.mode {
	case LINES:
		gl.PolygonMode(gl.FRONT_AND_BACK, gl.LINE)
		gl.DrawElements(gl.LINES, d.numFaces, gl.UNSIGNED_SHORT, 0)
		gl.PolygonMode(gl.FRONT_AND_BACK, gl.FILL)
	case POINTS:
		gl.Enable(gl.PROGRAM_POINT_SIZE)
		gl.DrawArrays(gl.POINTS, 0, d.numVerts)
		gl.Disable(gl.PROGRAM_POINT_SIZE)
	case TRIANGLES:
		if len(d.texs) > 1 && d.texs[0].fn > 0 {
			// Multiple textures on one model specify which verticies they apply to.
			for _, tex := range d.texs {
				// Use the same texture unit and sampler. Just update which
				// image is being sampled.
				gl.BindTexture(gl.TEXTURE_2D, tex.tid)
				// fn is the number of triangles, 3 indicies per triangle.
				// f0 is the offset in triangles where each triangle has 3 indicies
				//    of 2 bytes (uShort) each.
				gl.DrawElements(gl.TRIANGLES, tex.fn*3, gl.UNSIGNED_SHORT, int64(3*2*tex.f0))
			}
		} else {
			// Single textures are handled with a standard bindUniforms
			gl.DrawElements(gl.TRIANGLES, d.numFaces, gl.UNSIGNED_SHORT, 0)
		}
	}
}
Beispiel #3
0
// BindFrame creates a framebuffer object with an associated texture.
//    http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/
//    http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-16-shadow-mapping/
func (gc *opengl) BindFrame(buf int, fbo, tid, db *uint32) (err error) {
	size := int32(1024)
	gl.GenFramebuffers(1, fbo)
	gl.BindFramebuffer(gl.FRAMEBUFFER, *fbo)

	// Create a texture specifically for the framebuffer.
	gl.GenTextures(1, tid)
	gl.BindTexture(gl.TEXTURE_2D, *tid)
	switch buf {
	case IMAGE_BUFF:
		gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, size, size,
			0, gl.RGBA, gl.UNSIGNED_BYTE, gl.Pointer(nil))
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)

		// Add a depth buffer to mimic the normal framebuffer behaviour for 3D objects.
		gl.GenRenderbuffers(1, db)
		gl.BindRenderbuffer(gl.RENDERBUFFER, *db)
		gl.RenderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT, size, size)
		gl.FramebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, *db)

		// Associate the texture with the framebuffer.
		gl.FramebufferTexture(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, *tid, 0)
		buffType := uint32(gl.COLOR_ATTACHMENT0)
		gl.DrawBuffers(1, &buffType)
	case DEPTH_BUFF:
		gl.TexImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT16, size, size,
			0, gl.DEPTH_COMPONENT, gl.FLOAT, gl.Pointer(nil))
		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)
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_FUNC, gl.LEQUAL)
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_COMPARE_MODE, gl.COMPARE_REF_TO_TEXTURE)

		// Associate the texture with the framebuffer.
		gl.FramebufferTexture(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, *tid, 0)
		gl.DrawBuffer(gl.NONE)
	default:
		return fmt.Errorf("BindFrame unrecognized buffer type.")
	}

	// Report any problems.
	glerr := gl.CheckFramebufferStatus(gl.FRAMEBUFFER)
	if glerr != gl.FRAMEBUFFER_COMPLETE {
		return fmt.Errorf("BindFrame error %X", glerr)
	}
	if glerr := gl.GetError(); glerr != gl.NO_ERROR {
		err = fmt.Errorf("Failed binding framebuffer %X", glerr)
	}
	gl.BindFramebuffer(gl.FRAMEBUFFER, 0) // clean up by resetting to default framebuffer.
	return err
}
Beispiel #4
0
// setTextureMode is used to switch to a repeating
// texture instead of a 1:1 texture mapping.
func (gc *opengl) setTextureMode(tid uint32, repeat bool) {
	gl.BindTexture(gl.TEXTURE_2D, tid)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAX_LEVEL, 7)
	if repeat {
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
		gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
	} else {
		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_MAG_FILTER, gl.LINEAR)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR)
}
Beispiel #5
0
// useTexture makes the given texture the active texture.
func (gc *opengl) useTexture(sampler, texUnit int32, tid uint32) {
	gc.bindUniform(sampler, i1, 1, texUnit)
	gl.ActiveTexture(gl.TEXTURE0 + uint32(texUnit))
	gl.BindTexture(gl.TEXTURE_2D, tid)
}
Beispiel #6
0
// initRender is one time initialization that creates a single VAO
// to display a single ray trace generated texture.
func (rt *rtrace) initRender() {
	rt.verts = []float32{ // four verticies for a quad.
		0, 0, 0,
		4, 0, 0,
		0, 4, 0,
		4, 4, 0,
	}
	rt.faces = []uint8{ // create quad from 2 triangles.
		0, 2, 1,
		1, 2, 3,
	}
	rt.uvs = []float32{ // texture coordinates to sample the image.
		0, 0,
		1, 0,
		0, 1,
		1, 1,
	}

	// Start up OpenGL and create a single vertex array object.
	gl.Init()
	gl.GenVertexArrays(1, &rt.vao)
	gl.BindVertexArray(rt.vao)

	// vertex data.
	var vbuff uint32
	gl.GenBuffers(1, &vbuff)
	gl.BindBuffer(gl.ARRAY_BUFFER, vbuff)
	gl.BufferData(gl.ARRAY_BUFFER, int64(len(rt.verts)*4), gl.Pointer(&(rt.verts[0])), gl.STATIC_DRAW)
	gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0)
	gl.EnableVertexAttribArray(0)

	// faces data.
	var ebuff uint32
	gl.GenBuffers(1, &ebuff)
	gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, ebuff)
	gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, int64(len(rt.faces)), gl.Pointer(&(rt.faces[0])), gl.STATIC_DRAW)

	// texture coordatinates
	var tbuff uint32
	gl.GenBuffers(1, &tbuff)
	gl.BindBuffer(gl.ARRAY_BUFFER, tbuff)
	gl.BufferData(gl.ARRAY_BUFFER, int64(len(rt.uvs)*4), gl.Pointer(&(rt.uvs[0])), gl.STATIC_DRAW)
	var tattr uint32 = 2
	gl.VertexAttribPointer(tattr, 2, gl.FLOAT, false, 0, 0)
	gl.EnableVertexAttribArray(tattr)

	// use ray trace generated texture image.
	bounds := rt.img.Bounds()
	width, height := int32(bounds.Dx()), int32(bounds.Dy())
	ptr := gl.Pointer(&(rt.img.Pix[0]))
	gl.GenTextures(1, &rt.texId)
	gl.BindTexture(gl.TEXTURE_2D, rt.texId)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
	gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, ptr)

	// texture sampling shader.
	loader := load.NewLoader()
	shader := "tuv"
	vsrc, verr := loader.Vsh(shader)
	fsrc, ferr := loader.Fsh(shader)
	if verr != nil || ferr != nil {
		log.Fatalf("Failed to load shaders %s %s\n", verr, ferr)
	}
	rt.shaders = gl.CreateProgram()
	if err := gl.BindProgram(rt.shaders, vsrc, fsrc); err != nil {
		log.Fatalf("Failed to create program: %s\n", err)
	}
	rt.mvpId = gl.GetUniformLocation(rt.shaders, "mvpm")
	rt.tex2D = gl.GetUniformLocation(rt.shaders, "sampler2D")
	rt.mvp = render.NewMvp().Set(lin.NewM4().Ortho(0, 4, 0, 4, 0, 10))

	// set some state that doesn't need to change during drawing.
	gl.ClearColor(0.0, 0.0, 0.0, 1.0)
}