ComputerCraft

ComputerCraft

21M Downloads

Palettes

dmarcuse opened this issue ยท 13 comments

commented

Given the complexity and nuances of a palette system, I wanted to open an issue for discussion on the topic.

The way I would implement it would be a system where you can change the RGB values for colors at runtime, but are still limited to 16 colors total. This gives you a lot of flexibility if you're designing something complex like a game or OS, while not increasing bandwidth or overcomplicating things.

However, there's still other issues - how would it work with the window API? Should there be rate limiting or similar to prevent people switching colors rapidly? Should term.setColor take a single value for hex (0xff00ff) or three separate values (255, 0, 255)?

commented
commented

Rate limiting would be kinda weird. I'd rather make it a relatively slow function that chews up execution time so that people avoid doing it in a loop. Even if it's just setting the same parameters repeatedly, that's going to be redundant and cause problems with simultaneous execution.

I'd go with (R, G, B) myself, I find it very easy to understand. That's the way code.org does it.

commented

A some nice color cycling effects crossed my mind after reading this.

commented

I've started work on this, I'll make a WIP PR soon.

commented

What about having black and white (maybe also grays) being unmodifiable, so they can be used for things like multishell tabs while making sure that they look the same?

commented
commented

Re the window API, it consists of one function which returns a terminal object. If you redirect to an object and then try to call a term function that object doesn't support, you get a crash. So "completely leaving functions out" isn't really an option.

All windows have a "parent" terminal object, which is what they're actually rendering to whenever you draw something into them. Multishell works by giving each tab its own window, but they all render through the one parent tab (usually term.native()).

My answer would be to give windows the same colour changing functionality as the main displays / monitors get (allowing them to modify their parents as they wish), and throw in an additional function "restorePalette" (just for windows) with the same mentality as the existing "restoreCursor". Making multishell compatible with the new windows would then only require a call to that restoration function when switching tabs.

I discourage reserving any indexes within the palette. If individual coders want to leave certain parts unmodified so they don't mess up multishell, then that's great , but with such a tiny palette any completely locked areas are a big handicap. It's just not worth it when you consider that most users will probably never see the tab bar anyway; there are already ways to make a script "multishell incompatible", and yet I've never seen any complaints or confusion about that.

Using colour values in the range of 0-1 sounds weird to me. Putting aside that float precision will cause issues, I've never worked with an image format that maps directly to such a scheme. I don't see why R,G,B / single hex codes can't both be accepted, though - just so long as there's a function that can remap multiple palette indexes in a single call (by accepting a table, for preference) I'm happy.

commented

@BombBloke I understand how the window API works, I was just asking about how it should be handled when there are multiple windows trying to use different palettes.

I'm also not sure about the 0-1 RGB, especially considering that internally they're converted to single bytes (0-255) anyways....

commented

Hence the mentality behind your changes to the window API in #197 seem mostly sufficient to me, though I still think a single function to change the whole 16-colour palette in one go would be nice. [...]

Fair point, I'll add that to the PR when I get around to it. Done!

Perhaps with image renderers; I wouldn't know about those. Of all the storage formats I've decoded I've yet to find one that uses more than one byte per intensity (often less, but never more), and in code, I've never used non-integral values to define intensities either.

That would explain it. In rendering, you tend towards using 0-1 floating points for each channel because it simplifies applying cool effects to stuff with shaders.

All that might really mean is that it's at least worth asking for some more opinions. But if setColour ends up wanting values in the range of 0-1, I for one will find myself using "x/255" an awful lot.

Since it seems to be a matter of preference, it might be worth compromising by adding a colours.rgb8(hex)/colours.rgb8(r, g, b) function, that will convert its parameter(s) to the 0-1 range, so you can do things like term.setColour(colours.white, colours.rgb8(0xFF00FF)) or term.setColour(colours.white, colours.rgb8(255, 0, 255)).

commented

Then I'm saying to handle it the same way it's handled when multiple windows set the text/background colours, or want to move the cursor around.

commented

My answer would be to give windows the same colour changing functionality as the main displays / monitors get (allowing them to modify their parents as they wish), and throw in an additional function "restorePalette" (just for windows) with the same mentality as the existing "restoreCursor". Making multishell compatible with the new windows would then only require a call to that restoration function when switching tabs.

This would still cause issues when you have multiple windows on-screen, because the palette doesn't affect single pixels, but the entire screen. So when you're rendering two or more windows, you have to pick one to work with.

Either way, multishell works in my implementation in #197, though it doesn't do the whole restore stuff, it simply updates the palette when it needs to render.

Using colour values in the range of 0-1 sounds weird to me. Putting aside that float precision will cause issues, I've never worked with an image format that maps directly to such a scheme.

Really? This is pretty traditional in computer graphics, especially when you're working with OpenGL. Infact, ComputerCraft converts them to 0-1 range to render them anyway. I find them much nicer than 0-255 regardless of that either way, because you can easily multiply colours and they're completely independent of the framebuffer's colour depth.

commented

This would still cause issues when you have multiple windows on-screen, because the palette doesn't affect single pixels, but the entire screen.

Same deal as with the cursor position - it can't sit and blink within multiple windows at the same time. These aren't problems for the window API to solve, though: that's up to the coders who work with it.

Hence the mentality behind your changes to the window API in #197 seem mostly sufficient to me, though I still think a single function to change the whole 16-colour palette in one go would be nice. Otherwise, trying to change all 16 colours in a window (and how often will people change one colour at a time?) requires 16 pairs loops, and hence 256 calls to the parent terminal's setColour function, and if that parent has a parent, it only gets worse from there.

Really? This is pretty traditional in computer graphics, especially when you're working with OpenGL.

Perhaps with image renderers; I wouldn't know about those. Of all the storage formats I've decoded I've yet to find one that uses more than one byte per intensity (often less, but never more), and in code, I've never used non-integral values to define intensities either.

All that might really mean is that it's at least worth asking for some more opinions. But if setColour ends up wanting values in the range of 0-1, I for one will find myself using "x/255" an awful lot.

commented

This is in now