Binding variables to typedefs?

Started by
9 comments, last by WitchLord 14 years, 1 month ago
Hey folks, been a while sine I been here..so long that they wiped out my username :). Anyways, I am using AngelScript for an online compiler, and I have a question : I define a typedef as such :

typedef uint Color;
Is there any way to bind attributes to the typedef (like we do for classes), such that I can do :

Color col;
col.r = 255;
col.g = 128;
col.b = 128;
col.a = 64;

// My current implementation created functions to set and get the colors
Color c2 = RGBA( CR(col), CG(col), CB(col), CA(col) );

// What I want to do is
Color c2 = RGBA(c.r, c.g, c.b, c.a);
Advertisement
Why don't you implement the color as a Class and then write a copy constructor?
class Color {	float r, g, b, a;		Color(float r, float g, float b, float a) {		this.r = r;		this.g = g;		this.b = b;		this.a = a;	}		Color(const Color &in c) {		r = c.r;		g = c.g;		b = c.b;		a = c.a;	}}Color col1(0.5, 0.3, 0.7, 1.0); // Assigns the appropriate colors to the class.Color col2(col1); // Copies the color values from col1 to col2.


You can also implement some more methods, which will then easily allow you to subtract, add, multiply, divide, etc.

Color col3 = col1 * col2;


I've been trying to do something very similar just two hours ago, but I decided I need to study the blending modes a bit.


Quote:Original post by lxnyce2
Is there any way to bind attributes to the typedef (like we do for classes)


No, this is not possible. A typedef is just an alias for the real type, you cannot change the real type.

However, if you do what Bismuth suggests you can get what you want, i.e. a primitive type with member attributes for each color channel.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Thanks guys. I was trying to avoid the overhead of creating a class for two reasons :

1. The native type for color is really a uint, so that worked out nicely
2. It will be called thousands of times so I didn't want to add the overhead of a class variable to the mix.

I guess I will have to take some time out to benchmark and see which method is faster. Surely the class method is a little bit slower, but surely accessing components via a function call rather than a reference might slow things down also.
If you register the type as a value type, it can still be treated as an uint by the C++ application. Currently the value types have quite a high overhead in AngelScript as they are allocated on the heap, but I plan on changing this to allocating the on the stack as ordinary primitives. This change will be transparent to the application once I implement it, so you got nothing to loose by doing it like this.

engine->RegisterObjectType("color", sizeof(UINT), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE);engine->RegisterObjectProperty("color", "uint8 a", 3);engine->RegisterObjectProperty("color", "uint8 r", 2);engine->RegisterObjectProperty("color", "uint8 g", 1);engine->RegisterObjectProperty("color", "uint8 b", 0);engine->RegisterObjectBehaviour("color", asBEHAVE_CONSTRUCT, "void f(uint8 a, uint8 r, uint8 g, uint8 b)", asFUNCTION(color_construct), asCALL_CDECL_OBJLAST);void color_construct(BYTE a, BYTE r, BYTE g, BYTE b, UINT *self){  *self = (a << 24)|(r << 16)|(g << 8)|(b);}

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

union Color{	unsigned int value;	struct	{		unsigned char r,g,b,a;	};};
Quote:Original post by Molle85
union Color{	unsigned int value;	struct	{		unsigned char r,g,b,a;	};};

Congratulations that is illegal in two ways :)
unions can not define types and you can not access both of the union types yet only the active member.
nvm, missed the part about you using AngelScript
I don't think angelscript supports unions, but who amongst us hasn't posted in a forum not realizing what we're doing :). Anyways, I have some preliminary benchmark numbers and one more issue.

Old Code Using Typedef Method
void PostProcess() {	Color col;	int avg;	for (int off=canvas.Width()*canvas.Height()-1; off>=0; off--) {		col = canvas.GetPixelOffset(off);		avg = REDVAL(col) + GREENVAL(col) + BLUEVAL(col);		avg /= 3;		canvas.SetPixelOffset(off, RGBA(avg, avg, avg, ALPHAVAL(col)));	}}


New Code Using Class Method
void PostProcess() {	Color4 col;	int avg;	for (int off=canvas.Width()*canvas.Height()-1; off>=0; off--) {		col = canvas.GetPixelOffset(off);		avg = col.r + col.g + col.b;		col.r = avg;		col.g = avg;		col.b = avg;		canvas.SetPixelOffset(off, col.ToInt());	}}


Using the old method, best time over 10+ runs was 109ms.
Using the new method, best time over 10+ runs was 98ms.

So I figure throw in one more optimization since i'm using a class for the color now :
void PostProcess() {	Color4 col;	int avg;	for (int off=canvas.Width()*canvas.Height()-1; off>=0; off--) {		col = canvas.GetPixelOffset(off);		col.MakeGray();		canvas.SetPixelOffset(off, col.ToInt());	}}

Using this method, best time over 10+ runs was 73ms.

Conclusion - New method is definitely faster. It looks like function call overhead was larger than the class usage overhead after all. Now there is just one issue I can't seem to get my head around.

Notice in the examples I had to use "col.ToInt()". I registered an asBEHAVE_VALUE_CAST in my color test class as such :
	r = engine->RegisterObjectType("Color4", sizeof(UINT), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_PRIMITIVE);		r = engine->RegisterObjectProperty("Color4", "uint8 a", 3);		r = engine->RegisterObjectProperty("Color4", "uint8 r", 2);		r = engine->RegisterObjectProperty("Color4", "uint8 g", 1);		r = engine->RegisterObjectProperty("Color4", "uint8 b", 0);		r = engine->RegisterObjectBehaviour("Color4", asBEHAVE_CONSTRUCT, "void f(uint8 r, uint8 g, uint8 b, uint8 a)", asFUNCTION(color_construct4), asCALL_CDECL_OBJLAST); assert( r >= 0 );		//r = engine->RegisterObjectBehaviour("Color4", asBEHAVE_CONSTRUCT, "void f(uint col)", asFUNCTION(color_construct1), asCALL_CDECL_OBJLAST); assert( r >= 0 );		r = engine->RegisterObjectBehaviour("Color4", asBEHAVE_ASSIGNMENT, "Color4 &f(uint col)", asFUNCTION(uint_to_color), asCALL_CDECL_OBJLAST); assert( r >= 0 );		r = engine->RegisterObjectBehaviour("Color4", asBEHAVE_VALUE_CAST, "uint f() const", asFUNCTION(color_to_uint), asCALL_CDECL_OBJLAST); assert( r >= 0 );		r = engine->RegisterObjectMethod("Color4", "uint ToInt() const", asFUNCTION(color_to_uint), asCALL_CDECL_OBJLAST); assert( r >= 0 );		r = engine->RegisterObjectMethod("Color4", "void MakeGray() const", asFUNCTION(color_makegray), asCALL_CDECL_OBJLAST); assert( r >= 0 );


However the following code throws an error : Can't implicitly convert from 'Color4&' to 'uint'.
	Color4 col = 1;	uint ctmp = col;


Any ideas?
Well, I changed the cast method to an implicit cast, and that seemed to do the trick. No clue why, though :).

See here for the documentation : http://www.angelcode.com/angelscript/sdk/docs/manual/doc_reg_opbeh.html

FYI - speed didn't change from 73ms, but that's to be expected since they were both using the same function. Thanks for all the help guys. I'll post a live link when I finalize the setup sometime in the next week.

This topic is closed to new replies.

Advertisement