It looks like you're new here. If you want to get involved, click one of these buttons!
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.
Comments
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.
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
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:
The mathematical vector. It has x, y and perhaps more predefined components, there are functions to make useful special purpose calculations.
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.
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?
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 asvec4()
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?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
I didn't even realize there was a color object until like a week ago. I was just doing the vec4() object thing.
@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.
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?
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 writec = (5*red + 2*blue)/7
.Yeah I'm unsure about this now. I'm thinking about just improving the colour type.
The biggest improvement would be to spell it correctly!
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?
@GenobiJuan: I'm pretty sure he was just poking fun
Yes, we have joked about it before... TLL being Aussies and Andrew a Brit.
@GenobiJuan Australian, we follow English spelling for most things.
All Codea APIs will use US spelling — it's just confusing otherwise.
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 thatcolor(string)
returns a userdata appropriately initialised based on the colour name instring
might bring joy - say names based on the W3C extended color keyword names, but tolerant of the use of spaces and/or capital letters.@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.
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.Okay here's the initial plan for
color
in the next version of Codea. Let me know if you have any suggestions.Blend
This blends the two colours as if you were layering them in Photoshop. So the resulting colour is computed as:
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")
This mixes the two colours linearly. Where amount is from 0 to 1. So the result is:
Multiply
Computes the result as:
Add
Computes the results by adding all channels and clamping to a valid range.
Equality
Equality supported as in vectors
Supporting equality has my vote.
newColor = color1:mix(color2, proportion)
seems to me to be a better syntax thannewColor = 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%)?
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)
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
andbottom
identify the location of the bottom lefthand corner of image2 relative to the bottom lefthand corner of image1.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 thecolor
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?