image.go 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866
  1. // Copyright 2014 Hajime Hoshi
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package ebiten
  15. import (
  16. "fmt"
  17. "image"
  18. "image/color"
  19. "github.com/hajimehoshi/ebiten/v2/internal/affine"
  20. "github.com/hajimehoshi/ebiten/v2/internal/driver"
  21. "github.com/hajimehoshi/ebiten/v2/internal/graphics"
  22. "github.com/hajimehoshi/ebiten/v2/internal/mipmap"
  23. )
  24. // panicOnErrorAtImageAt indicates whether (*Image).At panics on an error or not.
  25. // This value is set only on testing.
  26. var panicOnErrorAtImageAt bool
  27. // Image represents a rectangle set of pixels.
  28. // The pixel format is alpha-premultiplied RGBA.
  29. // Image implements image.Image and draw.Image.
  30. type Image struct {
  31. // addr holds self to check copying.
  32. // See strings.Builder for similar examples.
  33. addr *Image
  34. mipmap *mipmap.Mipmap
  35. bounds image.Rectangle
  36. original *Image
  37. screen bool
  38. }
  39. func (i *Image) copyCheck() {
  40. if i.addr != i {
  41. panic("ebiten: illegal use of non-zero Image copied by value")
  42. }
  43. }
  44. // Size returns the size of the image.
  45. func (i *Image) Size() (width, height int) {
  46. s := i.Bounds().Size()
  47. return s.X, s.Y
  48. }
  49. func (i *Image) isDisposed() bool {
  50. return i.mipmap == nil
  51. }
  52. func (i *Image) isSubImage() bool {
  53. return i.original != nil
  54. }
  55. // Clear resets the pixels of the image into 0.
  56. //
  57. // When the image is disposed, Clear does nothing.
  58. func (i *Image) Clear() {
  59. i.Fill(color.Transparent)
  60. }
  61. var (
  62. emptyImage = NewImage(3, 3)
  63. emptySubImage = emptyImage.SubImage(image.Rect(1, 1, 2, 2)).(*Image)
  64. )
  65. func init() {
  66. w, h := emptyImage.Size()
  67. pix := make([]byte, 4*w*h)
  68. for i := range pix {
  69. pix[i] = 0xff
  70. }
  71. // As emptyImage is used at Fill, use ReplacePixels instead.
  72. emptyImage.ReplacePixels(pix)
  73. }
  74. // Fill fills the image with a solid color.
  75. //
  76. // When the image is disposed, Fill does nothing.
  77. func (i *Image) Fill(clr color.Color) {
  78. // Use the original size to cover the entire region (#1691).
  79. // DrawImage automatically clips the rendering region.
  80. orig := i
  81. if i.isSubImage() {
  82. orig = i.original
  83. }
  84. w, h := orig.Size()
  85. op := &DrawImageOptions{}
  86. op.GeoM.Scale(float64(w), float64(h))
  87. r, g, b, a := clr.RGBA()
  88. var rf, gf, bf, af float64
  89. if a > 0 {
  90. rf = float64(r) / float64(a)
  91. gf = float64(g) / float64(a)
  92. bf = float64(b) / float64(a)
  93. af = float64(a) / 0xffff
  94. }
  95. op.ColorM.Scale(rf, gf, bf, af)
  96. op.CompositeMode = CompositeModeCopy
  97. i.DrawImage(emptySubImage, op)
  98. }
  99. func canSkipMipmap(geom GeoM, filter driver.Filter) bool {
  100. if filter != driver.FilterLinear {
  101. return true
  102. }
  103. return geom.det2x2() >= 0.999
  104. }
  105. // DrawImageOptions represents options for DrawImage.
  106. type DrawImageOptions struct {
  107. // GeoM is a geometry matrix to draw.
  108. // The default (zero) value is identity, which draws the image at (0, 0).
  109. GeoM GeoM
  110. // ColorM is a color matrix to draw.
  111. // The default (zero) value is identity, which doesn't change any color.
  112. ColorM ColorM
  113. // CompositeMode is a composite mode to draw.
  114. // The default (zero) value is regular alpha blending.
  115. CompositeMode CompositeMode
  116. // Filter is a type of texture filter.
  117. // The default (zero) value is FilterNearest.
  118. Filter Filter
  119. }
  120. // DrawImage draws the given image on the image i.
  121. //
  122. // DrawImage accepts the options. For details, see the document of
  123. // DrawImageOptions.
  124. //
  125. // For drawing, the pixels of the argument image at the time of this call is
  126. // adopted. Even if the argument image is mutated after this call, the drawing
  127. // result is never affected.
  128. //
  129. // When the image i is disposed, DrawImage does nothing.
  130. // When the given image img is disposed, DrawImage panics.
  131. //
  132. // When the given image is as same as i, DrawImage panics.
  133. //
  134. // DrawImage works more efficiently as batches
  135. // when the successive calls of DrawImages satisfy the below conditions:
  136. //
  137. // * All render targets are same (A in A.DrawImage(B, op))
  138. // * Either all ColorM element values are same or all the ColorM have only
  139. // diagonal ('scale') elements
  140. // * If only (*ColorM).Scale is applied to a ColorM, the ColorM has only
  141. // diagonal elements. The other ColorM functions might modify the other
  142. // elements.
  143. // * All CompositeMode values are same
  144. // * All Filter values are same
  145. //
  146. // Even when all the above conditions are satisfied, multiple draw commands can
  147. // be used in really rare cases. Ebiten images usually share an internal
  148. // automatic texture atlas, but when you consume the atlas, or you create a huge
  149. // image, those images cannot be on the same texture atlas. In this case, draw
  150. // commands are separated. The texture atlas size is 4096x4096 so far. Another
  151. // case is when you use an offscreen as a render source. An offscreen doesn't
  152. // share the texture atlas with high probability.
  153. //
  154. // For more performance tips, see https://ebiten.org/documents/performancetips.html
  155. func (i *Image) DrawImage(img *Image, options *DrawImageOptions) {
  156. i.copyCheck()
  157. if img.isDisposed() {
  158. panic("ebiten: the given image to DrawImage must not be disposed")
  159. }
  160. if i.isDisposed() {
  161. return
  162. }
  163. dstBounds := i.Bounds()
  164. dstRegion := driver.Region{
  165. X: float32(dstBounds.Min.X),
  166. Y: float32(dstBounds.Min.Y),
  167. Width: float32(dstBounds.Dx()),
  168. Height: float32(dstBounds.Dy()),
  169. }
  170. // Calculate vertices before locking because the user can do anything in
  171. // options.ImageParts interface without deadlock (e.g. Call Image functions).
  172. if options == nil {
  173. options = &DrawImageOptions{}
  174. }
  175. bounds := img.Bounds()
  176. mode := driver.CompositeMode(options.CompositeMode)
  177. filter := driver.Filter(options.Filter)
  178. a, b, c, d, tx, ty := options.GeoM.elements32()
  179. sx0 := float32(bounds.Min.X)
  180. sy0 := float32(bounds.Min.Y)
  181. sx1 := float32(bounds.Max.X)
  182. sy1 := float32(bounds.Max.Y)
  183. vs := graphics.QuadVertices(sx0, sy0, sx1, sy1, a, b, c, d, tx, ty, 1, 1, 1, 1)
  184. is := graphics.QuadIndices()
  185. srcs := [graphics.ShaderImageNum]*mipmap.Mipmap{img.mipmap}
  186. i.mipmap.DrawTriangles(srcs, vs, is, options.ColorM.affineColorM(), mode, filter, driver.AddressUnsafe, dstRegion, driver.Region{}, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, false, canSkipMipmap(options.GeoM, filter))
  187. }
  188. // Vertex represents a vertex passed to DrawTriangles.
  189. type Vertex struct {
  190. // DstX and DstY represents a point on a destination image.
  191. DstX float32
  192. DstY float32
  193. // SrcX and SrcY represents a point on a source image.
  194. // Be careful that SrcX/SrcY coordinates are on the image's bounds.
  195. // This means that a left-upper point of a sub-image might not be (0, 0).
  196. SrcX float32
  197. SrcY float32
  198. // ColorR/ColorG/ColorB/ColorA represents color scaling values.
  199. // 1 means the original source image color is used.
  200. // 0 means a transparent color is used.
  201. ColorR float32
  202. ColorG float32
  203. ColorB float32
  204. ColorA float32
  205. }
  206. // Address represents a sampler address mode.
  207. type Address int
  208. const (
  209. // AddressUnsafe means there is no guarantee when the texture coodinates are out of range.
  210. AddressUnsafe Address = Address(driver.AddressUnsafe)
  211. // AddressClampToZero means that out-of-range texture coordinates return 0 (transparent).
  212. AddressClampToZero Address = Address(driver.AddressClampToZero)
  213. // AddressRepeat means that texture coordinates wrap to the other side of the texture.
  214. AddressRepeat Address = Address(driver.AddressRepeat)
  215. )
  216. // DrawTrianglesOptions represents options for DrawTriangles.
  217. type DrawTrianglesOptions struct {
  218. // ColorM is a color matrix to draw.
  219. // The default (zero) value is identity, which doesn't change any color.
  220. // ColorM is applied before vertex color scale is applied.
  221. //
  222. // If Shader is not nil, ColorM is ignored.
  223. ColorM ColorM
  224. // CompositeMode is a composite mode to draw.
  225. // The default (zero) value is regular alpha blending.
  226. CompositeMode CompositeMode
  227. // Filter is a type of texture filter.
  228. // The default (zero) value is FilterNearest.
  229. Filter Filter
  230. // Address is a sampler address mode.
  231. // The default (zero) value is AddressUnsafe.
  232. Address Address
  233. // EvenOdd represents whether the even-odd rule is applied or not.
  234. //
  235. // If EvenOdd is true, triangles are rendered based on the even-odd rule. If false, triangles are rendered without condition.
  236. // Whether overlapped regions by multiple triangles is rendered or not depends on the number of the overlapping:
  237. // if and only if the number is odd, the region is rendered.
  238. //
  239. // EvenOdd is useful when you want to render a complex polygon.
  240. // A complex polygon is a non-convex polygon like a concave polygon, a polygon with holes, or a self-intersecting polygon.
  241. // See examples/vector for actual usages.
  242. //
  243. // The default value is false.
  244. EvenOdd bool
  245. }
  246. // MaxIndicesNum is the maximum number of indices for DrawTriangles.
  247. const MaxIndicesNum = graphics.IndicesNum
  248. // DrawTriangles draws triangles with the specified vertices and their indices.
  249. //
  250. // If len(indices) is not multiple of 3, DrawTriangles panics.
  251. //
  252. // If len(indices) is more than MaxIndicesNum, DrawTriangles panics.
  253. //
  254. // The rule in which DrawTriangles works effectively is same as DrawImage's.
  255. //
  256. // When the given image is disposed, DrawTriangles panics.
  257. //
  258. // When the image i is disposed, DrawTriangles does nothing.
  259. func (i *Image) DrawTriangles(vertices []Vertex, indices []uint16, img *Image, options *DrawTrianglesOptions) {
  260. i.copyCheck()
  261. if img != nil && img.isDisposed() {
  262. panic("ebiten: the given image to DrawTriangles must not be disposed")
  263. }
  264. if i.isDisposed() {
  265. return
  266. }
  267. if len(indices)%3 != 0 {
  268. panic("ebiten: len(indices) % 3 must be 0")
  269. }
  270. if len(indices) > MaxIndicesNum {
  271. panic("ebiten: len(indices) must be <= MaxIndicesNum")
  272. }
  273. // TODO: Check the maximum value of indices and len(vertices)?
  274. dstBounds := i.Bounds()
  275. dstRegion := driver.Region{
  276. X: float32(dstBounds.Min.X),
  277. Y: float32(dstBounds.Min.Y),
  278. Width: float32(dstBounds.Dx()),
  279. Height: float32(dstBounds.Dy()),
  280. }
  281. if options == nil {
  282. options = &DrawTrianglesOptions{}
  283. }
  284. mode := driver.CompositeMode(options.CompositeMode)
  285. address := driver.Address(options.Address)
  286. var sr driver.Region
  287. if address != driver.AddressUnsafe {
  288. b := img.Bounds()
  289. sr = driver.Region{
  290. X: float32(b.Min.X),
  291. Y: float32(b.Min.Y),
  292. Width: float32(b.Dx()),
  293. Height: float32(b.Dy()),
  294. }
  295. }
  296. filter := driver.Filter(options.Filter)
  297. vs := graphics.Vertices(len(vertices))
  298. for i, v := range vertices {
  299. vs[i*graphics.VertexFloatNum] = v.DstX
  300. vs[i*graphics.VertexFloatNum+1] = v.DstY
  301. vs[i*graphics.VertexFloatNum+2] = v.SrcX
  302. vs[i*graphics.VertexFloatNum+3] = v.SrcY
  303. vs[i*graphics.VertexFloatNum+4] = v.ColorR
  304. vs[i*graphics.VertexFloatNum+5] = v.ColorG
  305. vs[i*graphics.VertexFloatNum+6] = v.ColorB
  306. vs[i*graphics.VertexFloatNum+7] = v.ColorA
  307. }
  308. is := make([]uint16, len(indices))
  309. copy(is, indices)
  310. srcs := [graphics.ShaderImageNum]*mipmap.Mipmap{img.mipmap}
  311. i.mipmap.DrawTriangles(srcs, vs, is, options.ColorM.affineColorM(), mode, filter, address, dstRegion, sr, [graphics.ShaderImageNum - 1][2]float32{}, nil, nil, options.EvenOdd, false)
  312. }
  313. // DrawTrianglesShaderOptions represents options for DrawTrianglesShader.
  314. //
  315. // This API is experimental.
  316. type DrawTrianglesShaderOptions struct {
  317. // CompositeMode is a composite mode to draw.
  318. // The default (zero) value is regular alpha blending.
  319. CompositeMode CompositeMode
  320. // Uniforms is a set of uniform variables for the shader.
  321. // The keys are the names of the uniform variables.
  322. // The values must be float or []float.
  323. // If the uniform variable type is an array, a vector or a matrix,
  324. // you have to specify linearly flattened values as a slice.
  325. // For example, if the uniform variable type is [4]vec4, the number of the slice values will be 16.
  326. Uniforms map[string]interface{}
  327. // Images is a set of the source images.
  328. // All the image must be the same size.
  329. Images [4]*Image
  330. // EvenOdd represents whether the even-odd rule is applied or not.
  331. //
  332. // If EvenOdd is true, triangles are rendered based on the even-odd rule. If false, triangles are rendered without condition.
  333. // Whether overlapped regions by multiple triangles is rendered or not depends on the number of the overlapping:
  334. // if and only if the number is odd, the region is rendered.
  335. //
  336. // EvenOdd is useful when you want to render a complex polygon.
  337. // A complex polygon is a non-convex polygon like a concave polygon, a polygon with holes, or a self-intersecting polygon.
  338. // See examples/vector for actual usages.
  339. //
  340. // The default value is false.
  341. EvenOdd bool
  342. }
  343. func init() {
  344. var op DrawTrianglesShaderOptions
  345. if got, want := len(op.Images), graphics.ShaderImageNum; got != want {
  346. panic(fmt.Sprintf("ebiten: len((DrawTrianglesShaderOptions{}).Images) must be %d but %d", want, got))
  347. }
  348. }
  349. // DrawTrianglesShader draws triangles with the specified vertices and their indices with the specified shader.
  350. //
  351. // For the details about the shader, see https://ebiten.org/documents/shader.html.
  352. //
  353. // If len(indices) is not multiple of 3, DrawTrianglesShader panics.
  354. //
  355. // If len(indices) is more than MaxIndicesNum, DrawTrianglesShader panics.
  356. //
  357. // When a specified image is non-nil and is disposed, DrawTrianglesShader panics.
  358. //
  359. // When the image i is disposed, DrawTrianglesShader does nothing.
  360. //
  361. // This API is experimental.
  362. func (i *Image) DrawTrianglesShader(vertices []Vertex, indices []uint16, shader *Shader, options *DrawTrianglesShaderOptions) {
  363. i.copyCheck()
  364. if i.isDisposed() {
  365. return
  366. }
  367. if len(indices)%3 != 0 {
  368. panic("ebiten: len(indices) % 3 must be 0")
  369. }
  370. if len(indices) > MaxIndicesNum {
  371. panic("ebiten: len(indices) must be <= MaxIndicesNum")
  372. }
  373. // TODO: Check the maximum value of indices and len(vertices)?
  374. dstBounds := i.Bounds()
  375. dstRegion := driver.Region{
  376. X: float32(dstBounds.Min.X),
  377. Y: float32(dstBounds.Min.Y),
  378. Width: float32(dstBounds.Dx()),
  379. Height: float32(dstBounds.Dy()),
  380. }
  381. if options == nil {
  382. options = &DrawTrianglesShaderOptions{}
  383. }
  384. mode := driver.CompositeMode(options.CompositeMode)
  385. vs := graphics.Vertices(len(vertices))
  386. for i, v := range vertices {
  387. vs[i*graphics.VertexFloatNum] = v.DstX
  388. vs[i*graphics.VertexFloatNum+1] = v.DstY
  389. vs[i*graphics.VertexFloatNum+2] = v.SrcX
  390. vs[i*graphics.VertexFloatNum+3] = v.SrcY
  391. vs[i*graphics.VertexFloatNum+4] = v.ColorR
  392. vs[i*graphics.VertexFloatNum+5] = v.ColorG
  393. vs[i*graphics.VertexFloatNum+6] = v.ColorB
  394. vs[i*graphics.VertexFloatNum+7] = v.ColorA
  395. }
  396. is := make([]uint16, len(indices))
  397. copy(is, indices)
  398. var imgs [graphics.ShaderImageNum]*mipmap.Mipmap
  399. var imgw, imgh int
  400. for i, img := range options.Images {
  401. if img == nil {
  402. continue
  403. }
  404. if img.isDisposed() {
  405. panic("ebiten: the given image to DrawRectShader must not be disposed")
  406. }
  407. if i == 0 {
  408. imgw, imgh = img.Size()
  409. } else {
  410. // TODO: Check imgw > 0 && imgh > 0
  411. if w, h := img.Size(); imgw != w || imgh != h {
  412. panic("ebiten: all the source images must be the same size with the rectangle")
  413. }
  414. }
  415. imgs[i] = img.mipmap
  416. }
  417. var sx, sy float32
  418. if options.Images[0] != nil {
  419. b := options.Images[0].Bounds()
  420. sx = float32(b.Min.X)
  421. sy = float32(b.Min.Y)
  422. }
  423. var sr driver.Region
  424. if img := options.Images[0]; img != nil {
  425. b := img.Bounds()
  426. sr = driver.Region{
  427. X: float32(b.Min.X),
  428. Y: float32(b.Min.Y),
  429. Width: float32(b.Dx()),
  430. Height: float32(b.Dy()),
  431. }
  432. }
  433. var offsets [graphics.ShaderImageNum - 1][2]float32
  434. for i, img := range options.Images[1:] {
  435. if img == nil {
  436. continue
  437. }
  438. b := img.Bounds()
  439. offsets[i][0] = -sx + float32(b.Min.X)
  440. offsets[i][1] = -sy + float32(b.Min.Y)
  441. }
  442. us := shader.convertUniforms(options.Uniforms)
  443. i.mipmap.DrawTriangles(imgs, vs, is, affine.ColorMIdentity{}, mode, driver.FilterNearest, driver.AddressUnsafe, dstRegion, sr, offsets, shader.shader, us, options.EvenOdd, false)
  444. }
  445. // DrawRectShaderOptions represents options for DrawRectShader.
  446. //
  447. // This API is experimental.
  448. type DrawRectShaderOptions struct {
  449. // GeoM is a geometry matrix to draw.
  450. // The default (zero) value is identity, which draws the rectangle at (0, 0).
  451. GeoM GeoM
  452. // CompositeMode is a composite mode to draw.
  453. // The default (zero) value is regular alpha blending.
  454. CompositeMode CompositeMode
  455. // Uniforms is a set of uniform variables for the shader.
  456. // The keys are the names of the uniform variables.
  457. // The values must be float or []float.
  458. // If the uniform variable type is an array, a vector or a matrix,
  459. // you have to specify linearly flattened values as a slice.
  460. // For example, if the uniform variable type is [4]vec4, the number of the slice values will be 16.
  461. Uniforms map[string]interface{}
  462. // Images is a set of the source images.
  463. // All the image must be the same size with the rectangle.
  464. Images [4]*Image
  465. }
  466. func init() {
  467. var op DrawRectShaderOptions
  468. if got, want := len(op.Images), graphics.ShaderImageNum; got != want {
  469. panic(fmt.Sprintf("ebiten: len((DrawRectShaderOptions{}).Images) must be %d but %d", want, got))
  470. }
  471. }
  472. // DrawRectShader draws a rectangle with the specified width and height with the specified shader.
  473. //
  474. // For the details about the shader, see https://ebiten.org/documents/shader.html.
  475. //
  476. // When one of the specified image is non-nil and is disposed, DrawRectShader panics.
  477. //
  478. // When the image i is disposed, DrawRectShader does nothing.
  479. //
  480. // This API is experimental.
  481. func (i *Image) DrawRectShader(width, height int, shader *Shader, options *DrawRectShaderOptions) {
  482. i.copyCheck()
  483. if i.isDisposed() {
  484. return
  485. }
  486. dstBounds := i.Bounds()
  487. dstRegion := driver.Region{
  488. X: float32(dstBounds.Min.X),
  489. Y: float32(dstBounds.Min.Y),
  490. Width: float32(dstBounds.Dx()),
  491. Height: float32(dstBounds.Dy()),
  492. }
  493. if options == nil {
  494. options = &DrawRectShaderOptions{}
  495. }
  496. mode := driver.CompositeMode(options.CompositeMode)
  497. var imgs [graphics.ShaderImageNum]*mipmap.Mipmap
  498. for i, img := range options.Images {
  499. if img == nil {
  500. continue
  501. }
  502. if img.isDisposed() {
  503. panic("ebiten: the given image to DrawRectShader must not be disposed")
  504. }
  505. if w, h := img.Size(); width != w || height != h {
  506. panic("ebiten: all the source images must be the same size with the rectangle")
  507. }
  508. imgs[i] = img.mipmap
  509. }
  510. var sx, sy float32
  511. if options.Images[0] != nil {
  512. b := options.Images[0].Bounds()
  513. sx = float32(b.Min.X)
  514. sy = float32(b.Min.Y)
  515. }
  516. a, b, c, d, tx, ty := options.GeoM.elements32()
  517. vs := graphics.QuadVertices(sx, sy, sx+float32(width), sy+float32(height), a, b, c, d, tx, ty, 1, 1, 1, 1)
  518. is := graphics.QuadIndices()
  519. var sr driver.Region
  520. if img := options.Images[0]; img != nil {
  521. b := img.Bounds()
  522. sr = driver.Region{
  523. X: float32(b.Min.X),
  524. Y: float32(b.Min.Y),
  525. Width: float32(b.Dx()),
  526. Height: float32(b.Dy()),
  527. }
  528. }
  529. var offsets [graphics.ShaderImageNum - 1][2]float32
  530. for i, img := range options.Images[1:] {
  531. if img == nil {
  532. continue
  533. }
  534. b := img.Bounds()
  535. offsets[i][0] = -sx + float32(b.Min.X)
  536. offsets[i][1] = -sy + float32(b.Min.Y)
  537. }
  538. us := shader.convertUniforms(options.Uniforms)
  539. i.mipmap.DrawTriangles(imgs, vs, is, affine.ColorMIdentity{}, mode, driver.FilterNearest, driver.AddressUnsafe, dstRegion, sr, offsets, shader.shader, us, false, canSkipMipmap(options.GeoM, driver.FilterNearest))
  540. }
  541. // SubImage returns an image representing the portion of the image p visible through r.
  542. // The returned value shares pixels with the original image.
  543. //
  544. // The returned value is always *ebiten.Image.
  545. //
  546. // If the image is disposed, SubImage returns nil.
  547. //
  548. // A sub-image returned by SubImage can be used as a rendering source and a rendering destination.
  549. // If a sub-image is used as a rendering source, the image is used as if it is a small image.
  550. // If a sub-image is used as a rendering destination, the region being rendered is clipped.
  551. func (i *Image) SubImage(r image.Rectangle) image.Image {
  552. i.copyCheck()
  553. if i.isDisposed() {
  554. return nil
  555. }
  556. r = r.Intersect(i.Bounds())
  557. // Need to check Empty explicitly. See the standard image package implementations.
  558. if r.Empty() {
  559. r = image.ZR
  560. }
  561. // Keep the original image's reference not to dispose that by GC.
  562. var orig = i
  563. if i.isSubImage() {
  564. orig = i.original
  565. }
  566. img := &Image{
  567. mipmap: i.mipmap,
  568. bounds: r,
  569. original: orig,
  570. }
  571. img.addr = img
  572. return img
  573. }
  574. // Bounds returns the bounds of the image.
  575. func (i *Image) Bounds() image.Rectangle {
  576. if i.isDisposed() {
  577. panic("ebiten: the image is already disposed")
  578. }
  579. return i.bounds
  580. }
  581. // ColorModel returns the color model of the image.
  582. func (i *Image) ColorModel() color.Model {
  583. return color.RGBAModel
  584. }
  585. // At returns the color of the image at (x, y).
  586. //
  587. // At loads pixels from GPU to system memory if necessary, which means that At can be slow.
  588. //
  589. // At always returns a transparent color if the image is disposed.
  590. //
  591. // Note that an important logic should not rely on values returned by At, since
  592. // the returned values can include very slight differences between some machines.
  593. //
  594. // At can't be called outside the main loop (ebiten.Run's updating function) starts.
  595. func (i *Image) At(x, y int) color.Color {
  596. r, g, b, a := i.at(x, y)
  597. return color.RGBA{r, g, b, a}
  598. }
  599. // RGBA64At implements image.RGBA64Image's RGBA64At.
  600. //
  601. // RGBA64At loads pixels from GPU to system memory if necessary, which means
  602. // that RGBA64At can be slow.
  603. //
  604. // RGBA64At always returns a transparent color if the image is disposed.
  605. //
  606. // Note that an important logic should not rely on values returned by RGBA64At,
  607. // since the returned values can include very slight differences between some machines.
  608. //
  609. // RGBA64At can't be called outside the main loop (ebiten.Run's updating function) starts.
  610. func (i *Image) RGBA64At(x, y int) color.RGBA64 {
  611. r, g, b, a := i.at(x, y)
  612. return color.RGBA64{uint16(r) * 0x101, uint16(g) * 0x101, uint16(b) * 0x101, uint16(a) * 0x101}
  613. }
  614. func (i *Image) at(x, y int) (r, g, b, a uint8) {
  615. if i.isDisposed() {
  616. return 0, 0, 0, 0
  617. }
  618. if !image.Pt(x, y).In(i.Bounds()) {
  619. return 0, 0, 0, 0
  620. }
  621. pix, err := i.mipmap.Pixels(x, y, 1, 1)
  622. if err != nil {
  623. if panicOnErrorAtImageAt {
  624. panic(err)
  625. }
  626. theUIContext.setError(err)
  627. return 0, 0, 0, 0
  628. }
  629. return pix[0], pix[1], pix[2], pix[3]
  630. }
  631. // Set sets the color at (x, y).
  632. //
  633. // Set loads pixels from GPU to system memory if necessary, which means that Set can be slow.
  634. //
  635. // In the current implementation, successive calls of Set invokes loading pixels at most once, so this is efficient.
  636. //
  637. // If the image is disposed, Set does nothing.
  638. func (i *Image) Set(x, y int, clr color.Color) {
  639. i.copyCheck()
  640. if i.isDisposed() {
  641. return
  642. }
  643. if !image.Pt(x, y).In(i.Bounds()) {
  644. return
  645. }
  646. if i.isSubImage() {
  647. i = i.original
  648. }
  649. r, g, b, a := clr.RGBA()
  650. pix := []byte{byte(r >> 8), byte(g >> 8), byte(b >> 8), byte(a >> 8)}
  651. if err := i.mipmap.ReplacePixels(pix, x, y, 1, 1); err != nil {
  652. theUIContext.setError(err)
  653. }
  654. }
  655. // Dispose disposes the image data.
  656. // After disposing, most of image functions do nothing and returns meaningless values.
  657. //
  658. // Calling Dispose is not mandatory. GC automatically collects internal resources that no objects refer to.
  659. // However, calling Dispose explicitly is helpful if memory usage matters.
  660. //
  661. // If the image is a sub-image, Dispose does nothing.
  662. //
  663. // When the image is disposed, Dipose does nothing.
  664. func (i *Image) Dispose() {
  665. i.copyCheck()
  666. if i.isDisposed() {
  667. return
  668. }
  669. if i.isSubImage() {
  670. return
  671. }
  672. i.mipmap.MarkDisposed()
  673. i.mipmap = nil
  674. }
  675. // ReplacePixels replaces the pixels of the image with p.
  676. //
  677. // The given p must represent RGBA pre-multiplied alpha values.
  678. // len(pix) must equal to 4 * (bounds width) * (bounds height).
  679. //
  680. // ReplacePixels works on a sub-image.
  681. //
  682. // When len(pix) is not appropriate, ReplacePixels panics.
  683. //
  684. // When the image is disposed, ReplacePixels does nothing.
  685. func (i *Image) ReplacePixels(pixels []byte) {
  686. i.copyCheck()
  687. if i.isDisposed() {
  688. return
  689. }
  690. r := i.Bounds()
  691. // Do not need to copy pixels here.
  692. // * In internal/mipmap, pixels are copied when necessary.
  693. // * In internal/shareable, pixels are copied to make its paddings.
  694. if err := i.mipmap.ReplacePixels(pixels, r.Min.X, r.Min.Y, r.Dx(), r.Dy()); err != nil {
  695. theUIContext.setError(err)
  696. }
  697. }
  698. // NewImage returns an empty image.
  699. //
  700. // If width or height is less than 1 or more than device-dependent maximum size, NewImage panics.
  701. //
  702. // NewImage panics if RunGame already finishes.
  703. func NewImage(width, height int) *Image {
  704. if isRunGameEnded() {
  705. panic(fmt.Sprintf("ebiten: NewImage cannot be called after RunGame finishes"))
  706. }
  707. if width <= 0 {
  708. panic(fmt.Sprintf("ebiten: width at NewImage must be positive but %d", width))
  709. }
  710. if height <= 0 {
  711. panic(fmt.Sprintf("ebiten: height at NewImage must be positive but %d", height))
  712. }
  713. i := &Image{
  714. mipmap: mipmap.New(width, height),
  715. bounds: image.Rect(0, 0, width, height),
  716. }
  717. i.addr = i
  718. return i
  719. }
  720. // NewImageFromImage creates a new image with the given image (source).
  721. //
  722. // If source's width or height is less than 1 or more than device-dependent maximum size, NewImageFromImage panics.
  723. //
  724. // NewImageFromImage panics if RunGame already finishes.
  725. func NewImageFromImage(source image.Image) *Image {
  726. if isRunGameEnded() {
  727. panic(fmt.Sprintf("ebiten: NewImage cannot be called after RunGame finishes"))
  728. }
  729. size := source.Bounds().Size()
  730. width, height := size.X, size.Y
  731. if width <= 0 {
  732. panic(fmt.Sprintf("ebiten: source width at NewImageFromImage must be positive but %d", width))
  733. }
  734. if height <= 0 {
  735. panic(fmt.Sprintf("ebiten: source height at NewImageFromImage must be positive but %d", height))
  736. }
  737. i := &Image{
  738. mipmap: mipmap.New(width, height),
  739. bounds: image.Rect(0, 0, width, height),
  740. }
  741. i.addr = i
  742. i.ReplacePixels(imageToBytes(source))
  743. return i
  744. }
  745. func newScreenFramebufferImage(width, height int) *Image {
  746. i := &Image{
  747. mipmap: mipmap.NewScreenFramebufferMipmap(width, height),
  748. bounds: image.Rect(0, 0, width, height),
  749. screen: true,
  750. }
  751. i.addr = i
  752. return i
  753. }