CyanPrime
CyanPrime

Reputation: 5193

how to bit shift a u16*'s data?

Sorry if this doesn't make any sence, but I'm trying my best to understand it myself.

So I basically have a pointer to data for a texture in openGL, it's 16 bpp ( pcx.image.data16 ), and I need to turn on the alpha bit for each pixel. So I've came up with this, but as you can tell it's really bad.

for(int i = 0; i < (TEXTURE_SIZE_128 * TEXTURE_SIZE_128); i++){
        pcx.image.data16 |=  1 << ((16 * i) + 15);
    }

I'm getting these errors:

c:/Users/me/Desktop/neronds/source/neroedge.cpp:40:43: error: invalid operands of types 'u16* {aka short unsigned int*}' and 'int' to binary 'operator|'
c:/Users/me/Desktop/neronds/source/neroedge.cpp:40:43: error:   in evaluation of 'operator|=(u16* {aka short unsigned int*}, int)'

How do I get fix these errors, and am I on the right track to changing the alpha bit per pixel?

Upvotes: 1

Views: 964

Answers (2)

datenwolf
datenwolf

Reputation: 162164

You were already given answers how to fix it, but no explanation why your code was wrong. Let's have a look at this piece of code:

pcx.image.data16 |=  1 << ((16 * i) + 15);

Obviously you fell for the idea, that the compiler sees an array as a long string of individual bits. Also you fell for the misconception that you could bit shift arbitrarily long. However this is not how C and C++ work. The bitshift only works on the width of the types it is applied. There are some rules which type is used by the compiler depending on the participating types. So let's break down the types:

(int) << (((int) * (int)) + (int));

okay, there's only int in there, so the type operated on will be int. Depending on plattform there is only a limited number of bits. But let's say for convenience that int has 64 bits. This means that any left shift of a 1 of more than 65 bits will shift the bit out of the available bits and you're getting zero bits set. But we're not done yet.

After that you're assigning that int to a uint16_t. Now here's the next misconception. A type of uint16_t is specified to provide at least 16 bits (C is not very exact in those things, because it may run on a plattform where word size is not a multiple of 8 bits). But for the sake of this explanation let's assume that it are exactly 16 bits. The assignment

(uint16_t) = (int)

coerces, i.e. it throws away the bits, not fitting into the L value.

Last but not least: The expression pcx.image.data16 is a pointer. This pointer points to the very first element of your data array. By assigning to this pointer you're only changing this pointer, not the data it points to. So you have to dereference the pointer. You can dereference a pointer by prepending it with a * or by appending a indexing operator[…]. Note that * and [0] are identical! So if you did a

 *pcx.image.data16;

this would only dereference to the first array element (which will probably have 16 bits, but maybe more). Anyway: You can not assign a larger bitvector to it, that "wraps" into the next elements (and that is a good thing!).

So the solution is, to iterate over all of the elements of the array, and for each element set that additional bit:

for(int i = 0; i < (TEXTURE_SIZE_128 * TEXTURE_SIZE_128); i++){
    pcx.image.data16[i] |=  1 << 15;
}

Upvotes: 0

01d55
01d55

Reputation: 1912

Try this:

for(unsigned i = 0; i < (TEXTURE_SIZE_128 * TEXTURE_SIZE_128); i++)
    {
        constexpr u16 ALPHA_BIT = 1 << 15;
        pcx.image.data16[i] |= ALPHA_BIT;
    }

If your compiler does not yet support constexpr (a c++11 feature) use const instead.

Upvotes: 5

Related Questions