storing colors as RGB triplets

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
storing colors as RGB triplets
by on (#137854)
It gets tiring having to pull out a calculator everytime you need to edit the color palette for your game, so I thought of a way of making palette editing easier.

Store each color as 3 bytes. One for each primary. While it's loading the palette into cram, have the CPU shift the RGB triplets into 0bbbbbgggggrrrrr format.
Re: storing colors as RGB triplets
by on (#137855)
Or just make macros. For Super NES and Game Boy Advance, it might look like this:
Code:
.define RGB(r,g,b) ((r) | ((g) << 5) | ((b) << 10))


As used in this sample project:
Code:
palette:
  .word RGB(15,23,31),RGB(12,12, 0),RGB(14,23, 0),RGB(16,31, 0)
  .word RGB( 0, 0,15),RGB(15,15, 0),RGB(23,23, 8),RGB(31,31,16)
palette_size = * - palette

objpalette:
  .word               RGB(16, 8, 0),RGB( 6, 6, 6),RGB(12,12,12)
  .word RGB(18,18,18),RGB(23,23,23),RGB(16, 0, 0),RGB(24, 0, 0)
  .word RGB(20,16,14),RGB(31,22,20),RGB(21, 0, 0),RGB(31, 0, 0)
  .word RGB( 0, 0,15),RGB( 0, 0, 3),RGB(21, 0, 0),RGB(31, 0, 0)
objpalette_size = * - objpalette


For Genesis, the macro becomes
Code:
#define RGB(r,g,b) (((r) << 1) | ((g) << 5) | ((b) << 9))
Re: storing colors as RGB triplets
by on (#137856)
Or even better, convert it from from another more friendly colourspace, either with macros or run-time computing, depending on your needs. Persoally I find the RGB colourspace the less intuitive to work with.
Re: storing colors as RGB triplets
by on (#137861)
tepples wrote:
For Genesis, the macro becomes
Code:
#define RGB(r,g,b) (((r) << 1) | ((g) << 5) | ((b) << 9))

In this case don't even bother though, write the vaule as hexadecimal and each digit is one of the BGR components (only even numbers are usable, but yeah), so for example orange is 0x08E, or turquoise is 0xAA0, or magenta is 0xE0E, etc.
Re: storing colors as RGB triplets
by on (#137904)
Bregalad wrote:
Or even better, convert it from from another more friendly colourspace, either with macros or run-time computing, depending on your needs. Persoally I find the RGB colourspace the less intuitive to work with.


I could also create a handpicked palette like Retro City Rampage, Shovel Knight, and Arne's stuff, for my future SNES projects. I can take the colors I have so far, merge colors that are almost indistinguishable, and recycle colors whenever possible. If I need a color I don't have, I can make a new one.
Re: storing colors as RGB triplets
by on (#137908)
tepples wrote:
Or just make macros. For Super NES and Game Boy Advance, it might look like this:
Code:
.define RGB(r,g,b) ((r) | ((g) << 5) | ((b) << 10))


Wouldn't that be a user defined ''expression' rather than a macro?
Re: storing colors as RGB triplets
by on (#137912)
From ca65 Users Guide: C style macros: "Starting with version 2.5 of the assembler, there is a second macro type available: C style macros using the .DEFINE directive."
Re: storing colors as RGB triplets
by on (#137928)
Calling that a macro, seems like a misnomer. Heh.
Re: storing colors as RGB triplets
by on (#137931)
No, it's a very standard use of the word macro. The original use of macro in computer software is to replace some small (micro) input with something large (macro). In the case of an assembler or C, it's replacing a small name with a larger piece of code.

ca65 is a little bit of an oddball in that it has two separate directives, .macro and .define, but they are both macros by the definition I'm familiar with, and also are both called macros in the documentation of ca65. It's a little different than the C macros they're modelled after, since it's not really a preprocessor text substitution in ca65.
Re: storing colors as RGB triplets
by on (#137956)
rainwarrior wrote:
No, it's a very standard use of the word macro. The original use of macro in computer software is to replace some small (micro) input with something large (macro). In the case of an assembler or C, it's replacing a small name with a larger piece of code.


Then maybe I'm old school? I dunno. I've specifically used macros to replace code or structured data defines, but that's clearly neither; it's just an expression. I use user-defined expressions in much the same manner as macros; to replace something larger with something more compact (usually for readability), but the expression itself doesn't contain code or data. It only contains the method of how it (data only) should be interpreted. Maybe that's getting down to semantics, but that seems a big of enough difference IMO - to warrant a different description/name/whatever. Maybe the difference here is Assembly vs higher level languages? I would say macros are a huge part of assembly language compared to other higher level languages. Then again, I don't have a lot of exposure to C/C++ and other higher level language culture/scene, to really form a judgement on that side. But the work that I have done, 'defines' are nothing more than a label replacement for anything else in the compiler and real macros are nothing more than in-lining an otherwise defined function.


Quote:
ca65 is a little bit of an oddball in that it has two separate directives, .macro and .define, but they are both macros by the definition I'm familiar with, and also are both called macros in the documentation of ca65. It's a little different than the C macros they're modelled after, since it's not really a preprocessor text substitution in ca65.


PCEAS has this too, and is not defined as a macro, but defined as exactly what it is; user defined expression. It makes a clear distinction between the two. Edit: I just looked at PCEAS and they call it a user defined function: "same calculation [used] again and again in expressions". Not function is the C sense of the meaning. Label .func ((\1) << 12) | ((\2) >> 4)
Re: storing colors as RGB triplets
by on (#137959)
Well, in C, the term "expression" is well defined. C macros are not in themselves expressions, though the resulting output may form an expression. i.e. expressions are a subset of things that a macro can output.

This is also true in ca65, even though its macros are not text replacement (i think it's more like "token replacement", internally). For instance, a label is not an expression, but you can create them with ca65 macros. The very first example in the ca65 documentation is: ".define EQU =". The fragment of code "=" is not an expression either.

I'm not familiar with PCEAS, but if its "define" can only produce expressions, then maybe the the terminology it chooses is deliberate and appropriate?
Re: storing colors as RGB triplets
by on (#137983)
Quote:
but if its "define" can only produce expressions, then maybe the the terminology it chooses is deliberate and appropriate?

It would seem so.

Quote:
The very first example in the ca65 documentation is: ".define EQU =". The fragment of code "=" is not an expression either.

Ahh, I see. It definitely states "C style macro" as well. I think this is the point of contention. "define" is all three in C:

(expression. or rather function since it's actually gonna be applied to something. It's an expression by definition, it's a function by application)
#define CURSOR(top, bottom) (((top) << 8) | (bottom))

(macro: actual processor code generation)
#define getrandom(min, max) \
((rand()%(int)(((max) + 1)-(min)))+ (min))

(equate. self explanatory)
#define WIDTH 80
#define LENGTH ( WIDTH + 10 )

I think C uses a very liberal/loose sense of the word macro, for the very reason being the differences between C and assembler. By that definition, all mnemonics used in an assembler are just macros. C use is most likely truer to the original definition of macro (for whatever that is), where as Assembly is much more limited in syntax and ops to tie down terms to specifics. CA65's maintainers seem to have a more C bias approach/view, than other assemblers back in the day? I don't have enough exposure to all those old assemblers to say for sure. Anyway, this all seems kind of pointless now. My original point was a call for clarity, but apparently clarity is specifically based on who wrote which assembler, or where you take your methodology from, etc.
Re: storing colors as RGB triplets
by on (#138001)
The origin of the term macro comes from assemblers. Specifically it referred to a way to make multiple output instructions from a single statement. A "macro instruction". It later came to apply to a lot more things (macros for a word processor, C preprocessor macros, etc.) where it is just more generally a substitution.

You could implement an assembler's mnemonics with a macro system, but I don't think it's particularly useful to think of single instruction mnemonics as macros. To be a macro it has to be something that you can define yourself; the instruction mnemonics are pre-defined, a core language feature. They're not substituting something large for something small, they're a 1:1 unit.

The thing is, though, when it comes to computer languages terms like this are generally very well defined. They have to be; it's necessary to have a rigorous specification to make a compiler/assembler. In C, the macro is a text substitution; it's not an expression (though it can produce one), and it's not a function. The definitions it uses aren't loose at all; they are formal and explicit.

All three of your example macros unambiguously produce "expressions". I'm not sure what is different between them in that way. The C language also has a specific definition of what a function is, and a macro isn't one, in itself, though a macro can define a function, of course (and the definition of a function is also an expression, by the way!). If you want to step outside the C language's definition, sure you can call it a "function" in the general sense of something that operates on an input to produce an output, but I don't really see the use of talking about it this way (just like I don't see the use in calling a built-in mnemonic a macro).

For example, look at the "inline" language feature. Part of the reason this exists is to discourage people from using macros to create pseudo inline functions, because of all the problems inherent in this approach. There is good reason to use the terms as they are defined. C++11 even added the "constexpr" feature to make compile-time calculations explicit where it is needed, instead of an optional optimization of inline functions.

Code:
#define MUL(a,b) (a*b)
int x = MUL(1+2,3+4); // x = 1+(2*3)+4

constexpr int mul(int a, int b) { return a*b; }
int z = mul(1+2,3+4); // z = (1+2)*(3+4)


Obviously you can define MUL as ((a)*(b)) to get around this specific case, but the point I'm trying to get across is that macros behave differently, and it's useful to talk about them with the correct terminology so that you don't make this kind of mistake. Calling a macro a "function" would seem to obfuscate this difference. Often times the reason you would want to use a macro is because it can do things that a function can't. The fact that macros can produce things other than expressions is a part of this! The example of ".define EQU =" already mentioned should adequately demonstrate this.
Re: storing colors as RGB triplets
by on (#138009)
rainwarrior wrote:
You could implement an assembler's mnemonics with a macro system

Which blargg actually did for the SPC700. Add Z80, GBZ80, and 68000 and I'll be set ;-)
Re: storing colors as RGB triplets
by on (#138031)
I'll might as well post the color palette on here and the RGB triplets, when I get to it. I'm currently working on animating more moves for the player character, which is a priority for me.