The Inbox: Graphics-nice.285.mcz

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

The Inbox: Graphics-nice.285.mcz

commits-2
Nicolas Cellier uploaded a new version of Graphics to project The Inbox:
http://source.squeak.org/inbox/Graphics-nice.285.mcz

==================== Summary ====================

Name: Graphics-nice.285
Author: nice
Time: 1 January 2014, 8:53:32.416 pm
UUID: 04aee02d-83ae-4b4d-aed9-968a6a7487db
Ancestors: Graphics-nice.284

Change Color implementation from 10 bits per (rgb) component to 8 bits per component.
Several considerations motivate this change:
- no Graphic output is using 10 bits;
- alpha channel is already stored using 8 bits;
- 8 bits matches nowadays most used 32 bits depth Form - thus it's an optimization.
Note that the tolerance for testing Color components has to be increased to a value >= (1/255), I suggest 0.005.

=============== Diff against Graphics-nice.284 ===============

Item was added:
+ (PackageInfo named: 'Graphics') preamble: '"Change color components from 10 to 8 bits"
+ Color allSubInstancesDo:
+ [:c |
+ | rgb |
+ rgb := c instVarNamed: ''rgb''.
+ rgb := (rgb bitAnd: 16r3FC00000) >> 2 + (rgb bitAnd: 16rFF000) >> 2 + (rgb bitAnd: 16r3FC) >> 2.
+ c instVarNamed: ''rgb'' put: rgb; flushCache].'!

Item was changed:
  ----- Method: Color class>>initialize (in category 'class initialization') -----
  initialize
  "Color initialize"
 
  "Details: Externally, the red, green, and blue components of color
  are floats in the range [0.0..1.0]. Internally, they are represented
  as integers in the range [0..ComponentMask] packing into a
  small integer to save space and to allow fast hashing and
  equality testing.
 
  For a general description of color representations for computer
  graphics, including the relationship between the RGB and HSV
  color models used here, see Chapter 17 of Foley and van Dam,
  Fundamentals of Interactive Computer Graphics, Addison-Wesley,
  1982."
 
+ ComponentMask := 255.
+ HalfComponentMask := 128.  "used to round up in integer calculations"
+ ComponentMax := 255.0.  "a Float used to normalize components"
+ RedShift := 16.
+ GreenShift := 8.
- ComponentMask := 1023.
- HalfComponentMask := 512.  "used to round up in integer calculations"
- ComponentMax := 1023.0.  "a Float used to normalize components"
- RedShift := 20.
- GreenShift := 10.
  BlueShift := 0.
 
  PureRed := self r: 1 g: 0 b: 0.
  PureGreen := self r: 0 g: 1 b: 0.
  PureBlue := self r: 0 g: 0 b: 1.
  PureYellow := self r: 1 g: 1 b: 0.
  PureCyan := self r: 0 g: 1 b: 1.
  PureMagenta := self r: 1 g: 0 b: 1.
 
  RandomStream := Random new.
 
  self initializeIndexedColors.
  self initializeGrayToIndexMap.
  self initializeNames.
  self initializeHighLights.
  !

Item was changed:
  ----- Method: Color class>>initializeGrayToIndexMap (in category 'class initialization') -----
  initializeGrayToIndexMap
  "Build an array of gray values available in the 8-bit colormap. This array is indexed by a gray level between black (1) and white (256) and returns the pixel value for the corresponding gray level."
  "Note: This method must be called after initializeIndexedColors, since it uses IndexedColors."
  "Color initializeGrayToIndexMap"
 
  | grayLevels grayIndices c distToClosest dist indexOfClosest |
  "record the level and index of each gray in the 8-bit color table"
  grayLevels := OrderedCollection new.
  grayIndices := OrderedCollection new.
  "Note: skip the first entry, which is reserved for transparent"
  2 to: IndexedColors size do: [:i |
  c := IndexedColors at: i.
  c saturation = 0.0 ifTrue: [  "c is a gray"
+ grayLevels add: c privateBlue.  "top 8 bits; R, G, and B are the same"
- grayLevels add: (c privateBlue) >> 2.  "top 8 bits; R, G, and B are the same"
  grayIndices add: i - 1]].  "pixel values are zero-based"
  grayLevels := grayLevels asArray.
  grayIndices := grayIndices asArray.
 
  "for each gray level in [0..255], select the closest match"
  GrayToIndexMap := ByteArray new: 256.
  0 to: 255 do: [:level |
  distToClosest := 10000.  "greater than distance to any real gray"
  1 to: grayLevels size do: [:i |
  dist := (level - (grayLevels at: i)) abs.
  dist < distToClosest ifTrue: [
  distToClosest := dist.
  indexOfClosest := grayIndices at: i]].
  GrayToIndexMap at: (level + 1) put: indexOfClosest].
  !

Item was changed:
  ----- Method: Color>>asHTMLColor (in category 'conversions') -----
  asHTMLColor
+ ^'#' , (rgb printStringBase: 16 length: 6 padded: true)!
- | s |
- s := '#000000' copy.
- s at: 2 put: (Character digitValue: ((rgb bitShift: -6 - RedShift) bitAnd: 15)).
- s at: 3 put: (Character digitValue: ((rgb bitShift: -2 - RedShift) bitAnd: 15)).
- s at: 4 put: (Character digitValue: ((rgb bitShift: -6 - GreenShift) bitAnd: 15)).
- s at: 5 put: (Character digitValue: ((rgb bitShift: -2 - GreenShift) bitAnd: 15)).
- s at: 6 put: (Character digitValue: ((rgb bitShift: -6 - BlueShift) bitAnd: 15)).
- s at: 7 put: (Character digitValue: ((rgb bitShift: -2 - BlueShift) bitAnd: 15)).
- ^ s!

Item was changed:
  ----- Method: Color>>closestPixelValue1 (in category 'conversions') -----
  closestPixelValue1
  "Return the nearest approximation to this color for a monochrome Form."
 
  "fast special cases"
  rgb = 0 ifTrue: [^ 1].  "black"
+ rgb = 16rFFFFFFF ifTrue: [^ 0].  "white"
- rgb = 16r3FFFFFFF ifTrue: [^ 0].  "white"
 
  self luminance > 0.5
  ifTrue: [^ 0]  "white"
  ifFalse: [^ 1].  "black"
  !

Item was changed:
  ----- Method: Color>>closestPixelValue2 (in category 'conversions') -----
  closestPixelValue2
  "Return the nearest approximation to this color for a 2-bit deep Form."
 
  | lum |
  "fast special cases"
  rgb = 0 ifTrue: [^ 1].  "black"
+ rgb = 16rFFFFFFF ifTrue: [^ 2].  "opaque white"
- rgb = 16r3FFFFFFF ifTrue: [^ 2].  "opaque white"
 
  lum := self luminance.
  lum < 0.2 ifTrue: [^ 1].  "black"
  lum > 0.6 ifTrue: [^ 2].  "opaque white"
  ^ 3  "50% gray"
  !

Item was changed:
  ----- Method: Color>>closestPixelValue4 (in category 'conversions') -----
  closestPixelValue4
  "Return the nearest approximation to this color for a 4-bit deep Form."
 
  | bIndex |
  "fast special cases"
  rgb = 0 ifTrue: [^ 1].  "black"
+ rgb = 16rFFFFFFF ifTrue: [^ 2].  "opaque white"
- rgb = 16r3FFFFFFF ifTrue: [^ 2].  "opaque white"
 
  rgb = PureRed privateRGB ifTrue: [^ 4].
  rgb = PureGreen privateRGB ifTrue: [^ 5].
  rgb = PureBlue privateRGB ifTrue: [^ 6].
  rgb = PureCyan privateRGB ifTrue: [^ 7].
  rgb = PureYellow privateRGB ifTrue: [^ 8].
  rgb = PureMagenta privateRGB ifTrue: [^ 9].
 
  bIndex := (self luminance * 8.0) rounded.  "bIndex in [0..8]"
  ^ #(
  1 "black"
  10 "1/8 gray"
  11 "2/8 gray"
  12 "3/8 gray"
  3 "4/8 gray"
  13 "5/8 gray"
  14 "6/8 gray"
  15 "7/8 gray"
  2 "opaque white"
  ) at: bIndex + 1.
  !

Item was changed:
  ----- Method: Color>>closestPixelValue8 (in category 'conversions') -----
  closestPixelValue8
  "Return the nearest approximation to this color for an 8-bit deep Form."
 
  "fast special cases"
  rgb = 0 ifTrue: [^ 1].  "black"
+ rgb = 16rFFFFFFF ifTrue: [^ 255].  "white"
- rgb = 16r3FFFFFFF ifTrue: [^ 255].  "white"
 
  self saturation < 0.2 ifTrue: [
+ ^ GrayToIndexMap at: self privateGreen + 1.  "nearest gray"
- ^ GrayToIndexMap at: (self privateGreen >> 2) + 1.  "nearest gray"
  ] ifFalse: [
  "compute nearest entry in the color cube"
  ^ 40 +
   ((((self privateRed * 5) + HalfComponentMask) // ComponentMask) * 36) +
   ((((self privateBlue * 5) + HalfComponentMask) // ComponentMask) * 6) +
   (((self privateGreen * 5) + HalfComponentMask) // ComponentMask)].
  !

Item was changed:
  ----- Method: Color>>pixelValueForDepth: (in category 'conversions') -----
  pixelValueForDepth: d
  "Returns an integer representing the bits that appear in a single pixel of this color in a Form of the given depth. The depth must be one of 1, 2, 4, 8, 16, or 32. Contrast with pixelWordForDepth: and bitPatternForDepth:, which return either a 32-bit word packed with the given pixel value or a multiple-word Bitmap containing a pattern. The inverse is the class message colorFromPixelValue:depth:"
  "Details: For depths of 8 or less, the result is a colorMap index. For depths of 16 and 32, it is a direct color value with 5 or 8 bits per color component."
  "Transparency: The pixel value zero is reserved for transparent. For depths greater than 8, black maps to the darkest possible blue."
 
  | val |
  d > 8 "most common case"
  ifTrue:
  [d = 32 ifTrue: [
  "eight bits per component; top 8 bits set to all ones (opaque alpha)"
+ ^rgb = 0 ifTrue: [16rFF000001] ifFalse: [rgb bitOr: 16rFF000000]].
- val := (LargePositiveInteger new: 4)
- at: 4 put: 16rFF;
- at: 3 put: ((rgb bitShift: -22) bitAnd: 16rFF);
- at: 2 put: ((rgb bitShift: -12) bitAnd: 16rFF);
- at: 1 put: ((rgb bitShift: -2) bitAnd: 16rFF);
- normalize. "normalize is not necessary as long as SmallInteger maxVal highBit < 32, but let's be future proof"
- ^val < 16rFF000001 ifTrue: [16rFF000001] ifFalse: [val]].
 
  d = 16 ifTrue: [
  "five bits per component; top bits ignored"
+ val := (((rgb bitShift: -9) bitAnd: 16r7C00) bitOr:
+ ((rgb bitShift: -6) bitAnd: 16r03E0)) bitOr:
+ ((rgb bitShift: -3) bitAnd: 16r001F).
- val := (((rgb bitShift: -15) bitAnd: 16r7C00) bitOr:
- ((rgb bitShift: -10) bitAnd: 16r03E0)) bitOr:
- ((rgb bitShift: -5) bitAnd: 16r001F).
  ^val < 1 ifTrue: [1] ifFalse: [val]].
 
  d = 12 ifTrue: [  "for indexing a color map with 4 bits per color component"
+ val := (((rgb bitShift: -12) bitAnd: 16r0F00) bitOr:
+ ((rgb bitShift: -8) bitAnd: 16r00F0)) bitOr:
+ ((rgb bitShift: -4) bitAnd: 16r000F).
- val := (((rgb bitShift: -18) bitAnd: 16r0F00) bitOr:
- ((rgb bitShift: -12) bitAnd: 16r00F0)) bitOr:
- ((rgb bitShift: -6) bitAnd: 16r000F).
  ^val < 1 ifTrue: [1] ifFalse: [val]].
 
  d = 9 ifTrue: [  "for indexing a color map with 3 bits per color component"
+ val := (((rgb bitShift: -15) bitAnd: 16r01C0) bitOr:
+ ((rgb bitShift: -10) bitAnd: 16r0038)) bitOr:
+ ((rgb bitShift: -5) bitAnd: 16r0007).
- val := (((rgb bitShift: -21) bitAnd: 16r01C0) bitOr:
- ((rgb bitShift: -14) bitAnd: 16r0038)) bitOr:
- ((rgb bitShift: -7) bitAnd: 16r0007).
  ^val < 1 ifTrue: [1] ifFalse: [val]]].
  d = 8 ifTrue: [^ self closestPixelValue8].
  d = 4 ifTrue: [^ self closestPixelValue4].
  d = 2 ifTrue: [^ self closestPixelValue2]..
  d = 1 ifTrue: [^ self closestPixelValue1].
 
  self error: 'unknown pixel depth: ', d printString
  !

Item was added:
+ (PackageInfo named: 'Graphics') postscript: '"The cache might hold incorrect values during 10->8 bits per component transition"
+ Color allSubInstancesDo: [:c | c flushCache].'!


Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Graphics-nice.285.mcz

Tobias Pape

On 01.01.2014, at 19:55, [hidden email] wrote:

> Nicolas Cellier uploaded a new version of Graphics to project The Inbox:
> http://source.squeak.org/inbox/Graphics-nice.285.mcz
>
> ==================== Summary ====================
>
> Name: Graphics-nice.285
> Author: nice
> Time: 1 January 2014, 8:53:32.416 pm
> UUID: 04aee02d-83ae-4b4d-aed9-968a6a7487db
> Ancestors: Graphics-nice.284
>
> Change Color implementation from 10 bits per (rgb) component to 8 bits per component.
> Several considerations motivate this change:
> - no Graphic output is using 10 bits;
Au contraire!
http://lmgtfy.com/?q=10+bit+graphics
https://nvidia.custhelp.com/app/answers/detail/a_id/3011/~/10-bit-per-color-support-on-nvidia-geforce-gpus
http://www.luminous-landscape.com/reviews/accessories/10bit.shtml
http://www.amd.com/us/Documents/10-Bit.pdf

Best
        -Tobias

> - alpha channel is already stored using 8 bits;
> - 8 bits matches nowadays most used 32 bits depth Form - thus it's an optimization.
> Note that the tolerance for testing Color components has to be increased to a value >= (1/255), I suggest 0.005.
>
> =============== Diff against Graphics-nice.284 ===============
>
> Item was added:
> + (PackageInfo named: 'Graphics') preamble: '"Change color components from 10 to 8 bits"
> + Color allSubInstancesDo:
> + [:c |
> + | rgb |
> + rgb := c instVarNamed: ''rgb''.
> + rgb := (rgb bitAnd: 16r3FC00000) >> 2 + (rgb bitAnd: 16rFF000) >> 2 + (rgb bitAnd: 16r3FC) >> 2.
> + c instVarNamed: ''rgb'' put: rgb; flushCache].'!
>
> Item was changed:
>  ----- Method: Color class>>initialize (in category 'class initialization') -----
>  initialize
>   "Color initialize"
>
>   "Details: Externally, the red, green, and blue components of color
>   are floats in the range [0.0..1.0]. Internally, they are represented
>   as integers in the range [0..ComponentMask] packing into a
>   small integer to save space and to allow fast hashing and
>   equality testing.
>
>   For a general description of color representations for computer
>   graphics, including the relationship between the RGB and HSV
>   color models used here, see Chapter 17 of Foley and van Dam,
>   Fundamentals of Interactive Computer Graphics, Addison-Wesley,
>   1982."
>
> + ComponentMask := 255.
> + HalfComponentMask := 128.  "used to round up in integer calculations"
> + ComponentMax := 255.0.  "a Float used to normalize components"
> + RedShift := 16.
> + GreenShift := 8.
> - ComponentMask := 1023.
> - HalfComponentMask := 512.  "used to round up in integer calculations"
> - ComponentMax := 1023.0.  "a Float used to normalize components"
> - RedShift := 20.
> - GreenShift := 10.
>   BlueShift := 0.
>
>   PureRed := self r: 1 g: 0 b: 0.
>   PureGreen := self r: 0 g: 1 b: 0.
>   PureBlue := self r: 0 g: 0 b: 1.
>   PureYellow := self r: 1 g: 1 b: 0.
>   PureCyan := self r: 0 g: 1 b: 1.
>   PureMagenta := self r: 1 g: 0 b: 1.
>
>   RandomStream := Random new.
>
>   self initializeIndexedColors.
>   self initializeGrayToIndexMap.
>   self initializeNames.
>   self initializeHighLights.
>  !
>
> Item was changed:
>  ----- Method: Color class>>initializeGrayToIndexMap (in category 'class initialization') -----
>  initializeGrayToIndexMap
>   "Build an array of gray values available in the 8-bit colormap. This array is indexed by a gray level between black (1) and white (256) and returns the pixel value for the corresponding gray level."
>   "Note: This method must be called after initializeIndexedColors, since it uses IndexedColors."
>   "Color initializeGrayToIndexMap"
>
>   | grayLevels grayIndices c distToClosest dist indexOfClosest |
>   "record the level and index of each gray in the 8-bit color table"
>   grayLevels := OrderedCollection new.
>   grayIndices := OrderedCollection new.
>   "Note: skip the first entry, which is reserved for transparent"
>   2 to: IndexedColors size do: [:i |
>   c := IndexedColors at: i.
>   c saturation = 0.0 ifTrue: [  "c is a gray"
> + grayLevels add: c privateBlue.  "top 8 bits; R, G, and B are the same"
> - grayLevels add: (c privateBlue) >> 2.  "top 8 bits; R, G, and B are the same"
>   grayIndices add: i - 1]].  "pixel values are zero-based"
>   grayLevels := grayLevels asArray.
>   grayIndices := grayIndices asArray.
>
>   "for each gray level in [0..255], select the closest match"
>   GrayToIndexMap := ByteArray new: 256.
>   0 to: 255 do: [:level |
>   distToClosest := 10000.  "greater than distance to any real gray"
>   1 to: grayLevels size do: [:i |
>   dist := (level - (grayLevels at: i)) abs.
>   dist < distToClosest ifTrue: [
>   distToClosest := dist.
>   indexOfClosest := grayIndices at: i]].
>   GrayToIndexMap at: (level + 1) put: indexOfClosest].
>  !
>
> Item was changed:
>  ----- Method: Color>>asHTMLColor (in category 'conversions') -----
>  asHTMLColor
> + ^'#' , (rgb printStringBase: 16 length: 6 padded: true)!
> - | s |
> - s := '#000000' copy.
> - s at: 2 put: (Character digitValue: ((rgb bitShift: -6 - RedShift) bitAnd: 15)).
> - s at: 3 put: (Character digitValue: ((rgb bitShift: -2 - RedShift) bitAnd: 15)).
> - s at: 4 put: (Character digitValue: ((rgb bitShift: -6 - GreenShift) bitAnd: 15)).
> - s at: 5 put: (Character digitValue: ((rgb bitShift: -2 - GreenShift) bitAnd: 15)).
> - s at: 6 put: (Character digitValue: ((rgb bitShift: -6 - BlueShift) bitAnd: 15)).
> - s at: 7 put: (Character digitValue: ((rgb bitShift: -2 - BlueShift) bitAnd: 15)).
> - ^ s!
>
> Item was changed:
>  ----- Method: Color>>closestPixelValue1 (in category 'conversions') -----
>  closestPixelValue1
>   "Return the nearest approximation to this color for a monochrome Form."
>
>   "fast special cases"
>   rgb = 0 ifTrue: [^ 1].  "black"
> + rgb = 16rFFFFFFF ifTrue: [^ 0].  "white"
> - rgb = 16r3FFFFFFF ifTrue: [^ 0].  "white"
>
>   self luminance > 0.5
>   ifTrue: [^ 0]  "white"
>   ifFalse: [^ 1].  "black"
>  !
>
> Item was changed:
>  ----- Method: Color>>closestPixelValue2 (in category 'conversions') -----
>  closestPixelValue2
>   "Return the nearest approximation to this color for a 2-bit deep Form."
>
>   | lum |
>   "fast special cases"
>   rgb = 0 ifTrue: [^ 1].  "black"
> + rgb = 16rFFFFFFF ifTrue: [^ 2].  "opaque white"
> - rgb = 16r3FFFFFFF ifTrue: [^ 2].  "opaque white"
>
>   lum := self luminance.
>   lum < 0.2 ifTrue: [^ 1].  "black"
>   lum > 0.6 ifTrue: [^ 2].  "opaque white"
>   ^ 3  "50% gray"
>  !
>
> Item was changed:
>  ----- Method: Color>>closestPixelValue4 (in category 'conversions') -----
>  closestPixelValue4
>   "Return the nearest approximation to this color for a 4-bit deep Form."
>
>   | bIndex |
>   "fast special cases"
>   rgb = 0 ifTrue: [^ 1].  "black"
> + rgb = 16rFFFFFFF ifTrue: [^ 2].  "opaque white"
> - rgb = 16r3FFFFFFF ifTrue: [^ 2].  "opaque white"
>
>   rgb = PureRed privateRGB ifTrue: [^ 4].
>   rgb = PureGreen privateRGB ifTrue: [^ 5].
>   rgb = PureBlue privateRGB ifTrue: [^ 6].
>   rgb = PureCyan privateRGB ifTrue: [^ 7].
>   rgb = PureYellow privateRGB ifTrue: [^ 8].
>   rgb = PureMagenta privateRGB ifTrue: [^ 9].
>
>   bIndex := (self luminance * 8.0) rounded.  "bIndex in [0..8]"
>   ^ #(
>   1 "black"
>   10 "1/8 gray"
>   11 "2/8 gray"
>   12 "3/8 gray"
>   3 "4/8 gray"
>   13 "5/8 gray"
>   14 "6/8 gray"
>   15 "7/8 gray"
>   2 "opaque white"
>   ) at: bIndex + 1.
>  !
>
> Item was changed:
>  ----- Method: Color>>closestPixelValue8 (in category 'conversions') -----
>  closestPixelValue8
>   "Return the nearest approximation to this color for an 8-bit deep Form."
>
>   "fast special cases"
>   rgb = 0 ifTrue: [^ 1].  "black"
> + rgb = 16rFFFFFFF ifTrue: [^ 255].  "white"
> - rgb = 16r3FFFFFFF ifTrue: [^ 255].  "white"
>
>   self saturation < 0.2 ifTrue: [
> + ^ GrayToIndexMap at: self privateGreen + 1.  "nearest gray"
> - ^ GrayToIndexMap at: (self privateGreen >> 2) + 1.  "nearest gray"
>   ] ifFalse: [
>   "compute nearest entry in the color cube"
>   ^ 40 +
>    ((((self privateRed * 5) + HalfComponentMask) // ComponentMask) * 36) +
>    ((((self privateBlue * 5) + HalfComponentMask) // ComponentMask) * 6) +
>    (((self privateGreen * 5) + HalfComponentMask) // ComponentMask)].
>  !
>
> Item was changed:
>  ----- Method: Color>>pixelValueForDepth: (in category 'conversions') -----
>  pixelValueForDepth: d
>   "Returns an integer representing the bits that appear in a single pixel of this color in a Form of the given depth. The depth must be one of 1, 2, 4, 8, 16, or 32. Contrast with pixelWordForDepth: and bitPatternForDepth:, which return either a 32-bit word packed with the given pixel value or a multiple-word Bitmap containing a pattern. The inverse is the class message colorFromPixelValue:depth:"
>   "Details: For depths of 8 or less, the result is a colorMap index. For depths of 16 and 32, it is a direct color value with 5 or 8 bits per color component."
>   "Transparency: The pixel value zero is reserved for transparent. For depths greater than 8, black maps to the darkest possible blue."
>
>   | val |
>   d > 8 "most common case"
>   ifTrue:
>   [d = 32 ifTrue: [
>   "eight bits per component; top 8 bits set to all ones (opaque alpha)"
> + ^rgb = 0 ifTrue: [16rFF000001] ifFalse: [rgb bitOr: 16rFF000000]].
> - val := (LargePositiveInteger new: 4)
> - at: 4 put: 16rFF;
> - at: 3 put: ((rgb bitShift: -22) bitAnd: 16rFF);
> - at: 2 put: ((rgb bitShift: -12) bitAnd: 16rFF);
> - at: 1 put: ((rgb bitShift: -2) bitAnd: 16rFF);
> - normalize. "normalize is not necessary as long as SmallInteger maxVal highBit < 32, but let's be future proof"
> - ^val < 16rFF000001 ifTrue: [16rFF000001] ifFalse: [val]].
>  
>   d = 16 ifTrue: [
>   "five bits per component; top bits ignored"
> + val := (((rgb bitShift: -9) bitAnd: 16r7C00) bitOr:
> + ((rgb bitShift: -6) bitAnd: 16r03E0)) bitOr:
> + ((rgb bitShift: -3) bitAnd: 16r001F).
> - val := (((rgb bitShift: -15) bitAnd: 16r7C00) bitOr:
> - ((rgb bitShift: -10) bitAnd: 16r03E0)) bitOr:
> - ((rgb bitShift: -5) bitAnd: 16r001F).
>   ^val < 1 ifTrue: [1] ifFalse: [val]].
>
>   d = 12 ifTrue: [  "for indexing a color map with 4 bits per color component"
> + val := (((rgb bitShift: -12) bitAnd: 16r0F00) bitOr:
> + ((rgb bitShift: -8) bitAnd: 16r00F0)) bitOr:
> + ((rgb bitShift: -4) bitAnd: 16r000F).
> - val := (((rgb bitShift: -18) bitAnd: 16r0F00) bitOr:
> - ((rgb bitShift: -12) bitAnd: 16r00F0)) bitOr:
> - ((rgb bitShift: -6) bitAnd: 16r000F).
>   ^val < 1 ifTrue: [1] ifFalse: [val]].
>
>   d = 9 ifTrue: [  "for indexing a color map with 3 bits per color component"
> + val := (((rgb bitShift: -15) bitAnd: 16r01C0) bitOr:
> + ((rgb bitShift: -10) bitAnd: 16r0038)) bitOr:
> + ((rgb bitShift: -5) bitAnd: 16r0007).
> - val := (((rgb bitShift: -21) bitAnd: 16r01C0) bitOr:
> - ((rgb bitShift: -14) bitAnd: 16r0038)) bitOr:
> - ((rgb bitShift: -7) bitAnd: 16r0007).
>   ^val < 1 ifTrue: [1] ifFalse: [val]]].
>   d = 8 ifTrue: [^ self closestPixelValue8].
>   d = 4 ifTrue: [^ self closestPixelValue4].
>   d = 2 ifTrue: [^ self closestPixelValue2]..
>   d = 1 ifTrue: [^ self closestPixelValue1].
>
>   self error: 'unknown pixel depth: ', d printString
>  !
>
> Item was added:
> + (PackageInfo named: 'Graphics') postscript: '"The cache might hold incorrect values during 10->8 bits per component transition"
> + Color allSubInstancesDo: [:c | c flushCache].'!
>
>



signature.asc (1K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Graphics-nice.285.mcz

Nicolas Cellier

2014/1/1 Tobias Pape <[hidden email]>

On 01.01.2014, at 19:55, [hidden email] wrote:

> Nicolas Cellier uploaded a new version of Graphics to project The Inbox:
> http://source.squeak.org/inbox/Graphics-nice.285.mcz
>
> ==================== Summary ====================
>
> Name: Graphics-nice.285
> Author: nice
> Time: 1 January 2014, 8:53:32.416 pm
> UUID: 04aee02d-83ae-4b4d-aed9-968a6a7487db
> Ancestors: Graphics-nice.284
>
> Change Color implementation from 10 bits per (rgb) component to 8 bits per component.
> Several considerations motivate this change:
> - no Graphic output is using 10 bits;

Au contraire!
http://lmgtfy.com/?q=10+bit+graphics
https://nvidia.custhelp.com/app/answers/detail/a_id/3011/~/10-bit-per-color-support-on-nvidia-geforce-gpus
http://www.luminous-landscape.com/reviews/accessories/10bit.shtml
http://www.amd.com/us/Documents/10-Bit.pdf

Best
        -Tobias

Thanks for the links Tobias, that's interesting.
Well, no graphics output in Squeak was what I meaned.
Squeak is far from being able to exploit those 10 bits, because it would require
- BitBlt support with a new format (30 bits depth)
- per device gamma correction
It's also unclear for me how the alpha channel is represented/processed (pre-processed?)

Do you have plans for such support?

Nicolas
 

> - alpha channel is already stored using 8 bits;
> - 8 bits matches nowadays most used 32 bits depth Form - thus it's an optimization.
> Note that the tolerance for testing Color components has to be increased to a value >= (1/255), I suggest 0.005.
>
> =============== Diff against Graphics-nice.284 ===============
>
> Item was added:
> + (PackageInfo named: 'Graphics') preamble: '"Change color components from 10 to 8 bits"
> + Color allSubInstancesDo:
> +     [:c |
> +     | rgb |
> +     rgb := c instVarNamed: ''rgb''.
> +     rgb := (rgb bitAnd: 16r3FC00000) >> 2 + (rgb bitAnd: 16rFF000) >> 2 + (rgb bitAnd: 16r3FC) >> 2.
> +     c instVarNamed: ''rgb'' put: rgb; flushCache].'!
>
> Item was changed:
>  ----- Method: Color class>>initialize (in category 'class initialization') -----
>  initialize
>       "Color initialize"
>
>       "Details: Externally, the red, green, and blue components of color
>       are floats in the range [0.0..1.0]. Internally, they are represented
>       as integers in the range [0..ComponentMask] packing into a
>       small integer to save space and to allow fast hashing and
>       equality testing.
>
>       For a general description of color representations for computer
>       graphics, including the relationship between the RGB and HSV
>       color models used here, see Chapter 17 of Foley and van Dam,
>       Fundamentals of Interactive Computer Graphics, Addison-Wesley,
>       1982."
>
> +     ComponentMask := 255.
> +     HalfComponentMask := 128.  "used to round up in integer calculations"
> +     ComponentMax := 255.0.  "a Float used to normalize components"
> +     RedShift := 16.
> +     GreenShift := 8.
> -     ComponentMask := 1023.
> -     HalfComponentMask := 512.  "used to round up in integer calculations"
> -     ComponentMax := 1023.0.  "a Float used to normalize components"
> -     RedShift := 20.
> -     GreenShift := 10.
>       BlueShift := 0.
>
>       PureRed          := self r: 1 g: 0 b: 0.
>       PureGreen        := self r: 0 g: 1 b: 0.
>       PureBlue         := self r: 0 g: 0 b: 1.
>       PureYellow       := self r: 1 g: 1 b: 0.
>       PureCyan         := self r: 0 g: 1 b: 1.
>       PureMagenta := self r: 1 g: 0 b: 1.
>
>       RandomStream := Random new.
>
>       self initializeIndexedColors.
>       self initializeGrayToIndexMap.
>       self initializeNames.
>       self initializeHighLights.
>  !
>
> Item was changed:
>  ----- Method: Color class>>initializeGrayToIndexMap (in category 'class initialization') -----
>  initializeGrayToIndexMap
>       "Build an array of gray values available in the 8-bit colormap. This array is indexed by a gray level between black (1) and white (256) and returns the pixel value for the corresponding gray level."
>       "Note: This method must be called after initializeIndexedColors, since it uses IndexedColors."
>       "Color initializeGrayToIndexMap"
>
>       | grayLevels grayIndices c distToClosest dist indexOfClosest |
>       "record the level and index of each gray in the 8-bit color table"
>       grayLevels := OrderedCollection new.
>       grayIndices := OrderedCollection new.
>       "Note: skip the first entry, which is reserved for transparent"
>       2 to: IndexedColors size do: [:i |
>               c := IndexedColors at: i.
>               c saturation = 0.0 ifTrue: [  "c is a gray"
> +                     grayLevels add: c privateBlue.  "top 8 bits; R, G, and B are the same"
> -                     grayLevels add: (c privateBlue) >> 2.  "top 8 bits; R, G, and B are the same"
>                       grayIndices add: i - 1]].  "pixel values are zero-based"
>       grayLevels := grayLevels asArray.
>       grayIndices := grayIndices asArray.
>
>       "for each gray level in [0..255], select the closest match"
>       GrayToIndexMap := ByteArray new: 256.
>       0 to: 255 do: [:level |
>               distToClosest := 10000.  "greater than distance to any real gray"
>               1 to: grayLevels size do: [:i |
>                       dist := (level - (grayLevels at: i)) abs.
>                       dist < distToClosest ifTrue: [
>                               distToClosest := dist.
>                               indexOfClosest := grayIndices at: i]].
>               GrayToIndexMap at: (level + 1) put: indexOfClosest].
>  !
>
> Item was changed:
>  ----- Method: Color>>asHTMLColor (in category 'conversions') -----
>  asHTMLColor
> +     ^'#' , (rgb printStringBase: 16 length: 6 padded: true)!
> -     | s |
> -     s := '#000000' copy.
> -     s at: 2 put: (Character digitValue: ((rgb bitShift: -6 - RedShift) bitAnd: 15)).
> -     s at: 3 put: (Character digitValue: ((rgb bitShift: -2 - RedShift) bitAnd: 15)).
> -     s at: 4 put: (Character digitValue: ((rgb bitShift: -6 - GreenShift) bitAnd: 15)).
> -     s at: 5 put: (Character digitValue: ((rgb bitShift: -2 - GreenShift) bitAnd: 15)).
> -     s at: 6 put: (Character digitValue: ((rgb bitShift: -6 - BlueShift) bitAnd: 15)).
> -     s at: 7 put: (Character digitValue: ((rgb bitShift: -2 - BlueShift) bitAnd: 15)).
> -     ^ s!
>
> Item was changed:
>  ----- Method: Color>>closestPixelValue1 (in category 'conversions') -----
>  closestPixelValue1
>       "Return the nearest approximation to this color for a monochrome Form."
>
>       "fast special cases"
>       rgb = 0 ifTrue: [^ 1].  "black"
> +     rgb = 16rFFFFFFF ifTrue: [^ 0].  "white"
> -     rgb = 16r3FFFFFFF ifTrue: [^ 0].  "white"
>
>       self luminance > 0.5
>               ifTrue: [^ 0]  "white"
>               ifFalse: [^ 1].  "black"
>  !
>
> Item was changed:
>  ----- Method: Color>>closestPixelValue2 (in category 'conversions') -----
>  closestPixelValue2
>       "Return the nearest approximation to this color for a 2-bit deep Form."
>
>       | lum |
>       "fast special cases"
>       rgb = 0 ifTrue: [^ 1].  "black"
> +     rgb = 16rFFFFFFF ifTrue: [^ 2].  "opaque white"
> -     rgb = 16r3FFFFFFF ifTrue: [^ 2].  "opaque white"
>
>       lum := self luminance.
>       lum < 0.2 ifTrue: [^ 1].  "black"
>       lum > 0.6 ifTrue: [^ 2].  "opaque white"
>       ^ 3  "50% gray"
>  !
>
> Item was changed:
>  ----- Method: Color>>closestPixelValue4 (in category 'conversions') -----
>  closestPixelValue4
>       "Return the nearest approximation to this color for a 4-bit deep Form."
>
>       | bIndex |
>       "fast special cases"
>       rgb = 0 ifTrue: [^ 1].  "black"
> +     rgb = 16rFFFFFFF ifTrue: [^ 2].  "opaque white"
> -     rgb = 16r3FFFFFFF ifTrue: [^ 2].  "opaque white"
>
>       rgb = PureRed privateRGB ifTrue: [^ 4].
>       rgb = PureGreen privateRGB ifTrue: [^ 5].
>       rgb = PureBlue privateRGB ifTrue: [^ 6].
>       rgb = PureCyan privateRGB ifTrue: [^ 7].
>       rgb = PureYellow privateRGB ifTrue: [^ 8].
>       rgb = PureMagenta privateRGB ifTrue: [^ 9].
>
>       bIndex := (self luminance * 8.0) rounded.  "bIndex in [0..8]"
>       ^ #(
>               1       "black"
>               10      "1/8 gray"
>               11      "2/8 gray"
>               12      "3/8 gray"
>               3       "4/8 gray"
>               13      "5/8 gray"
>               14      "6/8 gray"
>               15      "7/8 gray"
>               2       "opaque white"
>       ) at: bIndex + 1.
>  !
>
> Item was changed:
>  ----- Method: Color>>closestPixelValue8 (in category 'conversions') -----
>  closestPixelValue8
>       "Return the nearest approximation to this color for an 8-bit deep Form."
>
>       "fast special cases"
>       rgb = 0 ifTrue: [^ 1].  "black"
> +     rgb = 16rFFFFFFF ifTrue: [^ 255].  "white"
> -     rgb = 16r3FFFFFFF ifTrue: [^ 255].  "white"
>
>       self saturation < 0.2 ifTrue: [
> +             ^ GrayToIndexMap at: self privateGreen + 1.  "nearest gray"
> -             ^ GrayToIndexMap at: (self privateGreen >> 2) + 1.  "nearest gray"
>       ] ifFalse: [
>               "compute nearest entry in the color cube"
>               ^ 40 +
>                 ((((self privateRed * 5) + HalfComponentMask) // ComponentMask) * 36) +
>                 ((((self privateBlue * 5) + HalfComponentMask) // ComponentMask) * 6) +
>                 (((self privateGreen * 5) + HalfComponentMask) // ComponentMask)].
>  !
>
> Item was changed:
>  ----- Method: Color>>pixelValueForDepth: (in category 'conversions') -----
>  pixelValueForDepth: d
>       "Returns an integer representing the bits that appear in a single pixel of this color in a Form of the given depth. The depth must be one of 1, 2, 4, 8, 16, or 32. Contrast with pixelWordForDepth: and bitPatternForDepth:, which return either a 32-bit word packed with the given pixel value or a multiple-word Bitmap containing a pattern. The inverse is the class message colorFromPixelValue:depth:"
>       "Details: For depths of 8 or less, the result is a colorMap index. For depths of 16 and 32, it is a direct color value with 5 or 8 bits per color component."
>       "Transparency: The pixel value zero is reserved for transparent. For depths greater than 8, black maps to the darkest possible blue."
>
>       | val |
>       d > 8 "most common case"
>               ifTrue:
>                       [d = 32 ifTrue: [
>                               "eight bits per component; top 8 bits set to all ones (opaque alpha)"
> +                             ^rgb = 0 ifTrue: [16rFF000001] ifFalse: [rgb bitOr: 16rFF000000]].
> -                             val := (LargePositiveInteger new: 4)
> -                                     at: 4 put: 16rFF;
> -                                     at: 3 put: ((rgb bitShift: -22) bitAnd: 16rFF);
> -                                     at: 2 put: ((rgb bitShift: -12) bitAnd: 16rFF);
> -                                     at: 1 put: ((rgb bitShift: -2) bitAnd: 16rFF);
> -                                     normalize. "normalize is not necessary as long as SmallInteger maxVal highBit < 32, but let's be future proof"
> -                             ^val < 16rFF000001 ifTrue: [16rFF000001] ifFalse: [val]].
>
>                       d = 16 ifTrue: [
>                               "five bits per component; top bits ignored"
> +                             val := (((rgb bitShift: -9) bitAnd: 16r7C00) bitOr:
> +                                      ((rgb bitShift: -6) bitAnd: 16r03E0)) bitOr:
> +                                      ((rgb bitShift: -3) bitAnd: 16r001F).
> -                             val := (((rgb bitShift: -15) bitAnd: 16r7C00) bitOr:
> -                                      ((rgb bitShift: -10) bitAnd: 16r03E0)) bitOr:
> -                                      ((rgb bitShift: -5) bitAnd: 16r001F).
>                               ^val < 1 ifTrue: [1] ifFalse: [val]].
>
>                       d = 12 ifTrue: [  "for indexing a color map with 4 bits per color component"
> +                             val := (((rgb bitShift: -12) bitAnd: 16r0F00) bitOr:
> +                                      ((rgb bitShift: -8) bitAnd: 16r00F0)) bitOr:
> +                                      ((rgb bitShift: -4) bitAnd: 16r000F).
> -                             val := (((rgb bitShift: -18) bitAnd: 16r0F00) bitOr:
> -                                      ((rgb bitShift: -12) bitAnd: 16r00F0)) bitOr:
> -                                      ((rgb bitShift: -6) bitAnd: 16r000F).
>                               ^val < 1 ifTrue: [1] ifFalse: [val]].
>
>                       d = 9 ifTrue: [  "for indexing a color map with 3 bits per color component"
> +                             val := (((rgb bitShift: -15) bitAnd: 16r01C0) bitOr:
> +                                      ((rgb bitShift: -10) bitAnd: 16r0038)) bitOr:
> +                                      ((rgb bitShift: -5) bitAnd: 16r0007).
> -                             val := (((rgb bitShift: -21) bitAnd: 16r01C0) bitOr:
> -                                      ((rgb bitShift: -14) bitAnd: 16r0038)) bitOr:
> -                                      ((rgb bitShift: -7) bitAnd: 16r0007).
>                               ^val < 1 ifTrue: [1] ifFalse: [val]]].
>       d = 8 ifTrue: [^ self closestPixelValue8].
>       d = 4 ifTrue: [^ self closestPixelValue4].
>       d = 2 ifTrue: [^ self closestPixelValue2]..
>       d = 1 ifTrue: [^ self closestPixelValue1].
>
>       self error: 'unknown pixel depth: ', d printString
>  !
>
> Item was added:
> + (PackageInfo named: 'Graphics') postscript: '"The cache might hold incorrect values during 10->8 bits per component transition"
> + Color allSubInstancesDo: [:c | c flushCache].'!
>
>







Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Graphics-nice.285.mcz

Tobias Pape
r
On 02.01.2014, at 15:14, Nicolas Cellier <[hidden email]> wrote:

>
> 2014/1/1 Tobias Pape <[hidden email]>
>
> On 01.01.2014, at 19:55, [hidden email] wrote:
>
> > Nicolas Cellier uploaded a new version of Graphics to project The Inbox:
> > http://source.squeak.org/inbox/Graphics-nice.285.mcz
> >
> > ==================== Summary ====================
> >
> > Name: Graphics-nice.285
> > Author: nice
> > Time: 1 January 2014, 8:53:32.416 pm
> > UUID: 04aee02d-83ae-4b4d-aed9-968a6a7487db
> > Ancestors: Graphics-nice.284
> >
> > Change Color implementation from 10 bits per (rgb) component to 8 bits per component.
> > Several considerations motivate this change:
> > - no Graphic output is using 10 bits;
>
> Au contraire!
> http://lmgtfy.com/?q=10+bit+graphics
> https://nvidia.custhelp.com/app/answers/detail/a_id/3011/~/10-bit-per-color-support-on-nvidia-geforce-gpus
> http://www.luminous-landscape.com/reviews/accessories/10bit.shtml
> http://www.amd.com/us/Documents/10-Bit.pdf
>
> Best
>         -Tobias
>
> Thanks for the links Tobias, that's interesting.
> Well, no graphics output in Squeak was what I meaned.
> Squeak is far from being able to exploit those 10 bits, because it would require
> - BitBlt support with a new format (30 bits depth)
> - per device gamma correction
> It's also unclear for me how the alpha channel is represented/processed (pre-processed?)
>
> Do you have plans for such support?
>

No, it is just that the terms “graphics output 10bit” triggered something for me.
(It’s famous by Apple not providing it natively, some people say).
I am not against this change, but just wanted to lighten the webs around 10bit color.

Best
        -Tobias



signature.asc (1K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: The Inbox: Graphics-nice.285.mcz

Bert Freudenberg
In reply to this post by Nicolas Cellier

On 02.01.2014, at 15:14, Nicolas Cellier <[hidden email]> wrote:


2014/1/1 Tobias Pape <[hidden email]>

On 01.01.2014, at 19:55, [hidden email] wrote:

> Nicolas Cellier uploaded a new version of Graphics to project The Inbox:
> http://source.squeak.org/inbox/Graphics-nice.285.mcz
>
> ==================== Summary ====================
>
> Name: Graphics-nice.285
> Author: nice
> Time: 1 January 2014, 8:53:32.416 pm
> UUID: 04aee02d-83ae-4b4d-aed9-968a6a7487db
> Ancestors: Graphics-nice.284
>
> Change Color implementation from 10 bits per (rgb) component to 8 bits per component.
> Several considerations motivate this change:
> - no Graphic output is using 10 bits;

Au contraire!
http://lmgtfy.com/?q=10+bit+graphics
https://nvidia.custhelp.com/app/answers/detail/a_id/3011/~/10-bit-per-color-support-on-nvidia-geforce-gpus
http://www.luminous-landscape.com/reviews/accessories/10bit.shtml
http://www.amd.com/us/Documents/10-Bit.pdf

Best
        -Tobias

Thanks for the links Tobias, that's interesting.
Well, no graphics output in Squeak was what I meaned.
Squeak is far from being able to exploit those 10 bits, because it would require
- BitBlt support with a new format (30 bits depth)
- per device gamma correction
It's also unclear for me how the alpha channel is represented/processed (pre-processed?)

You need to use OpenGL anyway to create a 10 bit display surface. I think you will still get an 8 bit alpha channel if you request 10 bits each for r, g, and b. But a typical texture format would be RGB10_A2 (with just 2 bits of alpha). Refer for example to the AMD document Tobias googled.

It makes little sense to use 10 bit color for a regular bitblt-based UI, so that is no reason to object.

However, looking at Graphics-nice.285, the only method that gets simpler is asHTMLColor. So except for reducing the resolution by 8 bits, what benefit do we have? I thought the original reason was to get rid of TranslucentColor, but since that would result in more LargeInts you didn't do it, right? 

- Bert -