diff --git a/docs/examples/alphablending.html b/docs/examples/alphablending.html index 1651a25f4..c8cab780a 100644 --- a/docs/examples/alphablending.html +++ b/docs/examples/alphablending.html @@ -82,7 +82,7 @@ func update(screen *ebiten.Image) error { func main() { var err error - ebitenImage, _, err = ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "ebiten.png"), ebiten.FilterNearest) + ebitenImage, _, err = ebitenutil.NewImageFromFile("_resources/images/ebiten.png", ebiten.FilterNearest) if err != nil { log.Fatal(err) } diff --git a/docs/examples/audio.html b/docs/examples/audio.html index 1b4201800..f9d38cebd 100644 --- a/docs/examples/audio.html +++ b/docs/examples/audio.html @@ -120,11 +120,11 @@ func playerBarRect() (x, y, w, h int) { func NewPlayer(audioContext *audio.Context) (*Player, error) { const bytesPerSample = 4 // TODO: This should be defined in audio package - wavF, err := ebitenutil.OpenFile(ebitenutil.JoinStringsIntoFilePath("_resources", "audio", "jab.wav")) + wavF, err := ebitenutil.OpenFile("_resources/audio/jab.wav") if err != nil { return nil, err } - mp3F, err := ebitenutil.OpenFile(ebitenutil.JoinStringsIntoFilePath("_resources", "audio", "classic.mp3")) + mp3F, err := ebitenutil.OpenFile("_resources/audio/classic.mp3") if err != nil { return nil, err } diff --git a/docs/examples/highdpi.html b/docs/examples/highdpi.html index cee053e9c..f852a2de4 100644 --- a/docs/examples/highdpi.html +++ b/docs/examples/highdpi.html @@ -43,37 +43,58 @@ import ( ) var ( - count int - highDPIImage *ebiten.Image + count int + highDPIImage *ebiten.Image + highDPIImageCh = make(chan *ebiten.Image) ) func init() { - // licensed under Public Domain + // Licensed under Public Domain // https://commons.wikimedia.org/wiki/File:As08-16-2593.jpg const url = "https://upload.wikimedia.org/wikipedia/commons/1/1f/As08-16-2593.jpg" - res, err := http.Get(url) - if err != nil { - log.Fatal(err) - } - defer res.Body.Close() + // Load the image asynchronously. + go func() { + res, err := http.Get(url) + if err != nil { + log.Fatal(err) + } + defer res.Body.Close() - img, _, err := image.Decode(res.Body) - if err != nil { - log.Fatal(err) - } + img, _, err := image.Decode(res.Body) + if err != nil { + log.Fatal(err) + } - highDPIImage, err = ebiten.NewImageFromImage(img, ebiten.FilterLinear) - if err != nil { - log.Fatal(err) - } + eimg, err := ebiten.NewImageFromImage(img, ebiten.FilterLinear) + if err != nil { + log.Fatal(err) + } + + highDPIImageCh <- eimg + close(highDPIImageCh) + }() } func update(screen *ebiten.Image) error { + if highDPIImage == nil { + // Use select and 'default' clause for non-blocking receiving. + select { + case img := <-highDPIImageCh: + highDPIImage = img + default: + } + } + if ebiten.IsRunningSlowly() { return nil } + if highDPIImage == nil { + ebitenutil.DebugPrint(screen, "Loading the image...") + return nil + } + scale := ebiten.DeviceScaleFactor() sw, sh := screen.Size() @@ -85,6 +106,7 @@ func update(screen *ebiten.Image) error { // The image is just too big. Adjust the scale. op.GeoM.Scale(0.25, 0.25) + // Scale the image by the device ratio so that the rendering result can be same // on various (diffrent-DPI) environments. op.GeoM.Scale(scale, scale) diff --git a/docs/examples/hsv.html b/docs/examples/hsv.html index d9302a291..e5f88eb15 100644 --- a/docs/examples/hsv.html +++ b/docs/examples/hsv.html @@ -47,15 +47,17 @@ const ( ) var ( - hueInt = 0 - saturationInt = 128 - valueInt = 128 - inverted = false + hue128 = 0 + saturation128 = 128 + value128 = 128 + + inverted = false prevPressedI = false gophersImage *ebiten.Image ) +// clamp clamps v to the range [min, max]. func clamp(v, min, max int) int { if min > max { panic("min must <= max") @@ -70,25 +72,30 @@ func clamp(v, min, max int) int { } func update(screen *ebiten.Image) error { + // Adjust HSV values along with the user's input. if ebiten.IsKeyPressed(ebiten.KeyQ) { - hueInt-- + hue128-- } if ebiten.IsKeyPressed(ebiten.KeyW) { - hueInt++ + hue128++ } if ebiten.IsKeyPressed(ebiten.KeyA) { - saturationInt-- + saturation128-- } if ebiten.IsKeyPressed(ebiten.KeyS) { - saturationInt++ + saturation128++ } if ebiten.IsKeyPressed(ebiten.KeyZ) { - valueInt-- + value128-- } if ebiten.IsKeyPressed(ebiten.KeyX) { - valueInt++ + value128++ } + hue128 = clamp(hue128, -256, 256) + saturation128 = clamp(saturation128, 0, 256) + value128 = clamp(value128, 0, 256) + pressedI := ebiten.IsKeyPressed(ebiten.KeyI) if pressedI && !prevPressedI { inverted = !inverted @@ -98,18 +105,19 @@ func update(screen *ebiten.Image) error { if ebiten.IsRunningSlowly() { return nil } - hueInt = clamp(hueInt, -256, 256) - saturationInt = clamp(saturationInt, 0, 256) - valueInt = clamp(valueInt, 0, 256) + // Center the image on the screen. w, h := gophersImage.Size() op := &ebiten.DrawImageOptions{} op.GeoM.Translate(float64(screenWidth-w)/2, float64(screenHeight-h)/2) - hue := float64(hueInt) * 2 * math.Pi / 128 - saturation := float64(saturationInt) / 128 - value := float64(valueInt) / 128 + // Change HSV. + hue := float64(hue128) * 2 * math.Pi / 128 + saturation := float64(saturation128) / 128 + value := float64(value128) / 128 op.ColorM.ChangeHSV(hue, saturation, value) + + // Invert the color. if inverted { op.ColorM.Scale(-1, -1, -1, 1) op.ColorM.Translate(1, 1, 1, 0) @@ -117,6 +125,7 @@ func update(screen *ebiten.Image) error { screen.DrawImage(gophersImage, op) + // Draw the text of the current status. msgInverted := "false" if inverted { msgInverted = "true" @@ -131,7 +140,7 @@ Inverted: %s [I]`, hue, saturation, value, msgInverted) func main() { var err error - gophersImage, _, err = ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "gophers.jpg"), ebiten.FilterNearest) + gophersImage, _, err = ebitenutil.NewImageFromFile("_resources/images/gophers.jpg", ebiten.FilterNearest) if err != nil { log.Fatal(err) } diff --git a/docs/examples/hue.html b/docs/examples/hue.html index ee8fba710..4a8f67859 100644 --- a/docs/examples/hue.html +++ b/docs/examples/hue.html @@ -52,20 +52,26 @@ var ( func update(screen *ebiten.Image) error { count++ + if ebiten.IsRunningSlowly() { return nil } + + // Center the image on the screen. w, h := gophersImage.Size() op := &ebiten.DrawImageOptions{} op.GeoM.Translate(float64(screenWidth-w)/2, float64(screenHeight-h)/2) + + // Rotate the hue. op.ColorM.RotateHue(float64(count%360) * 2 * math.Pi / 360) + screen.DrawImage(gophersImage, op) return nil } func main() { var err error - gophersImage, _, err = ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "gophers.jpg"), ebiten.FilterNearest) + gophersImage, _, err = ebitenutil.NewImageFromFile("_resources/images/gophers.jpg", ebiten.FilterNearest) if err != nil { log.Fatal(err) } diff --git a/docs/examples/infinitescroll.html b/docs/examples/infinitescroll.html index 8fe7e54bf..a1629532e 100644 --- a/docs/examples/infinitescroll.html +++ b/docs/examples/infinitescroll.html @@ -35,7 +35,6 @@ import ( "fmt" _ "image/png" "log" - "math" "github.com/hajimehoshi/ebiten" "github.com/hajimehoshi/ebiten/ebitenutil" @@ -47,10 +46,19 @@ const ( ) var ( - theViewport = &viewport{} - bgImage *ebiten.Image - repeatedBgImage *ebiten.Image - groundImage *ebiten.Image + bgImage *ebiten.Image +) + +func init() { + var err error + bgImage, _, err = ebitenutil.NewImageFromFile("_resources/images/tile.png", ebiten.FilterNearest) + if err != nil { + log.Fatal(err) + } +} + +var ( + theViewport = &viewport{} ) type viewport struct { @@ -58,80 +66,48 @@ type viewport struct { y16 int } -func round(x float64) float64 { - return math.Floor(x + 0.5) -} - func (p *viewport) Move() { w, h := bgImage.Size() - mx := w * 16 - my := h * 16 + maxX16 := w * 16 + maxY16 := h * 16 p.x16 += w / 32 p.y16 += h / 32 - - for mx <= p.x16 { - p.x16 -= mx - } - for my <= p.y16 { - p.y16 -= my - } - for p.x16 < 0 { - p.x16 += mx - } - for p.y16 < 0 { - p.y16 += my - } + p.x16 %= maxX16 + p.y16 %= maxY16 } func (p *viewport) Position() (int, int) { return p.x16, p.y16 } -func updateGroundImage(ground *ebiten.Image) { - ground.Clear() - x16, y16 := theViewport.Position() - op := &ebiten.DrawImageOptions{} - op.GeoM.Translate(float64(-x16)/16, float64(-y16)/16) - ground.DrawImage(repeatedBgImage, op) -} - -func drawGroundImage(screen *ebiten.Image, ground *ebiten.Image) { - op := &ebiten.DrawImageOptions{} - screen.DrawImage(ground, op) -} - func update(screen *ebiten.Image) error { theViewport.Move() + if ebiten.IsRunningSlowly() { return nil } - updateGroundImage(groundImage) - drawGroundImage(screen, groundImage) - msg := fmt.Sprintf("FPS: %0.2f", ebiten.CurrentFPS()) - ebitenutil.DebugPrint(screen, msg) - return nil -} + x16, y16 := theViewport.Position() + offsetX, offsetY := float64(-x16)/16, float64(-y16)/16 -func main() { - var err error - bgImage, _, err = ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "tile.png"), ebiten.FilterNearest) - if err != nil { - log.Fatal(err) - } + // Draw bgImage on the screen repeatedly. + const repeat = 3 w, h := bgImage.Size() - const repeat = 5 - repeatedBgImage, _ = ebiten.NewImage(w*repeat, h*repeat, ebiten.FilterNearest) for j := 0; j < repeat; j++ { for i := 0; i < repeat; i++ { op := &ebiten.DrawImageOptions{} op.GeoM.Translate(float64(w*i), float64(h*j)) - repeatedBgImage.DrawImage(bgImage, op) + op.GeoM.Translate(offsetX, offsetY) + screen.DrawImage(bgImage, op) } } - groundImage, _ = ebiten.NewImage(screenWidth, screenHeight, ebiten.FilterNearest) + ebitenutil.DebugPrint(screen, fmt.Sprintf("FPS: %0.2f", ebiten.CurrentFPS())) + return nil +} + +func main() { if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Infinite Scroll (Ebiten Demo)"); err != nil { log.Fatal(err) } diff --git a/docs/examples/keyboard.html b/docs/examples/keyboard.html index a176fc86f..2518ddf5c 100644 --- a/docs/examples/keyboard.html +++ b/docs/examples/keyboard.html @@ -49,7 +49,7 @@ var keyboardImage *ebiten.Image func init() { var err error - keyboardImage, _, err = ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "keyboard", "keyboard.png"), ebiten.FilterNearest) + keyboardImage, _, err = ebitenutil.NewImageFromFile("_resources/images/keyboard/keyboard.png", ebiten.FilterNearest) if err != nil { log.Fatal(err) } @@ -86,15 +86,7 @@ var keyNames = map[ebiten.Key]string{ } func update(screen *ebiten.Image) error { - if ebiten.IsRunningSlowly() { - return nil - } - const offsetX, offsetY = 24, 40 - op := &ebiten.DrawImageOptions{} - op.GeoM.Translate(offsetX, offsetY) - op.ColorM.Scale(0.5, 0.5, 0.5, 1) - screen.DrawImage(keyboardImage, op) - + // Collect pressed keys' names. pressed := []string{} for i := 0; i <= 9; i++ { if ebiten.IsKeyPressed(ebiten.Key(i) + ebiten.Key0) { @@ -102,12 +94,12 @@ func update(screen *ebiten.Image) error { } } for c := 'A'; c <= 'Z'; c++ { - if ebiten.IsKeyPressed(ebiten.Key(c) - 'A' + ebiten.KeyA) { + if ebiten.IsKeyPressed(ebiten.KeyA + ebiten.Key(c-'A')) { pressed = append(pressed, string(c)) } } for i := 1; i <= 12; i++ { - if ebiten.IsKeyPressed(ebiten.Key(i) + ebiten.KeyF1 - 1) { + if ebiten.IsKeyPressed(ebiten.KeyF1 + ebiten.Key(i-1)) { pressed = append(pressed, "F"+strconv.Itoa(i)) } } @@ -117,6 +109,22 @@ func update(screen *ebiten.Image) error { } } + if ebiten.IsRunningSlowly() { + return nil + } + + const ( + offsetX = 24 + offsetY = 40 + ) + + // Draw the base (grayed) keyboard image. + op := &ebiten.DrawImageOptions{} + op.GeoM.Translate(offsetX, offsetY) + op.ColorM.Scale(0.5, 0.5, 0.5, 1) + screen.DrawImage(keyboardImage, op) + + // Draw the highlighted keys. op = &ebiten.DrawImageOptions{} for _, p := range pressed { op.GeoM.Reset() diff --git a/docs/examples/life.html b/docs/examples/life.html index ff27fa831..321bee2f8 100644 --- a/docs/examples/life.html +++ b/docs/examples/life.html @@ -39,40 +39,50 @@ import ( "github.com/hajimehoshi/ebiten" ) -// World represents the game state +// World represents the game state. type World struct { area [][]bool - rnd *rand.Rand } -// NewWorld creates a new world -func NewWorld(width, height int) *World { - world := World{ - area: makeArea(width, height), - rnd: rand.New(rand.NewSource(time.Now().UnixNano())), +func newArea(width, height int) [][]bool { + a := make([][]bool, height) + for i := 0; i < height; i++ { + a[i] = make([]bool, width) } - return &world + return a } -// RandomSeed inits world with a random state -func (w *World) RandomSeed(limit int) { +// NewWorld creates a new world. +func NewWorld(width, height int, maxInitLiveCells int) *World { + w := &World{ + area: newArea(width, height), + } + w.init(maxInitLiveCells) + return w +} + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +// init inits world with a random state. +func (w *World) init(maxLiveCells int) { height := len(w.area) width := len(w.area[0]) - for i := 0; i < limit; i++ { - x := w.rnd.Intn(width) - y := w.rnd.Intn(height) + for i := 0; i < maxLiveCells; i++ { + x := rand.Intn(width) + y := rand.Intn(height) w.area[y][x] = true } } -// Progress game state by one tick -func (w *World) Progress() { +// Update game state by one tick. +func (w *World) Update() { height := len(w.area) width := len(w.area[0]) - next := makeArea(width, height) + next := newArea(width, height) for y := 0; y < height; y++ { for x := 0; x < width; x++ { - pop := neighbourCount(w.area, x, y) switch { case pop < 2: @@ -100,66 +110,63 @@ func (w *World) Progress() { w.area = next } -// DrawImage paints current game state -func (w *World) DrawImage(pix []uint8) { +// Draw paints current game state. +func (w *World) Draw(pix []byte) { height := len(w.area) width := len(w.area[0]) for y := 0; y < height; y++ { for x := 0; x < width; x++ { - pos := 4*y*width + 4*x + idx := 4*y*width + 4*x if w.area[y][x] { - pix[pos] = 0xff - pix[pos+1] = 0xff - pix[pos+2] = 0xff - pix[pos+3] = 0xff + pix[idx] = 0xff + pix[idx+1] = 0xff + pix[idx+2] = 0xff + pix[idx+3] = 0xff } else { - pix[pos] = 0 - pix[pos+1] = 0 - pix[pos+2] = 0 - pix[pos+3] = 0 + pix[idx] = 0 + pix[idx+1] = 0 + pix[idx+2] = 0 + pix[idx+3] = 0 } } } } -// neighbourCount calculates the Moore neighborhood of x, y +func max(a, b int) int { + if a < b { + return b + } + return a +} + +func min(a, b int) int { + if a < b { + return a + } + return b +} + +// neighbourCount calculates the Moore neighborhood of (x, y). func neighbourCount(a [][]bool, x, y int) int { - height := len(a) - width := len(a[0]) - lowX := 0 - if x > 0 { - lowX = x - 1 - } - lowY := 0 - if y > 0 { - lowY = y - 1 - } - highX := width - 1 - if x < width-1 { - highX = x + 1 - } - highY := height - 1 - if y < height-1 { - highY = y + 1 - } - near := 0 - for pY := lowY; pY <= highY; pY++ { - for pX := lowX; pX <= highX; pX++ { - if !(pX == x && pY == y) && a[pY][pX] { - near++ + w := len(a[0]) + h := len(a) + minI := max(x-1, 0) + minJ := max(y-1, 0) + maxI := min(x+1, w-1) + maxJ := min(y+1, h-1) + + c := 0 + for j := minJ; j <= maxJ; j++ { + for i := minI; i <= maxI; i++ { + if i == x && j == y { + continue + } + if a[j][i] { + c++ } } } - - return near -} - -func makeArea(width, height int) [][]bool { - area := make([][]bool, height) - for i := 0; i < height; i++ { - area[i] = make([]bool, width) - } - return area + return c } const ( @@ -168,23 +175,24 @@ const ( ) var ( - world = NewWorld(screenWidth, screenHeight) - pixels = make([]uint8, screenWidth*screenHeight*4) + world = NewWorld(screenWidth, screenHeight, int((screenWidth*screenHeight)/10)) + pixels = make([]byte, screenWidth*screenHeight*4) ) func update(screen *ebiten.Image) error { - world.Progress() + world.Update() + if ebiten.IsRunningSlowly() { return nil } - world.DrawImage(pixels) + + world.Draw(pixels) screen.ReplacePixels(pixels) return nil } func main() { - world.RandomSeed(int((screenWidth * screenHeight) / 10)) - if err := ebiten.Run(update, screenWidth, screenHeight, 2.0, "Game of Life (Ebiten Demo)"); err != nil { + if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Game of Life (Ebiten Demo)"); err != nil { log.Fatal(err) } } diff --git a/docs/examples/masking.html b/docs/examples/masking.html index 35ba52cef..12a51834f 100644 --- a/docs/examples/masking.html +++ b/docs/examples/masking.html @@ -48,9 +48,9 @@ const ( ) var ( - gophersImage *ebiten.Image - fiveyearsImage *ebiten.Image - maskImage *ebiten.Image + bgImage *ebiten.Image + fgImage *ebiten.Image + maskedFgImage *ebiten.Image spotLightImage *ebiten.Image spotLightX = 0 spotLightY = 0 @@ -58,6 +58,36 @@ var ( spotLightVY = 1 ) +func init() { + var err error + bgImage, _, err = ebitenutil.NewImageFromFile("_resources/images/gophers.jpg", ebiten.FilterNearest) + if err != nil { + log.Fatal(err) + } + + fgImage, _, err = ebitenutil.NewImageFromFile("_resources/images/fiveyears.jpg", ebiten.FilterNearest) + if err != nil { + log.Fatal(err) + } + + maskedFgImage, _ = ebiten.NewImage(screenWidth, screenHeight, ebiten.FilterNearest) + + // Initialize the spot light image. + const r = 64 + alphas := image.Point{r * 2, r * 2} + a := image.NewAlpha(image.Rectangle{image.ZP, alphas}) + for j := 0; j < alphas.Y; j++ { + for i := 0; i < alphas.X; i++ { + // d is the distance between (i, j) and the (circle) center. + d := math.Sqrt(float64((i-r)*(i-r) + (j-r)*(j-r))) + // Alphas around the center are 0 and values outside of the circle are 0xff. + b := uint8(max(0, min(0xff, int(3*d*0xff/r)-2*0xff))) + a.SetAlpha(i, j, color.Alpha{b}) + } + } + spotLightImage, _ = ebiten.NewImageFromImage(a, ebiten.FilterNearest) +} + func update(screen *ebiten.Image) error { spotLightX += spotLightVX spotLightY += spotLightVY @@ -79,22 +109,34 @@ func update(screen *ebiten.Image) error { spotLightY = -spotLightY + 2*maxY spotLightVY = -spotLightVY } + if ebiten.IsRunningSlowly() { return nil } - maskImage.Clear() + // Reset the maskedFgImage. + maskedFgImage.Fill(color.White) op := &ebiten.DrawImageOptions{} + op.CompositeMode = ebiten.CompositeModeCopy op.GeoM.Translate(float64(spotLightX), float64(spotLightY)) - maskImage.DrawImage(spotLightImage, op) + maskedFgImage.DrawImage(spotLightImage, op) + // Use 'source-in' composite mode so that the source image (fgImage) is used but the alpha + // is determined by the destination image (maskedFgImage). + // + // The result image is the source image with the destination alpha. In maskedFgImage, alpha + // values in the hole is 0 and alpha values in other places are 0xff. As a result, the + // maskedFgImage draws the source image with a hole that shape is spotLightImage. Note that + // RGB values in the destination image are ignored. + // + // See also https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin. op = &ebiten.DrawImageOptions{} - op.CompositeMode = ebiten.CompositeModeSourceOut - maskImage.DrawImage(fiveyearsImage, op) + op.CompositeMode = ebiten.CompositeModeSourceIn + maskedFgImage.DrawImage(fgImage, op) screen.Fill(color.RGBA{0x00, 0x00, 0x80, 0xff}) - screen.DrawImage(gophersImage, &ebiten.DrawImageOptions{}) - screen.DrawImage(maskImage, &ebiten.DrawImageOptions{}) + screen.DrawImage(bgImage, &ebiten.DrawImageOptions{}) + screen.DrawImage(maskedFgImage, &ebiten.DrawImageOptions{}) return nil } @@ -114,28 +156,6 @@ func min(a, b int) int { } func main() { - var err error - gophersImage, _, err = ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "gophers.jpg"), ebiten.FilterNearest) - if err != nil { - log.Fatal(err) - } - fiveyearsImage, _, err = ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "fiveyears.jpg"), ebiten.FilterNearest) - if err != nil { - log.Fatal(err) - } - maskImage, _ = ebiten.NewImage(screenWidth, screenHeight, ebiten.FilterNearest) - - as := image.Point{128, 128} - a := image.NewAlpha(image.Rectangle{image.ZP, as}) - for j := 0; j < as.Y; j++ { - for i := 0; i < as.X; i++ { - r := as.X / 2 - d := math.Sqrt(float64((i-r)*(i-r) + (j-r)*(j-r))) - b := uint8(max(0, min(0xff, 3*0xff-int(d*3*0xff)/r))) - a.SetAlpha(i, j, color.Alpha{b}) - } - } - spotLightImage, _ = ebiten.NewImageFromImage(a, ebiten.FilterNearest) if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Masking (Ebiten Demo)"); err != nil { log.Fatal(err) } diff --git a/docs/examples/mosaic.html b/docs/examples/mosaic.html index 41846f290..2c1d38096 100644 --- a/docs/examples/mosaic.html +++ b/docs/examples/mosaic.html @@ -51,13 +51,26 @@ var ( gophersRenderTarget *ebiten.Image ) +func init() { + var err error + gophersImage, _, err = ebitenutil.NewImageFromFile("_resources/images/gophers.jpg", ebiten.FilterNearest) + if err != nil { + log.Fatal(err) + } +} + func update(screen *ebiten.Image) error { if ebiten.IsRunningSlowly() { return nil } + + // Shrink the image once. op := &ebiten.DrawImageOptions{} op.GeoM.Scale(1.0/mosaicRatio, 1.0/mosaicRatio) gophersRenderTarget.DrawImage(gophersImage, op) + + // Enlarge the shrunk image. + // The filter is the nearest filter, so the result will be mosaic. op = &ebiten.DrawImageOptions{} op.GeoM.Scale(mosaicRatio, mosaicRatio) screen.DrawImage(gophersRenderTarget, op) @@ -65,11 +78,6 @@ func update(screen *ebiten.Image) error { } func main() { - var err error - gophersImage, _, err = ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "gophers.jpg"), ebiten.FilterNearest) - if err != nil { - log.Fatal(err) - } w, h := gophersImage.Size() gophersRenderTarget, _ = ebiten.NewImage(w/mosaicRatio, h/mosaicRatio, ebiten.FilterNearest) if err := ebiten.Run(update, screenWidth, screenHeight, 2, "Mosaic (Ebiten Demo)"); err != nil { diff --git a/docs/examples/perspective.html b/docs/examples/perspective.html index 3c43e05d5..2eb9c6130 100644 --- a/docs/examples/perspective.html +++ b/docs/examples/perspective.html @@ -73,7 +73,7 @@ func update(screen *ebiten.Image) error { func main() { var err error - gophersImage, _, err = ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "gophers.jpg"), ebiten.FilterNearest) + gophersImage, _, err = ebitenutil.NewImageFromFile("_resources/images/gophers.jpg", ebiten.FilterNearest) if err != nil { log.Fatal(err) } diff --git a/docs/examples/piano.html b/docs/examples/piano.html index a89f34387..61d82b386 100644 --- a/docs/examples/piano.html +++ b/docs/examples/piano.html @@ -56,7 +56,7 @@ var ( ) func init() { - f, err := ebitenutil.OpenFile(ebitenutil.JoinStringsIntoFilePath("_resources", "fonts", "arcade_n.ttf")) + f, err := ebitenutil.OpenFile("_resources/fonts/arcade_n.ttf") if err != nil { log.Fatal(err) } diff --git a/docs/examples/rotate.html b/docs/examples/rotate.html index 84769e68d..0cda9113f 100644 --- a/docs/examples/rotate.html +++ b/docs/examples/rotate.html @@ -66,7 +66,7 @@ func update(screen *ebiten.Image) error { func main() { var err error - gophersImage, _, err = ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "gophers.jpg"), ebiten.FilterNearest) + gophersImage, _, err = ebitenutil.NewImageFromFile("_resources/images/gophers.jpg", ebiten.FilterNearest) if err != nil { log.Fatal(err) } diff --git a/docs/examples/sprites.html b/docs/examples/sprites.html index 0b47b5408..19280d029 100644 --- a/docs/examples/sprites.html +++ b/docs/examples/sprites.html @@ -141,7 +141,7 @@ Press <- or -> to change the number of sprites`, ebiten.CurrentFPS(), spri func main() { var err error - img, _, err := ebitenutil.NewImageFromFile(ebitenutil.JoinStringsIntoFilePath("_resources", "images", "ebiten.png"), ebiten.FilterNearest) + img, _, err := ebitenutil.NewImageFromFile("_resources/images/ebiten.png", ebiten.FilterNearest) if err != nil { log.Fatal(err) }