add initial randoffset mode
This commit is contained in:
		
							parent
							
								
									82f09db519
								
							
						
					
					
						commit
						2d536f21f3
					
				
							
								
								
									
										5
									
								
								main.go
								
								
								
								
							
							
						
						
									
										5
									
								
								main.go
								
								
								
								
							| 
						 | 
				
			
			@ -69,7 +69,8 @@ func main() {
 | 
			
		|||
			// run RPC server, tasking clients to flut
 | 
			
		||||
			wg.Add(1)
 | 
			
		||||
			r := rpc.SummonRán(*ránAddr, stopChan, &wg)
 | 
			
		||||
			r.SetTask(img, offset, *address, *connections) // @incomplete
 | 
			
		||||
			// TODO: startup without a task, but init params
 | 
			
		||||
			r.SetTask(img, offset, *address, *connections)
 | 
			
		||||
 | 
			
		||||
		} else {
 | 
			
		||||
			// fetch server state and save to file
 | 
			
		||||
| 
						 | 
				
			
			@ -82,7 +83,7 @@ func main() {
 | 
			
		|||
 | 
			
		||||
			// local 🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊🌊
 | 
			
		||||
			wg.Add(1)
 | 
			
		||||
			go pixelflut.Flut(img, offset, *shuffle, *address, *connections, stopChan, &wg)
 | 
			
		||||
			go pixelflut.Flut(img, offset, *shuffle, false, false, false, *address, *connections, stopChan, &wg)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	} else if *hevringAddr != "" {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,21 +6,20 @@ import (
 | 
			
		|||
	"image"
 | 
			
		||||
	"image/color"
 | 
			
		||||
	"log"
 | 
			
		||||
	"math/rand"
 | 
			
		||||
	"net"
 | 
			
		||||
	"sync"
 | 
			
		||||
 | 
			
		||||
	"github.com/SpeckiJ/Hochwasser/render"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var funmode = false
 | 
			
		||||
 | 
			
		||||
// Flut asynchronously sends the given image to pixelflut server at `address`
 | 
			
		||||
//   using `conns` connections. Pixels are sent column wise, unless `shuffle`
 | 
			
		||||
//   is set. Stops when stop is closed.
 | 
			
		||||
// @cleanup: use FlutTask{} as arg
 | 
			
		||||
func Flut(img *image.NRGBA, position image.Point, shuffle bool, address string, conns int, stop chan bool, wg *sync.WaitGroup) {
 | 
			
		||||
func Flut(img *image.NRGBA, position image.Point, shuffle, rgbsplit, randoffset, recreateConns bool, address string, conns int, stop chan bool, wg *sync.WaitGroup) {
 | 
			
		||||
	var cmds commands
 | 
			
		||||
	if funmode {
 | 
			
		||||
	if rgbsplit {
 | 
			
		||||
		// do a RGB split of white
 | 
			
		||||
		imgmod := render.ImgColorFilter(img, color.NRGBA{0xff, 0xff, 0xff, 0xff}, color.NRGBA{0xff, 0, 0, 0xff})
 | 
			
		||||
		cmds = append(cmds, commandsFromImage(imgmod, image.Pt(position.X-10, position.Y-10))...)
 | 
			
		||||
| 
						 | 
				
			
			@ -36,11 +35,31 @@ func Flut(img *image.NRGBA, position image.Point, shuffle bool, address string,
 | 
			
		|||
	if shuffle {
 | 
			
		||||
		cmds.Shuffle()
 | 
			
		||||
	}
 | 
			
		||||
	messages := cmds.Chunk(conns)
 | 
			
		||||
 | 
			
		||||
	var messages [][]byte
 | 
			
		||||
	var maxX, maxY int
 | 
			
		||||
	if randoffset {
 | 
			
		||||
		maxX, maxY = CanvasSize(address)
 | 
			
		||||
		messages = cmds.Chunk(1) // each connection should send the full img
 | 
			
		||||
	} else {
 | 
			
		||||
		messages = cmds.Chunk(conns)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bombWg := sync.WaitGroup{}
 | 
			
		||||
	for _, msg := range messages {
 | 
			
		||||
	for i := 0; i < conns; i++ {
 | 
			
		||||
		msg := messages[0]
 | 
			
		||||
		if len(messages) > i {
 | 
			
		||||
			msg = messages[i]
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		bombWg.Add(1)
 | 
			
		||||
		if randoffset {
 | 
			
		||||
			msg = append(OffsetCmd(
 | 
			
		||||
				rand.Intn(maxX-img.Bounds().Canon().Dx()),
 | 
			
		||||
				rand.Intn(maxY-img.Bounds().Canon().Dy()),
 | 
			
		||||
			), msg...)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		go bombAddress(msg, address, stop, &bombWg)
 | 
			
		||||
	}
 | 
			
		||||
	bombWg.Wait()
 | 
			
		||||
| 
						 | 
				
			
			@ -49,6 +68,23 @@ func Flut(img *image.NRGBA, position image.Point, shuffle bool, address string,
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CanvasSize returns the size of the canvas as returned by the server
 | 
			
		||||
func CanvasSize(address string) (int, int) {
 | 
			
		||||
	conn, err := net.Dial("tcp", address)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	defer conn.Close()
 | 
			
		||||
 | 
			
		||||
	conn.Write([]byte("SIZE\n"))
 | 
			
		||||
	reader := bufio.NewReader(conn)
 | 
			
		||||
	res, err := reader.ReadSlice('\n')
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	return parseXY(res[5:])
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FetchImage asynchronously uses `conns` to fetch pixels within `bounds` from
 | 
			
		||||
//   a pixelflut server at `address`, and writes them into the returned Image.
 | 
			
		||||
func FetchImage(bounds image.Rectangle, address string, conns int, stop chan bool) (img *image.NRGBA) {
 | 
			
		||||
| 
						 | 
				
			
			@ -84,15 +120,7 @@ func readPixels(target *image.NRGBA, conn net.Conn, stop chan bool) {
 | 
			
		|||
 | 
			
		||||
			// parse response ("PX <x> <y> <col>\n")
 | 
			
		||||
			colorStart := len(res) - 7
 | 
			
		||||
			xy := res[3 : colorStart-1]
 | 
			
		||||
			yStart := 0
 | 
			
		||||
			for yStart = len(xy) - 2; yStart >= 0; yStart-- {
 | 
			
		||||
				if xy[yStart] == ' ' {
 | 
			
		||||
					break
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			x := asciiToInt(xy[:yStart])
 | 
			
		||||
			y := asciiToInt(xy[yStart+1:])
 | 
			
		||||
			x, y := parseXY(res[3 : colorStart-1])
 | 
			
		||||
			hex.Decode(col, res[colorStart:len(res)-1])
 | 
			
		||||
 | 
			
		||||
			target.SetNRGBA(x, y, color.NRGBA{col[0], col[1], col[2], 255})
 | 
			
		||||
| 
						 | 
				
			
			@ -100,6 +128,19 @@ func readPixels(target *image.NRGBA, conn net.Conn, stop chan bool) {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseXY(xy []byte) (int, int) {
 | 
			
		||||
	last := len(xy) - 1
 | 
			
		||||
	yStart := last - 1 // y is at least one char long
 | 
			
		||||
	for ; yStart >= 0; yStart-- {
 | 
			
		||||
		if xy[yStart] == ' ' {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	x := asciiToInt(xy[:yStart])
 | 
			
		||||
	y := asciiToInt(xy[yStart+1 : last])
 | 
			
		||||
	return x, y
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func asciiToInt(buf []byte) (v int) {
 | 
			
		||||
	for _, c := range buf {
 | 
			
		||||
		v = v*10 + int(c-'0')
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -32,6 +32,11 @@ func (c commands) Shuffle() {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddOffset uses the OFFSET command to send the image at a specific place (not supported by all servers. example: https://github.com/TobleMiner/shoreline)
 | 
			
		||||
func OffsetCmd(x, y int) []byte {
 | 
			
		||||
	return []byte(fmt.Sprintf("OFFSET %d %d\n", x, y))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CommandsFromImage converts an image to the respective pixelflut commands
 | 
			
		||||
func commandsFromImage(img *image.NRGBA, offset image.Point) (cmds commands) {
 | 
			
		||||
	b := img.Bounds()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,12 +30,14 @@ type Hevring struct {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
type FlutTask struct {
 | 
			
		||||
	Address  string
 | 
			
		||||
	MaxConns int
 | 
			
		||||
	Img      *image.NRGBA
 | 
			
		||||
	Offset   image.Point
 | 
			
		||||
	Shuffle  bool
 | 
			
		||||
	// Effects  []string // @idea shuffle, rgbsplit, randoffset, ...
 | 
			
		||||
	Address    string
 | 
			
		||||
	MaxConns   int
 | 
			
		||||
	Img        *image.NRGBA
 | 
			
		||||
	Offset     image.Point
 | 
			
		||||
	Shuffle    bool // TODO: refactor these as RenderOpts bitfield
 | 
			
		||||
	RGBSplit   bool
 | 
			
		||||
	RandOffset bool
 | 
			
		||||
	NewConn    bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type FlutAck struct{ Ok bool }
 | 
			
		||||
| 
						 | 
				
			
			@ -56,7 +58,7 @@ func (h *Hevring) Flut(task FlutTask, reply *FlutAck) error {
 | 
			
		|||
	h.task = task
 | 
			
		||||
	h.taskQuit = make(chan bool)
 | 
			
		||||
 | 
			
		||||
	go pixelflut.Flut(task.Img, task.Offset, task.Shuffle, task.Address, task.MaxConns, h.taskQuit, nil)
 | 
			
		||||
	go pixelflut.Flut(task.Img, task.Offset, task.Shuffle, task.RGBSplit, task.RandOffset, task.NewConn, task.Address, task.MaxConns, h.taskQuit, nil)
 | 
			
		||||
	reply.Ok = true
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										15
									
								
								rpc/repl.go
								
								
								
								
							
							
						
						
									
										15
									
								
								rpc/repl.go
								
								
								
								
							| 
						 | 
				
			
			@ -82,6 +82,21 @@ func RunREPL(f Fluter) {
 | 
			
		|||
				t.Shuffle = !t.Shuffle
 | 
			
		||||
				f.applyTask(t)
 | 
			
		||||
 | 
			
		||||
			case "rgbsplit":
 | 
			
		||||
				t := f.getTask()
 | 
			
		||||
				t.RGBSplit = !t.RGBSplit
 | 
			
		||||
				f.applyTask(t)
 | 
			
		||||
 | 
			
		||||
			case "randoffset":
 | 
			
		||||
				t := f.getTask()
 | 
			
		||||
				t.RandOffset = !t.RandOffset
 | 
			
		||||
				f.applyTask(t)
 | 
			
		||||
 | 
			
		||||
			case "newconn":
 | 
			
		||||
				t := f.getTask()
 | 
			
		||||
				t.NewConn = !t.NewConn
 | 
			
		||||
				f.applyTask(t)
 | 
			
		||||
 | 
			
		||||
			case "txt":
 | 
			
		||||
				if len(args) > 0 {
 | 
			
		||||
					if size, err := strconv.Atoi(args[0]); err == nil {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue