Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

color becomes vec4

SimeonSimeon Admin Mod
edited June 2012 in Suggestions Posts: 5,400

I'm posting this here to see if any of the more advanced Codea users can see a problem with this change to the runtime.

The proposal is to make the color(r,g,b,a) function simply return a new vec4 object with the specified values. In practice this should behave identically, except vec4 exposes its metatable. In addition, it makes things like the equals (==) and arithmetic operators (add, normalize and so on) available for colors.

All existing functions that accept color will now accept vec4 — again, this should be transparent to you as a Codea user.

vec4 has .r, .g, .b, .a accessors, as color did.

Can any one see any issues with this proposal?

Edit: Alternatively we could make color a more fleshed out object, but it feels redundant as the data is identical to a vec4.

Tagged:

Comments

  • Posts: 146

    This is a neat idea. I just have one thing, but I'm not sure wether this would be a problem: I have a data serializer for codea, that also takes care or the userdata objects. It recognizes the type of userdata by its metatable. Clearly, there will be no color type after this change. As long as there is no "hidden" data stored in the vec4 representing a color, meaning that color(r,g,b,a) == vec4(r,g,b,a) for identical values of r,g,b,a , it should not make any difference.

  • edited June 2012 Posts: 1,806

    Hi Simeon,

    I only see benefits, but I'm not up on metatables yet so some of the implications may be lost to me.

    On a trivial point - I assume that you aren't changing the syntax and color(r,g,b,a) remains the same - it's just the routines behind it change.

    One thought - do you check that the values are within range for entry ? i.e. 0 to 255. Is there an out of range error? and would we still be allowed to pass variables and arrays in to simplify code?

    Bri_G

    :)

  • Posts: 202

    Sorry, I can't see any benefits except for the one that you can get rid of an extra data structure.

    What you have to do, I think, is to explain (especially for beginners) the different meanings of a vector:

    1. The mathematical vector. It has x, y and perhaps more predefined components, there are functions to make useful special purpose calculations.

    2. The vector as a list (like std::vector in C++ is the dominant way of creating a list).

    You should explain that a vec4-diguised color has nothing to do with a vec2 where you can calculate the length of it, whereas vec2 and vec3 share similarities.

    I'm not a heavy user of colors, but it never occurred to me that I wanted to compare a color with an exact other color. Maybe painting programs want to do this in operations like "replace this red with green", and even then I'd suppose that such painting programs rather offer "replace this red and anything within a certain shade of it with green", and gone is the usefulness of color1 == color2. And if I modify a color, I work on its named parts, not on the color as an arbitrary list.

    A vec4 with a special purpose interpretation as a color ... well, I don't want to speak against it, I just doesn't make much sense to me. A color is a color, there is no similar context. A function that works on a color has little meaning for arbitrary vec4 values. A function that operates on arbitrary vec4 values ... can you imagine one that has a meaning with respect to colors? Maybe for fractals.

    Verdict: Use vec4, but explain the different purposes of vectors clearly.

  • Posts: 447

    I've had a bug by assuming that == worked for colors before. Took me a long time to find it too.

    But thinking more about it: doesn't == make it impossible to use that class as keys of tables in lua? You'd end with situations where obj1 == obj2 but table[obj1]~=table[obj2]. And as far as I know there would be no way to differentiate obj1 from obj2. Obviously a bigger issue than just color, but would be interested to hear your thoughts on it.

    As for color, I see @codeslinger's point that a color is not a vec4, and would rather keep the external interface separate. You could also implement color as a wrapper around vec4, and just fwd all methods to the vec4 methods?

  • edited June 2012 Posts: 489

    I have (previously) added pages to the wiki about these userdata here and here and about Codea's userdata more generally here.

    Making color() return the same userdata as vec4() has one odd side-effect: colors will then have vector-like functionality. I would suggest, @Simeon, that Codea remain true to its philosophy: Is it simple, elegant or beautiful to be able to calculate the dot-product of two colours?

  • SimeonSimeon Admin Mod
    edited June 2012 Posts: 5,400

    Thank you for the feedback.

    Would you prefer color become a more fleshed out object of its own? Perhaps with a special color * color multiplication that normalizes to the 255 range, and addition/subtraction that clamps.

    @ruilov it wasn't so much about not adding the methods to color, but to simplify by removing one redundant data type. It felt more "pure" to have color be vec4

  • Posts: 122

    I didn't even realize there was a color object until like a week ago. I was just doing the vec4() object thing.

  • edited June 2012 Posts: 4

    @Deamos really? But how are you doing indexed coloring for your mesh?

    Or are you steering clear of 3d altogether?

    @Simeon I second the notion as for days I've been trying to figure out why I can't seem to get it to so much as read the values from my tables associated with the r,g,b.
    (I usually leave off a cause the first is the index so its usually: i,r,g,b)

    As long as everything is in the same place they can be read but when you try modularizing everything then you run into some issues.

    Guys, I mean pretending the problem does not exist now won't eliminate it later.

  • Posts: 489

    As Codea userdata can be enhanced by individual users of the app, I think it is a difficult decision whether or not to extend the built-in functionality (and, consequently, complexity for users) of Codea's userdata.

    Some things are a chore (and it is a joy when somebody else has done your chores) and some things are a joy. You could imagine additional functionality for a color userdata but, if you build it in to the app, do you then deny some coder the joy of discovering and implementing that for himself or herself?

  • Posts: 2,161

    I've already done a fair bit of extension for colours. Not sure about "joy", though.

    My instinct is that this is a bad idea. I don't see any gain, but lots of room for confusion. Of course, you could do stuff internally to make your lives easier, but I can't think of a single operation where colour-is-vector would actually make life clearer for the user.

    Take mixing. I want to blend red and blue, so I want to take 5 parts red to 2 parts blue. I want to write c = blend(red,5,blue,2). I don't want to write c = (5*red + 2*blue)/7.

  • SimeonSimeon Admin Mod
    Posts: 5,400

    Yeah I'm unsure about this now. I'm thinking about just improving the colour type.

  • Posts: 2,161

    The biggest improvement would be to spell it correctly!

  • Posts: 580

    Ha! I am totally going to alias the color() function to be colour() from now on.

  • @Andrew_Stacey um actually spelling it correctly is a relative thing in England they do spell color that way.

    To which I must ask
    @Simeon are you english?

  • Posts: 580

    @GenobiJuan: I'm pretty sure he was just poking fun ;)

  • Posts: 384

    Yes, we have joked about it before... TLL being Aussies and Andrew a Brit.

  • SimeonSimeon Admin Mod
    Posts: 5,400

    @GenobiJuan Australian, we follow English spelling for most things.

    All Codea APIs will use US spelling — it's just confusing otherwise.

  • edited June 2012 Posts: 489

    Actually, the long list of colour definitions provided by @Andrew_Stacey in the example projects Roller Coaster and Anagrams, is an example of the sort of chore that I had in mind; I suspect everybody else is grateful that he took the time and trouble to do so.

    Extending color() in the Codea API so that color(string) returns a userdata appropriately initialised based on the colour name in string might bring joy - say names based on the W3C extended color keyword names, but tolerant of the use of spaces and/or capital letters.

  • Posts: 2,161

    @mpilgrem If you look carefully at the licence for those files, you'll see that I didn't - strictly speaking - create those lists. One nice perl script plus someone else's files was the limit of the chore for me.

    But you're right that such things are great when others do it and we can share code.

  • Posts: 489

    I've changed my previous comment to clarify what I meant. I've also stepped back from saying color(string) would have appeal for everyone. The point that users can choose whether or not to use something that can be shared as Lua code has considerable weight.

  • SimeonSimeon Admin Mod
    edited June 2012 Posts: 5,400

    Okay here's the initial plan for color in the next version of Codea. Let me know if you have any suggestions.

    Blend

    result = color.blend( source, dest )
    result = source:blend( dest )
    

    This blends the two colours as if you were layering them in Photoshop. So the resulting colour is computed as:

    red = source.r * source.alpha + dest.r * ( 1 - source.alpha )
    green = as above
    blue = as above
    alpha = source.alpha + dest.alpha
    

    One problem with implementing blend in this fashion is that it discards the destination alpha. We could pre-multiply the dest colour by its alpha, but I'm unsure if that's appropriate.

    (The above, and all following functions take into account that colours sit in the 0-255 range and normalise/clamp as appropriate.)

    Mix

    (Could also be named "interpolate" or "lerp")

    result = color.mix( source, dest, amount )
    result = source:mix( dest, amount )
    

    This mixes the two colours linearly. Where amount is from 0 to 1. So the result is:

    red = source.r * amount + dest.r * ( 1 - amount )
    green, blue and alpha = as above
    

    Multiply

    multipliedColor = color1 * color2
    

    Computes the result as:

    red = source.r * dest.r
    green = as above
    blue = as above
    alpha = source.alpha + dest.alpha
    

    Add

    addedColor = color1 + color2 
    

    Computes the results by adding all channels and clamping to a valid range.

    Equality

    Equality supported as in vectors

  • Posts: 489

    Supporting equality has my vote.

    newColor = color1:mix(color2, proportion) seems to me to be a better syntax than newColor = color1:interpolate(color2, proportion), if the meaning of 'mix' is documented in the in-app reference. The abbreviation for linear interpolation (lerp) might be intuitive (and, consequently, memorable) only for a small subset of potential users of Codea.

    I do not know enough about the practice of users to comment on the utility of the additional functionality. I wondered: Will this save a lot of users a lot of coding, or will providing this as part of the Codea API provide functionality that is a lot faster in execution than what users could achieve coding the same functionality in Lua?

    I also do not know enough about the principles to comment on the algorithms.

    I did wonder if newColor = color1:blend(color2) should be consistent with the (different) algorithm for alpha blending described in this Wikipedia article.

    I did wonder what 'multiplication' meant, conceptually, for colours with an alpha channel less than 100%. If you alpha blend two colours with 50% opacity, the result is a colour with 75% opacity (50% + 50% x 50%). Is it right that when you multiply those colours, the result is opaque (50% + 50% = 100%)?

  • edited June 2012 Posts: 489

    In respect of the mathematics for different types of compositing, does the W3C SVG Compositing Specification here help?

    (Update) Specifically, if I understand the specification correctly (and assuming that color1 = color(r1, g1, b1, a1) is not pre-multiplied):

    Multiply

    a3 = a1 + a2 - a1*a2 (clamped)

    r3 = (r1 * a1 * r2 * a2 + r1 * a1 * (1 - a2) + r2 * a2 * (1 - a1))/a3 (etc)

    Plus

    a3 = a1 + a2 (clamped)

    r3 = (r1 * a1 + r2 * a2)/a3 (clamped) (etc)

  • Posts: 489

    Thinking further about 'utility', I can imagine that people might use this functionality to composite images, pixel-by-pixel.

    If that is so, a 'faster execution' rationale might imply the functionality should be added to the image userdata rather than the color userdata. For example:

    newImage = image1:blend(image2)

    or

    newImage = image1:blend(image2, left, bottom)

    where optional arguments left and bottom identify the location of the bottom lefthand corner of image2 relative to the bottom lefthand corner of image1.

  • edited July 2012 Posts: 489

    I am still on a learning curve when it comes to compositing, but the following has occurred to me.

    People could use color userdata values to represent either straight or premultiplied format colours/pixels. However, some operations to composite colours/pixels may depend on whether or not the inputs are taken to be in a straight or premultiplied format. If the color userdata does not carry with it a flag to indicate whether or not it is taken to be in premultiplied format (and I am not suggesting that it should), does that imply that some of the suggested operations supplied by the Codea API will have to make an assumption about what format the userdata is taken to be in?

Sign In or Register to comment.