// 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))] } } }
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) } }
// 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 } } } } }
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) }
// 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]) } } }
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 } } }
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 } }
// 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) } } } }
// 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) }