Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ohrite committed Jul 26, 2023
0 parents commit 2007d14
Show file tree
Hide file tree
Showing 39 changed files with 1,468 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
28 changes: 28 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# The directory Mix will write compiled artifacts to.
/_build/
/example/_build/

# If you run "mix test --cover", coverage assets end up here.
/cover/

# The directory Mix downloads your dependencies sources to.
/deps/
/example/deps/

# Where third-party dependencies like ExDoc output generated docs.
/doc/

# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch

# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump

# Also ignore archive artifacts (built via "mix archive.build").
*.ez

# Ignore package tarball (built via "mix hex.build").
zenic-*.tar

# Temporary files, for example, from tests.
/tmp/
13 changes: 13 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright 2023 Doc Ritezel

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Zenic

A [Zdog](https://zzz.dog)-inspired round, flat 3D engine for [Scenic](https://github.com/ScenicFramework/scenic).

## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `zenic` to your list of dependencies in `mix.exs`:

```elixir
def deps do
[
{:zenic, "~> 0.1.0"}
]
end
```

Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at <https://hexdocs.pm/zenic>.

4 changes: 4 additions & 0 deletions example/.formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
4 changes: 4 additions & 0 deletions example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Readme text goes here


From template
1 change: 1 addition & 0 deletions example/assets/readme.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
assets_readme.txt
29 changes: 29 additions & 0 deletions example/config/config.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# This file is responsible for configuring your application
# and its dependencies with the aid of the Mix.Config module.
import Config

# connect the app's asset module to Scenic
config :scenic, :assets, module: Example.Assets

# Configure the main viewport for the Scenic application
config :example, :viewport,
name: :main_viewport,
size: {170, 170},
theme: :dark,
default_scene: Example.Scene.Home,
drivers: [
[
module: Scenic.Driver.Local,
name: :local,
window: [resizeable: false, title: "example"],
on_close: :stop_system
]
]

# It is also possible to import configuration files, relative to this
# directory. For example, you can emulate configuration per environment
# by uncommenting the line below and defining dev.exs, test.exs and such.
# Configuration from the imported file will override the ones defined
# here (which is why it is important to import them last).
#
# import_config "prod.exs"
4 changes: 4 additions & 0 deletions example/lib/assets.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
defmodule Example.Assets do
use Scenic.Assets.Static,
otp_app: :example
end
18 changes: 18 additions & 0 deletions example/lib/example.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
defmodule Example do
@moduledoc """
Starter application using the Scenic framework.
"""

def start(_type, _args) do
# load the viewport configuration from config
main_viewport_config = Application.get_env(:example, :viewport)

# start the application with the viewport
children = [
{Scenic, [main_viewport_config]},
Example.PubSub.Supervisor
]

Supervisor.start_link(children, strategy: :one_for_one)
end
end
26 changes: 26 additions & 0 deletions example/lib/pubsub/frame.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
defmodule Example.PubSub.Frame do
use GenServer

alias Scenic.PubSub

@name :frame
@version "1.0.0"
@description "Global animation frame counter"

@timer_ms div(1000, 30)

def start_link(_), do: GenServer.start_link(__MODULE__, :ok, name: @name)

def init(_) do
PubSub.register(:frame, version: @version, description: @description)
PubSub.publish(:frame, 0)
{:ok, timer} = :timer.send_interval(@timer_ms, :tick)
{:ok, %{timer: timer, frame: 0}}
end

def handle_info(:tick, %{frame: frame} = state) do
PubSub.publish(:frame, frame)

{:noreply, %{state | frame: frame + 1}}
end
end
17 changes: 17 additions & 0 deletions example/lib/pubsub/supervisor.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# a simple supervisor that starts up the Scenic.SensorPubSub server
# and any set of other sensor processes

defmodule Example.PubSub.Supervisor do
use Supervisor

def start_link(_) do
Supervisor.start_link(__MODULE__, :ok)
end

def init(:ok) do
[
Example.PubSub.Frame
]
|> Supervisor.init(strategy: :one_for_one)
end
end
33 changes: 33 additions & 0 deletions example/lib/scenes/home.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
defmodule Example.Scene.Home do
use Scenic.Scene
require Logger

alias Scenic.{Scene, Graph, PubSub}
alias Zenic.{Camera, Ellipse, Group, Rect, Transform}

import Scenic.Primitives
import Zenic.Scenic

@camera Camera.perspective(150, 150, 0.1, 1000.0, 10.0)
@rect Rect.new(20, 20, backface: true, fill: :salmon, stroke: {20, :salmon}, join: :round, transform: Transform.new(translate: {0, 0, -5}))
@ellipse Ellipse.new(20, 20, backface: true, stroke: {20, :purple}, join: :round, transform: Transform.new(translate: {0, 0, 5}))
@root Group.new([@ellipse, @rect], transform: Transform.new(scale: {100, 100, 1.0}, translate: {20, 20, 300}))

@graph Graph.build() |> add_specs_to_graph([
rrect_spec({150, 150, 10}, fill: :peach_puff, t: {10, 10}),
illustration_spec({[@root], @camera}, id: :illustration, t: {10, 10})
])

@impl Scene
def init(scene, _param, _opts) do
PubSub.subscribe(:frame)
{:ok, assign(push_graph(scene, @graph), graph: @graph)}
end

@impl true
def handle_info({{PubSub, :data}, {:frame, frame, _}}, %{assigns: %{graph: graph}} = scene) do
root = %{@root | transform: %{@root.transform | rotate: {{0, frame / 15, 0}, :xyz}}}
graph = Graph.modify(graph, :illustration, &illustration(&1, {[root], @camera}))
{:noreply, assign(push_graph(scene, graph), graph: graph)}
end
end
31 changes: 31 additions & 0 deletions example/mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
defmodule Example.MixProject do
use Mix.Project

def project do
[
app: :example,
version: "0.1.0",
elixir: "~> 1.9",
build_embedded: true,
start_permanent: Mix.env() == :prod,
deps: deps()
]
end

# Run "mix help compile.app" to learn about applications.
def application do
[
mod: {Example, []},
extra_applications: [:crypto]
]
end

# Run "mix help deps" to learn about dependencies.
defp deps do
[
{:scenic, "~> 0.11.0"},
{:scenic_driver_local, "~> 0.11.0"},
{:zenic, path: ".."}
]
end
end
10 changes: 10 additions & 0 deletions example/mix.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
%{
"elixir_make": {:hex, :elixir_make, "0.6.3", "bc07d53221216838d79e03a8019d0839786703129599e9619f4ab74c8c096eac", [:mix], [], "hexpm", "f5cbd651c5678bcaabdbb7857658ee106b12509cd976c2c2fca99688e1daf716"},
"ex_image_info": {:hex, :ex_image_info, "0.2.4", "610002acba43520a9b1cf1421d55812bde5b8a8aeaf1fe7b1f8823e84e762adb", [:mix], [], "hexpm", "fd1a7e02664e3b14dfd3b231d22fdd48bd3dd694c4773e6272b3a6228f1106bc"},
"font_metrics": {:hex, :font_metrics, "0.5.1", "10ce0b8b1bf092a2d3d307e05a7c433787ae8ca7cd1f3cf959995a628809a994", [:mix], [{:nimble_options, "~> 0.3", [hex: :nimble_options, repo: "hexpm", optional: false]}], "hexpm", "192e4288772839ae4dadccb0f5b1d5c89b73a0c3961ccea14b6181fdcd535e54"},
"input_event": {:hex, :input_event, "1.2.0", "18297c9572ace3b7f7f9e586c8cd5e9425e3cb6270d8d35322242c351d6ae5e0", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "1dc96fd4fb08b595bf1a93dd6c9d13f8aa5cfc52cff9e1179c3f994aaa9deeac"},
"nimble_options": {:hex, :nimble_options, "0.4.0", "c89babbab52221a24b8d1ff9e7d838be70f0d871be823165c94dd3418eea728f", [:mix], [], "hexpm", "e6701c1af326a11eea9634a3b1c62b475339ace9456c1a23ec3bc9a847bca02d"},
"scenic": {:hex, :scenic, "0.11.1", "9cabc40a1362de76b25c9b243503251c9e9287816fab88b539c55e8debdb6513", [:make, :mix], [{:elixir_make, "~> 0.6.2", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:ex_image_info, "~> 0.2.4", [hex: :ex_image_info, repo: "hexpm", optional: false]}, {:font_metrics, "~> 0.5.0", [hex: :font_metrics, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.3.4 or ~> 0.4.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:truetype_metrics, "~> 0.6", [hex: :truetype_metrics, repo: "hexpm", optional: false]}], "hexpm", "86845290002bb61ac34ab24573dfd0f15f1d17bb24fa68767af65601eaae5153"},
"scenic_driver_local": {:hex, :scenic_driver_local, "0.11.0", "c26f7665c3d4aa634a0f8873bd958cb3bfcc99cb96e2381422de3e78d244357c", [:make, :mix], [{:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:input_event, "~> 0.4 or ~> 1.0", [hex: :input_event, repo: "hexpm", optional: false]}, {:scenic, "~> 0.11.0", [hex: :scenic, repo: "hexpm", optional: false]}], "hexpm", "77b27b82a8fe41d5fade5c88cf413af098d3f3d56717c988097e7902ab9b9d03"},
"truetype_metrics": {:hex, :truetype_metrics, "0.6.1", "9119a04dc269dd8f63e85e12e4098f711cb7c5204a420f4896f40667b9e064f6", [:mix], [{:font_metrics, "~> 0.5", [hex: :font_metrics, repo: "hexpm", optional: false]}], "hexpm", "5711d4a3e4fc92eb073326fbe54208925d35168dc9b288c331ee666a8a84759b"},
}
2 changes: 2 additions & 0 deletions lib/zenic.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
defmodule Zenic do
end
68 changes: 68 additions & 0 deletions lib/zenic/box.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
defmodule Zenic.Box do
alias Zenic.{Transform, Rect, Renderable}

@default {Rect.new(1, 1), Rect.new(1, 1), Rect.new(1, 1), Rect.new(1, 1), Rect.new(1, 1),
Rect.new(1, 1)}
defstruct faces: @default, options: [], transform: Transform.new()

@type t :: %__MODULE__{
faces: {Rect.t(), Rect.t(), Rect.t(), Rect.t(), Rect.t(), Rect.t()},
options: keyword,
transform: Transform.t()
}

@spec new(width :: number, height :: number, depth :: number, options :: keyword) :: t()
def new(width \\ 1, height \\ 1, depth \\ 1, options \\ [])

def new(width, height, depth, options) do
{transform, options} = Keyword.pop(options, :transform, Transform.new())
{north_options, options} = Keyword.pop(options, :north, [])
{south_options, options} = Keyword.pop(options, :south, [])
{east_options, options} = Keyword.pop(options, :east, [])
{west_options, options} = Keyword.pop(options, :west, [])
{top_options, options} = Keyword.pop(options, :top, [])
{bottom_options, options} = Keyword.pop(options, :bottom, [])
north = Rect.new(width, height, Keyword.merge(north_options, transform: north(depth)))
east = Rect.new(depth, height, Keyword.merge(east_options, transform: east(width)))
west = Rect.new(depth, height, Keyword.merge(west_options, transform: west(width)))
south = Rect.new(width, height, Keyword.merge(south_options, transform: south(depth)))
top = Rect.new(width, depth, Keyword.merge(top_options, transform: top(height)))
bottom = Rect.new(width, depth, Keyword.merge(bottom_options, transform: bottom(height)))

%__MODULE__{
faces: {north, east, west, south, top, bottom},
options: options,
transform: transform
}
end

defp north(depth), do: Transform.new(translate: {0, 0, depth / 2}, rotate: {{0, 0, 0}, :xyz})

defp east(width),
do: Transform.new(translate: {-width / 2, 0, 0}, rotate: {{0, 3 * :math.pi() / 2, 0}, :xyz})

defp west(width),
do:
Transform.new(translate: {width - width / 2, 0, 0}, rotate: {{0, :math.pi() / 2, 0}, :xyz})

defp south(depth),
do: Transform.new(translate: {0, 0, -depth / 2}, rotate: {{:math.pi(), 0, 0}, :xyz})

defp top(height),
do:
Transform.new(
translate: {0, height - height / 2, 0},
rotate: {{3 * :math.pi() / 2, 0, 0}, :xyz}
)

defp bottom(height),
do: Transform.new(translate: {0, -height / 2, 0}, rotate: {{:math.pi() / 2, 0, 0}, :xyz})

defimpl Zenic.Renderable, for: __MODULE__ do
def to_specs(%{faces: faces, transform: transform}, camera, transforms) do
faces
|> Tuple.to_list()
|> Enum.reduce([], &(Renderable.to_specs(&1, camera, [transform | transforms]) ++ &2))
end
end
end
Loading

0 comments on commit 2007d14

Please sign in to comment.