Skip to content

Commit

Permalink
Merge branch 'master' into avoid-more-boxing
Browse files Browse the repository at this point in the history
  • Loading branch information
JD557 authored Nov 3, 2024
2 parents f536cc9 + 322ba11 commit 324df8e
Show file tree
Hide file tree
Showing 33 changed files with 183 additions and 76 deletions.
2 changes: 1 addition & 1 deletion docs/_docs/advanced-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ The Minart project is divided in multiple small packages:
- `minart-core`: This package is always required.
- `minart-backend`: Contains the default implementations for each backend (AWT, HTML and SDL).
While usually required, you can skip it if you plan to implement your own backend.
- `minart-image`: Contains logic to load and store images in PPM, BMP or QOI format.
- `minart-image`: Contains logic to load and store images in PBM/PPM, PDI, BMP or QOI format.
You can skip it if you don't plan to read or write any images.
- `minart-sound`: Contains logic to load and store sound files in WAV, AIFF, RTTTL or QOA format.
You can skip it if you don't plan to read or write any sound files.
6 changes: 4 additions & 2 deletions docs/_docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ <h2>Development status</h2>
<p>
Minart is still in a <strong>0.x version</strong>. Quoting the semver specification:
<blockquote>
Major version zero (0.y.z) is for initial development. Anything MAY change at any time. The public API SHOULD NOT be considered stable.
Major version zero (0.y.z) is for initial development. Anything MAY change at any time.
The public API SHOULD NOT be considered stable.
</blockquote>

As such, while it's OK to use Minart for small demos, it's not recommended to use it for commercial projects.
Expand All @@ -46,7 +47,8 @@ <h2>Limitations</h2>
as <a href="https://indigoengine.io">Indigo</a>.
</p>
<p>
Also, Minart is only suitable for bitmap graphics.
Also, Minart is only suitable for bitmap graphics. There are a few geometric
primitives, but those are quite limited.
For vector graphics it is recommended to use an appropriate library, such
as <a href="https://www.creativescala.org/doodle/">Doodle</a>.
</p>
1 change: 1 addition & 0 deletions docs/_docs/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Minart comes out of the box with some basic graphic features, such as:
- Double buffered canvas
- Integer scaling
- Surface blitting (with multiple blending modes)
- Simple shape and line rendering

It also includes **Surface views** and **Planes** which makes it possible to manipulate
(possibly unbounded) images with familiar operations such as `map` and `flatMap`.
Expand Down
7 changes: 7 additions & 0 deletions docs/_docs/structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ A `Canvas` is a special type of `MutableSurface`, which represents a window.

`SurfaceView`s and `Planes` are abstractions to quickly and efficiently manipulate `Surface`s.

## `eu.joaocosta.minart.geometry`

This package contains abstractions related to geometric primitives, such as
`Point`, `Matrix`, `Shape` and `Stroke`.

Most of the APIs in this package are still experimental, and may change in future versions.

## `eu.joaocosta.minart.audio`

This package contains all abstractions related to audio playback.
Expand Down
10 changes: 6 additions & 4 deletions docs/sidebar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ subsection:
page: ../../examples/release/08-loading-images.md
- title: "9. Surface Views"
page: ../../examples/release/09-surface-views.md
- title: "10. Audio Playback"
page: ../../examples/release/10-audio-playback.md
- title: "11. Loading Sounds"
page: ../../examples/release/11-loading-sounds.md
- title: "10. Vector Shapes"
page: ../../examples/release/10-vector-shapes.md
- title: "11. Audio Playback"
page: ../../examples/release/11-audio-playback.md
- title: "12. Loading Sounds"
page: ../../examples/release/12-loading-sounds.md
4 changes: 2 additions & 2 deletions examples/release/01-introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ scala-cli 01-introduction.md
The simplest way to use Minart is to simply include the `minart` library, which packages all modules.

```scala
//> using scala "3.3.3"
//> using dep "eu.joaocosta::minart::0.6.1"
//> using scala "3.3.4"
//> using dep "eu.joaocosta::minart::0.6.2"
```

As for the imports, the `eu.joaocosta.minart.backend.defaults` package contains the givens with the backend-specific (JVM/JS/Native) logic.
Expand Down
4 changes: 2 additions & 2 deletions examples/release/02-portable-applications.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ We start with the similar imports to the previous example.
Note, however, that we now also import `eu.joaocosta.minart.runtime.*`, which provides a platform agnostic runtime that we can use.

```scala
//> using scala "3.3.3"
//> using dep "eu.joaocosta::minart::0.6.1"
//> using scala "3.3.4"
//> using dep "eu.joaocosta::minart::0.6.2"

import eu.joaocosta.minart.backend.defaults.given
import eu.joaocosta.minart.graphics.*
Expand Down
4 changes: 2 additions & 2 deletions examples/release/03-animation.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ This time, we'll write an animated fire, updating at 60 frames per second!
As before, let's import the backend, graphics and runtime.

```scala
//> using scala "3.3.3"
//> using dep "eu.joaocosta::minart::0.6.1"
//> using scala "3.3.4"
//> using dep "eu.joaocosta::minart::0.6.2"

import eu.joaocosta.minart.backend.defaults.given
import eu.joaocosta.minart.graphics.*
Expand Down
4 changes: 2 additions & 2 deletions examples/release/04-pointer-input.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ As before, let's import the backend, graphics and runtime.
We also need to import the input package. We need this to read data from input devices, such as keyboard and mouse.

```scala
//> using scala "3.3.3"
//> using dep "eu.joaocosta::minart::0.6.1"
//> using scala "3.3.4"
//> using dep "eu.joaocosta::minart::0.6.2"

import eu.joaocosta.minart.backend.defaults.given
import eu.joaocosta.minart.graphics.*
Expand Down
4 changes: 2 additions & 2 deletions examples/release/05-stateful-applications.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ In this example, we will show how to write applications that manipulate a state
The dependencies will be the same as before. We also include Scala's `Random` here just to make the game more interesting.

```scala
//> using scala "3.3.3"
//> using dep "eu.joaocosta::minart::0.6.1"
//> using scala "3.3.4"
//> using dep "eu.joaocosta::minart::0.6.2"

import scala.util.Random

Expand Down
4 changes: 2 additions & 2 deletions examples/release/06-surfaces.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ A `Surface` is something with a `getPixel` operation (`MutableSurface`s also pro
For this example, we just need to use the graphics and runtime

```scala
//> using scala "3.3.3"
//> using dep "eu.joaocosta::minart::0.6.1"
//> using scala "3.3.4"
//> using dep "eu.joaocosta::minart::0.6.2"


import eu.joaocosta.minart.backend.defaults.given
Expand Down
4 changes: 2 additions & 2 deletions examples/release/07-canvas-settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ Here's a quick example on how to do that. In this example application, we will c
### Dependencies and imports

```scala
//> using scala "3.3.3"
//> using dep "eu.joaocosta::minart::0.6.1"
//> using scala "3.3.4"
//> using dep "eu.joaocosta::minart::0.6.2"

import eu.joaocosta.minart.backend.defaults.given
import eu.joaocosta.minart.graphics.*
Expand Down
6 changes: 3 additions & 3 deletions examples/release/08-loading-images.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

So far we always created our surfaces manually. This is fine for small demos and procedural graphics, but often it can be useful to load an image from an external file.

Minart has support for some image file formats (PPM, BMP and QOI). Here we will see how to load them.
Minart has support for some image file formats (PBM/PPM, PDI, BMP and QOI). Here we will see how to load them.

## A simple image viewer

Expand All @@ -14,8 +14,8 @@ This package also has an `Image` object with helpers to call the loaders.


```scala
//> using scala "3.3.3"
//> using dep "eu.joaocosta::minart::0.6.1"
//> using scala "3.3.4"
//> using dep "eu.joaocosta::minart::0.6.2"

import eu.joaocosta.minart.backend.defaults.given
import eu.joaocosta.minart.graphics.*
Expand Down
23 changes: 8 additions & 15 deletions examples/release/09-surface-views.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ This tutorial will show how to use those
### Dependencies and imports

```scala
//> using scala "3.3.3"
//> using dep "eu.joaocosta::minart::0.6.1"
//> using scala "3.3.4"
//> using dep "eu.joaocosta::minart::0.6.2"

import eu.joaocosta.minart.backend.defaults.given
import eu.joaocosta.minart.graphics.*
Expand Down Expand Up @@ -59,13 +59,12 @@ Let's see an example with multiple effects, such as:
- Wobble
- Checkerboard invert

Before we start, let's precompute the convolution window that we will use for the blur
Before we start, let's precompute the convolution kernel that we will use for the blur.
We could use a simple function, but Minart already provides some optimized kernels
out of the box.

```scala
val convolutionWindow = for {
x <- (-1 to 1)
y <- (-1 to 1)
} yield (x, y)
val blurKernel = Kernel.averageBlur(3, 3)

```

Expand All @@ -79,14 +78,8 @@ def application(t: Double, canvas: Canvas): Unit = {

val image = updatedBitmap.view.repeating // Create an infinite Plane from our surface
.scale(zoom, zoom) // Scale
.coflatMap { img => // Average blur
convolutionWindow.iterator
.map { case (x, y) => img(x, y) }
.foldLeft(Color(0, 0, 0)) { case (Color(r, g, b), Color(rr, gg, bb)) =>
Color(r + rr / 9, g + gg / 9, b + bb / 9)
}
}
.rotate(t) // Rotate
.coflatMap(blurKernel) // Average blur
.rotate(t) // Rotate
.contramap((x, y) => (x + (5 * Math.sin(t + y / 10.0)).toInt, y)) // Wobbly effect
.flatMap(color =>
(x, y) => // Checkerboard effect
Expand Down
102 changes: 102 additions & 0 deletions examples/release/10-vector-shapes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# 10. Vector shapes

Besides surfaces, Minart also allows you to render some basic vector shapes.

## Drawing shapes

### Dependencies and imports

The relevant methods are in the `eu.joaocosta.minart.geometry` package

```scala
//> using scala "3.3.4"
//> using dep "eu.joaocosta::minart::0.6.2"

import eu.joaocosta.minart.backend.defaults.given
import eu.joaocosta.minart.graphics.*
import eu.joaocosta.minart.geometry.*
import eu.joaocosta.minart.runtime.*
```

### Shapes

Vectorial shapes are represented by the `Shape` abstraction.

Minart already comes with some basic shapes, such as circle and convex polygons, with helper methods in the `Shape` companion object.

First, let's create a few shapes with those methods.

```scala
import eu.joaocosta.minart.geometry.Point

val triangle = Shape.triangle(Point(-16, 16), Point(0, -16), Point(16, 16))
val square = Shape.rectangle(Point(-16, -16), Point(16, 16))
val octagon = Shape.convexPolygon(
Point(-8, -16),
Point(8, -16),
Point(16, -8),
Point(16, 8),
Point(8, 16),
Point(-8, 16),
Point(-16, 8),
Point(-16, -8)
)
val circle = Shape.circle(Point(0, 0), 16)
```

### Faces

Notice that all shapes are defined with points in clockwise fashion.

All shapes have two faces: A front face and a back face.

Depending on the way they are defined (or transformed), different faces might be shown.

Minart allows you to set different colors for each face, and even no color at all!
This is helpful if, for some reason, you know you don't want to draw back faces.

### Rasterizing

Now we just need to use the `rasterizeShape` operation, just like we did with `blit`.

In this example we will also scale our images with time, to show how the color changes when the face flips.

There's also a `rasterizeStroke` operation to draw lines and a `rasterizeContour` operation to draw only the shape
contours (note that not all shapes support this, some transformations can make the contour computation impossible).

```scala
val frontfaceColor = Color(255, 0, 0)
val backfaceColor = Color(0, 255, 0)
val contourColor = Color(255, 255, 255)

def application(t: Double, canvas: Canvas): Unit = {
val scale = math.sin(t)
canvas.rasterizeShape(triangle.scale(scale, 1.0), Some(frontfaceColor), Some(backfaceColor))(32, 32)
canvas.rasterizeShape(square.scale(scale, 1.0), Some(frontfaceColor), Some(backfaceColor))(64, 32)
canvas.rasterizeShape(octagon.scale(scale, 1.0), Some(frontfaceColor), Some(backfaceColor))(32, 64)
canvas.rasterizeShape(circle.scale(scale, 1.0), Some(frontfaceColor), Some(backfaceColor))(64, 64)

canvas.rasterizeContour(triangle.scale(scale, 1.0), contourColor)(32, 32)
canvas.rasterizeContour(square.scale(scale, 1.0), contourColor)(64, 32)
canvas.rasterizeContour(octagon.scale(scale, 1.0), contourColor)(32, 64)
// Can't compute the contour of a circle scaled on only one dimension
//canvas.rasterizeContour(circle.scale(scale, 1.0), contourColor)(64, 64)
}
```

### Putting it all together

```scala
val canvasSettings = Canvas.Settings(width = 128, height = 128, scale = Some(4), clearColor = Color(0, 0, 0))

AppLoop
.statefulRenderLoop((t: Double) => (canvas: Canvas) => {
canvas.clear()
application(t, canvas)
canvas.redraw()
t + 0.01
}
)
.configure(canvasSettings, LoopFrequency.hz60, 0)
.run()
```
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# 10. Audio playback
# 11. Audio playback

Besides graphics and input, Minart also supports loading and playing back audio.

Expand All @@ -9,8 +9,8 @@ Here we will see how to generate audio waves and play a simple audio clip.
### Dependencies and imports

```scala
//> using scala "3.3.3"
//> using dep "eu.joaocosta::minart::0.6.1"
//> using scala "3.3.4"
//> using dep "eu.joaocosta::minart::0.6.2"

import eu.joaocosta.minart.audio.*
import eu.joaocosta.minart.backend.defaults.given
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# 11. Loading sounds
# 12. Loading sounds

Just like we did with images, we can also load audio clips from files.

Minart supports multiple audio formats (RTTL AIFF, WAV and QOA).
Minart supports multiple audio formats (RTTL, AIFF, WAV and QOA).

Here's a small example to play a clip from a file

Expand All @@ -16,8 +16,8 @@ This package also has an `Sound` object with helpers to call the loaders.


```scala
//> using scala "3.3.3"
//> using dep "eu.joaocosta::minart::0.6.1"
//> using scala "3.3.4"
//> using dep "eu.joaocosta::minart::0.6.2"

import eu.joaocosta.minart.audio.*
import eu.joaocosta.minart.audio.sound.*
Expand Down
4 changes: 2 additions & 2 deletions examples/snapshot/01-introduction.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ scala-cli 01-introduction.md
The simplest way to use Minart is to simply include the `minart` library, which packages all modules.

```scala
//> using scala "3.3.3"
//> using dep "eu.joaocosta::minart::0.6.2-SNAPSHOT"
//> using scala "3.3.4"
//> using dep "eu.joaocosta::minart::0.6.3-SNAPSHOT"
```

As for the imports, the `eu.joaocosta.minart.backend.defaults` package contains the givens with the backend-specific (JVM/JS/Native) logic.
Expand Down
4 changes: 2 additions & 2 deletions examples/snapshot/02-portable-applications.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ We start with the similar imports to the previous example.
Note, however, that we now also import `eu.joaocosta.minart.runtime.*`, which provides a platform agnostic runtime that we can use.

```scala
//> using scala "3.3.3"
//> using dep "eu.joaocosta::minart::0.6.2-SNAPSHOT"
//> using scala "3.3.4"
//> using dep "eu.joaocosta::minart::0.6.3-SNAPSHOT"

import eu.joaocosta.minart.backend.defaults.given
import eu.joaocosta.minart.graphics.*
Expand Down
4 changes: 2 additions & 2 deletions examples/snapshot/03-animation.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ This time, we'll write an animated fire, updating at 60 frames per second!
As before, let's import the backend, graphics and runtime.

```scala
//> using scala "3.3.3"
//> using dep "eu.joaocosta::minart::0.6.2-SNAPSHOT"
//> using scala "3.3.4"
//> using dep "eu.joaocosta::minart::0.6.3-SNAPSHOT"

import eu.joaocosta.minart.backend.defaults.given
import eu.joaocosta.minart.graphics.*
Expand Down
4 changes: 2 additions & 2 deletions examples/snapshot/04-pointer-input.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ As before, let's import the backend, graphics and runtime.
We also need to import the input package. We need this to read data from input devices, such as keyboard and mouse.

```scala
//> using scala "3.3.3"
//> using dep "eu.joaocosta::minart::0.6.2-SNAPSHOT"
//> using scala "3.3.4"
//> using dep "eu.joaocosta::minart::0.6.3-SNAPSHOT"

import eu.joaocosta.minart.backend.defaults.given
import eu.joaocosta.minart.graphics.*
Expand Down
Loading

0 comments on commit 324df8e

Please sign in to comment.