Overoptimizers anonymous - Hue shifting

Started by
-1 comments, last by Khatharr 11 years, 9 months ago
This maybe should go in the general forum, but since it deals with color spaces I'm putting it here and it can be moved if desired.

Anyway.... Can you make it faster/better?

The goal is to write a function that accepts a 32-bit ARGB color and an signed integral number of degrees. The function returns the result of shifting the hue of the color by the number of degrees indicated.

Relevant info: http://en.wikipedia.org/wiki/Hue

Note - the forum is doing nastiness to my indentation, sorry.


//Just for fun, trying to create the fastest possible
//hue_shift function for the 32-bit ARGB color space.
//Here's what I have so far:

union uCol {
struct {
BYTE blue;
BYTE green;
BYTE red;
BYTE alpha;
};
BYTE channels[4];
UINT uint;
};

BYTE region_lut[] = {3, 4, 0xFF, 5, 2, 0xFF, 1, 0};

uCol hue_shift(uCol rgba, int degrees) {
int hue, region;
BYTE range, minim;
/* [ASM BLOCK TRANSLATION INTO C++]
int index = 0;
if(rgba.red >= rgba.green) {index += 1;}
if(rgba.red >= rgba.blue) {index += 2;}
if(rgba.green >= rgba.blue) {index += 4;}
region = region_lut[index];
*/
__asm {
pushad //push the registers to the stack
xor eax,eax //clear register a
movzx ebx,rgba.red //place the red channel in b
movzx ecx,rgba.green //green in c
movzx edx,rgba.blue //blue in d
cmp ebx,ecx //compare b and c
jl test02 //if b is less than c goto next test
or eax,1 //else set bit 1 in register a
test02: cmp ebx,edx //compare b and d
jl test03 //if b is less than d goto next test
or eax,2 //else set bit 2 in register a
test03: cmp ecx,edx //compare c and d
jl lookup //if c is less than d goto lookup
or eax,4 //else set bit 3 in register a
lookup: movzx ebx,region_lut[eax] //place the lookup value in register b
mov region,ebx //copy b to the variable 'region'
popad //restore the register values
}

switch(region) {
case 0: //RGB
range = rgba.red;
hue = rgba.green;
minim = rgba.blue;
break;
case 1: //GRB
range = rgba.green;
hue = rgba.red;
minim = rgba.blue;
break;
case 2: //GBR
range = rgba.green;
hue = rgba.blue;
minim = rgba.red;
break;
case 3: //BGR
range = rgba.blue;
hue = rgba.green;
minim = rgba.red;
break;
case 4: //BRG
range = rgba.blue;
hue = rgba.red;
minim = rgba.green;
break;
case 5: //RBG
range = rgba.red;
hue = rgba.blue;
minim = rgba.green;
break;
default:
break; //error
}

//There is no saturation, so the color is not changed.
if(range == minim) {return rgba;}

range -= minim;
hue -= minim;

if(region & 1) {hue = range - hue;}


/* [ASM BLOCK TRANSLATION INTO C++]
region += degrees / 60;
int new_hue = degrees % 60;
new_hue *= range;
new_hue /= 60;
new_hue += hue;
if(new_hue < 0) {
new_hue += range;
--region;
}
if(new_hue > range) {
new_hue -= range;
++region;
}
hue = (BYTE)new_hue;
region %= 6;
if(region < 0) {region += 6;}
range += minim;
*/
__asm {
pushad
xor edx,edx
mov eax,degrees
mov ebx,60
cdq
idiv ebx //we're dividing 'degrees' by 60
add region,eax //adding the whole number part to 'region'
movzx ecx,range
imul edx,ecx //multiplying the remainder by 'range'
mov eax,edx
xor edx,edx
cdq
idiv ebx //then dividing it by 60
add eax,hue //and adding 'hue' to it
//This section corrects the value such that it is gequal zero and
//lequal 'range' and finally sets 'hue' to the resulting value.
//If the value has to be up-stepped (have 'range' added to it)
//then 'region' is decremented. If the value has to be down-
//stepped ('range' subtracted) then 'region' is incremented.
cmp eax,0
jge geq_zero
add eax,ecx
dec region
jmp leq_rang
geq_zero: cmp eax,ecx
jle leq_rang
sub eax,ecx
inc region
leq_rang: mov hue,eax
//Here we correct 'region' to be within the range 0 to 5.
//Then just kick out the result values to memory and finish
//the block.
mov ebx,6
xor edx,edx
mov eax,region
cdq
idiv ebx
cmp edx,0
jge done
add edx,6
done: mov region,edx
add cl,minim
mov range,cl
popad
}
switch(region) {
case 0: //RGB
rgba.red = range;
rgba.green = minim + (BYTE)hue;
rgba.blue = minim;
break;
case 1: //GRB
rgba.green = range;
rgba.red = range - (BYTE)hue;
rgba.blue = minim;
break;
case 2: //GBR
rgba.green = range;
rgba.blue = minim + (BYTE)hue;
rgba.red = minim;
break;
case 3: //BGR
rgba.blue = range;
rgba.green = range - (BYTE)hue;
rgba.red = minim;
break;
case 4: //BRG
rgba.blue = range;
rgba.red = minim + (BYTE)hue;
rgba.green = minim;
break;
case 5: //RBG
rgba.red = range;
rgba.blue = range - (BYTE)hue;
rgba.green = minim;
break;
default:
break; //error
}

return rgba;
}
void hurrrrrrrr() {__asm sub [ebp+4],5;}

There are ten kinds of people in this world: those who understand binary and those who don't.

This topic is closed to new replies.

Advertisement