go-susapp/renderer.go
2021-09-12 00:25:10 +01:00

274 lines
9.3 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package main
import (
"math"
"strconv"
"time"
"codehub.onpointcoding.net/sean/go-susapp/enum"
"codehub.onpointcoding.net/sean/go-susapp/innernetobjects"
"codehub.onpointcoding.net/sean/go-susapp/util"
"github.com/gotk3/gotk3/cairo"
"github.com/gotk3/gotk3/gtk"
"github.com/gotk3/gotk3/pango"
)
type Renderer struct {
state *State
da *gtk.DrawingArea
cr *cairo.Context
w float64
h float64
mouseX float64
mouseY float64
delta int64
}
var defaultRenderFont string = "Noto Sans"
func NewRenderer(state *State) *Renderer {
return &Renderer{state: state}
}
func (r *Renderer) Draw(da *gtk.DrawingArea, cr *cairo.Context) {
r.delta = time.Now().UnixMilli()
r.da = da
r.cr = cr
allocation := da.GetAllocation()
r.w = float64(allocation.GetWidth())
r.h = float64(allocation.GetHeight())
versionText := GetVersionFormatted(r.state.Version)
// Background
r.DrawFilledRectangle(0, 0, r.w, r.h, 0x14181c)
// Version numbers
r.DrawText(10, 10, versionText, "Noto Sans Display", 16, 0xffffff)
if r.state.Screen == enum.SCREEN_TITLE {
colorLen := enum.GetPlayerTotalColors()
for i := 0; i < colorLen; i++ {
r.DrawFilledRectangle(float64(i)*20+(r.w-float64(colorLen)-float64(colorLen*20))/2, 0, 20, 20, enum.GetPlayerMainColor(i))
r.DrawFilledRectangle(float64(i)*20+(r.w-float64(colorLen)-float64(colorLen*20))/2, 20, 20, 20, enum.GetPlayerShadedColor(i))
}
r.DrawButton(r.w-120, 20, 100, 40, r.state.Settings.PlayerName, defaultRenderFont, 16)
r.DrawButton(r.w-120, 60, 100, 40, r.state.Settings.ServerAddress, defaultRenderFont, 16)
r.DrawButton(r.w-120, 100, 100, 40, strconv.FormatInt(r.state.Settings.ServerPort, 10), defaultRenderFont, 16)
r.DrawTextInput((r.w-200)/2, (r.h-20)/2-60, 200, 40, r.state.TypedGameID, defaultRenderFont, 16, r.state.IsTypingReady)
r.DrawButton((r.w-200)/2, (r.h-20)/2, 200, 40, "Play", defaultRenderFont, 16)
r.DrawButton(r.w-60, r.h-60, 40, 40, "⚙", defaultRenderFont, 16)
} else if r.state.Screen == enum.SCREEN_WAITING {
mw := r.w / 2
mh := r.h / 2
a := float64(r.delta/10) * (math.Pi / 180)
b := a + math.Pi/2
c := a + math.Pi
d := a + math.Pi*3/2
r.DrawFilledRoundedRectangle(mw+50*math.Sin(a)-20, mh+50*math.Cos(a)-20, 40, 40, 1, 20, 0xffffff)
r.DrawFilledRoundedRectangle(mw+50*math.Sin(b)-20, mh+50*math.Cos(b)-20, 40, 40, 1, 20, 0xffffff)
r.DrawFilledRoundedRectangle(mw+50*math.Sin(c)-20, mh+50*math.Cos(c)-20, 40, 40, 1, 20, 0xffffff)
r.DrawFilledRoundedRectangle(mw+50*math.Sin(d)-20, mh+50*math.Cos(d)-20, 40, 40, 1, 20, 0xffffff)
} else if r.state.Screen == enum.SCREEN_LOBBY {
r.DrawButton((r.w-100)/2, r.h-60, 100, 40, util.CodeFromGameID(r.state.CurrentGame.GameID), defaultRenderFont, 16)
r.DrawButton(r.w-60, 20, 40, 40, "⚙", defaultRenderFont, 16)
if r.state.CurrentGame.GamePrivacy == 1 {
r.DrawButton((r.w-100)/2+120, r.h-60, 100, 40, "Public", defaultRenderFont, 16)
} else if r.state.CurrentGame.GamePrivacy == 0 {
r.DrawButton((r.w-100)/2+120, r.h-60, 100, 40, "Private", defaultRenderFont, 16)
}
r.DrawPlayers()
if r.state.IsLobbyMenuOpen {
mw := r.w / 2
mh := r.h / 2
overlayBottom := mh + 200
r.DrawFilledRectangle(0, 0, r.w, r.h, 0x80000000)
r.DrawFilledRoundedRectangle(mw-200, mh-200, 400, 400, 1, 20, 0x000000)
r.DrawButton((r.w-200)/2, overlayBottom-60, 200, 40, "Return to Game", defaultRenderFont, 16)
r.DrawButton((r.w-200)/2, overlayBottom-120, 200, 40, "Leave Game", defaultRenderFont, 16)
}
} else if r.state.Screen == enum.SCREEN_ERROR {
mw := r.w / 2
mh := r.h / 2
r.DrawFilledRoundedRectangle(mw-200, mh-200, 400, 400, 1, 20, 0x000000)
r.DrawText(mw-190, mh-190, "Disconnected", defaultRenderFont, 16, 0xffffff)
r.DrawButton(mw+170, mh-210, 40, 40, "×", defaultRenderFont, 16)
if r.state.DisconnectReason == 0xfe {
r.DrawWrappedText(mw-190, mh-156, 380, r.state.DisconnectStringReason, defaultRenderFont, 16, 0xffffff)
} else {
r.DrawWrappedText(mw-190, mh-156, 380, enum.DisconnectMessageText(r.state.DisconnectReason), defaultRenderFont, 16, 0xffffff)
}
}
}
func (r *Renderer) SetRGB(red int, green int, blue int, alpha int) {
r.cr.SetSourceRGBA(float64(red)/0xff, float64(green)/0xff, float64(blue)/0xff, 0xff/float64(alpha))
}
func (r *Renderer) SetHex(hex int) {
r.SetRGB((hex/(256*256))%256, (hex/256)%256, hex%256, (hex/(256*256*256))%256)
}
func (r *Renderer) DrawRectangle(x float64, y float64, w float64, h float64, color int) {
r.SetHex(color)
r.cr.Rectangle(x, y, w, h)
r.cr.Stroke()
}
func (r *Renderer) DrawFilledRectangle(x float64, y float64, w float64, h float64, color int) {
r.SetHex(color)
r.cr.Rectangle(x, y, w, h)
r.cr.Fill()
}
func (r *Renderer) DrawBorderedRectangle(x float64, y float64, w float64, h float64, color int, border int) {
r.DrawFilledRectangle(x, y, w, h, color)
r.DrawRectangle(x, y, w, h, border)
}
func (r *Renderer) DrawRoundedRectangle(x float64, y float64, w float64, h float64, aspect float64, corner_radius float64, color int) {
a := corner_radius / aspect
d := math.Pi / 180
r.cr.NewPath()
r.cr.Arc(x+w-a, y+a, a, -90*d, 0*d)
r.cr.Arc(x+w-a, y+h-a, a, 0*d, 90*d)
r.cr.Arc(x+a, y+h-a, a, 90*d, 180*d)
r.cr.Arc(x+a, y+a, a, 180*d, 270*d)
r.cr.ClosePath()
r.SetHex(color)
r.cr.Stroke()
}
func (r *Renderer) DrawFilledRoundedRectangle(x float64, y float64, w float64, h float64, aspect float64, corner_radius float64, color int) {
a := corner_radius / aspect
d := math.Pi / 180
r.cr.NewPath()
r.cr.Arc(x+w-a, y+a, a, -90*d, 0*d)
r.cr.Arc(x+w-a, y+h-a, a, 0*d, 90*d)
r.cr.Arc(x+a, y+h-a, a, 90*d, 180*d)
r.cr.Arc(x+a, y+a, a, 180*d, 270*d)
r.cr.ClosePath()
r.SetHex(color)
r.cr.FillPreserve()
}
func (r *Renderer) DrawBorderedRoundedRectangle(x float64, y float64, w float64, h float64, aspect float64, corner_radius float64, color int, border int) {
a := corner_radius / aspect
d := math.Pi / 180
r.cr.NewPath()
r.cr.Arc(x+w-a, y+a, a, -90*d, 0*d)
r.cr.Arc(x+w-a, y+h-a, a, 0*d, 90*d)
r.cr.Arc(x+a, y+h-a, a, 90*d, 180*d)
r.cr.Arc(x+a, y+a, a, 180*d, 270*d)
r.cr.ClosePath()
r.SetHex(color)
r.cr.FillPreserve()
r.SetHex(border)
r.cr.Stroke()
}
func (r *Renderer) DrawText(x float64, y float64, text string, fontFamily string, fontSize float64, color int) {
layout := pango.CairoCreateLayout(r.cr)
font := pango.FontDescriptionFromString("sans normal 16")
font.SetFamily(fontFamily)
layout.SetFontDescription(font)
layout.SetText(text, len(text))
r.SetHex(color)
r.cr.MoveTo(x, y)
pango.CairoUpdateLayout(r.cr, layout)
pango.CairoShowLayout(r.cr, layout)
}
func (r *Renderer) DrawWrappedText(x float64, y float64, w float64, text string, fontFamily string, fontSize float64, color int) {
layout := pango.CairoCreateLayout(r.cr)
layout.SetWidth(int(w) * pango.SCALE)
font := pango.FontDescriptionFromString("sans normal 16")
font.SetFamily(fontFamily)
layout.SetFontDescription(font)
layout.SetText(text, len(text))
r.SetHex(color)
r.cr.MoveTo(x, y)
pango.CairoUpdateLayout(r.cr, layout)
pango.CairoShowLayout(r.cr, layout)
}
func (r *Renderer) DrawButton(x float64, y float64, w float64, h float64, text string, fontFamily string, fontSize float64) {
r.DrawFilledRoundedRectangle(x, y, w-4, h-4, w/h, 10, 0x000000)
if r.mouseX > x && r.mouseX < x+w && r.mouseY > y && r.mouseY < y+h {
r.DrawRoundedRectangle(x, y, w-4, h-4, w/h, 10, 0x00ff00)
} else {
r.DrawRoundedRectangle(x, y, w-4, h-4, w/h, 10, 0xffffff)
}
layout := pango.CairoCreateLayout(r.cr)
font := pango.FontDescriptionFromString("sans normal 16")
font.SetFamily(fontFamily)
layout.SetFontDescription(font)
layout.SetText(text, len(text))
textWidth, textHeight := layout.GetSize()
textWidth /= pango.SCALE
textHeight /= pango.SCALE
r.SetHex(0xffffff)
r.cr.MoveTo(x+(w-4-float64(textWidth))/2, y+(h-4-float64(textHeight))/2)
pango.CairoUpdateLayout(r.cr, layout)
pango.CairoShowLayout(r.cr, layout)
}
func (r *Renderer) DrawTextInput(x float64, y float64, w float64, h float64, text string, fontFamily string, fontSize float64, inFocus bool) {
if r.mouseX > x && r.mouseX < x+w && r.mouseY > y && r.mouseY < y+h {
r.DrawFilledRectangle(x, y+h-6, w-4, 2, 0x00ffff)
} else {
r.DrawFilledRectangle(x, y+h-6, w-4, 2, 0xffffff)
}
layout := pango.CairoCreateLayout(r.cr)
font := pango.FontDescriptionFromString("sans normal 16")
font.SetFamily(fontFamily)
layout.SetFontDescription(font)
layout.SetText(text, len(text))
textWidth, textHeight := layout.GetSize()
textWidth /= pango.SCALE
textHeight /= pango.SCALE
r.SetHex(0xffffff)
r.cr.MoveTo(x+(w-float64(textWidth))/2, y+(h-12-float64(textHeight))/2)
pango.CairoUpdateLayout(r.cr, layout)
pango.CairoShowLayout(r.cr, layout)
if inFocus && r.delta%1600 < 800 {
r.DrawFilledRectangle(x+(w+float64(textWidth))/2, y+4, 2, 20, 0xffffff)
}
}
func (r *Renderer) DrawPlayers() {
for _, item := range r.state.CurrentGame.PlayerNetObjects.ByPlayerClientID {
var t innernetobjects.InnerNetObject = *r.state.CurrentGame.NetObjects[item.PlayerNetworkTransform]
a, ok := t.(*innernetobjects.PlayerNetworkTransform)
if ok {
x := r.w/2 + float64(a.TargetPosition.X)*50
y := r.h/2 - float64(a.TargetPosition.Y)*50
r.DrawFilledRectangle(float64(x-5), float64(y-5), 10, 10, enum.GetPlayerMainColor(int(item.PlayerColor)))
r.DrawText(x, y, strconv.FormatFloat(float64(a.TargetPosition.X), 'e', 4, 64)+strconv.FormatFloat(float64(a.TargetPosition.Y), 'e', 4, 64), defaultRenderFont, 10, 0xffffff)
}
}
}