Skip to content

Commit

Permalink
add math.oblique, am.quads and am.struct_array functions
Browse files Browse the repository at this point in the history
  • Loading branch information
ianmaclarty committed Jun 13, 2016
1 parent 9b0ea8f commit 8bb0c64
Show file tree
Hide file tree
Showing 7 changed files with 245 additions and 37 deletions.
17 changes: 17 additions & 0 deletions doc/buffers.md
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,23 @@ table contains numbers they are used for the vector components and the
resulting view will have a quarter the number of elements as there are
numbers in the table.

### am.struct_array(size, spec) {#am.struct_array .func-def}

Returns a table of views of the given `size` as defined by
`spec`. `spec` is a sequence of view name (a string) and
view type (also a string) pairs.
The returned table can be passed directly
to the [`am.bind`](#am.bind) function.
The views all use the same underlying buffer.

For example:

~~~ {.lua}
local arr = am.struct_array(3, {"vert", "vec2", "color", "vec4"})
arr.vert:set{vec2(-1, 0), vec2(1, 0), vec2(0, 1)}
arr.color:set(vec4(1, 0, 0.5, 1))
~~~

![](images/screenshot3.jpg)


Binary file added doc/images/quads_example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 10 additions & 3 deletions doc/math.md
Original file line number Diff line number Diff line change
Expand Up @@ -544,14 +544,21 @@ Creates a 4x4 matrix for a symmetric perspective-view frustum.
- `near` and `far` are the distances of the near and far clipping
plains from the camera (these should be positive).

### math.ortho(left, right, bottom, top [, near, far]) {.func-def}
### math.ortho(left, right, bottom, top [, near, far]) {#math.ortho .func-def}

Creates a 4x4 orthographic projection matrix.
`near` and `far` are the distance from the viewer of the
near and far clipping plains (negative means behind the viewer).
Their default values are `-1` and `1`.

### math.perlin(pos [, period]) {.func-def}
### math.oblique(angle, zscale, left, right, bottom, top [, near, far]) {#math.oblique .func-def}

Creates a 4x4 oblique projection matrix.
`near` and `far` are the distance from the viewer of the
near and far clipping plains (negative means behind the viewer).
Their default values are `-1` and `1`.

### math.perlin(pos [, period]) {#math.perlin .func-def}

Generate perlin noise. `pos` can be a 2, 3, or 4 dimensional vector,
or a number. If the second argument is supplied then the noise will be
Expand All @@ -560,7 +567,7 @@ periodic with the given period. `period` should be of the same type as

The returned value is between -1 and 1.

### math.simplex(pos) {.func-def}
### math.simplex(pos) {#math.simplex .func-def}

Generate simplex noise. `pos` can be a 2, 3, or 4 dimensional vector,
or a number.
Expand Down
79 changes: 79 additions & 0 deletions doc/scene_nodes.md
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,85 @@ Fields:
the node hasn't been rendered yet,
or the named uniform wasn't set in an ancestor node.

### am.quads(n, spec) {#am.quads .func-def}

Returns a node that renders a set of quads. The returned node
is actually an [`am.bind`](#am.bind) node with an [`am.draw`](#am.draw)
node child. i.e. no program or blending is defined -- these
must be created separately as parent nodes.

`n` is initial capacity. Set this to the number of quads you think
you'll want to render. It doesn't matter if it's too small as the
capacity will be increased as required (though it's slightly faster
no capacity increases are required).

`spec` is a table of attribute name and type pairs (the same
as used for [`am.struct_array`](#am.struct_array) ).

Fields:

- `num_quads`: The number of quads. This is zero
initially.

Methods:
- `add_quad(data)`: adds a quad to be rendered. `data` is
a table where the keys are attribute names and the
values are the values of the 4 vertices of the quad.
The values can be specified in several ways:
- as a table where each each element is the value for the
left-top, left-bottom, right-bottom and right-top
corners of the quad.
- a single value for all corners.
- a view containing the values for the elements
As with the [`view:set`](#view:set) method, if the attribute
is a vector, a table of numbers is also accepted.
The quad number (starting at 1) is returned.
- `remove_quad(n)`: Removes the nth quad.
- Additionally methods are created for each attribute
of the form `quad_<attribute name>` that can be
used to update the value of a quad attribute.
The signature of the method is: `quad_attr(n, values)`
where `n` is the quad number and `values` has the
same meaning as in the `add_quad` method.

Example:

~~~ {.lua}
local quads = am.quads(2, {"vert", "vec2", "color", "vec3"})
quads:add_quad{vert = {vec2(-100, 0), vec2(-100, -100),
vec2(0, -100), vec2(0, 0)},
color = {vec3(1, 0, 0), vec3(0, 1, 0),
vec3(0, 0, 1), vec3(1, 1, 1)}}
quads:add_quad{vert = {vec2(0, 100), vec2(0, 0),
vec2(100, 0), vec2(100, 100)},
color = {vec3(1, 0, 0), vec3(0, 1, 0),
vec3(0, 0, 1), vec3(1, 1, 1)}}
local win = am.window{}
local prog = am.program([[
precision highp float;
attribute vec2 vert;
attribute vec3 color;
uniform mat4 MV;
uniform mat4 P;
varying vec3 v_color;
void main() {
v_color = color;
gl_Position = P * MV * vec4(vert, 0.0, 1.0);
}
]], [[
precision mediump float;
varying vec3 v_color;
void main() {
gl_FragColor = vec4(v_color, 1.0);
}
]])
win.scene = am.use_program(prog) ^ quads
~~~

The above program produces the following output:

![](images/quads_example.png)

### am.postprocess(settings) {#am.postprocess .func-def}

Allows for post-processing of a scene. First the children
Expand Down
56 changes: 56 additions & 0 deletions lua/buffer.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
local view_type_size = {
float = 4,
vec2 = 8,
vec3 = 12,
vec4 = 16,
byte = 1,
ubyte = 1,
byte_norm = 1,
ubyte_norm = 1,
short = 2,
ushort = 2,
short_norm = 2,
ushort_norm = 2,
ushort_elem = 2,
int = 4,
uint = 4,
uint_elem = 4,
}

function am.float_array(values)
local view = am.buffer(4 * #values):view("float", 0, 4)
view:set(values)
Expand Down Expand Up @@ -116,3 +135,40 @@ end
function am.vec4_array(values)
return vec_array(values, "vec4", 4)
end

local struct_array_mt = {}

function am.struct_array(capacity, spec)
local n = #spec
if n % 2 ~= 0 then
error("each attribute must have a corresponding type", 2)
elseif n == 0 then
error("no attributes given", 2)
end
local attrs = {}
local stride = 0
for i = 1, n, 2 do
local attr = spec[i]
local tp = spec[i + 1]
local sz = view_type_size[tp]
if not sz then
error("unknown view element type: "..tostring(tp), 2)
end
-- align
while stride % math.min(4, sz) ~= 0 do
stride = stride + 1
end
attrs[attr] = {type = tp, offset = stride}
stride = stride + sz
end
-- 4 byte align
while stride % 4 ~= 0 do
stride = stride + 1
end
local buffer = am.buffer(capacity * stride)
local views = {}
for attr, info in pairs(attrs) do
views[attr] = buffer:view(info.type, info.offset, stride)
end
return views
end
101 changes: 76 additions & 25 deletions lua/shapes.lua
Original file line number Diff line number Diff line change
Expand Up @@ -29,34 +29,85 @@ function am.quad_indices(n)
end
end

local view_type_size = {
float = 4,
vec2 = 8,
vec3 = 12,
vec4 = 16,
}

function am.quad_mesh(max, attrs)
local stride = 0
for attr, view_type in pairs(attrs) do
stride = stride + view_type_size[view_type]
end
local buffer = am.buffer(max * stride * 4)
local bindings = {}
local offset = 0
for attr, view_type in pairs(attrs) do
local view = buffer:view(view_type, offset, stride)
local sz = view_type_size[view_type]
bindings[attr] = view
offset = offset + sz
end
local node = am.bind(bindings) ^ am.draw("triangles", am.quad_indices(max))
function am.quads(capacity, spec)
capacity = math.max(1, capacity)
local n = 0
local bindings
local attrs
local views
local
function create_bindings()
bindings = am.struct_array(capacity * 4, spec)
attrs = {}
views = {}
for attr, view in pairs(bindings) do
table.insert(attrs, attr)
table.insert(views, view)
end
end
create_bindings()
local num_attrs = #attrs
local elements = am.quad_indices(capacity)
local draw_node = am.draw("triangles", elements, 1, 0)
local bind_node = am.bind(bindings) ^ draw_node
local
function expand(min_capacity)
local old_capacity = capacity
while capacity < min_capacity do
capacity = capacity * 2
end
local old_bindings = bindings
create_bindings()
for attr, view in pairs(bindings) do
bind_node[attr] = view
view:set(old_bindings[attr])
end
elements = am.quad_indices(capacity)
draw_node.elements = elements
end
for attr, view in pairs(bindings) do
node["quad_"..attr] = function(node, q, vals)
view:set(vals, (q - 1) * 4 + 1, 4)
bind_node["quad_"..attr] = function(bind_node, q, vals)
if q > capacity then
expand(q)
end
bindings[attr]:set(vals, (q - 1) * 4 + 1, 4)
if q > n then
n = q
draw_node.count = n * 6
end
end
end
return node
function bind_node:add_quad(quad)
n = n + 1
if n > capacity then
expand(n)
end
local i = (n - 1) * 4 + 1
for attr, vals in pairs(quad) do
bindings[attr]:set(vals, i, 4)
end
draw_node.count = n * 6
return n
end
function bind_node:remove_quad(q)
if q < n then
local j = (q - 1) * 4 + 1
local k = (q - 1) * 6 + 1
for i = 1, num_attrs do
local view = views[i]
view:set(view:slice(j + 4), j)
end
elseif q > n then
error("cannot remove quad "..q..", because it doesn't exist", 2)
end
n = n - 1
draw_node.count = n * 6
end
function bind_node:get_num_quads()
return n
end
bind_node:tag"quads"
return bind_node
end

function am.rect_verts_2d(x1, y1, x2, y2)
Expand Down
16 changes: 7 additions & 9 deletions src/am_math.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1250,19 +1250,17 @@ static int oblique(lua_State *L) {
int nargs = am_check_nargs(L, 4);
double angle = luaL_checknumber(L, 1);
double zScale = luaL_checknumber(L, 2);
double zOffset = luaL_checknumber(L, 3);
double left = luaL_checknumber(L, 4);
double right = luaL_checknumber(L, 5);
double bottom = luaL_checknumber(L, 6);
double top = luaL_checknumber(L, 7);
double left = luaL_checknumber(L, 3);
double right = luaL_checknumber(L, 4);
double bottom = luaL_checknumber(L, 5);
double top = luaL_checknumber(L, 6);
double near = -1.0;
double far = 1.0;
if (nargs > 7) {
near = luaL_checknumber(L, 8);
far = luaL_checknumber(L, 9);
if (nargs > 6) {
near = luaL_checknumber(L, 7);
far = luaL_checknumber(L, 8);
}
glm::dmat4 m1 = glm::ortho(left, right, bottom, top, near, far);
m1 = glm::translate(m1, glm::dvec3(0.0, 0.0, zOffset));
glm::dmat4 m2 = glm::transpose(glm::dmat4(1.0, 0.0, - zScale * cos(angle), 0.0,
0.0, 1.0, - zScale * sin(angle), 0.0,
0.0, 0.0, 1.0, 0.0,
Expand Down

0 comments on commit 8bb0c64

Please sign in to comment.