コード例 #1
0
ファイル: text_line.go プロジェクト: losinggeneration/glop
func (w *TextLine) preDraw(region Region) {
	if !w.initted {
		w.initted = true
		w.texture = gl.GenTexture()
		w.text = w.next_text
		w.figureDims()
	}
	if w.text != w.next_text {
		w.text = w.next_text
		w.figureDims()
	}

	gl.PushMatrix()

	gl.Color3d(0, 0, 0)
	gl.Begin(gl.QUADS)
	gl.Vertex2i(region.X, region.Y)
	gl.Vertex2i(region.X, region.Y+region.Dy)
	gl.Vertex2i(region.X+region.Dx, region.Y+region.Dy)
	gl.Vertex2i(region.X+region.Dx, region.Y)
	gl.End()

	gl.PushAttrib(gl.TEXTURE_BIT)
	gl.Enable(gl.TEXTURE_2D)
	w.texture.Bind(gl.TEXTURE_2D)

	gl.PushAttrib(gl.COLOR_BUFFER_BIT)
	gl.Enable(gl.BLEND)
	gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
}
コード例 #2
0
ファイル: widgets.go プロジェクト: MobRulesGames/glop
func (w *ImageBox) Draw(region Region) {
	w.Render_region = region

	// We check texture == 0 and not active because active only indicates if we
	// have a texture that we need to free later.  It's possible for us to have
	// a texture that someone else owns.
	if w.texture == 0 {
		return
	}

	gl.Enable(gl.TEXTURE_2D)
	w.texture.Bind(gl.TEXTURE_2D)
	gl.Enable(gl.BLEND)
	gl.Color4d(w.r, w.g, w.b, w.a)
	gl.Begin(gl.QUADS)
	gl.TexCoord2f(0, 0)
	gl.Vertex2i(region.X, region.Y)
	gl.TexCoord2f(0, -1)
	gl.Vertex2i(region.X, region.Y+region.Dy)
	gl.TexCoord2f(1, -1)
	gl.Vertex2i(region.X+region.Dx, region.Y+region.Dy)
	gl.TexCoord2f(1, 0)
	gl.Vertex2i(region.X+region.Dx, region.Y)
	gl.End()
	gl.Disable(gl.TEXTURE_2D)
}
コード例 #3
0
ファイル: gui.go プロジェクト: losinggeneration/glop
func (r Region) PushClipPlanes() {
	if len(clippers) == 0 {
		gl.Enable(gl.CLIP_PLANE0)
		gl.Enable(gl.CLIP_PLANE1)
		gl.Enable(gl.CLIP_PLANE2)
		gl.Enable(gl.CLIP_PLANE3)
		r.setClipPlanes()
		clippers = append(clippers, r)
	} else {
		cur := clippers[len(clippers)-1]
		clippers = append(clippers, r.Isect(cur))
		clippers[len(clippers)-1].setClipPlanes()
	}
}
コード例 #4
0
ファイル: sprite.go プロジェクト: MobRulesGames/glop
func (m *Manager) LoadSprite(path string) (*Sprite, error) {
	// We can't run this during an init() function because it will get queued to
	// run before the opengl context is created, so we just check here and run
	// it if we haven't run it before.
	gen_tex_once.Do(func() {
		render.Queue(func() {
			gl.Enable(gl.TEXTURE_2D)
			error_texture = gl.GenTexture()
			error_texture.Bind(gl.TEXTURE_2D)
			gl.TexEnvf(gl.TEXTURE_ENV, gl.TEXTURE_ENV_MODE, gl.MODULATE)
			gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR)
			gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
			gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
			gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
			pink := []byte{255, 0, 255, 255}
			glu.Build2DMipmaps(gl.TEXTURE_2D, 4, 1, 1, gl.RGBA, pink)
		})
	})

	path = filepath.Clean(path)
	err := m.loadSharedSprite(path)
	if err != nil {
		return nil, err
	}
	var s Sprite
	m.mutex.Lock()
	s.shared = m.shared[path]
	m.mutex.Unlock()
	s.anim_node = s.shared.anim_start
	s.state_node = s.shared.state_start
	return &s, nil
}
コード例 #5
0
ファイル: manager.go プロジェクト: genbattle/haunts
func RenderAdvanced(x, y, dx, dy, rot float64, flip bool) {
	if textureList != 0 {
		var run, op mathgl.Mat4
		run.Identity()
		op.Translation(float32(x), float32(y), 0)
		run.Multiply(&op)
		op.Translation(float32(dx/2), float32(dy/2), 0)
		run.Multiply(&op)
		op.RotationZ(float32(rot))
		run.Multiply(&op)
		if flip {
			op.Translation(float32(-dx/2), float32(-dy/2), 0)
			run.Multiply(&op)
			op.Scaling(float32(dx), float32(dy), 1)
			run.Multiply(&op)
		} else {
			op.Translation(float32(dx/2), float32(-dy/2), 0)
			run.Multiply(&op)
			op.Scaling(float32(-dx), float32(dy), 1)
			run.Multiply(&op)
		}
		gl.PushMatrix()
		gl.MultMatrixf(&run[0])
		gl.Enable(gl.TEXTURE_2D)
		gl.CallList(textureList)
		gl.PopMatrix()
	}
}
コード例 #6
0
ファイル: los_texture.go プロジェクト: genbattle/haunts
// Creates a LosTexture with the specified size, which must be a power of two.
func MakeLosTexture() *LosTexture {
	var lt LosTexture
	lt.pix = make([]byte, LosTextureSizeSquared)
	lt.p2d = make([][]byte, LosTextureSize)
	lt.rec = make(chan gl.Texture, 1)
	for i := 0; i < LosTextureSize; i++ {
		lt.p2d[i] = lt.pix[i*LosTextureSize : (i+1)*LosTextureSize]
	}

	render.Queue(func() {
		gl.Enable(gl.TEXTURE_2D)
		tex := gl.GenTexture()
		tex.Bind(gl.TEXTURE_2D)
		gl.TexEnvf(gl.TEXTURE_ENV, gl.TEXTURE_ENV_MODE, gl.MODULATE)
		gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
		gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
		gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
		gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
		gl.TexImage2D(gl.TEXTURE_2D, 0, gl.ALPHA, len(lt.p2d), len(lt.p2d), 0, gl.ALPHA, gl.BYTE, lt.pix)
		lt.rec <- tex
		runtime.SetFinalizer(&lt, losTextureFinalize)
	})

	return &lt
}
コード例 #7
0
ファイル: room_viewer.go プロジェクト: genbattle/haunts
func drawPrep() {
	gl.Disable(gl.DEPTH_TEST)
	gl.Disable(gl.TEXTURE_2D)
	gl.PolygonMode(gl.FRONT_AND_BACK, gl.FILL)
	gl.Enable(gl.BLEND)
	gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
	gl.ClearStencil(0)
	gl.Clear(gl.STENCIL_BUFFER_BIT)
}
コード例 #8
0
ファイル: los_texture.go プロジェクト: genbattle/haunts
// Updates OpenGl with any changes that have been made to the texture.
// OpenGl calls in this method are run on the render thread
func (lt *LosTexture) Remap() {
	if !lt.ready() {
		return
	}
	render.Queue(func() {
		gl.Enable(gl.TEXTURE_2D)
		lt.tex.Bind(gl.TEXTURE_2D)
		gl.TexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, len(lt.p2d), len(lt.p2d), gl.ALPHA, lt.pix)
	})
}
コード例 #9
0
ファイル: texture.go プロジェクト: genbattle/haunts
func makeErrorTexture() {
	gl.Enable(gl.TEXTURE_2D)
	error_texture = gl.GenTexture()
	error_texture.Bind(gl.TEXTURE_2D)
	gl.TexEnvf(gl.TEXTURE_ENV, gl.TEXTURE_ENV_MODE, gl.MODULATE)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
	transparent := []byte{0, 0, 0, 0}
	glu.Build2DMipmaps(gl.TEXTURE_2D, 4, 1, 1, gl.RGBA, transparent)
}
コード例 #10
0
ファイル: sheet.go プロジェクト: losinggeneration/glop
func (s *sheet) makeTexture(pixer <-chan []byte) {
	gl.Enable(gl.TEXTURE_2D)
	s.texture = gl.GenTexture()
	s.texture.Bind(gl.TEXTURE_2D)
	gl.TexEnvf(gl.TEXTURE_ENV, gl.TEXTURE_ENV_MODE, gl.MODULATE)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
	data := <-pixer
	glu.Build2DMipmaps(gl.TEXTURE_2D, 4, s.dx, s.dy, gl.RGBA, data)
	memory.FreeBlock(data)
}
コード例 #11
0
ファイル: manager.go プロジェクト: genbattle/haunts
func Render(x, y, dx, dy float64) {
	var run, op mathgl.Mat4
	run.Identity()
	op.Translation(float32(x), float32(y), 0)
	run.Multiply(&op)
	op.Scaling(float32(dx), float32(dy), 1)
	run.Multiply(&op)

	gl.PushMatrix()
	gl.Enable(gl.TEXTURE_2D)
	gl.MultMatrixf(&run[0])
	gl.CallList(textureList)
	gl.PopMatrix()
}
コード例 #12
0
ファイル: ui_dialog.go プロジェクト: genbattle/haunts
func (mdb *MediumDialogBox) Draw(region gui.Region) {
	mdb.region = region
	if mdb.done {
		return
	}
	gl.Enable(gl.TEXTURE_2D)
	gl.Color4ub(255, 255, 255, 255)
	mdb.layout.Background.Data().RenderNatural(region.X, region.Y)
	for _, button := range mdb.buttons {
		button.RenderAt(region.X, region.Y)
	}

	for i := range mdb.format.Sections {
		section := mdb.format.Sections[i]
		data := mdb.data.Pages[mdb.data.cur_page].Sections[i]
		p := section.Paragraph
		d := base.GetDictionary(p.Size)
		var just gui.Justification
		switch p.Halign {
		case "left":
			just = gui.Left
		case "right":
			just = gui.Right
		case "center":
			just = gui.Center
		default:
			base.Error().Printf("Unknown justification '%s'", p.Halign)
			p.Halign = "left"
		}
		var valign gui.Justification
		switch p.Valign {
		case "top":
			valign = gui.Top
		case "bottom":
			valign = gui.Bottom
		case "center":
			valign = gui.Center
		default:
			base.Error().Printf("Unknown justification '%s'", p.Valign)
			p.Valign = "top"
		}
		gl.Color4ub(255, 255, 255, 255)

		d.RenderParagraph(data.Text, float64(p.X+region.X), float64(p.Y+region.Y)-d.MaxHeight()/2, 0, float64(p.Dx), d.MaxHeight(), just, valign)

		gl.Color4ub(255, 255, 255, byte(data.shading*255))
		tex := data.Image.Data()
		tex.RenderNatural(region.X+section.X-tex.Dx()/2, region.Y+section.Y-tex.Dy()/2)
	}
}
コード例 #13
0
ファイル: widgets.go プロジェクト: MobRulesGames/glop
func (w *ImageBox) SetImage(path string) {
	w.UnsetImage()
	data, err := os.Open(path)
	if err != nil {
		// TODO: Log error
		return
	}

	var img image.Image
	img, _, err = image.Decode(data)
	if err != nil {
		// TODO: Log error
		return
	}

	w.Request_dims.Dx = img.Bounds().Dx()
	w.Request_dims.Dy = img.Bounds().Dy()
	canvas := image.NewRGBA(image.Rect(0, 0, img.Bounds().Dx(), img.Bounds().Dy()))
	for y := 0; y < canvas.Bounds().Dy(); y++ {
		for x := 0; x < canvas.Bounds().Dx(); x++ {
			r, g, b, a := img.At(x, y).RGBA()
			base := 4*x + canvas.Stride*y
			canvas.Pix[base] = uint8(r)
			canvas.Pix[base+1] = uint8(g)
			canvas.Pix[base+2] = uint8(b)
			canvas.Pix[base+3] = uint8(a)
		}
	}

	w.texture = gl.GenTexture()
	gl.Enable(gl.TEXTURE_2D)
	w.texture.Bind(gl.TEXTURE_2D)
	gl.TexEnvf(gl.TEXTURE_ENV, gl.TEXTURE_ENV_MODE, gl.MODULATE)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
	glu.Build2DMipmaps(gl.TEXTURE_2D, 4, img.Bounds().Dx(), img.Bounds().Dy(), gl.RGBA, canvas.Pix)

	w.active = true
}
コード例 #14
0
ファイル: text_line.go プロジェクト: losinggeneration/glop
func (w *TextLine) figureDims() {
	// Always draw the text as white on a transparent background so that we can change
	// the color easily through opengl
	w.rdims.Dx, w.rdims.Dy = drawText(w.font, w.context, color.RGBA{255, 255, 255, 255}, image.NewRGBA(image.Rect(0, 0, 1, 1)), w.text)
	texture_dims := Dims{
		Dx: int(nextPowerOf2(uint32(w.rdims.Dx))),
		Dy: int(nextPowerOf2(uint32(w.rdims.Dy))),
	}
	w.rgba = image.NewRGBA(image.Rect(0, 0, texture_dims.Dx, texture_dims.Dy))
	drawText(w.font, w.context, color.RGBA{255, 255, 255, 255}, w.rgba, w.text)

	gl.Enable(gl.TEXTURE_2D)
	w.texture.Bind(gl.TEXTURE_2D)
	gl.TexEnvf(gl.TEXTURE_ENV, gl.TEXTURE_ENV_MODE, gl.MODULATE)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
	gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
	glu.Build2DMipmaps(gl.TEXTURE_2D, 4, w.rgba.Bounds().Dx(), w.rgba.Bounds().Dy(), gl.RGBA, w.rgba.Pix)
	gl.Disable(gl.TEXTURE_2D)
}
コード例 #15
0
ファイル: tables.go プロジェクト: losinggeneration/glop
func (w *VerticalTable) Draw(region Region) {
	gl.Enable(gl.BLEND)
	gl.Disable(gl.TEXTURE_2D)
	dx := region.Dx
	if dx > w.Request_dims.Dx && !w.Ex {
		dx = w.Request_dims.Dx
	}
	dy := region.Dy
	if dy > w.Request_dims.Dy && !w.Ex {
		dy = w.Request_dims.Dy
	}
	gl.Color4d(
		w.params.Background.R,
		w.params.Background.G,
		w.params.Background.B,
		w.params.Background.A)
	gl.Begin(gl.QUADS)
	gl.Vertex2i(region.X, region.Y+region.Dy-dy)
	gl.Vertex2i(region.X, region.Y+region.Dy)
	gl.Vertex2i(region.X+dx, region.Y+region.Dy)
	gl.Vertex2i(region.X+dx, region.Y+region.Dy-dy)
	gl.End()
	gl.Color4d(
		w.params.Border.R,
		w.params.Border.G,
		w.params.Border.B,
		w.params.Border.A)
	gl.Begin(gl.LINES)
	gl.Vertex2i(region.X, region.Y+region.Dy-dy)
	gl.Vertex2i(region.X, region.Y+region.Dy)

	gl.Vertex2i(region.X, region.Y+region.Dy)
	gl.Vertex2i(region.X+dx, region.Y+region.Dy)

	gl.Vertex2i(region.X+dx, region.Y+region.Dy)
	gl.Vertex2i(region.X+dx, region.Y+region.Dy-dy)

	gl.Vertex2i(region.X+dx, region.Y+region.Dy-dy)
	gl.Vertex2i(region.X, region.Y+region.Dy-dy)
	gl.End()

	fill_available := region.Dy - w.Request_dims.Dy
	if fill_available < 0 {
		fill_available = 0
	}
	fill_request := 0
	for _, child := range w.Children {
		if _, ey := child.Expandable(); ey {
			fill_request += child.Requested().Dy
		}
	}
	var child_region Region
	child_region.Y = region.Y + region.Dy
	for _, child := range w.Children {
		child_region.Dims = child.Requested()
		if _, ey := child.Expandable(); ey && fill_request > 0 {
			child_region.Dy += (child_region.Dy * fill_available) / fill_request
		}
		if region.Dy < w.Request_dims.Dy {
			child_region.Dims.Dy *= region.Dy
			child_region.Dims.Dy /= w.Request_dims.Dy
		}
		if child_region.Dx > region.Dx {
			child_region.Dx = region.Dx
		}
		if ex, _ := child.Expandable(); child_region.Dx < region.Dx && ex {
			child_region.Dx = region.Dx
		}
		child_region.X = region.X
		child_region.Y -= child_region.Dy
		child_region.Y -= w.params.Spacing
		child.Draw(child_region)
	}
	w.Render_region = region
}
コード例 #16
0
ファイル: room_viewer.go プロジェクト: genbattle/haunts
func drawFloor(room *Room, floor mathgl.Mat4, temp *WallTexture, cstack base.ColorStack, los_tex *LosTexture, los_alpha float64, floor_drawer []FloorDrawer) {
	gl.MatrixMode(gl.MODELVIEW)
	gl.PushMatrix()
	gl.LoadIdentity()
	gl.MultMatrixf(&floor[0])
	defer gl.PopMatrix()

	gl.Enable(gl.STENCIL_TEST)
	defer gl.Disable(gl.STENCIL_TEST)

	gl.StencilFunc(gl.ALWAYS, 4, 4)
	gl.StencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE)
	gl.Disable(gl.TEXTURE_2D)
	gl.Begin(gl.QUADS)
	gl.Vertex2i(0, 0)
	gl.Vertex2i(0, room.Size.Dy)
	gl.Vertex2i(room.Size.Dx, room.Size.Dy)
	gl.Vertex2i(room.Size.Dx, 0)
	gl.End()
	gl.StencilFunc(gl.EQUAL, 4, 15)
	gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP)

	// Draw the floor
	gl.Enable(gl.TEXTURE_2D)
	cstack.ApplyWithAlpha(los_alpha)
	room.Floor.Data().Render(0, 0, float64(room.Size.Dx), float64(room.Size.Dy))

	if los_tex != nil {
		los_tex.Bind()
		gl.BlendFunc(gl.SRC_ALPHA_SATURATE, gl.SRC_ALPHA)
		gl.Color4d(0, 0, 0, 1)
		gl.Begin(gl.QUADS)
		gl.TexCoord2i(0, 0)
		gl.Vertex2i(-room.X, -room.Y)
		gl.TexCoord2i(1, 0)
		gl.Vertex2i(-room.X, los_tex.Size()-room.Y)
		gl.TexCoord2i(1, 1)
		gl.Vertex2i(los_tex.Size()-room.X, los_tex.Size()-room.Y)
		gl.TexCoord2i(0, 1)
		gl.Vertex2i(los_tex.Size()-room.X, -room.Y)
		gl.End()
		gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
	}
	cstack.ApplyWithAlpha(los_alpha)
	{
		g_texs = g_texs[0:0]
		if temp != nil {
			g_texs = append(g_texs, *temp)
		}
		for _, tex := range room.WallTextures {
			g_texs = append(g_texs, *tex)
		}
		for i, tex := range g_texs {
			if tex.X >= float32(room.Size.Dx) {
				tex.Rot -= 3.1415926535 / 2
			}
			if temp != nil && i == 0 {
				cstack.Push(1, 0.7, 0.7, 0.7)
			}
			cstack.ApplyWithAlpha(los_alpha)
			tex.Render()
			if temp != nil && i == 0 {
				cstack.Pop()
			}
		}
	}

	gl.PushMatrix()
	gl.Translated(-float64(room.X), -float64(room.Y), 0)
	for _, fd := range floor_drawer {
		fd.RenderOnFloor()
	}
	gl.PopMatrix()

	// Re-enable textures because floor_drawer.RenderOnFloor() might have
	// disabled them
	gl.Enable(gl.TEXTURE_2D)

	gl.StencilFunc(gl.ALWAYS, 5, 5)
	gl.StencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE)
	gl.Disable(gl.TEXTURE_2D)
	gl.Color4d(0, 0, 0, 0)
	gl.Begin(gl.QUADS)
	gl.Vertex2i(0, 0)
	gl.Vertex2i(0, room.Size.Dy)
	gl.Vertex2i(room.Size.Dx, room.Size.Dy)
	gl.Vertex2i(room.Size.Dx, 0)
	gl.End()
}
コード例 #17
0
ファイル: los_texture.go プロジェクト: genbattle/haunts
func losTextureFinalize(lt *LosTexture) {
	render.Queue(func() {
		gl.Enable(gl.TEXTURE_2D)
		lt.tex.Delete()
	})
}
コード例 #18
0
ファイル: roster_chooser.go プロジェクト: genbattle/haunts
func (rc *RosterChooser) Draw(r gui.Region) {
	rc.Render_region = r
	r.PushClipPlanes()
	defer r.PopClipPlanes()
	gl.Enable(gl.TEXTURE_2D)

	{ // Up button
		x := r.X
		y := r.Y + r.Dy - rc.layout.Up.Data().Dy()
		rc.render.up.X = x
		rc.render.up.Y = y
		rc.render.up.Dx = rc.layout.Up.Data().Dx()
		rc.render.up.Dy = rc.layout.Up.Data().Dy()
		if rc.mouse.Inside(rc.render.up) {
			gl.Color4d(1, 1, 1, 1)
		} else {
			gl.Color4d(0.8, 0.8, 0.8, 1)
		}
		rc.layout.Up.Data().RenderNatural(x, y)
	}

	{ // Down button
		x := r.X
		y := r.Y + rc.layout.Down.Data().Dy()
		rc.render.down.X = x
		rc.render.down.Y = y
		rc.render.down.Dx = rc.layout.Down.Data().Dx()
		rc.render.down.Dy = rc.layout.Down.Data().Dy()
		if rc.mouse.Inside(rc.render.down) {
			gl.Color4d(1, 1, 1, 1)
		} else {
			gl.Color4d(0.8, 0.8, 0.8, 1)
		}
		rc.layout.Down.Data().RenderNatural(x, y)
	}

	{ // Options
		rc.render.all_options.X = r.X + rc.layout.Down.Data().Dx()
		rc.render.all_options.Y = r.Y + r.Dy - rc.layout.Num_options*rc.layout.Option.Dy
		rc.render.all_options.Dx = rc.layout.Option.Dx
		rc.render.all_options.Dy = rc.layout.Num_options * rc.layout.Option.Dy
		rc.render.all_options.PushClipPlanes()
		x := rc.render.all_options.X
		y := r.Y + r.Dy - rc.layout.Option.Dy + int(float64(rc.layout.Option.Dy)*rc.focus_pos)
		for i := range rc.options {
			rc.render.options[i] = gui.Region{
				gui.Point{x, y},
				gui.Dims{rc.layout.Option.Dx, rc.layout.Option.Dy},
			}
			hovered := rc.mouse.Inside(rc.render.options[i])
			selected := rc.selected[i]
			selectable := rc.selector(i, rc.selected, false)
			rc.options[i].Draw(hovered, selected, selectable, rc.render.options[i])
			y -= rc.layout.Option.Dy
		}

		rc.render.all_options.PopClipPlanes()
	}

	{ // Text
		d := base.GetDictionary(15)
		x := r.X
		y := float64(r.Y) + d.MaxHeight()/2
		x1 := float64(x + r.Dx/3)
		x2 := float64(x + (2*r.Dx)/3)

		rc.render.done = gui.Region{
			gui.Point{x, r.Y},
			gui.Dims{r.Dx / 2, int(d.MaxHeight() * 2)},
		}
		rc.render.undo = gui.Region{
			gui.Point{x + r.Dx/2, r.Y},
			gui.Dims{r.Dx / 2, int(d.MaxHeight() * 2)},
		}

		if rc.mouse.Inside(rc.render.done) {
			gl.Color4d(1, 1, 1, 1)
		} else {
			gl.Color4d(0.6, 0.6, 0.6, 1)
		}
		d.RenderString("Done", x1, y, 0, d.MaxHeight(), gui.Center)

		if rc.on_undo != nil {
			if rc.mouse.Inside(rc.render.undo) {
				gl.Color4d(1, 1, 1, 1)
			} else {
				gl.Color4d(0.6, 0.6, 0.6, 1)
			}
			d.RenderString("Undo", x2, y, 0, d.MaxHeight(), gui.Center)
		}

	}
}
コード例 #19
0
ファイル: room_viewer.go プロジェクト: genbattle/haunts
func drawFurniture(roomx, roomy int, mat mathgl.Mat4, zoom float32, furniture []*Furniture, temp_furniture *Furniture, extras []Drawable, cstack base.ColorStack, los_tex *LosTexture, los_alpha float64) {
	gl.Enable(gl.TEXTURE_2D)
	gl.Color4d(1, 1, 1, los_alpha)
	gl.PushMatrix()
	gl.LoadIdentity()

	board_to_window := func(mx, my float32) (x, y float32) {
		v := mathgl.Vec4{X: mx, Y: my, W: 1}
		v.Transform(&mat)
		x, y = v.X, v.Y
		return
	}

	g_stuff = g_stuff[0:0]
	for i := range furniture {
		g_stuff = append(g_stuff, furniture[i])
	}
	if temp_furniture != nil {
		g_stuff = append(g_stuff, temp_furniture)
	}
	for i := range extras {
		g_stuff = append(g_stuff, extras[i])
	}
	g_stuff = OrderRectObjects(g_stuff)

	for i := len(g_stuff) - 1; i >= 0; i-- {
		f := g_stuff[i]
		var near_x, near_y, dx, dy float32

		idx, idy := f.Dims()
		dx = float32(idx)
		dy = float32(idy)
		switch d := f.(type) {
		case *Furniture:
			ix, iy := d.Pos()
			near_x = float32(ix)
			near_y = float32(iy)

		case Drawable:
			fx, fy := d.FPos()
			near_x = float32(fx)
			near_y = float32(fy)
		}

		vis_tot := 1.0
		if los_tex != nil {
			vis_tot = 0.0

			// If we're looking at a piece of furniture that blocks Los then we
			// can't expect to have Los to all of it, so we will check the squares
			// around it.  Full visibility will mean that half of the surrounding
			// cells are visible.
			blocks_los := false
			// Also need to check if it is an enemy unit
			if _, ok := f.(*Furniture); ok {
				blocks_los = true
			}

			if blocks_los {
				for x := near_x - 1; x < near_x+dx+1; x++ {
					vis_tot += float64(los_tex.Pix()[int(x)+roomx][int(near_y-1)+roomy])
					vis_tot += float64(los_tex.Pix()[int(x)+roomx][int(near_y+dy+1)+roomy])
				}
				for y := near_y; y < near_y+dy; y++ {
					vis_tot += float64(los_tex.Pix()[int(near_x-1)+roomx][int(y)+roomy])
					vis_tot += float64(los_tex.Pix()[int(near_x+dx+1)+roomx][int(y)+roomy])
				}
				vis_tot /= float64((dx*2 + dy*2 + 4) * 255 / 2)
				if vis_tot > 1 {
					vis_tot = 1
				}
			} else {
				for x := near_x; x < near_x+dx; x++ {
					for y := near_y; y < near_y+dy; y++ {
						vis_tot += float64(los_tex.Pix()[int(x)+roomx][int(y)+roomy])
					}
				}
				vis_tot /= float64(dx * dy * 255)
			}
		}

		leftx, _ := board_to_window(near_x, near_y+dy)
		rightx, _ := board_to_window(near_x+dx, near_y)
		_, boty := board_to_window(near_x, near_y)
		if f == temp_furniture {
			cstack.Push(1, 0, 0, 0.4)
		} else {
			bot := (LosMinVisibility / 255.0)
			vis := (vis_tot - bot) / (1 - bot)
			vis = vis * vis
			vis = vis*(1-bot) + bot
			vis = vis * vis
			cstack.Push(vis, vis, vis, 1)
		}
		cstack.ApplyWithAlpha(los_alpha)
		cstack.Pop()
		switch d := f.(type) {
		case *Furniture:
			d.Render(mathgl.Vec2{leftx, boty}, rightx-leftx)

		case Drawable:
			gl.Enable(gl.TEXTURE_2D)
			x := (leftx + rightx) / 2
			d.Render(mathgl.Vec2{x, boty}, rightx-leftx)
		}
	}
	gl.PopMatrix()
}
コード例 #20
0
ファイル: manager.go プロジェクト: genbattle/haunts
func handleLoadRequest(req loadRequest) {
	f, _ := os.Open(req.path)
	im, _, err := image.Decode(f)
	f.Close()
	if err != nil {
		return
	}
	gray := true
	dx := im.Bounds().Dx()
	dy := im.Bounds().Dy()
	for i := 0; i < dx; i++ {
		for j := 0; j < dy; j++ {
			r, g, b, _ := im.At(i, j).RGBA()
			if r != g || g != b {
				gray = false
				break
			}
		}
		if !gray {
			break
		}
	}
	var canvas draw.Image
	var pix []byte
	if gray {
		ga := NewGrayAlpha(im.Bounds())
		pix = ga.Pix
		canvas = ga
	} else {
		pix = memory.GetBlock(4 * req.data.dx * req.data.dy)
		canvas = &image.RGBA{pix, 4 * req.data.dx, im.Bounds()}
	}
	draw.Draw(canvas, im.Bounds(), im, image.Point{}, draw.Src)
	load_mutex.Lock()
	load_count += len(pix)
	manual_unlock := false
	// This prevents us from trying to send too much to opengl in a single
	// frame.  If we go over the threshold then we hold the lock until we're
	// done sending data to opengl, then other requests will be free to
	// queue up and they will run on the next frame.
	if load_count < load_threshold {
		load_mutex.Unlock()
	} else {
		manual_unlock = true
	}
	render.Queue(func() {
		{
			gl.Enable(gl.TEXTURE_2D)
			req.data.texture = gl.GenTexture()
			req.data.texture.Bind(gl.TEXTURE_2D)
			gl.TexEnvf(gl.TEXTURE_ENV, gl.TEXTURE_ENV_MODE, gl.MODULATE)
			gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR)
			gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
			gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT)
			gl.TexParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT)
		}
		if gray {
			glu.Build2DMipmaps(gl.TEXTURE_2D, gl.LUMINANCE_ALPHA, req.data.dx, req.data.dy, gl.LUMINANCE_ALPHA, pix)
		} else {
			glu.Build2DMipmaps(gl.TEXTURE_2D, gl.RGBA, req.data.dx, req.data.dy, gl.RGBA, pix)
		}
		memory.FreeBlock(pix)
		if manual_unlock {
			load_count = 0
			load_mutex.Unlock()
		}
	})
}
コード例 #21
0
ファイル: room_viewer.go プロジェクト: genbattle/haunts
// room: the wall to draw
// wall: the texture to render on the wall
// temp: an additional texture to render along with the other detail textures
// specified in room
// left,right: the xy planes of the left and right walls
func drawWall(room *Room, floor, left, right mathgl.Mat4, temp_tex *WallTexture, temp_door doorInfo, cstack base.ColorStack, los_tex *LosTexture, los_alpha float64) {
	gl.Enable(gl.STENCIL_TEST)
	defer gl.Disable(gl.STENCIL_TEST)

	gl.MatrixMode(gl.MODELVIEW)
	gl.PushMatrix()
	defer gl.PopMatrix()

	var dz int
	if room.Wall.Data().Dx() > 0 {
		dz = room.Wall.Data().Dy() * (room.Size.Dx + room.Size.Dy) / room.Wall.Data().Dx()
	}
	corner := float32(room.Size.Dx) / float32(room.Size.Dx+room.Size.Dy)
	gl.LoadIdentity()
	gl.MultMatrixf(&floor[0])

	g_texs = g_texs[0:0]
	if temp_tex != nil {
		g_texs = append(g_texs, *temp_tex)
	}
	for _, tex := range room.WallTextures {
		g_texs = append(g_texs, *tex)
	}

	do_right_wall := func() {
		gl.Begin(gl.QUADS)
		gl.TexCoord2f(1, 0)
		gl.Vertex3i(room.Size.Dx, 0, 0)
		gl.TexCoord2f(1, -1)
		gl.Vertex3i(room.Size.Dx, 0, -dz)
		gl.TexCoord2f(corner, -1)
		gl.Vertex3i(room.Size.Dx, room.Size.Dy, -dz)
		gl.TexCoord2f(corner, 0)
		gl.Vertex3i(room.Size.Dx, room.Size.Dy, 0)
		gl.End()
	}

	g_doors = g_doors[0:0]
	for _, door := range room.Doors {
		g_doors = append(g_doors, door)
	}
	if temp_door.Door != nil {
		g_doors = append(g_doors, temp_door.Door)
	}

	alpha := 0.2

	do_right_doors := func(opened bool) {
		for _, door := range g_doors {
			if door.Facing != FarRight {
				continue
			}
			if door.IsOpened() != opened {
				continue
			}
			door.TextureData().Bind()
			if door == temp_door.Door {
				if temp_door.Valid {
					cstack.Push(0, 0, 1, alpha)
				} else {
					cstack.Push(1, 0, 0, alpha)
				}
			}
			cstack.ApplyWithAlpha(alpha * los_alpha)
			gl.Begin(gl.QUADS)
			height := float64(door.Width*door.TextureData().Dy()) / float64(door.TextureData().Dx())
			gl.TexCoord2f(1, 0)
			gl.Vertex3d(float64(room.Size.Dx), float64(door.Pos), 0)
			gl.TexCoord2f(1, -1)
			gl.Vertex3d(float64(room.Size.Dx), float64(door.Pos), -height)
			gl.TexCoord2f(0, -1)
			gl.Vertex3d(float64(room.Size.Dx), float64(door.Pos+door.Width), -height)
			gl.TexCoord2f(0, 0)
			gl.Vertex3d(float64(room.Size.Dx), float64(door.Pos+door.Width), 0)
			gl.End()
			if door == temp_door.Door {
				cstack.Pop()
			}
		}
	}

	// Right wall
	gl.StencilFunc(gl.NOTEQUAL, 8, 7)
	gl.StencilOp(gl.DECR_WRAP, gl.REPLACE, gl.REPLACE)
	gl.Color4d(0, 0, 0, 0)
	do_right_wall()
	gl.Enable(gl.TEXTURE_2D)
	cstack.ApplyWithAlpha(alpha * los_alpha)
	gl.StencilFunc(gl.EQUAL, 8, 15)
	gl.StencilOp(gl.KEEP, gl.ZERO, gl.ZERO)
	do_right_doors(true)
	cstack.ApplyWithAlpha(1.0 * los_alpha)
	gl.StencilFunc(gl.EQUAL, 15, 15)
	gl.StencilOp(gl.KEEP, gl.ZERO, gl.ZERO)
	do_right_doors(true)
	for _, alpha := range []float64{alpha, 1.0} {
		cstack.ApplyWithAlpha(alpha * los_alpha)
		if alpha == 1.0 {
			gl.StencilFunc(gl.EQUAL, 15, 15)
			gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP)
		} else {
			gl.StencilFunc(gl.EQUAL, 8, 15)
			gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP)
		}
		room.Wall.Data().Bind()

		do_right_wall()

		gl.PushMatrix()
		gl.LoadIdentity()
		gl.MultMatrixf(&right[0])
		for i, tex := range g_texs {
			dx, dy := float32(room.Size.Dx), float32(room.Size.Dy)
			if tex.Y > dy {
				tex.X, tex.Y = dx+tex.Y-dy, dy+dx-tex.X
			}
			if tex.X > dx {
				tex.Rot -= 3.1415926535 / 2
			}
			tex.X -= dx
			if temp_tex != nil && i == 0 {
				cstack.Push(1, 0.7, 0.7, 0.7)
			}
			cstack.ApplyWithAlpha(alpha * los_alpha)
			tex.Render()
			if temp_tex != nil && i == 0 {
				cstack.Pop()
			}
		}
		gl.PopMatrix()
	}
	cstack.ApplyWithAlpha(alpha * los_alpha)
	gl.StencilFunc(gl.EQUAL, 8, 15)
	do_right_doors(false)
	cstack.ApplyWithAlpha(1.0 * los_alpha)
	gl.StencilFunc(gl.EQUAL, 15, 15)
	do_right_doors(false)
	// Go back over the area we just drew on and replace it with all b0001
	gl.StencilFunc(gl.ALWAYS, 1, 1)
	gl.StencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE)
	gl.Color4d(0, 0, 0, 0)
	do_right_wall()

	// Now that the entire wall has been draw we can cast shadows on it if we've
	// got a los texture
	if los_tex != nil {
		los_tex.Bind()
		gl.BlendFunc(gl.SRC_ALPHA_SATURATE, gl.SRC_ALPHA)
		gl.Color4d(0, 0, 0, 1)

		tx := (float64(room.X+room.Size.Dx) - 0.5) / float64(los_tex.Size())
		ty := (float64(room.Y) + 0.5) / float64(los_tex.Size())
		ty2 := (float64(room.Y+room.Size.Dy) - 0.5) / float64(los_tex.Size())
		gl.Begin(gl.QUADS)
		gl.TexCoord2d(ty, tx)
		gl.Vertex3i(room.Size.Dx, 0, 0)
		gl.TexCoord2d(ty, tx)
		gl.Vertex3i(room.Size.Dx, 0, -dz)
		gl.TexCoord2d(ty2, tx)
		gl.Vertex3i(room.Size.Dx, room.Size.Dy, -dz)
		gl.TexCoord2d(ty2, tx)
		gl.Vertex3i(room.Size.Dx, room.Size.Dy, 0)
		gl.End()
		gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
	}

	do_left_wall := func() {
		gl.Begin(gl.QUADS)
		gl.TexCoord2f(corner, 0)
		gl.Vertex3i(room.Size.Dx, room.Size.Dy, 0)
		gl.TexCoord2f(corner, -1)
		gl.Vertex3i(room.Size.Dx, room.Size.Dy, -dz)
		gl.TexCoord2f(0, -1)
		gl.Vertex3i(0, room.Size.Dy, -dz)
		gl.TexCoord2f(0, 0)
		gl.Vertex3i(0, room.Size.Dy, 0)
		gl.End()
	}

	do_left_doors := func(opened bool) {
		for _, door := range g_doors {
			if door.Facing != FarLeft {
				continue
			}
			if door.IsOpened() != opened {
				continue
			}
			door.TextureData().Bind()
			if door == temp_door.Door {
				if temp_door.Valid {
					cstack.Push(0, 0, 1, alpha)
				} else {
					cstack.Push(1, 0, 0, alpha)
				}
			}
			cstack.ApplyWithAlpha(alpha * los_alpha)
			gl.Begin(gl.QUADS)
			height := float64(door.Width*door.TextureData().Dy()) / float64(door.TextureData().Dx())
			gl.TexCoord2f(0, 0)
			gl.Vertex3d(float64(door.Pos), float64(room.Size.Dy), 0)
			gl.TexCoord2f(0, -1)
			gl.Vertex3d(float64(door.Pos), float64(room.Size.Dy), -height)
			gl.TexCoord2f(1, -1)
			gl.Vertex3d(float64(door.Pos+door.Width), float64(room.Size.Dy), -height)
			gl.TexCoord2f(1, 0)
			gl.Vertex3d(float64(door.Pos+door.Width), float64(room.Size.Dy), 0)
			gl.End()
			if door == temp_door.Door {
				cstack.Pop()
			}
		}
	}

	gl.StencilFunc(gl.NOTEQUAL, 8, 7)
	gl.StencilOp(gl.DECR_WRAP, gl.REPLACE, gl.REPLACE)
	gl.Color4d(0, 0, 0, 0)
	do_left_wall()
	gl.Enable(gl.TEXTURE_2D)
	cstack.ApplyWithAlpha(alpha * los_alpha)
	gl.StencilFunc(gl.EQUAL, 8, 15)
	gl.StencilOp(gl.KEEP, gl.ZERO, gl.ZERO)
	do_left_doors(true)
	cstack.ApplyWithAlpha(1.0 * los_alpha)
	gl.StencilFunc(gl.EQUAL, 15, 15)
	gl.StencilOp(gl.KEEP, gl.ZERO, gl.ZERO)
	do_left_doors(true)
	for _, alpha := range []float64{alpha, 1.0} {
		if alpha == 1.0 {
			gl.StencilFunc(gl.EQUAL, 15, 15)
			gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP)
		} else {
			gl.StencilFunc(gl.EQUAL, 8, 15)
			gl.StencilOp(gl.KEEP, gl.KEEP, gl.KEEP)
		}
		room.Wall.Data().Bind()
		cstack.ApplyWithAlpha(alpha * los_alpha)
		do_left_wall()

		gl.PushMatrix()
		gl.LoadIdentity()
		gl.MultMatrixf(&left[0])
		for i, tex := range g_texs {
			dx, dy := float32(room.Size.Dx), float32(room.Size.Dy)
			if tex.X > dx {
				tex.X, tex.Y = dx+dy-tex.Y, dy+tex.X-dx
			}
			tex.Y -= dy
			if temp_tex != nil && i == 0 {
				cstack.Push(1, 0.7, 0.7, 0.7)
			}
			cstack.ApplyWithAlpha(alpha * los_alpha)
			tex.Render()
			if temp_tex != nil && i == 0 {
				cstack.Pop()
			}
		}
		gl.PopMatrix()
	}
	cstack.ApplyWithAlpha(alpha * los_alpha)
	gl.StencilFunc(gl.EQUAL, 8, 15)
	do_left_doors(false)
	cstack.ApplyWithAlpha(1.0 * los_alpha)
	gl.StencilFunc(gl.EQUAL, 15, 15)
	do_left_doors(false)
	// Go back over the area we just drew on and replace it with all b0010
	gl.StencilFunc(gl.ALWAYS, 2, 2)
	gl.StencilOp(gl.REPLACE, gl.REPLACE, gl.REPLACE)
	gl.Color4d(0, 0, 0, 0)
	do_left_wall()

	// Now that the entire wall has been draw we can cast shadows on it if we've
	// got a los texture
	if los_tex != nil {
		los_tex.Bind()
		gl.BlendFunc(gl.SRC_ALPHA_SATURATE, gl.SRC_ALPHA)
		gl.Color4d(0, 0, 0, 1)

		ty := (float64(room.Y+room.Size.Dy) - 0.5) / float64(los_tex.Size())
		tx := (float64(room.X) + 0.5) / float64(los_tex.Size())
		tx2 := (float64(room.X+room.Size.Dx) - 0.5) / float64(los_tex.Size())
		gl.Begin(gl.QUADS)
		gl.TexCoord2d(ty, tx)
		gl.Vertex3i(0, room.Size.Dy, 0)
		gl.TexCoord2d(ty, tx)
		gl.Vertex3i(0, room.Size.Dy, -dz)
		gl.TexCoord2d(ty, tx2)
		gl.Vertex3i(room.Size.Dx, room.Size.Dy, -dz)
		gl.TexCoord2d(ty, tx2)
		gl.Vertex3i(room.Size.Dx, room.Size.Dy, 0)
		gl.End()
		gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
	}
}
コード例 #22
0
ファイル: ui_main_bar.go プロジェクト: genbattle/haunts
func (m *MainBar) Draw(region gui.Region) {
	m.region = region
	gl.Enable(gl.TEXTURE_2D)
	m.layout.Background.Data().Bind()
	gl.Color4d(1, 1, 1, 1)
	gl.Begin(gl.QUADS)
	gl.TexCoord2d(0, 0)
	gl.Vertex2i(region.X, region.Y)

	gl.TexCoord2d(0, -1)
	gl.Vertex2i(region.X, region.Y+region.Dy)

	gl.TexCoord2d(1, -1)
	gl.Vertex2i(region.X+region.Dx, region.Y+region.Dy)

	gl.TexCoord2d(1, 0)
	gl.Vertex2i(region.X+region.Dx, region.Y)
	gl.End()

	buttons := m.no_actions_buttons
	if m.ent != nil && len(m.ent.Actions) > m.layout.Actions.Count {
		buttons = m.all_buttons
	}
	for _, button := range buttons {
		button.RenderAt(region.X, region.Y)
	}

	ent := m.game.HoveredEnt()
	if ent == nil {
		ent = m.ent
	}
	if ent != nil && ent.Stats != nil {
		gl.Color4d(1, 1, 1, 1)
		ent.Still.Data().Bind()
		tdx := ent.Still.Data().Dx()
		tdy := ent.Still.Data().Dy()
		cx := region.X + m.layout.CenterStillFrame.X
		cy := region.Y + m.layout.CenterStillFrame.Y
		gl.Begin(gl.QUADS)
		gl.TexCoord2d(0, 0)
		gl.Vertex2i(cx-tdx/2, cy-tdy/2)

		gl.TexCoord2d(0, -1)
		gl.Vertex2i(cx-tdx/2, cy+tdy/2)

		gl.TexCoord2d(1, -1)
		gl.Vertex2i(cx+tdx/2, cy+tdy/2)

		gl.TexCoord2d(1, 0)
		gl.Vertex2i(cx+tdx/2, cy-tdy/2)
		gl.End()

		m.layout.Name.RenderString(ent.Name)
		m.layout.Ap.RenderString(fmt.Sprintf("Ap:%d", ent.Stats.ApCur()))
		m.layout.Hp.RenderString(fmt.Sprintf("Hp:%d", ent.Stats.HpCur()))
		m.layout.Corpus.RenderString(fmt.Sprintf("Corpus:%d", ent.Stats.Corpus()))
		m.layout.Ego.RenderString(fmt.Sprintf("Ego:%d", ent.Stats.Ego()))

		gl.Color4d(1, 1, 1, 1)
		m.layout.Divider.Data().Bind()
		tdx = m.layout.Divider.Data().Dx()
		tdy = m.layout.Divider.Data().Dy()
		cx = region.X + m.layout.Name.X
		cy = region.Y + m.layout.Name.Y - 5
		gl.Begin(gl.QUADS)
		gl.TexCoord2d(0, 0)
		gl.Vertex2i(cx-tdx/2, cy-tdy/2)

		gl.TexCoord2d(0, -1)
		gl.Vertex2i(cx-tdx/2, cy+(tdy+1)/2)

		gl.TexCoord2d(1, -1)
		gl.Vertex2i(cx+(tdx+1)/2, cy+(tdy+1)/2)

		gl.TexCoord2d(1, 0)
		gl.Vertex2i(cx+(tdx+1)/2, cy-tdy/2)
		gl.End()
	}
	if m.ent != nil && m.ent.Stats != nil {
		// Actions
		{
			spacing := m.layout.Actions.Icon_size * float64(m.layout.Actions.Count)
			spacing = m.layout.Actions.Width - spacing
			spacing /= float64(m.layout.Actions.Count - 1)
			m.state.Actions.space = spacing
			s := m.layout.Actions.Icon_size
			num_actions := len(m.ent.Actions)
			xpos := m.layout.Actions.X

			if num_actions > m.layout.Actions.Count {
				xpos -= m.state.Actions.scroll_pos * (s + spacing)
			}
			d := base.GetDictionary(10)
			var r gui.Region
			r.X = int(m.layout.Actions.X)
			r.Y = int(m.layout.Actions.Y - d.MaxHeight())
			r.Dx = int(m.layout.Actions.Width)
			r.Dy = int(m.layout.Actions.Icon_size + d.MaxHeight())
			r.PushClipPlanes()

			gl.Color4d(1, 1, 1, 1)
			for i, action := range m.ent.Actions {

				// Highlight the selected action
				if action == m.game.current_action {
					gl.Disable(gl.TEXTURE_2D)
					gl.Color4d(1, 0, 0, 1)
					gl.Begin(gl.QUADS)
					gl.Vertex3d(xpos-2, m.layout.Actions.Y-2, 0)
					gl.Vertex3d(xpos-2, m.layout.Actions.Y+s+2, 0)
					gl.Vertex3d(xpos+s+2, m.layout.Actions.Y+s+2, 0)
					gl.Vertex3d(xpos+s+2, m.layout.Actions.Y-2, 0)
					gl.End()
				}
				gl.Enable(gl.TEXTURE_2D)
				action.Icon().Data().Bind()
				if action.Preppable(m.ent, m.game) {
					gl.Color4d(1, 1, 1, 1)
				} else {
					gl.Color4d(0.5, 0.5, 0.5, 1)
				}
				gl.Begin(gl.QUADS)
				gl.TexCoord2d(0, 0)
				gl.Vertex3d(xpos, m.layout.Actions.Y, 0)

				gl.TexCoord2d(0, -1)
				gl.Vertex3d(xpos, m.layout.Actions.Y+s, 0)

				gl.TexCoord2d(1, -1)
				gl.Vertex3d(xpos+s, m.layout.Actions.Y+s, 0)

				gl.TexCoord2d(1, 0)
				gl.Vertex3d(xpos+s, m.layout.Actions.Y, 0)
				gl.End()
				gl.Disable(gl.TEXTURE_2D)

				ypos := m.layout.Actions.Y - d.MaxHeight() - 2
				d.RenderString(fmt.Sprintf("%d", i+1), xpos+s/2, ypos, 0, d.MaxHeight(), gui.Center)

				xpos += spacing + m.layout.Actions.Icon_size
			}

			r.PopClipPlanes()

			// Now, if there is a selected action, position it between the arrows
			if m.state.Actions.selected != nil {
				// a := m.state.Actions.selected
				d := base.GetDictionary(15)
				x := m.layout.Actions.X + m.layout.Actions.Width/2
				y := float64(m.layout.ActionLeft.Y)
				str := fmt.Sprintf("%s:%dAP", m.state.Actions.selected.String(), m.state.Actions.selected.AP())
				gl.Color4d(1, 1, 1, 1)
				d.RenderString(str, x, y, 0, d.MaxHeight(), gui.Center)
			}
		}

		// Conditions
		{
			gl.Color4d(1, 1, 1, 1)
			c := m.layout.Conditions
			d := base.GetDictionary(int(c.Size))
			ypos := c.Y + c.Height - d.MaxHeight() + m.state.Conditions.scroll_pos
			var r gui.Region
			r.X = int(c.X)
			r.Y = int(c.Y)
			r.Dx = int(c.Width)
			r.Dy = int(c.Height)
			r.PushClipPlanes()
			for _, s := range m.ent.Stats.ConditionNames() {
				d.RenderString(s, c.X+c.Width/2, ypos, 0, d.MaxHeight(), gui.Center)
				ypos -= float64(d.MaxHeight())
			}

			r.PopClipPlanes()
		}

		// Gear
		if m.ent.ExplorerEnt != nil && m.ent.ExplorerEnt.Gear != nil {
			gear := m.ent.ExplorerEnt.Gear
			layout := m.layout.Gear
			icon := gear.Small_icon.Data()
			icon.RenderNatural(int(layout.X), int(layout.Y))
			d := base.GetDictionary(10)
			d.RenderString("Gear", layout.X+float64(icon.Dx())/2, layout.Y-d.MaxHeight(), 0, d.MaxHeight(), gui.Center)
		}
	}

	// Mouseover text
	if m.state.MouseOver.active {
		var x int
		switch m.state.MouseOver.location {
		case mouseOverActions:
			x = int(m.layout.Actions.X + m.layout.Actions.Width/2)
		case mouseOverConditions:
			x = int(m.layout.Conditions.X + m.layout.Conditions.Width/2)
		case mouseOverGear:
		default:
			base.Warn().Printf("Got an unknown mouseover location: %d", m.state.MouseOver.location)
			m.state.MouseOver.active = false
		}
		y := m.layout.Background.Data().Dy() - 40
		d := base.GetDictionary(15)
		d.RenderString(m.state.MouseOver.text, float64(x), float64(y), 0, d.MaxHeight(), gui.Center)
	}
}