Skip to content

Commit

Permalink
Add Ben's osci3d~ example.
Browse files Browse the repository at this point in the history
  • Loading branch information
agraef committed Mar 1, 2024
1 parent 2fd5b39 commit b39f29f
Show file tree
Hide file tree
Showing 4 changed files with 252 additions and 0 deletions.
6 changes: 6 additions & 0 deletions pdlua/examples/osci3d-/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# osci3d-
simple 3d oscilloscope for pure data based on pdlua with gui extensions

Please check https://github.com/ben-wes/osci3d- for the latest source!

![GitHub Image](osci3d~.png)
60 changes: 60 additions & 0 deletions pdlua/examples/osci3d-/osci3d~-help.pd
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#N canvas 324 80 867 747 12;
#X declare -lib pdlua -path pdlua;
#X obj 80 75 declare -lib pdlua -path pdlua;
#X msg 504 122 zoom \$1;
#X msg 340 202 grid \$1;
#X obj 340 178 tgl 19 1 empty empty empty 0 -10 0 12 #fcfcfc #000000 #000000 1 1;
#X obj 507 75 hsl 162 19 0.1 10 1 0 empty empty empty -2 -10 0 12 #fcfcfc #000000 #000000 0 1;
#X floatatom 504 99 5 0 0 0 - - - 0;
#X obj 507 162 hsl 162 19 1 64 1 0 empty empty empty -2 -10 0 12 #fcfcfc #000000 #000000 0 1;
#X floatatom 504 186 5 0 0 0 - - - 0;
#X msg 504 209 interval \$1;
#X obj 507 249 hsl 162 19 2 1024 0 0 empty empty empty -2 -10 0 12 #fcfcfc #000000 #000000 0 1;
#X floatatom 504 273 5 0 0 0 - - - 0;
#X msg 504 296 buffer \$1;
#X obj 507 336 hsl 162 19 1 10 0 0 empty empty empty -2 -10 0 12 #fcfcfc #000000 #000000 0 1;
#X floatatom 504 360 5 0 0 0 - - - 0;
#X msg 504 383 stroke \$1;
#X obj 507 423 hsl 162 19 0 2 0 0 empty empty empty -2 -10 0 12 #fcfcfc #000000 #000000 0 1;
#X floatatom 504 447 5 0 0 0 - - - 0;
#X msg 504 470 perspective \$1;
#X msg 273 202 reset;
#X obj 208 266 osc~ 149.1;
#X obj 80 218 osc~ 49.3;
#X obj 144 242 osc~ 99.2;
#X obj 80 291 osci3d~ 200;
#X msg 340 75 color 0 60 120;
#X obj 507 509 hsl 162 19 64 480 0 0 empty empty empty -2 -10 0 12 #fcfcfc #000000 #000000 0 1;
#X floatatom 504 533 5 0 0 0 - - - 0;
#X msg 504 556 resize \$1;
#X text 76 499 initialized with [osci3d~ 200];
#X text 76 539 optional argument for initial size;
#X msg 340 140 background 32 32 32;
#X msg 340 99 color 180 255 0;
#X connect 1 0 22 3;
#X connect 2 0 22 3;
#X connect 3 0 2 0;
#X connect 4 0 5 0;
#X connect 5 0 1 0;
#X connect 6 0 7 0;
#X connect 7 0 8 0;
#X connect 8 0 22 3;
#X connect 9 0 10 0;
#X connect 10 0 11 0;
#X connect 11 0 22 3;
#X connect 12 0 13 0;
#X connect 13 0 14 0;
#X connect 14 0 22 3;
#X connect 15 0 16 0;
#X connect 16 0 17 0;
#X connect 17 0 22 3;
#X connect 18 0 22 3;
#X connect 19 0 22 2;
#X connect 20 0 22 0;
#X connect 21 0 22 1;
#X connect 23 0 22 3;
#X connect 24 0 25 0;
#X connect 25 0 26 0;
#X connect 26 0 22 3;
#X connect 29 0 22 3;
#X connect 30 0 22 3;
186 changes: 186 additions & 0 deletions pdlua/examples/osci3d-/osci3d~.pd_lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
local osci3d = pd.Class:new():register("osci3d~")

function osci3d:initialize(sel, atoms)
self.SIZE = type(atoms[1]) == "number" and atoms[1] or 480
self.inlets = {SIGNAL, SIGNAL, SIGNAL, DATA}
self:reset()
self.signalIndex = 1
self.cameraDistance = 6
self.gridLines = self:createGrid(-2, 2, 0.5)

self:set_size(self.SIZE, self.SIZE)
return true
end

function osci3d:reset()
self.BUFFERSIZE = 512
self:set_buffer()
self.SAMPLING_INTERVAL = 8
self.DRAW_GRID = 1
self.STROKE_WIDTH = 1
self.ZOOM = 1
self.COLOR = {Colors.foreground}
self.BACKGROUND = {Colors.background}
self.PERSPECTIVE = 1
self.rotationAngleX, self.rotationAngleY = 0, 0
self.rotationStartAngleX, self.rotationStartAngleY = 0, 0
end

function osci3d:postinitialize()
self.clock = pd.Clock:new():register(self, "tick")
self.clock:delay(20)
end

function osci3d:finalize()
self.clock:destruct()
end

function osci3d:tick()
self:repaint()
self.clock:delay(20)
end

function osci3d:createGrid(minVal, maxVal, step)
local grid = {}
for i = minVal, maxVal, step do
table.insert(grid, {{i, 0, minVal}, {i, 0, maxVal}})
table.insert(grid, {{minVal, 0, i}, {maxVal, 0, i}})
end
return grid
end

function osci3d:mouse_down(x, y)
self.dragStartX, self.dragStartY = x, y
end

function osci3d:mouse_up(x, y)
self.rotationStartAngleX, self.rotationStartAngleY = self.rotationAngleX, self.rotationAngleY
end

function osci3d:mouse_drag(x, y)
self.rotationAngleY = self.rotationStartAngleY + ((x-self.dragStartX) / 50)
self.rotationAngleX = self.rotationStartAngleX - ((y-self.dragStartY) / 50)
end

function osci3d:perform(in1, in2, in3)
for i = 1, #in1, self.SAMPLING_INTERVAL do
-- circular buffer
self.signal[self.signalIndex] = {in1[i], in2[i], in3[i]}
self.signalIndex = (self.signalIndex % self.BUFFERSIZE) + 1
end
end

function osci3d:paint(g)
g.set_color(table.unpack(self.BACKGROUND))
g.fill_all()

-- draw ground grid
if self.DRAW_GRID == 1 then
g.set_color(192, 192, 192)
for i = 1, #self.gridLines do
local lineFrom, lineTo = table.unpack(self.gridLines[i])

-- apply rotation to grid lines
lineFrom = self:rotateY(lineFrom, self.rotationAngleY)
lineFrom = self:rotateX(lineFrom, self.rotationAngleX)
lineTo = self:rotateY(lineTo , self.rotationAngleY)
lineTo = self:rotateX(lineTo , self.rotationAngleX)

local startX, startY = self:projectVertex(lineFrom, self.ZOOM)
local endX, endY = self:projectVertex( lineTo, self.ZOOM)
if lineFrom[3] > -self.cameraDistance and lineTo[3] > -self.cameraDistance then
g.draw_line(startX, startY, endX, endY, 1)
end
end
end

for i = 1, self.BUFFERSIZE do
local offsetIndex = (i + self.signalIndex-2) % self.BUFFERSIZE + 1
local rotatedVertex = self:rotateY(self.signal[offsetIndex], self.rotationAngleY)
self.rotatedSignal[i] = self:rotateX(rotatedVertex, self.rotationAngleX)
end

g.set_color(table.unpack(self.COLOR))
local p = path.start(self:projectVertex(self.rotatedSignal[1], self.ZOOM))
for i = 2, self.BUFFERSIZE do
p:line_to(self:projectVertex(self.rotatedSignal[i], self.ZOOM))
end
g.stroke_path(p, self.STROKE_WIDTH)
end

function osci3d:rotateY(vertex, angle)
local x, y, z = table.unpack(vertex)
local cosTheta = math.cos(angle)
local sinTheta = math.sin(angle)
local newX = x * cosTheta - z * sinTheta
local newZ = x * sinTheta + z * cosTheta
return {newX, y, newZ}
end

function osci3d:rotateX(vertex, angle)
local x, y, z = table.unpack(vertex)
local cosTheta = math.cos(angle)
local sinTheta = math.sin(angle)
local newY = y * cosTheta - z * sinTheta
local newZ = y * sinTheta + z * cosTheta
return {x, newY, newZ}
end

function osci3d:projectVertex(vertex)
local scale = self.cameraDistance / (self.cameraDistance + vertex[3] * self.PERSPECTIVE)
local screenX = self.SIZE / 2 + (vertex[1] * scale * self.ZOOM * self.SIZE * 0.25)
local screenY = self.SIZE / 2 - (vertex[2] * scale * self.ZOOM * self.SIZE * 0.25)
return screenX, screenY
end

function osci3d:set_buffer()
self.signal = {}
self.rotatedSignal = {}
-- fill ring buffer
for i = 1, self.BUFFERSIZE do
self.signal[i] = {0, 0, 0}
self.rotatedSignal[i] = {0, 0, 0}
end
end

function osci3d:in_4_zoom(x)
self.ZOOM = x[1]
end

function osci3d:in_4_grid(x)
self.DRAW_GRID = x[1]
end

function osci3d:in_4_resize(x)
self.SIZE = math.max(64, x[1])
self:set_size(self.SIZE, self.SIZE)
end

function osci3d:in_4_buffer(x)
self.BUFFERSIZE = math.max(2, math.floor(x[1]))
self:set_buffer()
end

function osci3d:in_4_interval(x)
self.SAMPLING_INTERVAL = math.max(1, math.floor(x[1]))
end

function osci3d:in_4_stroke(x)
self.STROKE_WIDTH = math.max(1, x[1])
end

function osci3d:in_4_perspective(x)
self.PERSPECTIVE = x[1]
end

function osci3d:in_4_reset()
self:reset()
end

function osci3d:in_4_color(x)
self.COLOR = {x[1], x[2], x[3]}
end

function osci3d:in_4_background(x)
self.BACKGROUND = {x[1], x[2], x[3]}
end
Binary file added pdlua/examples/osci3d-/osci3d~.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit b39f29f

Please sign in to comment.