123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- package door
- import (
- "bytes"
- )
- type SpinRite struct {
- Width uint8 // Width of the animation (must be odd)
- Length uint8 // Width of the worm (must be odd)
- Color []byte // Color (default CYAN ON BLUE)
- OutputB []byte // Output CP437/bytes (Width)
- OutputR []rune // Output Unicode (Width)
- Buffer []uint8 // Output calculate buffer (Width)
- Runes []rune // blank, center, top, bottom, both
- Bytes []byte // blank, center, top, bottom, both
- CenterPos uint8 // Center Position (Width - 1) / 2
- StartPos uint8 // Starting Position (Length -1) / 2
- Index uint8 // Index of current iteration
- output *bytes.Buffer // Buffer for output
- }
- /*
- Other center character options: · ∞
- We default to ∞
- [ █████ ]
- [ ▄▄███▀▀ ]
- [ ▄▄▄▄█▀▀▀▀ ]
- [ ▄▄▄▄▄•▀▀▀▀▀ ]
- [▄▄▄▄▄ • ▀▀▀▀▀]
- [█▄▄▄ • ▀▀▀█]
- [██▄ • ▀██]
- [██▀ • ▄██]
- [█▀▀▀ • ▄▄▄█]
- [█▀▀▀▀ • ▄▄▄▄█]
- [ ▀▀▀▀▀•▄▄▄▄▄ ]
- [ ▀▀▀▀█▄▄▄▄ ]
- [ ▀▀███▄▄ ]
- */
- /*
- 0 = Blank
- 1 = Center Character
- 2 = Top
- 3 = Bottom
- 4 = Full Block
- */
- func SpinRiteInit(width uint8, length uint8, color []byte) SpinRite {
- if len(color) == 0 {
- color = ColorText("CYAN ON BLUE")
- }
- var center uint8 = ((width - 1) / 2)
- var start uint8 = ((length - 1) / 2)
- var result SpinRite = SpinRite{Width: width,
- Length: length,
- Color: color,
- CenterPos: center,
- StartPos: start,
- Buffer: make([]uint8, width),
- Index: 0,
- output: &bytes.Buffer{}}
- if Unicode {
- result.OutputR = make([]rune, width)
- result.Runes = []rune{' ', '\u221e', '\u2580', '\u2584', '\u2588'}
- } else {
- result.OutputB = make([]byte, width)
- result.Bytes = []byte{' ', 0xec, 0xdf, 0xdc, 0xdb}
- }
- return result
- }
- func (sr *SpinRite) PosToIndex(pos int8, top bool) (index uint8, level bool) {
- if top {
- if pos >= int8(sr.Width) {
- // wrap around
- level = !top
- idx := int8(sr.Width) + (int8(sr.Width) - (pos + 1))
- index = uint8(idx)
- } else {
- level = top
- index = uint8(pos)
- }
- } else {
- // bottom
- if pos < 0 {
- level = !top
- pos++
- index = uint8(-pos)
- } else {
- level = top
- index = uint8(pos)
- }
- }
- return
- }
- func (sr *SpinRite) Calculate() {
- for i := range sr.Buffer {
- sr.Buffer[i] = 0
- }
- sr.Buffer[sr.CenterPos] = 1
- // [ S C s ]
- var top int8 = int8(sr.CenterPos) - int8(sr.StartPos) + int8(sr.Index)
- var bottom int8 = int8(sr.CenterPos) + int8(sr.StartPos) - int8(sr.Index)
- var l int8
- for l = 0; l < int8(sr.Length); l++ {
- var index uint8
- var level bool
- index, level = sr.PosToIndex(top+l, true)
- // log.Println("TOP", l, top+l, index, level)
- if level {
- sr.Buffer[index] |= 0x02
- } else {
- sr.Buffer[index] |= 0x04
- }
- index, level = sr.PosToIndex(bottom-l, false)
- // log.Println("BOT", l, bottom-l, index, level)
- if level {
- sr.Buffer[index] |= 0x02
- } else {
- sr.Buffer[index] |= 0x04
- }
- }
- // log.Println("Index", sr.Index, "Buffer", sr.Buffer)
- var reset bool = true
- // Convert from buffer to output
- if Unicode {
- for l = 0; l < int8(sr.Width); l++ {
- switch sr.Buffer[l] {
- case 0:
- sr.OutputR[l] = sr.Runes[0]
- case 1:
- sr.OutputR[l] = sr.Runes[1]
- reset = false
- case 2, 3:
- sr.OutputR[l] = sr.Runes[2]
- reset = false
- case 4, 5:
- sr.OutputR[l] = sr.Runes[3]
- reset = false
- case 6, 7:
- sr.OutputR[l] = sr.Runes[4]
- }
- }
- } else {
- for l = 0; l < int8(sr.Width); l++ {
- switch sr.Buffer[l] {
- case 0:
- sr.OutputB[l] = sr.Bytes[0]
- case 1:
- sr.OutputB[l] = sr.Bytes[1]
- reset = false
- case 2, 3:
- sr.OutputB[l] = sr.Bytes[2]
- reset = false
- case 4, 5:
- sr.OutputB[l] = sr.Bytes[3]
- reset = false
- case 6, 7:
- sr.OutputB[l] = sr.Bytes[4]
- }
- }
- }
- if reset {
- // log.Println("RESET")
- sr.Index = 0
- }
- }
- func (sr *SpinRite) Output() []byte {
- // var result string
- sr.output.Reset()
- // sr.Result.Reset()
- sr.output.Write(sr.Color)
- sr.Calculate()
- if Unicode {
- // result = string(sr.OutputR)
- for _, r := range sr.OutputR {
- sr.output.WriteRune(r)
- }
- // Use the above, benchmark.
- // sr.output.WriteString(string(sr.OutputR))
- } else {
- //result = string(sr.OutputB)
- sr.output.Write(sr.OutputB)
- }
- sr.Index++
- // return sr.Color + result
- return sr.output.Bytes()
- }
- type SpinRiteMsg struct {
- SpinRite
- Messages []string
- MsgIndex int
- Next bool
- }
- func SpinRiteMsgInit(width uint8, length uint8, color []byte, messages []string) SpinRiteMsg {
- var result SpinRiteMsg = SpinRiteMsg{SpinRite: SpinRiteInit(width, length, color)}
- if Unicode {
- result.Runes[1] = result.Runes[0]
- } else {
- result.SpinRite.Bytes[1] = result.SpinRite.Bytes[0]
- }
- result.Messages = messages
- result.MsgIndex = 0
- result.Next = false
- return result
- }
- func (sr *SpinRiteMsg) Output() []byte {
- sr.output.Reset()
- sr.Calculate()
- if sr.Next && sr.Index == 0 {
- sr.MsgIndex++
- if sr.MsgIndex == len(sr.Messages) {
- sr.MsgIndex = 0
- }
- }
- if sr.Index != 0 {
- sr.Next = true
- }
- // Place message
- var message string = sr.Messages[sr.MsgIndex]
- var msg []rune = []rune(message)
- var pos int = int(sr.CenterPos)
- // Bug: If we're changing to next message (sr.Next == True) ... but the
- // message is > SpinRite.Length, it shows the text beyond what it should.
- var texthalf int = StringLen([]byte(message)) / 2
- // Place text center, outwards. Stopping if there's no space.
- for i := 0; i < texthalf+1; i++ {
- if Unicode {
- if sr.OutputR[pos+i] == ' ' {
- if texthalf+i < StringLen([]byte(message)) {
- sr.OutputR[pos+i] = []rune(msg)[texthalf+i]
- }
- } else {
- break
- }
- if i != 0 {
- if sr.OutputR[pos-i] == ' ' {
- sr.OutputR[pos-i] = []rune(msg)[texthalf-i]
- } else {
- break
- }
- }
- } else {
- if sr.OutputB[pos+i] == ' ' {
- if texthalf+i < StringLen([]byte(message)) {
- sr.OutputB[pos+i] = byte(msg[texthalf+i])
- }
- } else {
- break
- }
- if i != 0 {
- if sr.OutputB[pos-i] == ' ' {
- sr.OutputB[pos-i] = byte(msg[texthalf-i])
- } else {
- break
- }
- }
- }
- }
- /*
- for i := 0; i < len(msg); i++ {
- if Unicode {
- if sr.OutputR[pos+i] == ' ' {
- sr.OutputR[pos+i] = []rune(msg)[i]
- }
- } else {
- if sr.OutputB[pos+i] == ' ' {
- sr.OutputB[pos+i] = byte(msg[i])
- }
- }
- }
- */
- sr.output.Write(sr.Color)
- if Unicode {
- for _, r := range sr.OutputR {
- sr.output.WriteRune(r)
- }
- // result = string(sr.OutputR)
- } else {
- sr.output.Write(sr.OutputB)
- // result = string(sr.OutputB)
- }
- sr.Index++
- // return sr.Color + result
- return sr.output.Bytes()
- }
|