Big refactor
Signed-off-by: Martyn Ranyard <m@rtyn.berlin>
This commit is contained in:
		
							parent
							
								
									2202ba2fc0
								
							
						
					
					
						commit
						bed25ca03c
					
				
					 10 changed files with 461 additions and 132 deletions
				
			
		
							
								
								
									
										27
									
								
								internal/patterns/common.go
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										27
									
								
								internal/patterns/common.go
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,27 @@ | ||||||
|  | package patterns | ||||||
|  | 
 | ||||||
|  | func Even(number int) bool { | ||||||
|  | 	return number %2 == 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func FillPanel(w int, h int, r byte, g byte, b byte) [][]RGBcolor { | ||||||
|  | 	grid := make([][]RGBcolor, w) | ||||||
|  | 	for i := 0; i < w; i++ { | ||||||
|  | 		grid[i] = make([]RGBcolor, h) | ||||||
|  | 	} | ||||||
|  | 	for x := 0; x < w; x++ { | ||||||
|  | 		for y := 0; y < h; y++ { | ||||||
|  | 			var rgb [3]byte | ||||||
|  | 			rgb[0] = r | ||||||
|  | 			rgb[1] = g | ||||||
|  | 			rgb[2] = b | ||||||
|  | 			grid[x][y] = rgb | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return grid | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | func FillPanelRGB(w int, h int, colour RGBcolor) [][]RGBcolor { | ||||||
|  | 	return FillPanel(w,h,colour[0],colour[1],colour[2]) | ||||||
|  | } | ||||||
							
								
								
									
										49
									
								
								internal/patterns/experiment.go
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										49
									
								
								internal/patterns/experiment.go
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,49 @@ | ||||||
|  | package patterns | ||||||
|  | 
 | ||||||
|  | import "math" | ||||||
|  | 
 | ||||||
|  | var sineoffset int = 0 | ||||||
|  | var lastSineSpeed uint16 = 0 | ||||||
|  | 
 | ||||||
|  | func Sinewave(w int, h int, bgColor RGBcolor, fgColor RGBcolor, speed uint16) [][]RGBcolor  { | ||||||
|  | 	if speed != lastSineSpeed { | ||||||
|  | 		lastSineSpeed = speed | ||||||
|  | 		sineoffset = 0 | ||||||
|  | 	} | ||||||
|  |     sineoffset += int(speed/40) | ||||||
|  | 	background := FillPanelRGB(w,h,bgColor) | ||||||
|  | 	for x := 0; x < w; x++ { | ||||||
|  | 		y := int(math.Round((math.Sin(float64(x+sineoffset))+1) / 2 * float64(h-1))) | ||||||
|  | 		background[x][y] = fgColor | ||||||
|  | 	} | ||||||
|  | 	return background | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | var lastSinePos int = 0 | ||||||
|  | 
 | ||||||
|  | func SineChase(w int, h int, bgColor RGBcolor, fgColor RGBcolor, speed uint16) [][]RGBcolor  { | ||||||
|  | 	if speed != lastSineSpeed { | ||||||
|  | 		lastSineSpeed = speed | ||||||
|  | 		lastSinePos = 0 | ||||||
|  | 	} | ||||||
|  | 	background := FillPanelRGB(w,h,bgColor) | ||||||
|  | 	y := int(math.Round((math.Sin(float64(lastSinePos))+1) / 2 * float64(h-1))) | ||||||
|  | 	background[lastSinePos][y] = fgColor | ||||||
|  | 	lastSinePos += 1 | ||||||
|  | 	if lastSinePos >= w { | ||||||
|  | 		lastSinePos = 0 | ||||||
|  | 	} | ||||||
|  | 	return background | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ZigZag(w int, h int) [][]RGBcolor  { | ||||||
|  | 	var bgColor = [3]byte{0,0,0} | ||||||
|  | 	var fgColor = [3]byte{255,0,0} | ||||||
|  | 	//var a = [5]int{2, 4, 6, 8, 10} | ||||||
|  | 	background := FillPanelRGB(w,h,bgColor) | ||||||
|  | 	for x := 0; x < w; x++ { | ||||||
|  | 		y := x % (h-1) | ||||||
|  | 		background[x][y] = fgColor | ||||||
|  | 	} | ||||||
|  | 	return background | ||||||
|  | } | ||||||
							
								
								
									
										16
									
								
								internal/patterns/gradient.go
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										16
									
								
								internal/patterns/gradient.go
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,16 @@ | ||||||
|  | package patterns | ||||||
|  | 
 | ||||||
|  | // gradient returns from fromX to toX fading from (fromR,fromG,fromB) to (toR,toG,toB) | ||||||
|  | // at least that's the idea. | ||||||
|  | func Gradient(fromR byte, fromG byte, fromB byte, toR byte, toG byte, toB byte, fromX int, toX int) []byte { | ||||||
|  | 	ret := make([]byte, toX*3) | ||||||
|  | 	var stepR float32 = (float32(toR) - float32(fromR)) / (float32(toX) - float32(fromX)) | ||||||
|  | 	var stepG float32 = (float32(toG) - float32(fromG)) / (float32(toX) - float32(fromX)) | ||||||
|  | 	var stepB float32 = (float32(toB) - float32(fromB)) / (float32(toX) - float32(fromX)) | ||||||
|  | 	for i := fromX; i < toX*3; i += 3 { | ||||||
|  | 		ret[i] = fromR + byte(float32(i/3)*stepR) | ||||||
|  | 		ret[i+1] = fromG + byte(float32(i/3)*stepG) | ||||||
|  | 		ret[i+2] = fromB + byte(float32(i/3)*stepB) | ||||||
|  | 	} | ||||||
|  | 	return ret | ||||||
|  | } | ||||||
							
								
								
									
										27
									
								
								internal/patterns/plaincolour.go
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										27
									
								
								internal/patterns/plaincolour.go
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,27 @@ | ||||||
|  | package patterns | ||||||
|  | 
 | ||||||
|  | import "math/rand" | ||||||
|  | import "time" | ||||||
|  | 
 | ||||||
|  | func RedPanel(w int, h int) [][]RGBcolor { | ||||||
|  | 	return FillPanel(w, h, 255, 0, 0) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | var lastColour RGBcolor | ||||||
|  | var lastIteration uint16 = 0 | ||||||
|  | 
 | ||||||
|  | func RandomColourPanel(w int, h int, speed uint16) [][]RGBcolor { | ||||||
|  | 	if lastIteration > 0 { | ||||||
|  | 		lastIteration -= 40 | ||||||
|  | 	} | ||||||
|  | 	if lastIteration <= 0 { | ||||||
|  | 		r := rand.New(rand.NewSource(time.Now().UnixNano())) | ||||||
|  | 		var newColour RGBcolor | ||||||
|  | 		newColour[0] = byte(r.Intn(255)) | ||||||
|  | 		newColour[1] = byte(r.Intn(255)) | ||||||
|  | 		newColour[2] = byte(r.Intn(255)) | ||||||
|  | 		lastColour = newColour | ||||||
|  | 		lastIteration = speed | ||||||
|  | 	} | ||||||
|  | 	return FillPanel(w, h, lastColour[0], lastColour[1], lastColour[2]) | ||||||
|  | } | ||||||
							
								
								
									
										68
									
								
								internal/patterns/plasma.go
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										68
									
								
								internal/patterns/plasma.go
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,68 @@ | ||||||
|  | package patterns | ||||||
|  | 
 | ||||||
|  | import "math" | ||||||
|  | 
 | ||||||
|  | type RGBcolor = [3]byte | ||||||
|  | 
 | ||||||
|  | func plasmaRGBFromVal(val byte) (byte, byte, byte) { | ||||||
|  | 	var r byte | ||||||
|  | 	var g byte | ||||||
|  | 	var b byte | ||||||
|  | 	if val < 85 { | ||||||
|  | 		r = val * 3 | ||||||
|  | 		g = 255 - r | ||||||
|  | 		b = 0 | ||||||
|  | 	} else if val < 170 { | ||||||
|  | 		b = (val - 85) * 3 | ||||||
|  | 		r = 255 - b | ||||||
|  | 		g = 0 | ||||||
|  | 	} else { | ||||||
|  | 		g = (val - 170) * 3 | ||||||
|  | 		b = 255 - g | ||||||
|  | 		r = 0 | ||||||
|  | 	} | ||||||
|  | 	return r, g, b | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | func LinearPlasma(l int) []byte { | ||||||
|  | 	line := make([]byte, l*3) | ||||||
|  | 	for i := 0; i < l*3; i += 3 { | ||||||
|  | 		val := byte(i % 256) | ||||||
|  | 		r, g, b := plasmaRGBFromVal(val) | ||||||
|  | 		line[i] = r | ||||||
|  | 		line[i+1] = g | ||||||
|  | 		line[i+2] = b | ||||||
|  | 	} | ||||||
|  | 	return line | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | var offset float64 = 0.5 | ||||||
|  | 
 | ||||||
|  | func PlasmaPanel(w int, h int, speed uint16) [][]RGBcolor { | ||||||
|  | 	grid := make([][]RGBcolor, w) | ||||||
|  | 	for i := 0; i < w; i++ { | ||||||
|  | 		grid[i] = make([]RGBcolor, h) | ||||||
|  | 	} | ||||||
|  | 	scale := math.Pi * 2.0 / float64(w) | ||||||
|  | 	step := float64(5 * speed / 40) | ||||||
|  | 	offset -= step | ||||||
|  | 	if offset < 0 { | ||||||
|  | 		offset += 1.0 | ||||||
|  | 	} | ||||||
|  | 	for y := 0; y < h; y++ { | ||||||
|  | 		for x := 0; x < w; x++ { | ||||||
|  | 			u := math.Cos((float64(x) + offset) * scale) | ||||||
|  | 			v := math.Cos((float64(y) + offset) * scale) | ||||||
|  | 			w := math.Cos((float64(w) + offset) * scale) | ||||||
|  | 			e := (u + v + w + 3.0) / 6.0 | ||||||
|  | 			r, g, b := plasmaRGBFromVal(byte((offset + e) * 255)) | ||||||
|  | 			var rgb [3]byte | ||||||
|  | 			rgb[0] = r | ||||||
|  | 			rgb[1] = g | ||||||
|  | 			rgb[2] = b | ||||||
|  | 			grid[x][y] = rgb | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return grid | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								internal/patterns/staticpatterns.go
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										17
									
								
								internal/patterns/staticpatterns.go
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,17 @@ | ||||||
|  | package patterns | ||||||
|  | 
 | ||||||
|  | func AlternateRGBLinear(R0 byte, G0 byte, B0 byte, R1 byte, G1 byte, B1 byte, fromX int, toX int) []byte { | ||||||
|  | 	ret := make([]byte, toX*3) | ||||||
|  | 	for i := fromX; i < toX*3; i += 3 { | ||||||
|  | 		if Even(i) { | ||||||
|  | 			ret[i] = R0 | ||||||
|  | 			ret[i+1] = G0 | ||||||
|  | 			ret[i+2] = B0 | ||||||
|  | 		} else { | ||||||
|  | 			ret[i] = R1 | ||||||
|  | 			ret[i+1] = G1 | ||||||
|  | 			ret[i+2] = B1 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return ret | ||||||
|  | } | ||||||
							
								
								
									
										7
									
								
								internal/queue/queue.go
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								internal/queue/queue.go
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,7 @@ | ||||||
|  | package queue | ||||||
|  | 
 | ||||||
|  | type QueueItem struct { | ||||||
|  | 	Effect string | ||||||
|  | 	Duration uint16 | ||||||
|  | 	Speed uint16 //only used by some patterns | ||||||
|  | } | ||||||
							
								
								
									
										88
									
								
								internal/remapping/remapping.go
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										88
									
								
								internal/remapping/remapping.go
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,88 @@ | ||||||
|  | package remapping | ||||||
|  | 
 | ||||||
|  | type RGBcolor = [3]byte | ||||||
|  | 
 | ||||||
|  | func Even(number int) bool { | ||||||
|  | 	return number %2 == 0 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func Slice512(s []byte) [512]byte { | ||||||
|  | 	var ret [512]byte | ||||||
|  | 	for i := range s { | ||||||
|  | 		if i < 512 { | ||||||
|  | 			ret[i] = s[i] | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return ret | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func SliceUnlenthed(s [512]byte) []byte { | ||||||
|  | 	ret := make([]byte, 512) | ||||||
|  | 	for i := range s { | ||||||
|  | 		ret[i] = s[i] | ||||||
|  | 	} | ||||||
|  | 	return ret | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func SliceRearrange(rowwidth int, rows int, alternaterows bool, inslice []byte) [][]byte { | ||||||
|  | 	var flippedslice []byte | ||||||
|  | 	if alternaterows { | ||||||
|  | 		flippedslice = make([]byte, len(inslice)+3) | ||||||
|  | 		for r := 0; r < rows; r++ { | ||||||
|  | 			rowzero := (r * rowwidth * 3) | ||||||
|  | 			if Even(r) { | ||||||
|  | 				for c := 0; c < (rowwidth)*3; c += 3 { | ||||||
|  | 					flippedslice[rowzero+c] = inslice[rowzero+c] | ||||||
|  | 					flippedslice[rowzero+c+1] = inslice[rowzero+c+1] | ||||||
|  | 					flippedslice[rowzero+c+2] = inslice[rowzero+c+2] | ||||||
|  | 				} | ||||||
|  | 			} else { | ||||||
|  | 				x := rowwidth * 3 | ||||||
|  | 				for c := 0; c < (rowwidth)*3; c += 3 { | ||||||
|  | 					x = x - 3 | ||||||
|  | 					flippedslice[rowzero+x] = inslice[rowzero+c] | ||||||
|  | 					flippedslice[rowzero+x+1] = inslice[rowzero+c+1] | ||||||
|  | 					flippedslice[rowzero+x+2] = inslice[rowzero+c+2] | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	} else { | ||||||
|  | 		flippedslice = inslice | ||||||
|  | 	} | ||||||
|  | 	currentUniverse := 0 | ||||||
|  | 	currentUniversePosition := 0 | ||||||
|  | 	universes := make([][]byte, (len(flippedslice)/510)+1) | ||||||
|  | 	currentUniverseSlice := make([]byte, 511) | ||||||
|  | 	currentRowReverse := false | ||||||
|  | 	for i := range flippedslice { | ||||||
|  | 		if currentUniversePosition >= 510 { | ||||||
|  | 			universes[currentUniverse] = currentUniverseSlice | ||||||
|  | 			if !currentRowReverse { | ||||||
|  | 				currentRowReverse = true | ||||||
|  | 			} else { | ||||||
|  | 				currentRowReverse = false | ||||||
|  | 			} | ||||||
|  | 			currentUniverse += 1 | ||||||
|  | 			currentUniversePosition = 0 | ||||||
|  | 			currentUniverseSlice = make([]byte, 511) | ||||||
|  | 		} | ||||||
|  | 		currentUniverseSlice[currentUniversePosition] = flippedslice[i] | ||||||
|  | 		currentUniversePosition += 1 | ||||||
|  | 	} | ||||||
|  | 	universes[currentUniverse] = currentUniverseSlice | ||||||
|  | 	return universes | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func XYGridToLinear(w int, h int, grid [][]RGBcolor) []byte { | ||||||
|  | 	ret := make([]byte, w*h*3) | ||||||
|  | 	i := 0 | ||||||
|  | 	for y := 0; y < h; y++ { | ||||||
|  | 		for x := 0; x < w; x++ { | ||||||
|  | 			ret[i] = grid[x][y][0] | ||||||
|  | 			ret[i+1] = grid[x][y][1] | ||||||
|  | 			ret[i+2] = grid[x][y][2] | ||||||
|  | 			i += 3 | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return ret | ||||||
|  | } | ||||||
							
								
								
									
										70
									
								
								internal/webserver/webserver.go
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										70
									
								
								internal/webserver/webserver.go
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,70 @@ | ||||||
|  | package webserver | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 
 | ||||||
|  | 	"github.com/gorilla/handlers" | ||||||
|  | 	"github.com/gorilla/mux" | ||||||
|  | 	queue "git.martyn.berlin/martyn/LEDController/internal/queue" | ||||||
|  | 
 | ||||||
|  | 	"fmt" | ||||||
|  | 	"net/http" | ||||||
|  | 	"os" | ||||||
|  | 	"time" | ||||||
|  | 	"strconv" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func HealthHandler(response http.ResponseWriter, request *http.Request) { | ||||||
|  | 	response.Header().Add("Content-type", "text/plain") | ||||||
|  | 	fmt.Fprint(response, "I'm okay jack!") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func NotFoundHandler(response http.ResponseWriter, request *http.Request) { | ||||||
|  | 	response.WriteHeader(404) | ||||||
|  | 	fmt.Fprint(response, "I'm lost!") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func RootHandler(response http.ResponseWriter, request *http.Request) { | ||||||
|  | 	response.Header().Add("Content-type", "text/plain") | ||||||
|  | 	fmt.Fprint(response, "Not implemented") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | var globalQueue chan queue.QueueItem; | ||||||
|  | 
 | ||||||
|  | func PatternHandler(response http.ResponseWriter, request *http.Request) { | ||||||
|  | 	vars := mux.Vars(request) | ||||||
|  | 	response.Header().Add("Content-type", "text/plain") | ||||||
|  | 	var e queue.QueueItem | ||||||
|  | 	e.Effect = vars["pattern"] | ||||||
|  | 	i, _ := strconv.Atoi(vars["duration"]) | ||||||
|  | 	e.Duration = uint16(i) | ||||||
|  | 	_, found := vars["speed"] | ||||||
|  | 	if found { | ||||||
|  | 		i, _ := strconv.Atoi(vars["speed"]) | ||||||
|  | 		e.Speed = uint16(i) | ||||||
|  | 		fmt.Printf("Speed passed %d\n",e.Speed) | ||||||
|  | 	} else { | ||||||
|  | 		e.Speed = 40 | ||||||
|  | 	} | ||||||
|  | 	globalQueue <- e | ||||||
|  | 	fmt.Fprint(response, "OKAY") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func HandleHTTP(queueChannel chan queue.QueueItem) { | ||||||
|  | 	globalQueue = queueChannel | ||||||
|  | 	r := mux.NewRouter() | ||||||
|  | 	loggedRouter := handlers.LoggingHandler(os.Stdout, r) | ||||||
|  | 	r.NotFoundHandler = http.HandlerFunc(NotFoundHandler) | ||||||
|  | 	r.HandleFunc("/", RootHandler) | ||||||
|  | 	r.HandleFunc("/healthz", HealthHandler) | ||||||
|  | 	r.HandleFunc("/pattern/{pattern}/{duration}", PatternHandler) | ||||||
|  | 	r.HandleFunc("/pattern/{pattern}/{duration}/{speed}", PatternHandler) | ||||||
|  | 	http.Handle("/", r) | ||||||
|  | 	srv := &http.Server{ | ||||||
|  | 		Handler:      loggedRouter, | ||||||
|  | 		Addr:         "0.0.0.0:5353", | ||||||
|  | 		WriteTimeout: 15 * time.Second, | ||||||
|  | 		ReadTimeout:  15 * time.Second, | ||||||
|  | 	} | ||||||
|  | 	fmt.Println("Listening on 0.0.0.0:5353") | ||||||
|  | 	srv.ListenAndServe() | ||||||
|  | } | ||||||
							
								
								
									
										224
									
								
								main.go
									
										
									
									
									
								
							
							
						
						
									
										224
									
								
								main.go
									
										
									
									
									
								
							|  | @ -1,154 +1,114 @@ | ||||||
| package main | package main | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"fmt" | ||||||
| 	"log" | 	"log" | ||||||
| 	"time" | 	"time" | ||||||
| 	"fmt" | 
 | ||||||
|  | 	webserver "git.martyn.berlin/martyn/LEDController/internal/webserver" | ||||||
|  | 	queue "git.martyn.berlin/martyn/LEDController/internal/queue" | ||||||
|  | 	remapping "git.martyn.berlin/martyn/LEDController/internal/remapping" | ||||||
|  | 	patterns "git.martyn.berlin/martyn/LEDController/internal/patterns" | ||||||
| 
 | 
 | ||||||
| 	"github.com/Hundemeier/go-sacn/sacn" | 	"github.com/Hundemeier/go-sacn/sacn" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func even(number int) bool { | type RGBcolor = [3]byte | ||||||
|     return number%2 == 0 |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| func slice_rearrange(rowwidth int, rows int, alternaterows bool, inslice []byte) [][]byte { | var currentFrame [2][512]byte | ||||||
| 	var flippedslice []byte | var channels [2]chan<-[512]byte  | ||||||
| 	if alternaterows { | var sema = make(chan struct{}, 1) // a binary semaphore guarding currentFrame | ||||||
| 		flippedslice = make([]byte, len(inslice)+3) |  | ||||||
| 		for r := 0; r < rows; r++ { |  | ||||||
| 			rowzero := (r*rowwidth*3) |  | ||||||
| 			if even(r) { |  | ||||||
| 				for c := 0; c < (rowwidth)*3; c+=3 { |  | ||||||
| 					flippedslice[rowzero+c] = inslice[rowzero+c] |  | ||||||
| 					flippedslice[rowzero+c+1] = inslice[rowzero+c+1] |  | ||||||
| 					flippedslice[rowzero+c+2] = inslice[rowzero+c+2] |  | ||||||
| 				} |  | ||||||
| 			} else { |  | ||||||
| 				x := rowwidth*3 |  | ||||||
| 				for c := 0; c < (rowwidth)*3; c+=3 { |  | ||||||
| 					x = x-3 |  | ||||||
| 					fmt.Println(x) |  | ||||||
| 					flippedslice[rowzero+x] = inslice[rowzero+c] |  | ||||||
| 					flippedslice[rowzero+x+1] = inslice[rowzero+c+1] |  | ||||||
| 					flippedslice[rowzero+x+2] = inslice[rowzero+c+2]/* |  | ||||||
| 					flippedslice[rowzero+c] = inslice[rowzero+(((rowwidth-1)*3)-c)] |  | ||||||
| 					flippedslice[rowzero+c+1] = inslice[rowzero+(((rowwidth-1)*3)-c)-1] |  | ||||||
| 					flippedslice[rowzero+c+2] = inslice[rowzero+(((rowwidth-1)*3)-c)-2]*/ |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 		} |  | ||||||
| 	} else { |  | ||||||
| 		flippedslice = inslice |  | ||||||
| 	} |  | ||||||
| 	currentUniverse := 0 |  | ||||||
| 	currentUniversePosition := 0 |  | ||||||
| 	universes := make([][]byte, (len(flippedslice)/510)+1) |  | ||||||
| 	currentUniverseSlice := make([]byte, 511) |  | ||||||
| 	currentRowReverse := false; |  | ||||||
| 	for i := range(flippedslice) { |  | ||||||
| 		if currentUniversePosition >= 510 { |  | ||||||
| 			fmt.Println("Reached end of universe!") |  | ||||||
| 			universes[currentUniverse] = currentUniverseSlice |  | ||||||
| 			if (!currentRowReverse) { |  | ||||||
| 				currentRowReverse = true |  | ||||||
| 			} else { |  | ||||||
| 				currentRowReverse = false |  | ||||||
| 			} |  | ||||||
| 			currentUniverse += 1 |  | ||||||
| 			currentUniversePosition = 0 |  | ||||||
| 			currentUniverseSlice = make([]byte, 511) |  | ||||||
| 		} |  | ||||||
| 		currentUniverseSlice[currentUniversePosition] = flippedslice[i] |  | ||||||
| 		currentUniversePosition += 1 |  | ||||||
| 	} |  | ||||||
| 	universes[currentUniverse] = currentUniverseSlice |  | ||||||
|   	return universes |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| func alternate(R0 byte, G0 byte, B0 byte, R1 byte, G1 byte, B1 byte, fromX int, toX int) []byte { | var currentEffect queue.QueueItem; | ||||||
| 	ret := make([]byte, toX*3); | var globalEffectChannel = make(chan queue.QueueItem, 1024) | ||||||
| 	for i := fromX; i < toX*3; i+=3 { | 
 | ||||||
| 		if even(i) { | func foreverLoop() { | ||||||
| 			ret[i] = R0 | 	for /*ever*/ { | ||||||
| 			ret[i+1] = G0 | 		time.Sleep(40 * time.Millisecond) //25fps | ||||||
| 			ret[i+2] = B0 | 		for u := 0; u < 2; u++ { | ||||||
| 		} else { | 			sema <- struct{}{} // acquire token | ||||||
| 			ret[i] = R1 | 			channels[u] <- currentFrame[u] | ||||||
| 			ret[i+1] = G1 | 			<- sema | ||||||
| 			ret[i+2] = B1 |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|     return ret |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // gradient returns from fromX to toX fading from (fromR,fromG,fromB) to (toR,toG,toB) |  | ||||||
| // at least that's the idea. |  | ||||||
| func gradient(fromR byte, fromG byte, fromB byte, toR byte, toG byte, toB byte, fromX int, toX int) []byte { |  | ||||||
| 	ret := make([]byte, toX*3); |  | ||||||
| 	var stepR float32 = (float32(toR) - float32(fromR)) / (float32(toX) - float32(fromX)) |  | ||||||
| 	var stepG float32 = (float32(toG) - float32(fromG)) / (float32(toX) - float32(fromX)) |  | ||||||
| 	var stepB float32 = (float32(toB) - float32(fromB)) / (float32(toX) - float32(fromX)) |  | ||||||
| 	for i := fromX; i < toX*3; i+=3 { |  | ||||||
| 		ret[i] = fromR+byte(float32(i/3)*stepR) |  | ||||||
| 		ret[i+1] = fromG+byte(float32(i/3)*stepG) |  | ||||||
| 		ret[i+2] = fromB+byte(float32(i/3)*stepB) |  | ||||||
| 	} |  | ||||||
|     return ret |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func slice512(s []byte) [512]byte { |  | ||||||
| 	var ret [512]byte |  | ||||||
| 	for i := range(s) { |  | ||||||
| 		if i < 512 { |  | ||||||
| 			ret[i] = s[i] |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return ret |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func sliceUnlenthed(s [512]byte) []byte { |  | ||||||
| 	ret := make([]byte, 512) |  | ||||||
| 	for i := range(s) { |  | ||||||
| 		ret[i] = s[i] |  | ||||||
| 	} |  | ||||||
| 	return ret |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func main() { | func main() { | ||||||
|  | 	go func() { | ||||||
|  | 		fmt.Printf("Starting webserver on port %s\n", "5353") | ||||||
|  | 		webserver.HandleHTTP(globalEffectChannel) | ||||||
|  | 	}() | ||||||
| 	//instead of "" you could provide an ip-address that the socket should bind to | 	//instead of "" you could provide an ip-address that the socket should bind to | ||||||
| 	trans, err := sacn.NewTransmitter("", [16]byte{1, 2, 3}, "test") | 	trans, err := sacn.NewTransmitter("", [16]byte{1, 2}, "test") | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		log.Fatal(err) | 		log.Fatal(err) | ||||||
| 	} | 	} | ||||||
| 	 |  | ||||||
| 	//activates the first universe |  | ||||||
| 	ch1, err := trans.Activate(1) |  | ||||||
| 	if err != nil { |  | ||||||
| 		log.Fatal(err) |  | ||||||
| 	} |  | ||||||
| 	ch2, err := trans.Activate(2) |  | ||||||
| 	if err != nil { |  | ||||||
| 		log.Fatal(err) |  | ||||||
| 	} |  | ||||||
| 	//deactivate the channel on exit |  | ||||||
| 	defer close(ch1) |  | ||||||
| 	defer close(ch2) |  | ||||||
| 
 | 
 | ||||||
| 	//set a unicast destination, and/or use multicast | 	//activates the universes | ||||||
| 	trans.SetMulticast(1, false)//this specific setup will not multicast on windows,  | 	for i := 0; i < 2; i++ { | ||||||
| 	//because no bind address was provided | 		channels[i], err =  trans.Activate(uint16(i+1)) | ||||||
| 	 | 		//deactivate the channel on exit | ||||||
| 	//set some example ip-addresses | 		defer close(channels[i]) | ||||||
| 	trans.SetDestinations(1, []string{"192.168.1.139"}) | 		trans.SetMulticast(uint16(i+1), false) //this specific setup will not multicast on windows, | ||||||
| 	trans.SetMulticast(2, false)//this specific setup will not multicast on windows,  | 		trans.SetDestinations(uint16(i+1), []string{"192.168.1.139"}) | ||||||
| 	trans.SetDestinations(2, []string{"192.168.1.139"}) |  | ||||||
| 	 |  | ||||||
| 	//send some random data for 10 seconds |  | ||||||
| 	for i := 0; i < 20; i++ { |  | ||||||
| 		channels := slice_rearrange(68,4,true,gradient(255,255,255,0,0,0,0,272)) |  | ||||||
| 		ch1 <- slice512(channels[0]) |  | ||||||
| 		ch2 <- slice512(channels[1]) |  | ||||||
| 		time.Sleep(500 * time.Millisecond) |  | ||||||
| 	} | 	} | ||||||
| } | 
 | ||||||
|  | 	// Plasma for start frame | ||||||
|  | 	rearranged := remapping.SliceRearrange(68, 4, true, remapping.XYGridToLinear(68, 4, patterns.PlasmaPanel(68, 4, 40))) | ||||||
|  | 	currentFrame[0] = remapping.Slice512(rearranged[0]) | ||||||
|  | 	currentFrame[1]	= remapping.Slice512(rearranged[1]) | ||||||
|  | 	var e queue.QueueItem | ||||||
|  | 	e.Effect = "red" | ||||||
|  | 	e.Duration = 40 * 50 | ||||||
|  | 	globalEffectChannel <- e | ||||||
|  | 	e.Effect = "plasma" | ||||||
|  | 	e.Duration = 0 | ||||||
|  | 	e.Speed = 40 | ||||||
|  | 	globalEffectChannel <- e | ||||||
|  | 
 | ||||||
|  | 	go func() { | ||||||
|  | 		for /*ever*/ { | ||||||
|  | 			if currentEffect.Duration > 0 { | ||||||
|  | 				currentEffect.Duration -= 40 | ||||||
|  | 			} else { | ||||||
|  | 				if len(globalEffectChannel) > 0 { | ||||||
|  | 					currentEffect = <- globalEffectChannel | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			var rearranged [][]byte | ||||||
|  | 			switch currentEffect.Effect { | ||||||
|  | 				case "line": | ||||||
|  | 					rearranged = remapping.SliceRearrange(68, 4, true, remapping.XYGridToLinear(68, 4, patterns.ZigZag(68, 4))) | ||||||
|  | 				case "plasma": | ||||||
|  | 					rearranged = remapping.SliceRearrange(68, 4, true, remapping.XYGridToLinear(68, 4, patterns.PlasmaPanel(68, 4, currentEffect.Speed))) | ||||||
|  | 				case "red": | ||||||
|  | 					rearranged = remapping.SliceRearrange(68, 4, false, remapping.XYGridToLinear(68, 4, patterns.RedPanel(68,4))) | ||||||
|  | 				case "random": | ||||||
|  | 					rearranged = remapping.SliceRearrange(68, 4, false, remapping.XYGridToLinear(68, 4, patterns.RandomColourPanel(68,4,currentEffect.Speed))) | ||||||
|  | 				case "linearplasma": | ||||||
|  | 					rearranged = remapping.SliceRearrange(68, 4, false, patterns.LinearPlasma(68*4)) | ||||||
|  | 				case "gradientred": | ||||||
|  | 					rearranged = remapping.SliceRearrange(68, 4, false, patterns.Gradient(255, 0, 0, 0, 0, 255, 0, 68*4)) | ||||||
|  | 				case "sine": | ||||||
|  | 					var black patterns.RGBcolor | ||||||
|  | 					var red patterns.RGBcolor | ||||||
|  | 					red[0] = 255 | ||||||
|  | 					rearranged = remapping.SliceRearrange(68, 4, true, remapping.XYGridToLinear(68, 4, patterns.Sinewave(68, 4, black, red, currentEffect.Speed))) | ||||||
|  | 				case "sinechase": | ||||||
|  | 					var black patterns.RGBcolor | ||||||
|  | 					var red patterns.RGBcolor | ||||||
|  | 					red[0] = 255 | ||||||
|  | 					rearranged = remapping.SliceRearrange(68, 4, true, remapping.XYGridToLinear(68, 4, patterns.SineChase(68, 4, black, red, currentEffect.Speed))) | ||||||
|  | 			    default: | ||||||
|  | 					rearranged = remapping.SliceRearrange(68, 4, false, remapping.XYGridToLinear(68, 4, patterns.FillPanel(68,4, 128,0,128))) | ||||||
|  | 			} | ||||||
|  | 			//rearranged := remapping.SliceRearrange(68,4,true,linearPlasma(68*4)) | ||||||
|  | 			sema <- struct{}{} // acquire token | ||||||
|  | 			currentFrame[0] = remapping.Slice512(rearranged[0]) | ||||||
|  | 			currentFrame[1]	= remapping.Slice512(rearranged[1]) | ||||||
|  | 			<- sema | ||||||
|  | 			time.Sleep(40 * time.Millisecond) | ||||||
|  | 		} | ||||||
|  | 	}() | ||||||
|  | 	foreverLoop(); | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue