WarpBlt from 16bpp to 32bpp

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

WarpBlt from 16bpp to 32bpp

Yoshiki Ohshima
  Hello,

  I think that this is a known issue, but can't remember when was the
last time we discussed this.  So, I'm bringing it up in a context I
encountered.

  Here is a sample code to illustate the problem:

-------------------
f _ (Form extent: 50@50 depth: 16) fillColor: Color green.
g _ Form extent: 100@100 depth: 32.

(WarpBlt current toForm: g)
  sourceForm: f;
  cellSize: 2;
  combinationRule: Form over;
  sourceQuad: (f boundingBox) innerCorners destRect: g boundingBox;
  warpBits.

"g fixAlpha."
g colorAt: 50@50  
-------------------

  First you fill a 16-bit form with green, and then warp blt it onto a
32-bit Form with the "over" rule.  You'd expect to get a green-colored
form as a result, right?

  One of the problem is that the alpha channel is set to 0 so it
results in "Color transparent".  You would imagine to fix it by "g
fixAlpha" above.

  However, if you uncomment the line and execute, you get "(Color r:
0.94 g: 0.0 b: 0.0)" as the result.  This is wrong.

  A part of BitBltSimulation>>warpPickSmoothPixels: nPixels
                              xDeltah: xDeltah yDeltah: yDeltah
                              xDeltav: xDeltav yDeltav: yDeltav
                              sourceMap: sourceMap
                              smoothing: n
                              dstShiftInc: dstShiftInc

says:

        "normalize rgba sums"
        nPix = 4 "Try to avoid divides for most common n"
                ifTrue:[r _ r >> 2. g _ g >> 2. b _ b >> 2. a _ a >> 2]
                ifFalse:[ r _ r // nPix. g _ g // nPix. b _ b // nPix. a _ a // nPix].
        rgb _ (a << 24) + (r << 16) + (g << 8) + b.

        "map the pixel"
        rgb = 0 ifTrue: [
                "only generate zero if pixel is really transparent"
                (r + g + b + a) > 0 ifTrue: [rgb _ 1]].
        rgb _ self mapPixel: rgb flags: cmFlags.

With the first assignment, the variable "rgb" holds a 32-bit pixel
value.  We know the destination is also 32 bit, so we even doesn't
have to map the pixel value.  However, the invocation of
#mapPixel:flags: takes the rgb value as if it is 16-bit and mask and
shift again.

  The right thing is to map the averaged rgb value back to the pixel
value in the source depth and then map the color.  For a practical
need, we can skip mapPixel:flags: if the dest is 32 and there is no
color map specified.

  And, the workaround I use is to use cellSize: 1 for this... But here
is another issue, actually.  WarpBlt>>cellSize: says:

cellSize: s
        cellSize _ s.
        cellSize = 1 ifTrue: [^ self].
        colorMap _ Color colorMapIfNeededFrom: 32 to: destForm depth.

so it trys to install a color map from 32-bit regardless the actuall
depth of the source.  Why?

-- Yoshiki

Reply | Threaded
Open this post in threaded view
|

Re: WarpBlt from 16bpp to 32bpp

Andreas.Raab
 > so it trys to install a color map from 32-bit regardless the actuall
 > depth of the source.  Why?

For precisely the reason you notice. The color map ensures that the
averaged pixel can be mapped from the 32bit RGBA representation into
whatever the destination depth is. Internally, when cellSize>1 we always
treat the input as 32bit since we know that WarpBlt will average that
way. But why this isn't working for 16->32 is a good question...

Cheers,
   - Andreas



Yoshiki Ohshima wrote:

>   Hello,
>
>   I think that this is a known issue, but can't remember when was the
> last time we discussed this.  So, I'm bringing it up in a context I
> encountered.
>
>   Here is a sample code to illustate the problem:
>
> -------------------
> f _ (Form extent: 50@50 depth: 16) fillColor: Color green.
> g _ Form extent: 100@100 depth: 32.
>
> (WarpBlt current toForm: g)
>   sourceForm: f;
>   cellSize: 2;
>   combinationRule: Form over;
>   sourceQuad: (f boundingBox) innerCorners destRect: g boundingBox;
>   warpBits.
>
> "g fixAlpha."
> g colorAt: 50@50  
> -------------------
>
>   First you fill a 16-bit form with green, and then warp blt it onto a
> 32-bit Form with the "over" rule.  You'd expect to get a green-colored
> form as a result, right?
>
>   One of the problem is that the alpha channel is set to 0 so it
> results in "Color transparent".  You would imagine to fix it by "g
> fixAlpha" above.
>
>   However, if you uncomment the line and execute, you get "(Color r:
> 0.94 g: 0.0 b: 0.0)" as the result.  This is wrong.
>
>   A part of BitBltSimulation>>warpPickSmoothPixels: nPixels
>                               xDeltah: xDeltah yDeltah: yDeltah
>                               xDeltav: xDeltav yDeltav: yDeltav
>                               sourceMap: sourceMap
>                               smoothing: n
>                               dstShiftInc: dstShiftInc
>
> says:
>
> "normalize rgba sums"
> nPix = 4 "Try to avoid divides for most common n"
> ifTrue:[r _ r >> 2. g _ g >> 2. b _ b >> 2. a _ a >> 2]
> ifFalse:[ r _ r // nPix. g _ g // nPix. b _ b // nPix. a _ a // nPix].
> rgb _ (a << 24) + (r << 16) + (g << 8) + b.
>
> "map the pixel"
> rgb = 0 ifTrue: [
> "only generate zero if pixel is really transparent"
> (r + g + b + a) > 0 ifTrue: [rgb _ 1]].
> rgb _ self mapPixel: rgb flags: cmFlags.
>
> With the first assignment, the variable "rgb" holds a 32-bit pixel
> value.  We know the destination is also 32 bit, so we even doesn't
> have to map the pixel value.  However, the invocation of
> #mapPixel:flags: takes the rgb value as if it is 16-bit and mask and
> shift again.
>
>   The right thing is to map the averaged rgb value back to the pixel
> value in the source depth and then map the color.  For a practical
> need, we can skip mapPixel:flags: if the dest is 32 and there is no
> color map specified.
>
>   And, the workaround I use is to use cellSize: 1 for this... But here
> is another issue, actually.  WarpBlt>>cellSize: says:
>
> cellSize: s
> cellSize _ s.
> cellSize = 1 ifTrue: [^ self].
> colorMap _ Color colorMapIfNeededFrom: 32 to: destForm depth.
>
> so it trys to install a color map from 32-bit regardless the actuall
> depth of the source.  Why?
>
> -- Yoshiki
>
>


Reply | Threaded
Open this post in threaded view
|

Re: WarpBlt from 16bpp to 32bpp

Andreas.Raab
Andreas Raab wrote:
>  > so it trys to install a color map from 32-bit regardless the actuall
>  > depth of the source.  Why?
>
> For precisely the reason you notice. The color map ensures that the
> averaged pixel can be mapped from the 32bit RGBA representation into
> whatever the destination depth is. Internally, when cellSize>1 we always
> treat the input as 32bit since we know that WarpBlt will average that
> way. But why this isn't working for 16->32 is a good question...

Okay, found it. The VM will substitute a standard color conversion if no
colorMap is given and since Color>>colorMapIfNeededFrom:to: will not
create an explicit color map for 32->32 bit conversions, the VM will use
a color map from the sourceForm's depth (16) to the destForm's depth
(32). Which, for WarpBlt w/ smoothing is just plain wrong.

Fix attached - it simply works around the problem by installing an
appropriate (no-op) color map for 32->32 conversions if necessary.

Cheers,
   - Andreas



WarpBlt-cellSize.st (823 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: WarpBlt from 16bpp to 32bpp

Yoshiki Ohshima
  Thank you, Andreas!

> Fix attached - it simply works around the problem by installing an
> appropriate (no-op) color map for 32->32 conversions if necessary.

  Passing ColorMap object does it.  I'll push it to the OLPC image...

-- Yoshiki