// Generic version of Draw
func Draw(pm nimble.PixMap, harmonics []Harmonic, cm colorMap) {
	setColoring(cm)
	n := len(harmonics)
	w := make([]complex64, n)
	u := make([]complex64, n)
	v := make([]complex64, n)
	z := make([]complex64, n)
	for i, h := range harmonics {
		w[i] = complex(h.Amplitude*clutRadius, 0) * euler(h.Phase)
		u[i] = euler(h.Ωx)
		v[i] = euler(h.Ωy)
	}
	for y := int32(0); y < pm.Height(); y++ {
		for i := 0; i < n; i++ {
			z[i] = w[i]
			w[i] *= v[i] // Rotate w by v
		}
		row := pm.Row(y)
		for x := range row {
			const offset float32 = clutCenter + 0.5
			s := complex(offset, offset)
			for i := 0; i < n; i++ {
				s += z[i]
				z[i] *= u[i]
			}
			row[x] = clut[int(imag(s))][int(real(s))]
		}
	}
}
Beispiel #2
0
func Draw(pm nimble.PixMap, cm colorMap, running bool) {
	setColoring(cm)
	width, height := pm.Size()
	if width != xSize || height != ySize {
		panic(fmt.Sprintf("radar.Draw: (width,height)=(%v,%v) (xSize,ySize)=(%v,%v)\n",
			width, height, xSize, ySize))
	}
	src := nimble.MakePixMap(width, height, getFrame(frameCounter), width)
	pm.Copy(0, 0, &src)
	if running {
		frameCounter = (frameCounter + 1) % (int32(len(frameStorage)) / frameSize)
	}
}
Beispiel #3
0
// Draw draws the given sprite at (x0,y0) on dst with the given color.
func Draw(dst nimble.PixMap, x0, y0 int32, src Sprite, color nimble.Pixel) {
	w, h := dst.Size()
	for _, s := range src.rows {
		y := y0 + int32(s.y)
		if uint32(y) < uint32(h) {
			d := dst.Row(y)
			for _, xoffset := range s.x {
				x := x0 + int32(xoffset)
				if uint32(x) < uint32(w) {
					d[x] = color
				}
			}
		}
	}
}
Beispiel #4
0
func DrawMenuBar(pm nimble.PixMap, menuBar []*Menu) {
	// Draw menu
	x := int32(0)
	for _, m := range menuBar {
		m.Draw(pm, x, 0)
		w, _ := m.TabSize()
		x += w
	}
	h := menuFont.Height()
	pm.DrawRect(nimble.Rect{Top: 0, Left: x, Bottom: h, Right: pm.Width()}, backgroundColor)
	pm.DrawRect(nimble.Rect{Top: h, Left: x, Bottom: h + 1, Right: pm.Width()}, separatorColor)
}
Beispiel #5
0
// Draw draws the score (as binary lights) on the given PixMap.
func Draw(pm nimble.PixMap, scoreValue int) {
	if pm.Height() != lightHeight {
		panic(fmt.Sprintf("score.Draw: pm.Height()=%v lightHeight=%v\n", pm.Height(), lightHeight))
	}
	for k := range lightColor {
		s := state(scoreValue >> uint(nLight-k-1) & 1)
		src := nimble.MakePixMap(lightWidth, lightHeight, getLight(k, s), lightWidth)
		pm.Copy(lightWidth*int32(k), 0, &src)
	}
}
// Draw draws a Fourier transform on the given PixMap.
// Transform values must lie on the unit circle in the complex plane.
func Draw(pm nimble.PixMap, harmonics []Harmonic, cm colorMap) {
	setColoring(cm)
	n := len(harmonics)
	// m = n rounded up to even
	m := n + n&1
	u := uStorage[:m]
	v := vStorage[:m]
	w := wStorage[:m]
	for i, h := range harmonics {
		for k := 0; k < vlen; k++ {
			d := h.Amplitude * clutRadius
			c := euler(h.Phase + float32(k+vlen)*h.Ωx)
			w[i].re[k] = d * real(c)
			w[i].im[k] = d * imag(c)
		}
		u[i].u1 = euler(vlen * h.Ωx)
		u[i].u3 = euler(pixelsPerFoot * h.Ωx)
		v[i] = euler(h.Ωy)
	}
	if n < m {
		// Zero the extra element.
		w[n] = cvec{}
		u[n] = u13{}
		v[n] = 0
	}
	width, height := pm.Size()
	p := width / pixelsPerFoot // Number of whole feet
	q := p * pixelsPerFoot     // Number of pixels in whole feet
	r := width - q             // Number of pixels in partial foot
	feet := feetStorage[:(width+pixelsPerFoot-1)/pixelsPerFoot]
	for y := int32(0); y < height; y++ {
		for i := 0; i < n; i += 2 {
			accumulateToFeet(
				(*[2]cvec)(unsafe.Pointer(&w[i])),
				(*[2]u13)(unsafe.Pointer(&u[i])), feet)
		}
		rotate(w, v)
		feetToPixel(feet[:p], &clut, pm.Row(y))
		if r != 0 {
			feetToPixel(feet[p:p+1], &clut, tmpStorage[:])
			copy(pm.Row(y)[q:q+r], tmpStorage[:r])
		}
	}
}
Beispiel #7
0
func draw(pm nimble.PixMap, text [][]byte) {
	if teletypeFont == nil {
		panic("teletype font missing")
	}
	width, height := pm.Size()

	// Clear area
	pm.Fill(nimble.Black)

	// Write lines of text
	for m := range text {
		x := int32(textLeftMargin)
		for j := range text[m] {
			if x >= width {
				break
			}
			kLimit := width - x
			if kLimit > charWidth {
				kLimit = charWidth
			}
			c := text[m][j]
			for i, mask := range teletypeFont[c] {
				y := int32(textTopMargin + m*textLineHeight + i)
				if y >= height {
					break
				}
				pixelRow := pm.Row(y)[x : x+kLimit]
				colorIndex := 0
				for k := range pixelRow {
					if mask&(1<<uint(k)) != 0 {
						pixelRow[k] = teletypeColor[colorIndex]
						colorIndex++
					} else {
						colorIndex = 0
					}
				}
			}
			x += charWidth
		}
	}
}
Beispiel #8
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
	}
}
Beispiel #9
0
// Draw the "fall" view onto the given PixMap.
func Draw(pm nimble.PixMap, invaders []Invader) {
	if pm.Width() != background.Width() || pm.Height() != background.Height() {
		panic("fall.Draw: pm and background differ in size")
	}

	drawDot := false
	time := nimble.Now()
	if time-lastDotTime >= dotTimeInterval {
		lastDotTime = time
		drawDot = true
	}

	pm.Copy(0, 0, &background)
	xScale := float32(pm.Width() - tickHalfWidth)   // Avoid clipping tic on right side
	yScale := float32(pm.Height() - tickHalfHeight) // Avoid clippling tic on bottom
	xOffset := float32(0)
	yOffset := float32(0)
	for _, inv := range invaders {
		x := int32(inv.Amplitude*xScale + xOffset)
		y := int32(inv.Progress*yScale + yOffset)
		r := nimble.Rect{
			Left:   x - tickHalfWidth,
			Top:    y - tickHalfHeight,
			Right:  x + tickHalfWidth,
			Bottom: y + tickHalfHeight,
		}
		pm.DrawRect(r, inv.Color)
		background.DrawRect(r, nimble.Black)
		if drawDot {
			if doty := r.Top - 1; background.Contains(x, doty) {
				background.SetPixel(x, doty, inv.Color)
			}
		}
	}
}
Beispiel #10
0
// Draw draws the menu with its upper left corner at (x,y)
func (m *Menu) Draw(pm nimble.PixMap, x, y int32) {
	// Draw the tab
	if m.tabWidth == 0 {
		// Lazily compute tabWidth and itemHeight
		m.computeTabSize()
	}
	var back, fore nimble.Pixel
	if m.hilightRow != showNone {
		back = tabHilightColor
		fore = backgroundColor
	} else {
		back = backgroundColor
		fore = foregroundColor
	}
	m.tabRect = nimble.MakeRect(x, y, 2*marginWidth+int32(m.tabWidth), int32(m.itemHeight))
	pm.DrawRect(m.tabRect, back)
	pm.DrawText(x+marginWidth, y, m.Label, fore, menuFont)
	pm.DrawRect(nimble.Rect{Left: m.tabRect.Left, Top: m.tabRect.Bottom, Right: m.tabRect.Right, Bottom: m.tabRect.Bottom + 1}, separatorColor)

	if m.hilightRow != showNone {
		if m.itemWidth == 0 {
			// Lazily compute itemsWidth
			w := int32(m.tabWidth)
			for i := range m.Items {
				p := m.Items[i].GetItem()
				w0, _ := menuFont.Size(p.Label)
				if w0 > w {
					w = w0
				}
			}
			m.itemWidth = uint16(checkWidth + w + 3 + 4*marginWidth)
		}
		w := int32(m.itemWidth)
		h := int32(m.itemHeight)
		m.itemsRect = nimble.MakeRect(x, m.tabRect.Bottom, w, h*int32(len(m.Items)))

		r := m.itemsRect
		r.Left += 1
		r.Right -= 1
		pm.DrawRect(r, backgroundColor)

		// Draw left border
		r.Left -= 1
		r.Right = r.Left + 1
		pm.DrawRect(r, separatorColor)

		// Draw middle border
		r.Left += 1 + checkWidth + 2*marginWidth
		r.Right = r.Left + 1
		pm.DrawRect(r, separatorColor)

		// Draw right border
		r.Left = m.itemsRect.Right - 1
		r.Right = r.Left + 1
		pm.DrawRect(r, separatorColor)

		// Draw the items
		checkX := x + 1 + marginWidth
		labelX := x + 2 + 3*marginWidth + checkWidth
		for i := range m.Items {
			mi := m.Items[i].GetItem()
			yi := m.itemsRect.Top + h*int32(i)
			if i == int(m.hilightRow-hilightBase) {
				pm.DrawRect(nimble.MakeRect(x, yi, int32(m.itemWidth), h), itemHilightColor)
			}
			if i == 0 {
				pm.DrawRect(nimble.Rect{x, yi, m.itemsRect.Right - 1, yi + 1}, separatorColor)
			} else if mi.Flags&Separator != 0 || i == 0 {
				pm.DrawRect(nimble.Rect{labelX - marginWidth, yi, m.itemsRect.Right - 1, yi + 1}, separatorColor)
			}
			fore := choose(mi.Flags&Disabled != 0, disabledForegroundColor, foregroundColor)
			if mi.Check != 0 {
				pm.DrawText(checkX, yi, string(mi.Check), fore, checkFont)
			}
			pm.DrawText(labelX, yi, mi.Label, fore, menuFont)
		}
	}
}
// 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)
	}
}
func (*context) Render(pm nimble.PixMap) {
	pm.Fill(nimble.Gray(0.1))
	theMenu.Draw(pm, 50, 100)
}