Change DWORD color alpha channel value - c++

I have a starting color: 0xffff00ff, which is a:255, r:255, g:0, b:255.
The goal is to change the alpha channel of the color to be less opaque based on a percentage. i.e. 50% opacity for that color is roughly 0x80ff00ff.
How I've tried to reach the solution:
DWORD cx = 0xffff00ff;
DWORD cn = .5;
DWORD nc = cx*cn;

DWORD cx = 0xffff00ff;
float cn = .5;
DWORD alphaMask=0xff000000;
DWORD nc = (cx|alphaMask)&((DWORD)(alphaMask*cn)|(~alphaMask));
This should do the trick. all I'm doing here is setting the first 8 bits of the DWORD to 1's with the or (symbolized by '|') and then anding those bits with the correct value you want them to be which is the alpha mask times cn. Of course I casted the result of the multiplication to make it a DWORD again.

This is tested code (in linux). However, you might find a simpler answer. Note: this is RGBA, not ARGB as you have referenced in your question.
double transparency = 0.500;
unsigned char *current_image_data_iterator = reinterpret_cast<unsigned char*>( const_cast<char *>( this->data.getCString() ) );
unsigned char *new_image_data_iterator = reinterpret_cast<unsigned char*>( const_cast<char *>( new_image_data->data.getCString() ) );
size_t x;
//cout << "transparency: " << transparency << endl;
for( x = 0; x < data_length; x += 4 ){
//rgb data is the same
*(new_image_data_iterator + x) = *(current_image_data_iterator + x);
*(new_image_data_iterator + x + 1) = *(current_image_data_iterator + x + 1);
*(new_image_data_iterator + x + 2) = *(current_image_data_iterator + x + 2);
//multiply the current opacity by the applied transparency
*(new_image_data_iterator + x + 3) = uint8_t( double(*(current_image_data_iterator + x + 3)) * ( transparency / 255.0 ) );
//cout << "Current Alpha: " << dec << static_cast<int>( *(current_image_data_iterator + x + 3) ) << endl;
//cout << "New Alpha: " << double(*(current_image_data_iterator + x + 3)) * ( transparency / 255.0 ) << endl;
//cout << "----" << endl;
}

typedef union ARGB
{
std::uint32_t Colour;
std::uint8_t A, R, G, B;
};
int main()
{
DWORD cx = 0xffff00ff;
reinterpret_cast<ARGB*>(&cx)->A = reinterpret_cast<ARGB*>(&cx)->A / 2;
std::cout<<std::hex<<cx;
}

The solution I chose to go with:
DWORD changeOpacity(DWORD color, float opacity) {
int alpha = (color >> 24) & 0xff;
int r = (color >> 16) & 0xff;
int g = (color >> 8) & 0xff;
int b = color & 0xff;
int newAlpha = ceil(alpha * opacity);
UINT newColor = r << 16;
newColor += g << 8;
newColor += b;
newColor += (newAlpha << 24);
return (DWORD)newColor;
}

I understand your question as: I wish to change a given rgba color component by a certain factor while keeping the same overall transparency.
For a color with full alpha (1.0 or 255), this is trivial: simply multiply the component without touching the others:
//typedef unsigned char uint8
enum COMPONENT {
RED,
GREEN,
BLUE,
ALPHA
};
struct rgba {
uint8 components[4];
// uint8 alpha, blue, green, red; // little endian
uint8 &operator[](int index){
return components[index];
}
};
rgba color;
if (color[ALPHA] == 255)
color[RED] *= factor;
else
ComponentFactor(color, RED, factor);
There's'probably not a single answer to that question in the general case. Consider that colors may be encoded alternatively in HSL or HSV. You might want to keep some of these parameters fixed, and allow other to change.
My approach to this problem would be to first try to find the hue distance between the source and target colors at full alpha, and then convert the real source color to HSV, apply the change in hue, then convert back to RGBA. Obviously, that second step is not necessary if the alpha is actually 1.0.
In pseudo code:
rgba ComponentFactor(rgba color, int component, double factor){
rgba fsrc = color, ftgt;
fsrc.alpha = 1.0; // set full alpha
ftgt = fsrc;
ftgt[component] *= factor; // apply factor
hsv hsrc = fsrc, htgt = ftgt; // convert to hsv color space
int distance = htgt.hue - hsrc.hue; // find the hue difference
hsv tmp = color; // convert actual color to hsv
tmp.hue += distance; // apply change in hue
rgba res = tmp; // convert back to RGBA space
return res;
}
Note how the above rely on type rgba and hsv to have implicit conversion constructors. Algorithms for conversion may be easily found with a web search. It should be also easy to derive struct definitions for hsv from the rgba one, or include individual component access as field members (rather than using the [] operator).
For instance:
//typedef DWORD uint32;
struct rgba {
union {
uint8 components[4];
struct {
uint8 alpha,blue,green,red; // little endian plaform
}
uint32 raw;
};
uint8 &operator[](int index){
return components[4 - index];
}
rgba (uint32 raw_):raw(raw_){}
rgba (uint8 r, uint8 g, uint8 b, uint8 a):
red(r), green(g), blue(b),alpha(a){}
};
Perhaps you will have to find a hue factor rather than a distance, or tweak other HSV components to achieve the desired result.

Related

Creating a UINT32 from 4 floats

Ok.
I'm working with the FW1FontWrapper code for use with DirectX
: https://archive.codeplex.com/?p=fw1
This has removed my need to use an outdated and useless font engine powered by textures.
However, the DrawString function within this Wrapper has a peculiar requirement for a Colour representation.
UINT32 Color : In the format 0xAaBbGgRr
The data I am given for this task is a constant Alpha value: 1.0f.
And 3 variable float values for R, G and B ranging from 0.0f to 1.0f.
Given the peculiar arrangement of colours within the UNIT32, I'm attempting to write a function that will create this UNIT32 using the 3 float values I am given.
My Attempt
UINT32 TextClassA::getColour(SentenceType* sentence)
{
//Convert each float value to its percentage of 255
int colorb = 255 * sentence->blue;
int colorg = 255 * sentence->green;
int colorr = 255 * sentence->red;
//convert each int to 8 bit Hex
UINT8 ucolorb = colorb;
UINT8 ucolorg = colorg;
UINT8 ucolorr = colorr;
//Push each hex back onto a UNIT32
UINT32 color = 0xFF + (ucolorb << 6) + (ucolorg << 4) + (ucolorr << 2);
return color;
}
SentenceType
red, green and blue are simply floats for each value of RGB from 0.0-1.0f
My Idea.
Was roughly that I could:
convert each float value to its percentage of 255 (not too worried about perfect accuracy.
Convert those integer values to UINT8s
Then push those back onto a UINT32
The implementation can be made clearer by avoiding all the temporary variables and using something like the code below. That said, any reasonable optimizing compiler should generate the same code in both cases.
UINT32 TextClassA::getColour(SentenceType* sentence)
{
//Convert color components to value between 0 and 255.
UINT32 r = 255 * sentence->red;
UINT32 b = 255 * sentence->blue;
UINT32 g = 255 * sentence->green;
//Combine the color components in a single value of the form 0xAaBbGgRr
return 0xFF000000 | r | (b << 16) | (g << 8);
}
I figured it out!!!
UINT32 TextClassA::getColour(SentenceType* sentence)
{
//Convert each float value to its percentage of 255
int colorb = 255 * sentence->blue;
int colorg = 255 * sentence->green;
int colorr = 255 * sentence->red;
//convert each int to 8 bit Hex
UINT8 ucolorb = 0x00 + colorb;
UINT8 ucolorg = 0x00 + colorg;
UINT8 ucolorr = 0x00 + colorr;
//Convert each UINT8 to a UINT32
UINT32 u32colorb = ucolorb;
UINT32 u32colorg = ucolorg;
UINT32 u32colorr = ucolorr;
//Create final UINT32s and push the converted UINT8s back onto each.
UINT32 u32finalcolorb = 0x00000000 | (u32colorb << 16);
UINT32 u32finalcolorg = 0x00000000 | (u32colorg << 8);
UINT32 u32finalcolorr = 0x00000000 | (u32colorr);
//0xAaBbGgRr
//Push each hex back onto a UNIT32
UINT32 color = 0xFF000000 | u32finalcolorb | u32finalcolorg |
u32finalcolorr;
return color;
}
My Mistake
...I believe, was trying to push UINT8s back, causing overflows, so I needed to convert to UINT32s first.

Pixels Overlay With transparency

I have 2 pixels in B8G8R8A8 (32) format.
Both pixels (top and bottom) has transparency (Alpha channel < 255 )
What is the way (formula) to overlay top pixel on the bottom one ?
(without using 3rd parties).
I tried to do something like this
struct FColor
{
public:
// Variables.
#if PLATFORM_LITTLE_ENDIAN
#ifdef _MSC_VER
// Win32 x86
union { struct{ uint8 B,G,R,A; }; uint32 AlignmentDummy; };
#else
// Linux x86, etc
uint8 B GCC_ALIGN(4);
uint8 G,R,A;
#endif
#else // PLATFORM_LITTLE_ENDIAN
union { struct{ uint8 A,R,G,B; }; uint32 AlignmentDummy; };
#endif
//...
};
FORCEINLINE FColor AlphaBlendColors(FColor pixel1, FColor pixel2)
{
FColor blendedColor;
//Calculate new Alpha:
uint8 newAlpha = 0;
newAlpha = pixel1.A + pixel2.A * (255 - pixel1.A);
//get FColor as uint32
uint32 colora = pixel1.DWColor();
uint32 colorb = pixel2.DWColor();
uint32 rb1 = ((0x100 - newAlpha) * (colora & 0xFF00FF)) >> 8;
uint32 rb2 = (newAlpha * (colorb & 0xFF00FF)) >> 8;
uint32 g1 = ((0x100 - newAlpha) * (colora & 0x00FF00)) >> 8;
uint32 g2 = (newAlpha * (colorb & 0x00FF00)) >> 8;
blendedColor = FColor(((rb1 | rb2) & 0xFF00FF) + ((g1 | g2) & 0x00FF00));
blendedColor.A = newAlpha;
return blendedColor;
}
But the result is far not what I want :-)
I looked for some Alpha blending formulas (I did never understand how would I calculate a new alpha of the overlay) -> perhaps I was going in a wrong direction ?
Edit:
Changing the newAlpha to newAlpha = FMath::Min(pixel1.A + pixel2.A, 255);
Actually gives a much better result, but is it right to calculate it like this ? Am I missing something here?
Working Example Based On Accepted Answer)
FORCEINLINE FColor AlphaBlendColors(FColor BottomPixel, FColor TopPixel)
{
FColor blendedColor;
//Calculate new Alpha:
float normA1 = 0.003921568627451f * (TopPixel.A);
float normA2 = 0.003921568627451f * (BottomPixel.A);
uint8 newAlpha = (uint8)((normA1 + normA2 * (1.0f - normA1)) * 255.0f);
if (newAlpha == 0)
{
return FColor(0,0,0,0);
}
//Going By Straight Alpha formula
float dstCoef = normA2 * (1.0f - normA1);
float multiplier = 255.0f / float(newAlpha);
blendedColor.R = (uint8)((TopPixel.R * normA1 + BottomPixel.R * dstCoef) * multiplier);
blendedColor.G = (uint8)((TopPixel.G * normA1 + BottomPixel.G * dstCoef) * multiplier);
blendedColor.B = (uint8)((TopPixel.B * normA1 + BottomPixel.B * dstCoef) * multiplier);
blendedColor.A = newAlpha;
return blendedColor;
}
Start by assuming that there is a third pixel below that happens to be opaque.
For the further notations, I will assume that alpha values are in [0,1].
Given: three pixels with the first one being on top, colors c_1, c_2, c_3, alpha values a_1, a_2, a_3 = 1
Then the resulting alpha value is obviously 1 and the color is
(a_1)*c_1 + (1-a_1)(*a_2)*c_2 + (1-a_1)*(1-a_2)*c_3
Now, we want to find some values c_k, a_k so that the formula above equates
(a_k)*c_k + (1-a_k)*c_3
We can solve this in two steps:
(1-a_k) = (1-a_1)*(1-a_2)
->
a_k = 1-(1-a_1)*(1-a_2)
and
(a_k)*c_k = (a_1)*c_1 + (1-a_1)(*a_2)*c_2
->
c_k = [(a_1)*c_1 + (1-a_1)(*a_2)*c_2] / a_k
Use those formulas (with a different range for your alpha values) and you get your desired color.
(Don't forget to catch a_k = 0)
edit: Explanation of the third pixel:
When you use your two pixels in any way, that is doing something that results it in being used to display something, they will be put over some other existing color that is opaque. For example, this might be the background color, but it could also be some color that is the result of applying many more transparent pixels on some background color.
What I now do to combine your two colors is to find a color that behaves just like those two colors. That is, putting it on top of some opaque color should result in the same as putting the original two colors on top of it. This is what I demand of the new color, resulting in the formula I use.
The formula is nothing than the result of applying two colors in succession on the third one.

Linear color gradient not working

I'm currently attempting to create a color gradient class for my Mandelbrot Set explorer.
It reads the color constraints (RGBA8888 color and position between 0 and 1) from a text file and adds them to a vector, which is lateron used to determine colors at a certain position.
To compute a color, the algorithm searches the next constraint to either side from the given position, splits the color into the four single channels, and then, for each one, searches the lower of both and adds a portion of the difference equal to the ratio (x-lpos)/(upos-lpos) to the lower color. Afterwards, the channels are shifted and ORed together, and then returned as RGBA8888 unsigned integer. (See the code below.)
EDIT: I completely rewrote the gradient class, fixing some issues and making it more readable for the sake of debugging (It gets slow as hell, though, but -Os more or less takes care of that). However, It's still not as it's supposed to be.
class Gradient { //remade, Some irrelevant methods and de-/constructors removed
private:
map<double, unsigned int> constraints;
public:
unsigned int operator[](double value) {
//Forbid out-of-range values, return black
if (value < 0 || value > 1+1E-10) return 0xff;
//Find upper and lower constraint
auto upperC = constraints.lower_bound(value);
if (upperC == constraints.end()) upperC = constraints.begin();
auto lowerC = upperC == constraints.begin() ? prev(constraints.end(), 1) : prev(upperC, 1);
if (value == lowerC->first) return lowerC->second;
double lpos = lowerC->first;
double upos = upperC->first;
if (upos < lpos) upos += 1;
//lower color channels
unsigned char lred = (lowerC->second >> 24) & 0xff;
unsigned char lgreen = (lowerC->second >> 16) & 0xff;
unsigned char lblue = (lowerC->second >> 8) & 0xff;
unsigned char lalpha = lowerC->second & 0xff;
//upper color channels
unsigned char ured = (upperC->second >> 24) & 0xff;
unsigned char ugreen = (upperC->second >> 16) & 0xff;
unsigned char ublue = (upperC->second >> 8) & 0xff;
unsigned char ualpha = upperC->second & 0xff;
unsigned char red = 0, green = 0, blue = 0, alpha = 0xff;
//Compute each channel using
// lower color + dist(lower, x)/dist(lower, upper) * diff(lower color, upper color)
if (lred < ured)
red = lred + (value - lpos)/(upos - lpos) * (ured - lred);
else red = ured + (upos - value)/(upos - lpos) * (ured - lred);
if (lgreen < ugreen)
green = lgreen + (value - lpos)/(upos - lpos) * (ugreen - green);
else green = ugreen + (upos - value)/(upos - lpos) * (ugreen - lgreen);
if (lblue < ublue)
blue = lblue + (value - lpos)/(upos - lpos) * (ublue - lblue);
else blue = ublue + (upos - value)/(upos - lpos) * (ublue - lblue);
if (lalpha < ualpha)
alpha = lalpha + (value - lpos)/(upos - lpos) * (ualpha - lalpha);
else alpha = ualpha + (upos - value)/(upos - lpos) * (ualpha - lalpha);
//Merge channels together and return
return (red << 24) | (green << 16) | (blue << 8 ) | alpha;
}
void addConstraint(unsigned int color, double position) {
constraints[position] = color;
}
};
Usage in the update method:
image[r + rres*i] = grd[ratio];
//With image being a vector<unsigned int>, which is then used as data source for a `SDL_Texture` using `SDL_UpdateTexture`
It only works partially, though. When I only use a black/white gradient, the resulting image is as intended:
Gradient file:
2
0 000000ff
1 ffffffff
However, when I use a more colorful gradient (a linear version of the Ultra Fractal gradient, input file below), the image is far from the intended result the image still doesn't show the desired coloring:
Gradient file:
5
0 000764ff
.16 206bcbff
.42 edffffff
.6425 ffaa00ff
0.8575 000200ff
What am I doing wrong? I've rewritten the operator[] method multiple times, without anything changing.
Questions for clarification or general remarks on my code are welcome.
Your problem is due to an over-complicated interpolation function.
When linearly interpolating in the range a .. b using another factor r (with range 0 .. 1) to indicate the position in that range it's completely unnecessary to determine whether a or b is greater. Either way around you can just use:
result = a + r * (b - a)
If r == 0 this is trivially shown to be a, and if r == 1 the a - a cancels out leaving just b. Similarly if r == 0.5 then the result is (a + b) / 2. It simply doesn't matter if a > b or vice-versa.
The preferred formulation in your case, since it avoids the b - a subtraction that possibly hits range clamping limits is:
result = (1 - r) * a + r * b;
which given appropriate * and + operators on your new RGBA class gives this trivial implementation of your mid function (with no need for per-component operations since they're handled in those operators):
static RGBA mid(const RGBA& a, const RGBA& b, double r) {
return (1.0 - r) * a + r * b;
}
See https://gist.github.com/raybellis/4f69345d8e0c4e83411b, where I've also refactored your RGBA class to put the clamping operations in the constructor rather than within the individual operators.
After some extensive trial-and-error, I finally managed to get it working. (at this point many thanks to #Alnitak, who suggested using a separate RGBA color class.)
The major problem was that, when a color value of the upper constraint was lower than the one of the lower one, I still multiplied with the ratio (x-l)/(u-l), when instead I should have used its pendant, 1 - (x-l)/(u-l), to refer to the color of the upper constraint as the basis for the new one.
Here follows the implementation of the RGBA class and the fixed gradient class:
class RGBA {
private:
unsigned int red = 0, green = 0, blue = 0, alpha = 0;
public:
static RGBA mid(RGBA a, RGBA b, double r) {
RGBA color;
if (a.red < b.red) color.red = a.red + (b.red - a.red) * r;
else color.red = b.red + (a.red - b.red) * (1-r);
if (a.green < b.green) color.green = a.green + (b.green - a.green) * r;
else color.green = b.green + (a.green - b.green) * (1-r);
if (a.blue < b.blue) color.blue = a.blue + (b.blue - a.blue) * r;
else color.blue = b.blue + (a.blue - b.blue) * (1-r);
if (a.alpha < b.alpha) color.alpha = a.alpha + (b.alpha - a.alpha) * r;
else color.alpha = b.alpha + (a.alpha - b.alpha) * (1-r);
return color;
}
RGBA() {};
RGBA(unsigned char _red, unsigned char _green, unsigned char _blue, unsigned char _alpha) :
red(_red), green(_green), blue(_blue), alpha(_alpha) {};
RGBA(unsigned int _rgba) {
red = (_rgba >> 24) & 0xff;
green = (_rgba >> 16) & 0xff;
blue = (_rgba >> 8) & 0xff;
alpha = _rgba & 0xff;
};
operator unsigned int() {
return (red << 24) | (green << 16) | (blue << 8 ) | alpha;
}
RGBA operator+(const RGBA& o) const {
return RGBA((red + o.red) & 0xff, (green + o.green) & 0xff, (blue + o.blue) & 0xff, (alpha + o.alpha) & 0xff);
}
RGBA operator-(const RGBA& o) const {
return RGBA(min(red - o.red, 0u), min(green - o.green, 0u), min(blue - o.blue, 0u), min(alpha - o.alpha, 0u));
}
RGBA operator~() {
return RGBA(0xff - red, 0xff - green, 0xff - blue, 0xff - alpha);
}
RGBA operator*(double _f) {
return RGBA((unsigned int) min(red * _f, 0.) & 0xff, (unsigned int) min(green * _f, 0.) & 0xff,
(unsigned int) min(blue * _f, 0.) & 0xff, (unsigned int) min(alpha * _f, 0.) & 0xff);
}
};
class Gradient {
private:
map<double, RGBA> constraints;
public:
Gradient() {
constraints[0] = RGBA(0x007700ff);
constraints[1] = RGBA(0xffffffff);
}
~Gradient() {}
void addConstraint(RGBA color, double position) {
constraints[position] = color;
}
void reset() {
constraints.clear();
}
unsigned int operator[](double value) {
if (value < 0 || value > 1+1E-10) return 0xff;
auto upperC = constraints.lower_bound(value);
if (upperC == constraints.end()) upperC = constraints.begin();
auto lowerC = upperC == constraints.begin() ? prev(constraints.end(), 1) : prev(upperC, 1);
if (value == lowerC->first) return lowerC->second;
double lpos = lowerC->first;
double upos = upperC->first;
if (upos < lpos) upos += 1;
RGBA lower = lowerC->second;
RGBA upper = upperC->second;
RGBA color = RGBA::mid(lower, upper, (value-lpos)/(upos-lpos));
return color;
}
size_t size() {
return constraints.size();
}
};
This is the result:

Bilinear re-sizing with C++ and vector of RGBA pixels

I am trying to re-size an image by using the bilinear technique I found here but I don't see anything but a black image.
So, in first place I have my image decoded with LodePNG and the pixels go into a vector<unsigned char> variable. It says that they are stored as RGBARGBA but when I tried to apply the image to a X11 window I realized they were stored as BGRABGRA. I don't know if is the X11 API which changes the order or the LodePNG decoder. Anyway, before anything, I convert the BGR to RGB:
// Here is where I have the pixels stored
vector<unsigned char> Image;
// Converting BGRA to RGBA, or vice-versa, I don't know, but it's how it is shown
// correctly on the window
unsigned char red, blue;
unsigned int i;
for(i=0; i<Image.size(); i+=4)
{
red = Image[i + 2];
blue = Image[i];
Image[i] = red;
Image[i + 2] = blue;
}
So, now I am trying to change the size of the image, before applying it to the window. The size would be the size of the window (stretch it).
I firstly try to convert the RGBA to int values, like this:
vector<int> IntImage;
for(unsigned i=0; i<Image.size(); i+=4)
{
IData.push_back(256*256*this->Data[i+2] + 256*this->Data[i+1] + this->Data[i]);
}
Now I have this function from the link I specified above, which is supposed to do the interpolation:
vector<int> resizeBilinear(vector<int> pixels, int w, int h, int w2, int h2) {
vector<int> temp(w2 * h2);
int a, b, c, d, x, y, index ;
float x_ratio = ((float)(w-1))/w2 ;
float y_ratio = ((float)(h-1))/h2 ;
float x_diff, y_diff, blue, red, green ;
for (int i=0;i<h2;i++) {
for (int j=0;j<w2;j++) {
x = (int)(x_ratio * j) ;
y = (int)(y_ratio * i) ;
x_diff = (x_ratio * j) - x ;
y_diff = (y_ratio * i) - y ;
index = (y*w+x) ;
a = pixels[index] ;
b = pixels[index+1] ;
c = pixels[index+w] ;
d = pixels[index+w+1] ;
// blue element
// Yb = Ab(1-w)(1-h) + Bb(w)(1-h) + Cb(h)(1-w) + Db(wh)
blue = (a&0xff)*(1-x_diff)*(1-y_diff) + (b&0xff)*(x_diff)*(1-y_diff) +
(c&0xff)*(y_diff)*(1-x_diff) + (d&0xff)*(x_diff*y_diff);
// green element
// Yg = Ag(1-w)(1-h) + Bg(w)(1-h) + Cg(h)(1-w) + Dg(wh)
green = ((a>>8)&0xff)*(1-x_diff)*(1-y_diff) + ((b>>8)&0xff)*(x_diff)*(1-y_diff) +
((c>>8)&0xff)*(y_diff)*(1-x_diff) + ((d>>8)&0xff)*(x_diff*y_diff);
// red element
// Yr = Ar(1-w)(1-h) + Br(w)(1-h) + Cr(h)(1-w) + Dr(wh)
red = ((a>>16)&0xff)*(1-x_diff)*(1-y_diff) + ((b>>16)&0xff)*(x_diff)*(1-y_diff) +
((c>>16)&0xff)*(y_diff)*(1-x_diff) + ((d>>16)&0xff)*(x_diff*y_diff);
temp.push_back(
((((int)red)<<16)&0xff0000) |
((((int)green)<<8)&0xff00) |
((int)blue) |
0xff); // hardcode alpha ;
}
}
return temp;
}
and I use it like this:
vector<int> NewImage = resizeBilinear(IntData, image_width, image_height, window_width, window_height);
which is supposed to return me the RGBA vector of the re-sized image. Now I am changing back to RGBA (from int)
Image.clear();
for(unsigned i=0; i<NewImage.size(); i++)
{
Image.push_back(NewImage[i] & 255);
Image.push_back((NewImage[i] >> 8) & 255);
Image.push_back((NewImage[i] >> 16) & 255);
Image.push_back(0xff);
}
and what I get is a black window (the default background color), so I don't know what am I missing. If I comment out the line where I get the new image and just convert back to RGBA the IntImage I get the correct values so I don't know if it is the messed up RGBA/int <> int/RGBA. I'm just lost now. I know this can be optimized/simplified but for now I just want to make it work.
The array access in your code is incorrect:
vector<int> temp(w2 * h2); // initializes the array to contain zeros
...
temp.push_back(...); // appends to the array, leaving the zeros unchanged
You should overwrite instead of appending; for that, calculate the array position:
temp[i * w2 + j] = ...;
Alternatively, initialize the array to an empty state, and append your stuff:
vector<int> temp;
temp.reserve(w2 * h2); // reserves some memory; array is still empty
...
temp.push_back(...); // appends to the array

SDL return code 3 from SDL at strange place in code

I am getting a 3 error code from an SDL executable, and it seems to be in a place where I pass a SDL color by value and I don't understand the reason.
void Map::draw(SDL_Surface *surface, int level){
//the surface is locked
if ( SDL_MUSTLOCK(surface) )
SDL_LockSurface(surface);
long start= (long)level * this->xmax * this->ymax;
long end= (long)(level+1) * this->xmax * this->ymax;
for(long n=start; n<end; ++n){
Node *pn= this->nodes+n;
//exit(18); //exit code is 18
draw_pixel_nolock(surface, pn->location.x, pn->location.y, colors[pn->content]);
}
//the surface is unlocked
if ( SDL_MUSTLOCK(surface) )
SDL_UnlockSurface(surface);
}
And the graphics function called is:
SDL_Color colors[]= { {0,0,0}, {0xFF,0,0}, {0,0xFF,0}, {0,0,0xFF} };
void PutPixel32_nolock(SDL_Surface * surface, int x, int y, Uint32 color)
{
Uint8 * pixel = (Uint8*)surface->pixels;
pixel += (y * surface->pitch) + (x * sizeof(Uint32));
*((Uint32*)pixel) = color;
}
void PutPixel24_nolock(SDL_Surface * surface, int x, int y, Uint32 color)
{
Uint8 * pixel = (Uint8*)surface->pixels;
pixel += (y * surface->pitch) + (x * sizeof(Uint8) * 3);
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
pixel[0] = (color >> 24) & 0xFF;
pixel[1] = (color >> 16) & 0xFF;
pixel[2] = (color >> 8) & 0xFF;
#else
pixel[0] = color & 0xFF;
pixel[1] = (color >> 8) & 0xFF;
pixel[2] = (color >> 16) & 0xFF;
#endif
}
void PutPixel16_nolock(SDL_Surface * surface, int x, int y, Uint32 color)
{
Uint8 * pixel = (Uint8*)surface->pixels;
pixel += (y * surface->pitch) + (x * sizeof(Uint16));
*((Uint16*)pixel) = color & 0xFFFF;
}
void PutPixel8_nolock(SDL_Surface * surface, int x, int y, Uint32 color)
{
Uint8 * pixel = (Uint8*)surface->pixels;
pixel += (y * surface->pitch) + (x * sizeof(Uint8));
*pixel = color & 0xFF;
}
//this function draws a pixel of wanted color on a surface at (x,y) coordinate
void draw_pixel_nolock(SDL_Surface *surface, int x, int y, SDL_Color s_color)
{ exit(19);//exit code is 3
//SDL_MapRGB return a color map depending on bpp (definition)
Uint32 color = SDL_MapRGB(surface->format, s_color.r, s_color.g, s_color.b);
//byte per pixel
int bpp = surface->format->BytesPerPixel;
//here is checked the number of byte used by our surface
switch (bpp)
{
case 1: // 1 byte => 8-bpp
PutPixel8_nolock(surface, x, y, color);
break;
case 2: // 2 byte => 16-bpp
PutPixel16_nolock(surface, x, y, color);
break;
case 3: // 3 byte => 24-bpp
PutPixel24_nolock(surface, x, y, color);
break;
case 4: // 4 byte => 32-bpp
PutPixel32_nolock(surface, x, y, color);
break;
}
}
The code returns error code 18 when I exit there, but never returns error code 19, and gives errror code 3 instead. What could possibly go wrong?
Without seeing the entire code it's hard to tell, but as a general practice:
Validate that
long start= (long)level * this->xmax * this->ymax;
long end= (long)(level+1) * this->xmax * this->ymax;
start and end are valid offsets for your node array, otherwise this->node + n will return a garbage pointer.
Validate that
Node *pn= this->nodes+n;
Is not null and a valid pointer to a Node object
Validate that
pn->content
Is within the bounds of your colors array