Jump to content
  • Advertisement
Sign in to follow this  
lxnyce2

Binding variables to typedefs?

This topic is 3197 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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);

Share this post


Link to post
Share on other sites
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.


Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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);
}

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!