// drawFrequonsFourier draws the frequency-domain representation of Frequons.
func drawFrequonsFourier(pm nimble.PixMap) {
	c := universe.Zoo
	h := harmonicStorage[:len(c)]

	var ampScale float32
	if autoGain.Value {
		// Compute L1 norm of amplitudes
		norm := float32(0)
		for i := range c {
			norm += math32.Abs(c[i].Amplitude)
		}
		ampScale = 1 / norm
	} else {
		ampScale = 1 / float32(len(c))
	}
	fracX, fracY := universe.BoxFraction()
	fracX *= zoomCompression
	fracY *= zoomCompression
	sizeX, sizeY := pm.Size()

	// Set up harmonics
	// (cx,cy) is center of fourier view
	cx, cy := 0.5*float32(sizeX)*fracX, 0.5*float32(sizeY)*fracY
	α, β := -0.5*cx, -0.5*cy
	ωScale := 200. / float32(sizeX*sizeY)
	for i := range h {
		ωx := (c[i].Sx - cx) * ωScale
		ωy := (c[i].Sy - cy) * ωScale
		h[i].Ωx = ωx
		h[i].Ωy = ωy
		h[i].Phase = α*ωx + β*ωy + phaseRoll
		// Scale amplitude so that DFT values fit within domain of color lookup table.
		h[i].Amplitude = c[i].Amplitude * ampScale
	}

	marginX := int32(math32.Round(0.5 * float32(sizeX) * (1 - fracX)))
	marginY := int32(math32.Round(0.5 * float32(sizeY) * (1 - fracY)))
	fourier.Draw(pm.Intersect(nimble.Rect{
		Left:   marginX,
		Right:  sizeX - marginX,
		Top:    marginY,
		Bottom: sizeY - marginY,
	}), h, universe.Scheme())
	if marginX != 0 || marginY != 0 {
		pm.DrawRect(nimble.Rect{Left: 0, Right: sizeX, Top: 0, Bottom: marginY}, nimble.Black)
		pm.DrawRect(nimble.Rect{Left: 0, Right: sizeX, Top: sizeY - marginY, Bottom: sizeY}, nimble.Black)
		pm.DrawRect(nimble.Rect{Left: 0, Right: marginX, Top: marginY, Bottom: sizeY - marginY}, nimble.Black)
		pm.DrawRect(nimble.Rect{Left: sizeX - marginX, Right: sizeX, Top: marginY, Bottom: sizeY - marginY}, nimble.Black)
	}
}
Esempio n. 2
0
func (context) Render(pm nimble.PixMap) {
	dt := updateClock()

	// Advance the boot sequence
	advanceBootSequence(dt)

	// Draw dividers
	for i, r := range divider {
		if i < dividerCount {
			pm.DrawRect(r, nimble.White)
		} else {
			pm.DrawRect(r, nimble.Black)
		}
	}

	if fourierIsVisible {
		// Update universe
		xf, yf := fourierPort.RelativeToLeftTop(mouseX, mouseY)
		switch universe.Update(dt, xf, yf) {
		case universe.GameWin:
			youWin()
		case universe.GameLose:
			youLose()
		}
		updateZoom(dt)

		// Fourier view
		if rollPhase.Value {
			updatePhaseRoll(dt)
		}
		drawFrequonsFourier(pm.Intersect(fourierPort))
		drawFrequonsSpatial(pm.Intersect(fourierPort), xf, yf)
		tallyFourierFrame()
	} else {
		// Teletype view
		teletype.Draw(pm.Intersect(fourierPort))
	}

	// Fall view
	if fallIsVisible {
		inv := invStorage[:len(universe.Zoo)-1]
		for k := range inv {
			c := &universe.Zoo[k+1]
			inv[k] = fall.Invader{
				Progress:  c.Progress,
				Amplitude: c.Amplitude,
				Color:     pastels.Pixel(0, int32(c.Id)),
			}
		}
		fall.Draw(pm.Intersect(fallPort), inv)
	} else {
		pm.DrawRect(fallPort, nimble.Black)
	}

	// Radar view
	if radarIsVisible {
		radar.Draw(pm.Intersect(radarPort), universe.Scheme(), radarIsRunning)
	} else {
		pm.DrawRect(radarPort, nimble.Black)
	}

	// Score
	if scoreIsVisible {
		score.Draw(pm.Intersect(scorePort), universe.NKill())
	} else {
		pm.DrawRect(scorePort, nimble.Black)
	}

	// Menu bar
	if len(menuBar) > 0 {
		menu.DrawMenuBar(pm, menuBar)
	}

	// Cursor
	showCursor := true
	switch currentMode {
	case modeGame:
		showCursor = false
	case modeTraining:
		showCursor = !fourierPort.Contains(mouseX, mouseY)
	}
	if showCursor != cursorIsVisible {
		nimble.ShowCursor(showCursor)
		cursorIsVisible = showCursor
	}
}