Skip to content

Commit

Permalink
Implementing cloth resize on window resize
Browse files Browse the repository at this point in the history
  • Loading branch information
esimov committed Oct 28, 2023
1 parent f2cbd84 commit 4c65b6e
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 51 deletions.
5 changes: 5 additions & 0 deletions cloth.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ func (c *Cloth) Init(posX, posY int, hud *Hud) {
clothX := c.width / c.spacing
clothY := c.height / c.spacing

// Skip the cloth initialization when the window is resized.
if c.isInitialized {
return
}

for y := 0; y <= clothY; y++ {
for x := 0; x <= clothX; x++ {
px := posX + x*c.spacing
Expand Down
63 changes: 32 additions & 31 deletions hud.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,25 @@ type (
)

type Hud struct {
hudTag struct{}
panelInit time.Time
ctrlBtn *Easing
sliders map[int]*slider
slide *Easing
reset widget.Clickable
debug widget.Bool
list layout.List
activator gesture.Click
closer gesture.Click
width int
height int
closeBtn int
btnSize int
controls gesture.Hover
isActive bool
hudTag struct{}
panelInit time.Time
panelWidth int
panelHeight int
winOffsetX float64 // stores the X offset on window horizontal resize
winOffsetY float64 // stores the Y offset on window vertical resize
ctrlBtn *Easing
sliders map[int]*slider
slide *Easing
reset widget.Clickable
debug widget.Bool
list layout.List
activator gesture.Click
closer gesture.Click
closeBtn int
btnSize int
controls gesture.Hover
isActive bool
showHelp bool
}

type slider struct {
Expand Down Expand Up @@ -89,18 +92,16 @@ func (h *Hud) addSlider(index int, s slider) {
h.sliders[index] = &s
}

// ShowHideControlsArea is responsible for showing or hiding the HUD control elements.
// After hovering the mouse over the bottom part of the window a certain amount of time
// it shows the HUD control by invoking an easing function.
func (h *Hud) ShowHideControlsArea(gtx layout.Context, th *material.Theme, m *Mouse, isActive bool) {
// ShowControlPanel is responsible for showing or hiding the HUD control elements.
func (h *Hud) ShowControlPanel(gtx layout.Context, th *material.Theme, m *Mouse, isActive bool) {
if h.reset.Pressed() {
for _, s := range h.sliders {
s.widget.Value = s.value
}
}

progress := h.slide.Update(gtx, isActive)
pos := h.slide.Animate(progress) * float64(h.height)
pos := h.slide.Animate(progress) * float64(h.panelHeight)

// This offset will apply to the rest of the content laid out in this function.
defer op.Offset(image.Pt(0, gtx.Constraints.Max.Y+h.closeBtn-int(pos))).Push(gtx.Ops).Pop()
Expand Down Expand Up @@ -182,11 +183,11 @@ func (h *Hud) ShowHideControlsArea(gtx layout.Context, th *material.Theme, m *Mo
pointer.CursorPointer.Add(gtx.Ops)

/* Draw HUD Contents */
sectionWidth := gtx.Dp(unit.Dp(h.width / 3))
sectionWidth := gtx.Dp(unit.Dp(h.panelWidth / 3))
layout.Flex{
Spacing: layout.SpaceEnd,
}.Layout(gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
layout.Rigid(func(gtx C) D {
gtx.Constraints.Min.X = sectionWidth
gtx.Constraints.Max.X = sectionWidth
layout := layout.UniformInset(unit.Dp(10)).Layout(gtx, func(gtx C) D {
Expand All @@ -201,30 +202,30 @@ func (h *Hud) ShowHideControlsArea(gtx layout.Context, th *material.Theme, m *Mo
return D{}
})
})
h.height = layout.Size.Y + h.closeBtn
h.panelHeight = layout.Size.Y + h.closeBtn
return layout
}),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
layout.Rigid(func(gtx C) D {
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
layout.Rigid(func(gtx C) D {
return layout.UniformInset(unit.Dp(5)).Layout(gtx, material.CheckBox(th, &h.debug, "Show Frame Rates").Layout)
}),
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
layout.Rigid(func(gtx C) D {
return layout.UniformInset(unit.Dp(10)).Layout(gtx, material.Button(th, &h.reset, "Reset").Layout)
}),
)
}),

layout.Flexed(1, func(gtx layout.Context) layout.Dimensions {
layout.Flexed(1, func(gtx C) D {
w := material.Body1(th, fmt.Sprintf("2D Cloth Simulation %s\nCopyright © 2023, Endre Simo", Version))
w.Alignment = text.End
w.Color = th.ContrastBg
w.TextSize = 12
txtOffs := h.height - (3 * h.closeBtn)
txtOffs := h.panelHeight - (3 * h.closeBtn)

defer op.Offset(image.Point{Y: txtOffs}).Push(gtx.Ops).Pop()
return layout.Flex{Axis: layout.Vertical}.Layout(gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions {
layout.Rigid(func(gtx C) D {
return layout.UniformInset(unit.Dp(10)).Layout(gtx, w.Layout)
}),
)
Expand All @@ -235,7 +236,7 @@ func (h *Hud) ShowHideControlsArea(gtx layout.Context, th *material.Theme, m *Mo
// DrawCtrlBtn draws the button which activates the main HUD area with the sliders.
func (h *Hud) DrawCtrlBtn(gtx layout.Context, th *material.Theme, m *Mouse, isActive bool) {
progress := h.slide.Update(gtx, isActive)
pos := h.slide.Animate(progress) * float64(h.height)
pos := h.slide.Animate(progress) * float64(h.panelHeight)
offset := gtx.Dp(unit.Dp(60))

offStack := op.Offset(image.Pt(0, gtx.Constraints.Max.Y-offset+int(pos))).Push(gtx.Ops)
Expand Down
51 changes: 33 additions & 18 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ var (
windowHeight = 580

// Gio Ops related variables
ops op.Ops
initTime time.Time
deltaTime time.Duration
sy unit.Dp
ops op.Ops
initTime time.Time
deltaTime time.Duration
mouseScrollY unit.Dp

// pprof related variables
profile string
Expand All @@ -62,7 +62,7 @@ func main() {
app.Title("Gio - 2D Cloth Simulation"),
app.Size(unit.Dp(windowWidth), unit.Dp(windowHeight)),
)
w.Perform(system.ActionMaximize)
//w.Perform(system.ActionMaximize)
if err := loop(w); err != nil {
log.Fatal(err)
}
Expand Down Expand Up @@ -106,7 +106,7 @@ func loop(w *app.Window) error {
case system.FrameEvent:
start := hrtime.Now()
gtx := layout.NewContext(&ops, e)
hud.width = windowWidth
hud.panelWidth = windowWidth
hud.btnSize = gtx.Dp(unit.Dp(40))
hud.closeBtn = gtx.Dp(unit.Dp(25))

Expand Down Expand Up @@ -136,7 +136,7 @@ func loop(w *app.Window) error {

key.InputOp{
Tag: &keyTag,
Keys: key.NameEscape + "|" + key.NameCtrl + "|" + key.NameAlt + "|" + key.NameSpace,
Keys: key.NameEscape + "|" + key.NameCtrl + "|" + key.NameAlt + "|" + key.NameSpace + "|" + key.NameF1,
}.Add(gtx.Ops)

if mouse.getLeftButton() {
Expand All @@ -156,8 +156,11 @@ func loop(w *app.Window) error {
for _, ev := range gtx.Queue.Events(&keyTag) {
if e, ok := ev.(key.Event); ok {
if e.State == key.Press {
if e.Name == key.NameSpace {
switch e.Name {
case key.NameSpace:
resetCloth()
case key.NameF1:
hud.showHelp = !hud.showHelp
}
}
if e.Name == key.NameEscape {
Expand All @@ -166,11 +169,24 @@ func loop(w *app.Window) error {
}
}

// Reset cloth on window resize.
// Reset the window offsets on resize.
hud.winOffsetX = 0
hud.winOffsetY = 0

if e.Size.X != windowWidth {
hud.winOffsetX = float64(e.Size.X-windowWidth) * 0.5
}
if e.Size.Y != windowHeight {
hud.winOffsetY = float64(e.Size.Y-windowHeight) * 0.25
}

if e.Size.X != windowWidth || e.Size.Y != windowHeight {
cloth.Init(windowWidth, windowHeight, hud)

windowWidth = e.Size.X
windowHeight = e.Size.Y
resetCloth()
cloth.width = windowWidth
cloth.height = windowHeight
}
fillBackground(gtx, color.NRGBA{R: 0xf2, G: 0xf2, B: 0xf2, A: 0xff})

Expand Down Expand Up @@ -207,13 +223,13 @@ func loop(w *app.Window) error {
key.FocusOp{Tag: keyTag}.Add(gtx.Ops)
switch ev.Type {
case pointer.Scroll:
sy += unit.Dp(ev.Scroll.Y)
if sy < minFocusArea {
sy = minFocusArea
} else if sy > mouse.maxScrollY {
sy = mouse.maxScrollY
mouseScrollY += unit.Dp(ev.Scroll.Y)
if mouseScrollY < minFocusArea {
mouseScrollY = minFocusArea
} else if mouseScrollY > mouse.maxScrollY {
mouseScrollY = mouse.maxScrollY
}
mouse.setScrollY(sy)
mouse.setScrollY(mouseScrollY)
case pointer.Move:
pos := mouse.getCurrentPosition(ev)
mouse.updatePosition(float64(pos.X), float64(pos.Y))
Expand Down Expand Up @@ -247,7 +263,6 @@ func loop(w *app.Window) error {
}
}
}

cloth.Update(gtx, mouse, hud, delta)
return layout.Dimensions{}
}),
Expand Down Expand Up @@ -282,7 +297,7 @@ func loop(w *app.Window) error {
}
}
hud.DrawCtrlBtn(gtx, th, mouse, hud.isActive)
hud.ShowHideControlsArea(gtx, th, mouse, hud.isActive)
hud.ShowControlPanel(gtx, th, mouse, hud.isActive)

return layout.Dimensions{}
}),
Expand Down
8 changes: 6 additions & 2 deletions particle.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
const (
clothPinDist = 4
defFocusArea = 50
minFocusArea = 20
minFocusArea = 30
maxFocusArea = 120
maxDragForce = 20
)
Expand Down Expand Up @@ -50,7 +50,6 @@ func NewParticle(x, y float64, hud *Hud, col color.NRGBA) *Particle {

// Update updates the particle system using the Verlet integration.
func (p *Particle) Update(gtx layout.Context, mouse *Mouse, hud *Hud, delta float64) {
//p.draw(gtx, float32(p.x), float32(p.y), 2)
p.update(gtx, mouse, hud, delta)
}

Expand Down Expand Up @@ -86,6 +85,11 @@ func (p *Particle) update(gtx layout.Context, mouse *Mouse, hud *Hud, dt float64
tearDistance := float64(hud.sliders[3].widget.Value)

if p.pinX {
// Recalculate the pinned particles position when the window is resized.
// We need to do this only for the pinned particles, because the rest
// of the particles will just adjust themselves.
p.x += hud.winOffsetX
p.y += hud.winOffsetY
return
}

Expand Down

0 comments on commit 4c65b6e

Please sign in to comment.