tinku99 wrote:
Could you explain the base mechanism,
I already explained it
in the documentation.
Quote:
MsgBox % blue.rgb()
The specific section of the documentation which explains this is:
Quote:
When the key of an operation (the first or only parameter) has no pre-existing value, the object's base is invoked. When a standard base object is invoked, it does the following:
...
- If this is a get or call operation, search for a matching key in the base object's own fields.
...
Call: If found, the field is called with the target object as the first parameter.
Source: AutoHotkey_L - Objects When you call
blue.rgb(), it fails to find
blue.rgb and so uses
blue.base.rgb instead.
Only when a method is invoked through this mechanism is the target object (
blue) automatically inserted into the parameter list.
Logic follows:
If
blue directly contains
rgb it has no particular meaning, so we assume
blue itself isn't relevant to the function-call (and wouldn't be expected as a parameter to the function). On the other hand, since
blue.base is intended to define the
behaviour of blue, there's a good chance that
blue is relevant, and may be expected and required by the function.
Quote:
MsgBox % Color.rgb() ; Displays blank, why??
That's the same as
f:="Color_RGB",%f%(); it won't work since it's missing a required parameter, but won't complain since it's essentially a dynamic function call.
Although in this particular example it isn't appropriate (since
Color is intended to define the behaviour of colors, not define a particular color), it can be worked around like this:
Code:
Color := Object("R", 0, "G", 0, "B", 255, "base", Object("rgb", "Color_RGB"))
If you need more information, please be more specific.
Quote:
; Displays 65535.
No, it doesn't...
Edit: In your Rosetta Code example, why use hotkeys? I would expect the sample to do its piece, then exit.
Quote:
img._SetCapacity(width * height)
This will allow img to hold up to
width*height objects, but it will only ever hold at most
height objects (see below).
Quote:
bitmap[height, width] := color
This will create an object for each unique 'height' value and create a field within said object for each unique 'width' value; i.e.
Code:
bitmap[1, 1] := x
bitmap[1, 2] := y
bitmap[2, 1] := z
This creates
two objects in bitmap: bitmap[1] containing two fields (1=x and 2=y) and bitmap[2] containing one field (1=z).
The idea of representing colours with a single RGB value internally and using accessors for the individual components - rather than vice versa as in your example - is that it would be more common to retrieve all three components (i.e. rgb) than one or two individual components. Each object and invocation (each pixel object, clr.R, clr.G, etc.) has a cost. Bitmap_Fill is a particularly "good" example of where
not to use objects. "Worse" example pending...
Reedit: Try this:
Code:
; Example at the bottom.
Bitmap(width = 1, height = 1, background = 0)
{
static BitmapType
if !BitmapType
BitmapType
:= Object("fill" , "Bitmap_Fill" ; img.fill(c)
, "__get" , "Bitmap_Get" ; img[...]
, "__set" , "Bitmap_Set") ; img[...] := ...
img := Object("width" , width
, "height", height
, "base" , BitmapType)
img._SetCapacity("_data", width * height * 4)
img.data := img._GetAddress("_data") ; Safe until _data is resized.
img.fill(background)
Return img
}
Bitmap_Get(bitmap, x, y, z="")
{
if z= ; return RGB values,
return v:=NumGet(bitmap.data, y*height + x*4)
else if (x="color") ; unless a color() is specifically requested
return color(v:=bitmap[y,z])
}
Bitmap_Set(bitmap, x, y, color, z="")
{
if (x="color") ; for symmetry:
x:=y, y:=color, color:=z ; params << 1
NumPut(IsObject(color)?color.RGB:color, bitmap.data, y*height + x*4)
return color
}
Bitmap_Fill(bitmap, color)
{
DllCall("ntdll\RtlFillMemoryUlong", "ptr", bitmap.data
, "uint", bitmap.width * bitmap.height * 4
, "uint", IsObject(color)?color.RGB:color)
}
Color(c_r, g="", b="")
{
static ColorType
if !ColorType
ColorType := Object("rgb", 0
, "__Set", "Color_Set"
, "__Get", "Color_Get")
if g= ; store an rgb value directly:
return Object("base", ColorType, "rgb", c_r)
else ; let Color_Set do all the calculations:
return Object("base", ColorType, "r", c_r, "g", g, "b", b)
}
Color_Get(clr, name)
{
static R=16,G=8,B=0
if name in R,G,B
return v := (clr.RGB >> %name%) & 255
}
Color_Set(clr, name, val)
{
static R=16,G=8,B=0
if name in R,G,B
{
val &= 255, n := %name%
v := clr.rgb := (val << n) | (clr.rgb & ~(0xff << n))
return val
}
}
test:
blue := color(0,0,255) ; rgb
cyan := color(0,255,255)
MsgBox % "blue:r,g,b,rgb " blue.R "," blue.G "," blue.B ", " blue.rgb
MsgBox % "cyan:r,g,b,rgb " cyan.R "," cyan.G "," cyan.B ", " cyan.RGB
blue_square := Bitmap(10, 10, blue)
x := color(blue_square[4,4]) ; get pixel(4,4)
msgbox % "blue: 4,4,R,G,B, RGB: " x.R ", " x.G ", " x.B ", " x.rgb
blue_square[4,4] := cyan ; set pixel(4,4)
x := blue_square.color[4,4] ; get pixel(4,4)
msgbox % "cyan: 4,4,R,G,B, RGB: " x.R ", " x.G ", " x.B ", " x.rgb
return
Color(), Color_Get(), etc. are the same as the example under
Meta-Functions, but more compact. Bitmap() shows how to use the new mode of _SetCapacity, and _GetAddress. Bitmap_Get and Bitmap_Set show how to index into a raw bitmap using NumGet/NumPut. They also demonstrate an
indexable property^ "img.color[x,y]" which is the same as "img[x,y]" but returns a Color object instead of an RGB value. Bitmap_Fill shows the most efficient way I'm aware of for filling raw (32-bit) bitmap data (or any block of memory).