274 lines
9.3 KiB
Go
274 lines
9.3 KiB
Go
|
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)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|