Example #1
0
func (c *glContext) fill(call *glCall) {
	pathSentinel := call.pathOffset + call.pathCount

	// Draw shapes
	gl.Enable(gl.STENCIL_TEST)
	c.setStencilMask(0xff)
	c.setStencilFunc(gl.ALWAYS, 0x00, 0xff)
	gl.ColorMask(false, false, false, false)

	// set bindpoint for solid loc
	c.setUniforms(call.uniformOffset, 0)
	checkError(c, "fill simple")

	gl.StencilOpSeparate(gl.FRONT, gl.KEEP, gl.KEEP, gl.INCR_WRAP)
	gl.StencilOpSeparate(gl.BACK, gl.KEEP, gl.KEEP, gl.DECR_WRAP)

	gl.Disable(gl.CULL_FACE)
	for i := call.pathOffset; i < pathSentinel; i++ {
		path := &c.paths[i]
		gl.DrawArrays(gl.TRIANGLE_FAN, path.fillOffset, path.fillCount)
	}
	gl.Enable(gl.CULL_FACE)

	// Draw anti-aliased pixels
	gl.ColorMask(true, true, true, true)
	c.setUniforms(call.uniformOffset+1, call.image)

	if c.flags&AntiAlias != 0 {
		c.setStencilFunc(gl.EQUAL, 0x00, 0xff)
		gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP)
		// Draw fringes
		for i := call.pathOffset; i < pathSentinel; i++ {
			path := &c.paths[i]
			gl.DrawArrays(gl.TRIANGLE_STRIP, path.strokeOffset, path.strokeCount)
		}
	}

	// Draw fill
	c.setStencilFunc(gl.NOTEQUAL, 0x00, 0xff)
	gl.StencilOp(gl.ZERO, gl.ZERO, gl.ZERO)
	gl.DrawArrays(gl.TRIANGLES, call.triangleOffset, call.triangleCount)

	gl.Disable(gl.STENCIL_TEST)
}
Example #2
0
func (c *glContext) stroke(call *glCall) {
	paths := c.paths[call.pathOffset : call.pathOffset+call.pathCount]

	if c.flags&StencilStrokes != 0 {
		gl.Enable(gl.STENCIL_TEST)
		c.setStencilMask(0xff)

		// Fill the stroke base without overlap
		c.setStencilFunc(gl.EQUAL, 0x00, 0xff)
		gl.StencilOp(gl.KEEP, gl.KEEP, gl.INCR)
		c.setUniforms(call.uniformOffset+1, call.image)
		checkError(c, "stroke fill 0")
		for i := range paths {
			path := &paths[i]
			gl.DrawArrays(gl.TRIANGLE_STRIP, path.strokeOffset, path.strokeCount)
		}

		// Draw anti-aliased pixels.
		c.setUniforms(call.uniformOffset, call.image)
		c.setStencilFunc(gl.EQUAL, 0x00, 0xff)
		gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP)
		for i := range paths {
			path := &paths[i]
			gl.DrawArrays(gl.TRIANGLE_STRIP, path.strokeOffset, path.strokeCount)
		}

		// Clear stencil buffer.
		gl.ColorMask(false, false, false, false)
		c.setStencilFunc(gl.ALWAYS, 0x00, 0xff)
		gl.StencilOp(gl.ZERO, gl.ZERO, gl.ZERO)
		checkError(c, "stroke fill 1")
		for i := range paths {
			path := &paths[i]
			gl.DrawArrays(gl.TRIANGLE_STRIP, path.strokeOffset, path.strokeCount)
		}
		gl.ColorMask(true, true, true, true)
		gl.Disable(gl.STENCIL_TEST)
	} else {
		c.setUniforms(call.uniformOffset, call.image)
		checkError(c, "stroke fill")
		for i := range paths {
			path := &paths[i]
			gl.DrawArrays(gl.TRIANGLE_STRIP, path.strokeOffset, path.strokeCount)
		}
	}
}
Example #3
0
func (b *blitter) commitGlyphs(ctx *context) {
	tc := b.glyphBatch.GlyphPage
	if tc == nil {
		return
	}
	sw, sh := tc.sizePixels.WH()
	dw, dh := ctx.sizePixels.WH()

	mSrc := math.CreateMat3(
		1.0/float32(sw), 0, 0,
		0, 1.0/float32(sh), 0,
		0.0, 0.0, 1,
	)
	mDst := math.CreateMat3(
		+2.0/float32(dw), 0, 0,
		0, -2.0/float32(dh), 0,
		-1.0, +1.0, 1,
	)
	vb := newVertexBuffer(
		newVertexStream("aDst", stFloatVec2, b.glyphBatch.DstRects),
		newVertexStream("aSrc", stFloatVec2, b.glyphBatch.SrcRects),
		newVertexStream("aClp", stFloatVec4, b.glyphBatch.ClipRects),
		newVertexStream("aCol", stFloatVec4, b.glyphBatch.Colors),
	)
	ib := newIndexBuffer(ptUshort, b.glyphBatch.Indices)
	s := newShape(vb, ib, dmTriangles)
	gl.Disable(gl.SCISSOR_TEST)
	s.draw(ctx, b.fontShader, uniformBindings{
		"source": tc,
		"mDst":   mDst,
		"mSrc":   mSrc,
	})
	gl.Enable(gl.SCISSOR_TEST)
	s.release()
	b.glyphBatch.GlyphPage = nil
	b.glyphBatch.DstRects = b.glyphBatch.DstRects[:0]
	b.glyphBatch.SrcRects = b.glyphBatch.SrcRects[:0]
	b.glyphBatch.ClipRects = b.glyphBatch.ClipRects[:0]
	b.glyphBatch.Colors = b.glyphBatch.Colors[:0]
	b.glyphBatch.Indices = b.glyphBatch.Indices[:0]
	b.stats.drawCallCount++
}
Example #4
0
func newViewport(driver *driver, width, height int, title string, fullscreen bool) *viewport {
	v := &viewport{
		fullscreen: fullscreen,
		scaling:    1,
		title:      title,
	}

	glfw.DefaultWindowHints()
	glfw.WindowHint(glfw.Samples, 4)
	var monitor *glfw.Monitor
	if fullscreen {
		monitor = glfw.GetPrimaryMonitor()
		if width == 0 || height == 0 {
			vm := monitor.GetVideoMode()
			width, height = vm.Width, vm.Height
		}
	}
	wnd, err := glfw.CreateWindow(width, height, v.title, monitor, nil)
	if err != nil {
		panic(err)
	}
	width, height = wnd.GetSize() // At this time, width and height serve as a "hint" for glfw.CreateWindow, so get actual values from window.

	wnd.MakeContextCurrent()

	v.context = newContext()

	cursorPoint := func(x, y float64) math.Point {
		// HACK: xpos is off by 1 and ypos is off by 3 on OSX.
		// Compensate until real fix is found.
		x -= 1.0
		y -= 3.0
		return math.Point{X: int(x), Y: int(y)}.ScaleS(1 / v.scaling)
	}
	wnd.SetCloseCallback(func(*glfw.Window) {
		v.Close()
	})
	wnd.SetPosCallback(func(w *glfw.Window, x, y int) {
		v.Lock()
		v.position = math.NewPoint(x, y)
		v.Unlock()
	})
	wnd.SetSizeCallback(func(_ *glfw.Window, w, h int) {
		v.Lock()
		v.sizeDipsUnscaled = math.Size{W: w, H: h}
		v.sizeDips = v.sizeDipsUnscaled.ScaleS(1 / v.scaling)
		v.Unlock()
		v.onResize.Fire()
	})
	wnd.SetFramebufferSizeCallback(func(_ *glfw.Window, w, h int) {
		v.Lock()
		v.sizePixels = math.Size{W: w, H: h}
		v.Unlock()
		gl.Viewport(0, 0, w, h)
		gl.ClearColor(kClearColorR, kClearColorG, kClearColorB, 1.0)
		gl.Clear(gl.COLOR_BUFFER_BIT)
	})
	wnd.SetCursorPosCallback(func(w *glfw.Window, x, y float64) {
		p := cursorPoint(w.GetCursorPos())
		v.Lock()
		if v.pendingMouseMoveEvent == nil {
			v.pendingMouseMoveEvent = &gxui.MouseEvent{}
			driver.Call(func() {
				v.Lock()
				ev := *v.pendingMouseMoveEvent
				v.pendingMouseMoveEvent = nil
				v.Unlock()
				v.onMouseMove.Fire(ev)
			})
		}
		v.pendingMouseMoveEvent.Point = p
		v.pendingMouseMoveEvent.State = getMouseState(w)
		v.Unlock()
	})
	wnd.SetCursorEnterCallback(func(w *glfw.Window, entered bool) {
		p := cursorPoint(w.GetCursorPos())
		ev := gxui.MouseEvent{
			Point: p,
		}
		ev.State = getMouseState(w)
		if entered {
			v.onMouseEnter.Fire(ev)
		} else {
			v.onMouseExit.Fire(ev)
		}
	})
	wnd.SetScrollCallback(func(w *glfw.Window, xoff, yoff float64) {
		p := cursorPoint(w.GetCursorPos())
		v.Lock()
		if v.pendingMouseScrollEvent == nil {
			v.pendingMouseScrollEvent = &gxui.MouseEvent{}
			driver.Call(func() {
				v.Lock()
				ev := *v.pendingMouseScrollEvent
				v.pendingMouseScrollEvent = nil
				ev.ScrollX, ev.ScrollY = int(v.scrollAccumX), int(v.scrollAccumY)
				if ev.ScrollX != 0 || ev.ScrollY != 0 {
					v.scrollAccumX -= float64(ev.ScrollX)
					v.scrollAccumY -= float64(ev.ScrollY)
					v.Unlock()
					v.onMouseScroll.Fire(ev)
				} else {
					v.Unlock()
				}
			})
		}
		v.pendingMouseScrollEvent.Point = p
		v.scrollAccumX += xoff * platform.ScrollSpeed
		v.scrollAccumY += yoff * platform.ScrollSpeed
		v.pendingMouseScrollEvent.State = getMouseState(w)
		v.Unlock()
	})
	wnd.SetMouseButtonCallback(func(w *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) {
		p := cursorPoint(w.GetCursorPos())
		ev := gxui.MouseEvent{
			Point:    p,
			Modifier: translateKeyboardModifier(mod),
		}
		ev.Button = translateMouseButton(button)
		ev.State = getMouseState(w)
		if action == glfw.Press {
			v.onMouseDown.Fire(ev)
		} else {
			v.onMouseUp.Fire(ev)
		}
	})
	wnd.SetKeyCallback(func(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
		ev := gxui.KeyboardEvent{
			Key:      translateKeyboardKey(key),
			Modifier: translateKeyboardModifier(mods),
		}
		switch action {
		case glfw.Press:
			v.onKeyDown.Fire(ev)
		case glfw.Release:
			v.onKeyUp.Fire(ev)
		case glfw.Repeat:
			v.onKeyRepeat.Fire(ev)
		}
	})
	wnd.SetCharModsCallback(func(w *glfw.Window, char rune, mods glfw.ModifierKey) {
		if !unicode.IsControl(char) &&
			!unicode.IsGraphic(char) &&
			!unicode.IsLetter(char) &&
			!unicode.IsMark(char) &&
			!unicode.IsNumber(char) &&
			!unicode.IsPunct(char) &&
			!unicode.IsSpace(char) &&
			!unicode.IsSymbol(char) {
			return // Weird unicode character. Ignore
		}

		ev := gxui.KeyStrokeEvent{
			Character: char,
			Modifier:  translateKeyboardModifier(mods),
		}
		v.onKeyStroke.Fire(ev)
	})
	wnd.SetRefreshCallback(func(w *glfw.Window) {
		if v.canvas != nil {
			v.render()
		}
	})

	fw, fh := wnd.GetFramebufferSize()
	posX, posY := wnd.GetPos()

	// Pre-multiplied alpha blending
	gl.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA)
	gl.Enable(gl.BLEND)
	gl.Enable(gl.SCISSOR_TEST)
	gl.Viewport(0, 0, fw, fh)
	gl.Scissor(0, 0, int32(fw), int32(fh))
	gl.ClearColor(kClearColorR, kClearColorG, kClearColorB, 1.0)
	gl.Clear(gl.COLOR_BUFFER_BIT)
	wnd.SwapBuffers()

	v.window = wnd
	v.driver = driver
	v.onClose = driver.createAppEvent(func() {})
	v.onResize = driver.createAppEvent(func() {})
	v.onMouseMove = gxui.CreateEvent(func(gxui.MouseEvent) {})
	v.onMouseEnter = driver.createAppEvent(func(gxui.MouseEvent) {})
	v.onMouseExit = driver.createAppEvent(func(gxui.MouseEvent) {})
	v.onMouseDown = driver.createAppEvent(func(gxui.MouseEvent) {})
	v.onMouseUp = driver.createAppEvent(func(gxui.MouseEvent) {})
	v.onMouseScroll = gxui.CreateEvent(func(gxui.MouseEvent) {})
	v.onKeyDown = driver.createAppEvent(func(gxui.KeyboardEvent) {})
	v.onKeyUp = driver.createAppEvent(func(gxui.KeyboardEvent) {})
	v.onKeyRepeat = driver.createAppEvent(func(gxui.KeyboardEvent) {})
	v.onKeyStroke = driver.createAppEvent(func(gxui.KeyStrokeEvent) {})
	v.onDestroy = driver.createDriverEvent(func() {})
	v.sizeDipsUnscaled = math.Size{W: width, H: height}
	v.sizeDips = v.sizeDipsUnscaled.ScaleS(1 / v.scaling)
	v.sizePixels = math.Size{W: fw, H: fh}
	v.position = math.Point{X: posX, Y: posY}
	return v
}
Example #5
0
func main() {
	err := glfw.Init(gl.ContextWatcher)
	if err != nil {
		panic(err)
	}
	defer glfw.Terminate()

	glfw.WindowHint(glfw.StencilBits, 1)
	glfw.WindowHint(glfw.Samples, 4)

	window, err := glfw.CreateWindow(1000*0.6, 600*0.6, "NanoVGo", nil, nil)
	if err != nil {
		panic(err)
	}
	window.SetKeyCallback(key)
	window.MakeContextCurrent()

	ctx, err := nanovgo.NewContext(0)
	defer ctx.Delete()

	if err != nil {
		panic(err)
	}

	demoData := LoadDemo(ctx)

	glfw.SwapInterval(0)

	fps := perfgraph.NewPerfGraph("Frame Time", "sans")

	for !window.ShouldClose() {
		t, _ := fps.UpdateGraph()

		fbWidth, fbHeight := window.GetFramebufferSize()
		winWidth, winHeight := window.GetSize()
		mx, my := window.GetCursorPos()

		pixelRatio := float32(fbWidth) / float32(winWidth)
		gl.Viewport(0, 0, fbWidth, fbHeight)
		if premult {
			gl.ClearColor(0, 0, 0, 0)
		} else {
			gl.ClearColor(0.3, 0.3, 0.32, 1.0)
		}
		gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)
		gl.Enable(gl.BLEND)
		gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
		gl.Enable(gl.CULL_FACE)
		gl.Disable(gl.DEPTH_TEST)

		ctx.BeginFrame(winWidth, winHeight, pixelRatio)

		demo.RenderDemo(ctx, float32(mx), float32(my), float32(winWidth), float32(winHeight), t, blowup, demoData)
		fps.RenderGraph(ctx, 5, 5)

		ctx.EndFrame()

		gl.Enable(gl.DEPTH_TEST)
		window.SwapBuffers()
		glfw.PollEvents()
	}

	demoData.FreeData(ctx)
}
Example #6
0
func (p *glParams) renderFlush() {
	c := p.context

	if len(c.calls) > 0 {
		gl.UseProgram(c.shader.program)

		gl.BlendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA)
		gl.Enable(gl.CULL_FACE)
		gl.CullFace(gl.BACK)
		gl.FrontFace(gl.CCW)
		gl.Enable(gl.BLEND)
		gl.Disable(gl.DEPTH_TEST)
		gl.Disable(gl.SCISSOR_TEST)
		gl.ColorMask(true, true, true, true)
		gl.StencilMask(0xffffffff)
		gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP)
		gl.StencilFunc(gl.ALWAYS, 0, 0xffffffff)
		gl.ActiveTexture(gl.TEXTURE0)
		gl.BindTexture(gl.TEXTURE_2D, gl.Texture{})
		c.stencilMask = 0xffffffff
		c.stencilFunc = gl.ALWAYS
		c.stencilFuncRef = 0
		c.stencilFuncMask = 0xffffffff

		b := castFloat32ToByte(c.vertexes)
		//dumpLog("vertex:", c.vertexes)
		// Upload vertex data
		gl.BindBuffer(gl.ARRAY_BUFFER, c.vertexBuffer)
		gl.BufferData(gl.ARRAY_BUFFER, b, gl.STREAM_DRAW)
		gl.EnableVertexAttribArray(c.shader.vertexAttrib)
		gl.EnableVertexAttribArray(c.shader.tcoordAttrib)
		gl.VertexAttribPointer(c.shader.vertexAttrib, 2, gl.FLOAT, false, 4*4, 0)
		gl.VertexAttribPointer(c.shader.tcoordAttrib, 2, gl.FLOAT, false, 4*4, 8)

		// Set view and texture just once per frame.
		gl.Uniform1i(c.shader.locations[glnvgLocTEX], 0)
		gl.Uniform2fv(c.shader.locations[glnvgLocVIEWSIZE], c.view[:])

		for i := range c.calls {
			call := &c.calls[i]
			switch call.callType {
			case glnvgFILL:
				c.fill(call)
			case glnvgCONVEXFILL:
				c.convexFill(call)
			case glnvgSTROKE:
				c.stroke(call)
			case glnvgTRIANGLES:
				c.triangles(call)
			}
		}
		gl.DisableVertexAttribArray(c.shader.vertexAttrib)
		gl.DisableVertexAttribArray(c.shader.tcoordAttrib)
		gl.Disable(gl.CULL_FACE)
		gl.BindBuffer(gl.ARRAY_BUFFER, gl.Buffer{})
		gl.UseProgram(gl.Program{})
		c.bindTexture(nil)
	}
	c.vertexes = c.vertexes[:0]
	c.paths = c.paths[:0]
	c.calls = c.calls[:0]
	c.uniforms = c.uniforms[:0]
}