You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

344 lines
6.7 KiB

  1. package pixel
  2. import (
  3. "encoding/binary"
  4. "errors"
  5. "image"
  6. "image/color"
  7. "image/draw"
  8. "maze.io/x/pixel/pixelcolor"
  9. )
  10. type Format int
  11. const (
  12. UnknownFormat Format = iota
  13. MHMSBFormat
  14. MVLSBFormat
  15. RGB332Format
  16. RGB565Format
  17. RGB888Format
  18. RGBA4444Format
  19. RGBA5551Format
  20. )
  21. func (f Format) ColorModel() color.Model {
  22. switch f {
  23. case MHMSBFormat, MVLSBFormat:
  24. return pixelcolor.BitModel
  25. case RGB332Format:
  26. return pixelcolor.RGB332Model
  27. case RGB565Format:
  28. return pixelcolor.RGB565Model
  29. case RGB888Format:
  30. return pixelcolor.RGB888Model
  31. case RGBA4444Format:
  32. return pixelcolor.RGBA4444Model
  33. case RGBA5551Format:
  34. return pixelcolor.RGBA5551Model
  35. default:
  36. return color.RGBAModel
  37. }
  38. }
  39. type Image interface {
  40. draw.Image
  41. }
  42. type Bitmap struct {
  43. Rect image.Rectangle
  44. Pix []byte
  45. Stride int
  46. Format Format
  47. }
  48. func NewBitmap(w, h int) *Bitmap {
  49. var (
  50. area = w * h
  51. pix = area >> 3
  52. )
  53. if pix<<3 != area {
  54. pix++
  55. }
  56. return &Bitmap{
  57. Rect: image.Rectangle{Max: image.Point{X: w, Y: h}},
  58. Pix: make([]byte, pix),
  59. Stride: w,
  60. Format: MVLSBFormat,
  61. }
  62. }
  63. func (b *Bitmap) ColorModel() color.Model {
  64. return b.Format.ColorModel()
  65. }
  66. func (b *Bitmap) Bounds() image.Rectangle {
  67. return b.Rect
  68. }
  69. func (b *Bitmap) At(x, y int) color.Color {
  70. if x < 0 || y < 0 || x >= b.Rect.Max.X || y >= b.Rect.Max.Y {
  71. return pixelcolor.Off
  72. }
  73. offset, mask := b.PixOffset(x, y)
  74. if offset >= len(b.Pix) {
  75. return pixelcolor.Off
  76. }
  77. return pixelcolor.Bit(b.Pix[offset]&byte(mask) != 0)
  78. }
  79. func (b *Bitmap) PixOffset(x, y int) (int, uint) {
  80. if b.Format == MVLSBFormat {
  81. offset := (y>>3)*b.Stride + x
  82. bit := uint(y & 7)
  83. return offset, 1 << bit
  84. }
  85. offset := (y*b.Stride + x) >> 3
  86. bit := uint(7 - (y & 7))
  87. return offset, 1 << bit
  88. }
  89. func (b *Bitmap) Set(x, y int, c color.Color) {
  90. b.SetBit(x, y, pixelcolor.ToBit(c))
  91. }
  92. func (b *Bitmap) SetBit(x, y int, c pixelcolor.Bit) {
  93. offset, mask := b.PixOffset(x, y)
  94. if offset < 0 || offset >= len(b.Pix) {
  95. return
  96. }
  97. if c {
  98. b.Pix[offset] |= byte(mask)
  99. } else {
  100. b.Pix[offset] &= ^byte(mask)
  101. }
  102. }
  103. type RGB332 struct {
  104. Rect image.Rectangle
  105. Pix []byte
  106. Stride int
  107. }
  108. func (b *RGB332) Bounds() image.Rectangle {
  109. return b.Rect
  110. }
  111. func (b *RGB332) At(x, y int) color.Color {
  112. if !(image.Point{X: x, Y: y}).In(b.Rect) {
  113. return pixelcolor.RGB332(0)
  114. }
  115. return pixelcolor.RGB332(b.Pix[y*b.Stride+x])
  116. }
  117. func (b *RGB332) Set(x, y int, c color.Color) {
  118. if !(image.Point{X: x, Y: y}).In(b.Rect) {
  119. return
  120. }
  121. b.Pix[y*b.Stride+x] = byte(pixelcolor.ToRGB332(c))
  122. }
  123. func (RGB332) ColorModel() color.Model {
  124. return pixelcolor.RGB332Model
  125. }
  126. func NewRGB332(w, h int) *RGB332 {
  127. return &RGB332{
  128. Rect: image.Rectangle{Max: image.Point{X: w, Y: h}},
  129. Stride: w,
  130. Pix: make([]byte, w*h),
  131. }
  132. }
  133. type RGB565 struct {
  134. Rect image.Rectangle
  135. Pix []byte
  136. Stride int
  137. }
  138. func (b *RGB565) Bounds() image.Rectangle {
  139. return b.Rect
  140. }
  141. func (b *RGB565) At(x, y int) color.Color {
  142. if !(image.Point{X: x, Y: y}).In(b.Rect) {
  143. return pixelcolor.RGB565(0)
  144. }
  145. return pixelcolor.RGB565(binary.BigEndian.Uint16(b.Pix[b.OffsetOf(x, y):]))
  146. }
  147. func (b *RGB565) Set(x, y int, c color.Color) {
  148. if !(image.Point{X: x, Y: y}).In(b.Rect) {
  149. return
  150. }
  151. binary.BigEndian.PutUint16(b.Pix[b.OffsetOf(x, y):], uint16(pixelcolor.ToRGB565(c)))
  152. }
  153. func (b *RGB565) OffsetOf(x, y int) (offset int) {
  154. return y*b.Stride + x*2
  155. }
  156. func (RGB565) ColorModel() color.Model {
  157. return pixelcolor.RGB565Model
  158. }
  159. func NewRGB565(w, h int) *RGB565 {
  160. return &RGB565{
  161. Rect: image.Rectangle{Max: image.Point{X: w, Y: h}},
  162. Pix: make([]byte, w*h*2),
  163. Stride: w * 2,
  164. }
  165. }
  166. type RGB888 struct {
  167. Rect image.Rectangle
  168. Pix []byte
  169. Stride int
  170. }
  171. func (b *RGB888) Bounds() image.Rectangle {
  172. return b.Rect
  173. }
  174. func (b *RGB888) At(x, y int) color.Color {
  175. if !(image.Point{X: x, Y: y}).In(b.Rect) {
  176. return color.Black
  177. }
  178. v := b.Pix[b.OffsetOf(x, y):]
  179. return pixelcolor.RGB888{v[0], v[1], v[2]}
  180. }
  181. func (b *RGB888) Set(x, y int, c color.Color) {
  182. if !(image.Point{X: x, Y: y}).In(b.Rect) {
  183. return
  184. }
  185. v := pixelcolor.ToRGB888(c)
  186. copy(b.Pix[b.OffsetOf(x, y):], []byte{v.R, v.G, v.B})
  187. }
  188. func (b *RGB888) OffsetOf(x, y int) (offset int) {
  189. return y*b.Stride + x*3
  190. }
  191. func (b *RGB888) ColorModel() color.Model {
  192. return pixelcolor.RGB888Model
  193. }
  194. func NewRGB888(w, h int) *RGB888 {
  195. return &RGB888{
  196. Rect: image.Rectangle{Max: image.Point{X: w, Y: h}},
  197. Pix: make([]byte, w*h*3),
  198. Stride: w * 3,
  199. }
  200. }
  201. type RGBA4444 struct {
  202. Rect image.Rectangle
  203. Pix []byte
  204. Stride int
  205. }
  206. func (b *RGBA4444) Bounds() image.Rectangle {
  207. return b.Rect
  208. }
  209. func (b *RGBA4444) At(x, y int) color.Color {
  210. if !(image.Point{X: x, Y: y}).In(b.Rect) {
  211. return color.Black
  212. }
  213. return pixelcolor.RGBA4444(binary.BigEndian.Uint16(b.Pix[b.OffsetOf(x, y):]))
  214. }
  215. func (b *RGBA4444) Set(x, y int, c color.Color) {
  216. if !(image.Point{X: x, Y: y}).In(b.Rect) {
  217. return
  218. }
  219. binary.BigEndian.PutUint16(b.Pix[b.OffsetOf(x, y):], uint16(pixelcolor.ToRGBA4444(c)))
  220. }
  221. func (b *RGBA4444) OffsetOf(x, y int) (offset int) {
  222. return y*b.Stride + x*3
  223. }
  224. func (b *RGBA4444) ColorModel() color.Model {
  225. return pixelcolor.RGBA4444Model
  226. }
  227. func NewRGBA4444(w, h int) *RGBA4444 {
  228. return &RGBA4444{
  229. Rect: image.Rectangle{Max: image.Point{X: w, Y: h}},
  230. Pix: make([]byte, w*h*2),
  231. Stride: w * 2,
  232. }
  233. }
  234. type RGBA5551 struct {
  235. Rect image.Rectangle
  236. Pix []byte
  237. Stride int
  238. }
  239. func (b *RGBA5551) Bounds() image.Rectangle {
  240. return b.Rect
  241. }
  242. func (b *RGBA5551) At(x, y int) color.Color {
  243. if !(image.Point{X: x, Y: y}).In(b.Rect) {
  244. return color.Black
  245. }
  246. return pixelcolor.RGBA5551(binary.BigEndian.Uint16(b.Pix[b.OffsetOf(x, y):]))
  247. }
  248. func (b *RGBA5551) Set(x, y int, c color.Color) {
  249. if !(image.Point{X: x, Y: y}).In(b.Rect) {
  250. return
  251. }
  252. binary.BigEndian.PutUint16(b.Pix[b.OffsetOf(x, y):], uint16(pixelcolor.ToRGBA5551(c)))
  253. }
  254. func (b *RGBA5551) OffsetOf(x, y int) (offset int) {
  255. return y*b.Stride + x*3
  256. }
  257. func (b *RGBA5551) ColorModel() color.Model {
  258. return pixelcolor.RGBA5551Model
  259. }
  260. func NewRGBA5551(w, h int) *RGBA5551 {
  261. return &RGBA5551{
  262. Rect: image.Rectangle{Max: image.Point{X: w, Y: h}},
  263. Pix: make([]byte, w*h*2),
  264. Stride: w * 2,
  265. }
  266. }
  267. func New(width, height int, format Format) (Image, error) {
  268. switch format {
  269. case MHMSBFormat, MVLSBFormat:
  270. b := NewBitmap(width, height)
  271. b.Format = format
  272. return b, nil
  273. case RGB332Format:
  274. return NewRGB332(width, height), nil
  275. case RGB565Format:
  276. return NewRGB565(width, height), nil
  277. case RGB888Format:
  278. return NewRGB888(width, height), nil
  279. case RGBA4444Format:
  280. return NewRGBA4444(width, height), nil
  281. case RGBA5551Format:
  282. return NewRGBA5551(width, height), nil
  283. default:
  284. return nil, errors.New("framebuffer: invalid format")
  285. }
  286. }
  287. func Must(width, height int, format Format) Image {
  288. b, err := New(width, height, format)
  289. if err != nil {
  290. panic(err)
  291. }
  292. return b
  293. }