Codea 1.5 (Beta 8)

Hi Beta group

The other thread was huge.

I’m uploading a new build (8), so I’ve decided to make a new thread.

Build 8 is mostly bug fixes — I’ve attempted to fix the shader lab crash reported in the previous thread, as well as many other things (see the release notes).

There is also a new feature: vector art asset support. If you want to try this out you can use the included vector sprite packs, or use your own PDF files. PDF is natively supported by iOS, so this seemed a good choice for vector graphics.

A note on this: even though your source art is in a vector format, Codea must rasterise the data in order to get it into OpenGL. So every time you render a vector asset at a new, specific size, Codea will cache a texture for that size. These textures will be flushed when memory is low, but it can cause a performance hit for large vector graphics.

Rendering a vector graphic at a fixed size every frame should be fine, however.

There is also a (currently undocumented) addition to readImage to allow you to specify a width and height for vector assets. So the new API is:

local img

-- Load the vector asset at its original pixel width/height
img = readImage( "Documents:My Vector Asset" )

-- Load the vector asset at a specific width, height is computed by aspect ratio
img = readImage( "Documents:My Vector Asset", width )

-- Load the vector asset at a specific width and height, squashing if necessary
img = readImage( "Documents:My Vector Asset", width, height )

Vector assets? You guys floor me - I would never have thought of it (unless in the context of SVG). This seems an excellent idea for non-resolution-dependant stuff. Me Like.

Whoop-dee-doo!

PDFs will be awesome. I have an idea of a use for them … but it needs developing so I’ll hold off on saying more until I’m clearer.

Just installed on my new iPad … but haven’t transferred the shaders yet. Going to do that now.

Scaling is noticeably slow. Not a big deal - just means you need to scale() rather than expect to be able to change the width/height in your loop.

Pretty cool. More sprite packs!

.@Bortels the demo app exhibits very bad behaviour with regards to vector assets — the ideal case is: choose your largest desired size and use readImage() to get that into a static image that you then render as a sprite. The sprite size options will then be as fast as normal. Rendering vector assets with sprite() is fine if the size doesn’t change much (or the sprite is fairly small).

Gravity and UserAcceleration are working again… sometimes. About 30% of the time, when I start a project, they run fine. 70% of the time the same project returns nothing but 0.

Okay, need to do a bit of thinking when using shaders on retina particularly when I’m using an image as an intermediate step. It looks as though I need to be sure to pass the real width to the shader instead of the apparent width - this means that I’d really like to know when I’m on a retina iPad or not. I remember some discussion about this - what was the conclusion?

Oh. My. Word.

Game-Of-Life running at full resolution on a retina screen. Getting fps of about 29 (which is a few frames better than iPad2 at its full resolution) with amazingly crisp display. Looks absolutely amazing.

(Never thought I’d be this amazed by some technology improvement, but retina really is something special.)

Oh, and I’ve yet to get gravity working.

And now it works … on an already running project where it wasn’t working before. I “hot switchef” from Codea and when I went back gravity had been switched on.

Gravity doesn’t seem to work for me. Will try it out more later on.

I’ve now successfully turned on gravity twice by doing that trick: double-click the “Home” button to switch to another app leaving the Codea program running and then double-click back again.

The Shader Editor is more stable in beta 1.5(8), but I find that it is still not stable and crashes out of Codea from time to time.

I have been experimenting with noise in the light of this github respository.

Lua:


--
-- Noise GLSL
--
-- Shader makes use of:
-- Array and textureless GLSL 2D simplex noise function.
-- Author : Ian McEwan, Ashima Arts.
-- https://github.com/ashima/webgl-noise

function setup()
    parameter.number("freq", 1, 10, 5)
    parameter.number("speed", 0, 1, 0.1)
    parameter.number("threshold", 0, 1, 0.5)
    origin = vec2()
    velDir = 0
    dVelDir = 0.1
    twoPi = 2 * math.pi
    m = mesh()
    m:addRect(WIDTH/2, HEIGHT/2, WIDTH, HEIGHT)
    m.shader = shader("Documents:Noise")
end

function draw()
    velDir = velDir + ((math.random() * 2 - 1) * dVelDir) % twoPi
    local vel = vec2(math.cos(velDir), math.sin(velDir)) * speed
    origin = origin + vel
    m.shader.origin = origin
    m.shader.freq = freq
    m.shader.threshold = threshold
    m:draw()
end

Vertex shader:


//
// Vertex shader: Noise
//

uniform mat4 modelViewProjection;
attribute vec4 position;
attribute vec2 texCoord;

varying highp vec2 vTexCoord;

void main() {
    vTexCoord = texCoord;
    gl_Position = modelViewProjection * position;
}

Fragment shader:


//
// Fragment shader: Noise
//

precision highp float;

uniform vec2 origin;
uniform float freq;
uniform float threshold;

varying highp vec2 vTexCoord;

// ---------------------------------------------------------------
// Array and textureless GLSL 2D simplex noise function.
// Author : Ian McEwan, Ashima Arts.
// https://github.com/ashima/webgl-noise
// ---------------------------------------------------------------
// Copyright (C) 2011 Ashima Arts. All rights reserved.
// Permission is hereby granted, free of charge, to any person
// obtaining a copy of this software and associated documentation
// files (the "Software"), to deal in the Software without
// restriction, including without limitation the rights to use,
// copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following
// conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.

vec3 mod289(vec3 x) {return x - floor(x / 289.0) * 289.0;}
vec2 mod289(vec2 x) {return x - floor(x / 289.0) * 289.0;}
vec3 permute(vec3 x) {return mod289(((x * 34.0) + 1.0) * x);}

float snoise(vec2 v) {
    const vec4 C = vec4(0.211324865405187,  // (3.0-sqrt(3.0))/6.0
                        0.366025403784439,  // 0.5*(sqrt(3.0)-1.0)
                       -0.577350269189626,  // -1.0 + 2.0 * C.x
                        0.024390243902439); // 1.0 / 41.0
    vec2 i = floor(v + dot(v, C.yy));
    vec2 x0 = v - i + dot(i, C.xx);
    vec2 i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
    vec4 x12 = x0.xyxy + C.xxzz;
    x12.xy -= i1;
    i = mod289(i);
    vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0))
         + i.x + vec3(0.0, i1.x, 1.0));
    vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy),
        dot(x12.zw, x12.zw)), 0.0);
    m = m*m;
    m = m*m;
    vec3 x = 2.0 * fract(p * C.www) - 1.0;
    vec3 h = abs(x) - 0.5;
    vec3 ox = floor(x + 0.5);
    vec3 a0 = x - ox;
    m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h);
    vec3 g;
    g.x = a0.x * x0.x + h.x * x0.y;
    g.yz = a0.yz * x12.xz + h.yz * x12.yw;
    return 130.0 * dot(m, g);
}
// ---------------------------------------------------------------

void main() {
    vec2 p = vTexCoord * freq + origin;
    float n = (snoise(p) + 1.0) / 2.0;
    n = (n > threshold) ? (n - threshold) / (1.0 - threshold) : 0.0;
    gl_FragColor = vec4(n, n, n, 1.0);
}

In beta 1.5(8), the Editor does not behave as I would expect it to when the backspace key is held down to delete long passages of code.

For example:

  1. Create a new default project and move to the very end. Hold down the backspace key.

  2. After a while, the Editor moves from deleting single characters to speed deleting of chunks of characters at a time.

  3. However, when deleting chunks, the characters to the right of the cursor are still displayed (for a while) even though they have been deleted.

.@mpilgrem i’ve tried your code: works fine. I’am not sure we need real time shaders for such images, however? At least it is an example of code syntax for complex computations. @Simeon i hope there will be some way to copy/paste shaders simpler than current process, cause it’ fairly boring to paste back an forth from the forum…

Hello @Jmv38. I am interested in procedural textures, which is why I am interested in noise in shaders.

PROBLEM with parameters.watch(): i am trying to use the parameters in some class to ajust the parameters of the created object. Here is the example of a class method i call in init():

function Modifier:start()
    -- cleanup the control panel
    parameter.clear()
    output.clear()
    self.title = "myTitle"
    parameter.watch(self.title)
    print(self.title)
end

In the setup of the main i create modif = Modifier(), that calls start().
This prints correctly “myTitle” in the output, but in the parameter region:

  • it prints “myTitle”.
  • and the error message “cannot evaluate expression”.
    I see from the doc i should have wrote parameter.watch(“self.title”) but then it doesn’t work at all.
    From this example (i’ve not tried all options), the parametrs functions seem to work with globally declared variable, but not with self.x variables. If it is true, and there is no simple workaround, then it makes the parameters function much less interesting: i dont’ want to use global variables for a user interface that will change depending on the context.
    Can sby tell me if there is a syntax trick i don’t know to make it work with self.x variables? Thanks in advance for your help.

Hello @Jmv38. The Lua expression in string in parameter.watch(string) has to evaluate to something that exists when the expression is evaluated (outside of your Lua code). For example:


Modifier = class()

function Modifier:init(title)
    self.title = title
end
    
function setup()
    modif = Modifier("My title.")
    parameter.watch("modif.title")
end

function draw()
    background(0)
end

(Edit) or, more complex:


Modifier = class()

function Modifier:init(title)
    self.title = title
end
    
function setup()
    modifiers = {}
    modif1 = Modifier("My title one.")
    table.insert(modifiers, modif1)
    modif2 = Modifier("My title two.")
    table.insert(modifiers, modif2)
    parameter.integer("watchedModifier", 1, 2, 1)
    parameter.watch("modifiers[watchedModifier].title")
end

function draw()
    background(0)
end

Hello @Simeon. Is it correct that where the Lua expression in string in parameter.watch(string) evaluates to more than one result, it is all but the last value that is discarded? I was expecting all but the first value to be discarded. For example:


function setup()
    array = {"A", "B", "C", "D"}
    watch = "unpack(array)"
    parameter.watch(watch)
end

function draw()
    -- It is the "D" value that is watched
    background(0)
end

.@mpilgrem thank you! From your suggestions i implemented this:

    parameter.watch(self.name..".description")

this way i dont have to create global variables, which i what i wanted first place? And i can call the watch from the object itself, so no need to expose those detail at higher level. The only thing i have to find is how an object can access it own name, i guess i’ll found that on the web, must be in the metatable or sthg. Thanks.

Re PDF import. Can it be that we can use multi-page PDFs? Then a single PDF can be an entire sprite pack.