pane.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665
  1. package tile
  2. import "fmt"
  3. import "gitlab.com/beoran/al5go/al"
  4. // import "gitlab.com/beoran/ebsgo/engine/geometry/point"
  5. import "gitlab.com/beoran/ebsgo/engine/physics"
  6. import "gitlab.com/beoran/ebsgo/engine/fifi"
  7. /* Tile blending direction constants. */
  8. const (
  9. BLEND_NORTHWEST = 0
  10. BLEND_NORTH = 1
  11. BLEND_NORTHEAST = 2
  12. BLEND_WEST = 3
  13. BLEND_EAST = 4
  14. BLEND_SOUTHWEST = 5
  15. BLEND_SOUTH = 6
  16. BLEND_SOUTHEAST = 7
  17. BLEND_DIRECTION_MAX = 8
  18. )
  19. /* Tile blending shapes */
  20. const (
  21. BLEND_CORNER = 0
  22. BLEND_SIDE = 1
  23. BLEND_SHAPE_MAX = 2
  24. )
  25. /* Tile blending types. */
  26. const (
  27. BLEND_SHARP = 0
  28. BLEND_GRADUAL = 1
  29. BLEND_FUZZY = 2
  30. BLEND_FUZZY_GRADUAL = 3
  31. BLEND_TYPE_MAX = 4
  32. )
  33. const BLEND_BITMAPS_MAX = 255
  34. /* A cache of generated generic blending masks. */
  35. var BlendMasks [BLEND_TYPE_MAX][BLEND_SHAPE_MAX]*al.Bitmap
  36. /* Lookup array with info on how the mask should be applied, i. e. flipped. */
  37. var BlendFlags [BLEND_DIRECTION_MAX]int = [BLEND_DIRECTION_MAX] int{
  38. 0,
  39. 0,
  40. al.FLIP_HORIZONTAL,
  41. 0,
  42. al.FLIP_HORIZONTAL,
  43. al.FLIP_VERTICAL,
  44. al.FLIP_VERTICAL,
  45. al.FLIP_HORIZONTAL | al.FLIP_VERTICAL,
  46. }
  47. /* Lookup array with info on which "side" mask should be used. */
  48. var BlendSides [BLEND_DIRECTION_MAX]int = [BLEND_DIRECTION_MAX]int {
  49. BLEND_CORNER,
  50. BLEND_SIDE ,
  51. BLEND_CORNER,
  52. BLEND_SIDE ,
  53. BLEND_SIDE ,
  54. BLEND_CORNER,
  55. BLEND_SIDE ,
  56. BLEND_CORNER,
  57. }
  58. /* Lookup array with info on how the mask should be turned, i. e. rotated. */
  59. var BlendAngles [BLEND_DIRECTION_MAX]float32 = [BLEND_DIRECTION_MAX]float32 {
  60. 0.0,
  61. 0.0,
  62. 0.0,
  63. 3 * al.PI / 2.0,
  64. al.PI / 2.0,
  65. 0.0,
  66. 0.0,
  67. 0.0,
  68. }
  69. /*
  70. ## Implementation of automatic overlapping ##
  71. In the simple case where there are only 2 different kinds of tiles,
  72. then for a tile somewhere in the map, that tile has 8 neighbours, and thus
  73. there are 8**2 or 256 different possible layouts of these neighbours around that
  74. single tile, and 256 different blends would be needed.
  75. Of course, this is a staggering amount for hand drawn graphics, and even for
  76. automatically generated mask images, this takes up a hefty chunk of memory,
  77. so some kind of simplification is needed.
  78. The first simplification is the use of the tile's blend value as a blend *priority*
  79. value. The tile with the lower blend priority will be blended with the
  80. tile with the higher blend priority blending over it. Tiles with equal blend
  81. priority will simply not blend. This reduces the possibilities because in
  82. cases where 3 or more tyle types must blend, without priorities,
  83. the number of possible blends would become even larger.
  84. Let's consider the possibilities takng symmetry in account. If only 2 tiles
  85. that will blend are adjacent, there are 8 possibilities. However there are 4
  86. symmetric rotations of the 2 cases of the 2 tiles being either side-to-side
  87. or corner to corner. In case of side-to side, the blend should go rougmly like
  88. this: (scaled down to 8x8
  89. ..........OOOOOOOO ................OO
  90. ..........OOOOOOOO ..............OOOO
  91. ..........OOOOOOOO ............OOOOOO
  92. ..........OOOOOOOO ............OOOOOO
  93. ..........OOOOOOOO => ............OOOOOO
  94. ..........OOOOOOOO ............OOOOOO
  95. ..........OOOOOOOO ...........OOOOOOO
  96. ..........OOOOOOOO ..........OOOOOOOO
  97. And corner to corner:
  98. OOOOOOOO OOOOOOOO
  99. OOOOOOOO OOOOOOOO
  100. OOOOOOOO OOOOOOOO
  101. OOOOOOOO OOOOOOOO
  102. OOOOOOOO => OOOOOOOO
  103. OOOOOOOO OOOOOOOO
  104. OOOOOOOO .OOOOOOO
  105. OOOOOOOO ..OOOOOO
  106. .......... ..........
  107. .......... ..........
  108. .......... ..........
  109. .......... ..........
  110. .......... => ..........
  111. .......... ..........
  112. .......... ..........
  113. .......... ..........
  114. If the masks are judiciouly chosen, and all align correctly,
  115. then it will suffice to have just 2 mask images which get rotated as needed,
  116. one mask for the side to side, and one for corner to corner.
  117. Each of the masks follows a strict pattern, that is, the side by side
  118. has a \__/ - like shape were the depth of the overlap is at most 1/4th of the
  119. tile height. (Or is it 1/3, let's check it out).
  120. Then, for every overlapping tile, an overlap bitmap can be generated
  121. when loading the tile layer it is in, and that bitmap can then be used to
  122. draw the tile in stead of the original bitmap.
  123. ## Implementation of automatic shadows ##
  124. Every cell in the tile pane contains a slice of shadow polygons,
  125. that is set up before rendering. This should in the future be used in stead of
  126. the current live polygons generated at draw time but this will require
  127. an approach where a camera transform is applied whilst drawing in stead of
  128. the current situation where we use the camera info directly to calculate
  129. the draw positions.
  130. */
  131. func PrepareBlend(blend * al.Bitmap, tile * Tile, blentile * Tile, direction int ) * al.Bitmap {
  132. side := BlendSides[direction]
  133. angle := BlendAngles[direction]
  134. flags := BlendFlags[direction]
  135. maskid:= tile.BlendMask
  136. mask := BlendMasks[maskid][side]
  137. if mask == nil {
  138. return nil
  139. } else {
  140. tile.DrawMaskedTo(blend, mask, angle, flags)
  141. return blend
  142. }
  143. }
  144. /**
  145. * A Cell is an individual part of a pane. It contains a tile,
  146. * a blend bitmap, two shadow polygons, and rendering flags.
  147. */
  148. type Cell struct {
  149. * Tile
  150. Blend * al.Bitmap
  151. Flags int
  152. Rotate float32
  153. Shadows [][8]float32 // Slice of shadow polygons.
  154. }
  155. /**
  156. * A Pane is a layer of tiles for use in a tile map or tiled
  157. * background. A pane consists of individual tiles from the same
  158. * tile set. Different panes may have different tile sets.
  159. */
  160. type Pane struct {
  161. Tileset * Set
  162. Cells [][]Cell
  163. GridW int
  164. GridH int
  165. PixelW int
  166. PixelH int
  167. // This bitmap is the atlas used for blends. XXX: Not implemented yet.
  168. Blends * al.Bitmap
  169. Name string
  170. };
  171. /* First group id of the tile set of the plane. */
  172. func (pane * Pane) FirstGID() int {
  173. if pane.Tileset == nil {
  174. return 0
  175. } else {
  176. return pane.Tileset.FirstGID
  177. }
  178. }
  179. /** Initializes a tile pane.
  180. * The pane will not clean up the tile set itself!
  181. */
  182. func (pane * Pane) Init(set * Set, gridw, gridh int, name string) (* Pane) {
  183. pane.Tileset = set
  184. pane.GridW = gridw
  185. pane.GridH = gridh
  186. pane.PixelW = pane.GridW * set.TileW
  187. pane.PixelH = pane.GridW * set.TileH
  188. pane.Name = name
  189. pane.Cells = make([][]Cell, pane.GridH)
  190. for i := range (pane.Cells) {
  191. pane.Cells[i] = make([]Cell, pane.GridW)
  192. }
  193. return pane
  194. }
  195. func NewPane(set * Set, gridw, gridh int, name string) (pane * Pane) {
  196. pane = &Pane{}
  197. return pane.Init(set, gridw, gridh, name)
  198. }
  199. func (pane * Pane) Outside(gridx, gridy int) bool {
  200. return ((gridx < 0) || (gridy < 0)) ||
  201. ((gridx >= pane.GridW) || (gridy >= pane.GridH))
  202. }
  203. func (pane * Pane) Cell(gridx, gridy int) * Cell {
  204. if pane.Outside(gridx, gridy) {
  205. return nil
  206. }
  207. return & pane.Cells[gridy][gridx]
  208. }
  209. func (pane * Pane) Tile(gridx, gridy int) * Tile {
  210. if pane.Outside(gridx, gridy) {
  211. return nil
  212. }
  213. return pane.Cells[gridy][gridx].Tile
  214. }
  215. func (pane * Pane) Blend(gridx, gridy int) * al.Bitmap {
  216. if pane.Outside(gridx, gridy) {
  217. return nil
  218. }
  219. return pane.Cells[gridy][gridx].Blend
  220. }
  221. func (pane * Pane) SetTile(gridx, gridy int, tile * Tile) * Tile {
  222. if pane.Outside(gridx, gridy) {
  223. return nil
  224. }
  225. pane.Cells[gridy][gridx].Tile = tile
  226. return tile
  227. }
  228. func (pane * Pane) SetTileIndex(gridx, gridy, index int) * Tile {
  229. return pane.SetTile(gridx, gridy, pane.Tileset.Tile(index))
  230. }
  231. func (pane * Pane) SetBlend(gridx, gridy int, blend * al.Bitmap) * al.Bitmap {
  232. if pane.Outside(gridx, gridy) {
  233. return nil
  234. }
  235. if nil != pane.Cells[gridy][gridx].Blend {
  236. pane.Cells[gridy][gridx].Blend.Destroy()
  237. }
  238. pane.Cells[gridy][gridx].Blend = blend
  239. return blend
  240. }
  241. func (pane * Pane) SetFlags(gridx, gridy int, flags int) int {
  242. if pane.Outside(gridx, gridy) {
  243. return -1
  244. }
  245. pane.Cells[gridy][gridx].Flags = flags
  246. return flags
  247. }
  248. func (pane * Pane) SetTileRect(gridx, gridy, gridw, gridh int, tile * Tile) * Tile {
  249. for jj := gridy ; jj < (gridy + gridh) ; jj++ {
  250. for ii := gridx ; ii < (gridx + gridh) ; ii++ {
  251. pane.SetTile(ii, jj, tile)
  252. }
  253. }
  254. return tile
  255. }
  256. func (pane * Pane) Fill(tile * Tile) * Tile {
  257. return pane.SetTileRect(0, 0, pane.GridW, pane.GridH, nil)
  258. }
  259. func (cell * Cell) AddShadowPolygon(polygon [8]float32) {
  260. cell.Shadows = append(cell.Shadows, polygon)
  261. }
  262. func (cell * Cell) DeleteShadowPolygons() {
  263. cell.Shadows = nil
  264. }
  265. type DrawIterator func (cell * Cell, x, y float32, tx, ty int)
  266. /* Draws the tiles of the pane using an iterator function.
  267. * This must be done in one call because changing the source bitmap is less optimal.
  268. * You must hold bitmap drawing yourself if applicable.
  269. */
  270. func (pane * Pane) DrawIterate(camera * physics.Camera, iter DrawIterator) {
  271. gridwide := pane.GridW
  272. gridhigh := pane.GridH
  273. tilewide := pane.Tileset.TileW
  274. tilehigh := pane.Tileset.TileH
  275. x := int(camera.X)
  276. y := int(camera.Y)
  277. tx_start := x / tilewide
  278. ty_start := y / tilehigh
  279. tx_delta := 1 + (int(camera.W) / tilewide)
  280. ty_delta := 1 + (int(camera.H) / tilehigh)
  281. tx_stop := tx_start + tx_delta
  282. ty_stop := ty_start + ty_delta
  283. tx_index := 0
  284. ty_index := 0
  285. // realwide := pane.PixelW
  286. // realhigh := pane.PixelH
  287. // drawflag := 0
  288. if tx_start < 0 { tx_start = 0; }
  289. if ty_start < 0 { ty_start = 0; }
  290. if tx_stop > gridwide { tx_stop = gridwide; }
  291. if ty_stop > gridhigh { ty_stop = gridhigh; }
  292. y_draw := float32(-y + (ty_start * tilehigh))
  293. for ty_index = ty_start; ty_index < ty_stop; ty_index++ {
  294. y_draw += float32(tilehigh)
  295. x_draw := float32(-x + (tx_start * tilewide))
  296. row := pane.Cells[ty_index]
  297. for tx_index = tx_start ; tx_index < tx_stop; tx_index++ {
  298. x_draw += float32(tilewide)
  299. cell := &row[tx_index]
  300. iter(cell, x_draw, y_draw, tx_index, ty_index)
  301. }
  302. }
  303. }
  304. /* Draws the tiles of the pane. This must be done in one call because
  305. * changing the source bitmap is less optimal. */
  306. func (pane * Pane) DrawTiles(camera * physics.Camera) {
  307. gridwide := pane.GridW
  308. gridhigh := pane.GridH
  309. tilewide := pane.Tileset.TileW
  310. tilehigh := pane.Tileset.TileH
  311. x := int(camera.X)
  312. y := int(camera.Y)
  313. tx_start := x / tilewide
  314. ty_start := y / tilehigh
  315. tx_delta := 1 + (int(camera.W) / tilewide)
  316. ty_delta := 1 + (int(camera.H) / tilehigh)
  317. tx_stop := tx_start + tx_delta
  318. ty_stop := ty_start + ty_delta
  319. tx_index := 0
  320. ty_index := 0
  321. // realwide := pane.PixelW
  322. // realhigh := pane.PixelH
  323. // drawflag := 0
  324. al.HoldBitmapDrawing(true)
  325. if tx_start < 0 { tx_start = 0; }
  326. if ty_start < 0 { ty_start = 0; }
  327. if tx_stop > gridwide { tx_stop = gridwide; }
  328. if ty_stop > gridhigh { ty_stop = gridhigh; }
  329. y_draw := float32(-y + (ty_start * tilehigh))
  330. for ty_index = ty_start; ty_index < ty_stop; ty_index++ {
  331. y_draw += float32(tilehigh)
  332. x_draw := float32(-x + (tx_start * tilewide))
  333. row := pane.Cells[ty_index]
  334. for tx_index = tx_start ; tx_index < tx_stop; tx_index++ {
  335. x_draw += float32(tilewide)
  336. cell := row[tx_index]
  337. if (cell.Tile != nil) {
  338. cell.Tile.Draw(x_draw, y_draw, cell.Flags)
  339. }
  340. }
  341. }
  342. // Let go of hold
  343. al.HoldBitmapDrawing(false)
  344. }
  345. /* Draws the blends of the pane. This must be done in one call because
  346. * changing the source bitmap is less optimal. */
  347. func (pane * Pane) DrawBlends(camera * physics.Camera) {
  348. gridwide := pane.GridW
  349. gridhigh := pane.GridH
  350. tilewide := pane.Tileset.TileW
  351. tilehigh := pane.Tileset.TileH
  352. x := int(camera.X)
  353. y := int(camera.Y)
  354. tx_start := x / tilewide
  355. ty_start := y / tilehigh
  356. tx_delta := 1 + (int(camera.W) / tilewide)
  357. ty_delta := 1 + (int(camera.H) / tilehigh)
  358. tx_stop := tx_start + tx_delta
  359. ty_stop := ty_start + ty_delta
  360. tx_index := 0
  361. ty_index := 0
  362. // realwide := pane.PixelW
  363. // realhigh := pane.PixelH
  364. // drawflag := 0
  365. // al.HoldBitmapDrawing(true)
  366. if tx_start < 0 { tx_start = 0; }
  367. if ty_start < 0 { ty_start = 0; }
  368. if tx_stop > gridwide { tx_stop = gridwide; }
  369. if ty_stop > gridhigh { ty_stop = gridhigh; }
  370. y_draw := float32(-y + (ty_start * tilehigh))
  371. for ty_index = ty_start; ty_index < ty_stop; ty_index++ {
  372. y_draw += float32(tilehigh)
  373. x_draw := float32(-x + (tx_start * tilewide))
  374. row := pane.Cells[ty_index]
  375. for tx_index = tx_start ; tx_index < tx_stop; tx_index++ {
  376. x_draw += float32(tilewide)
  377. cell := row[tx_index]
  378. if (cell.Blend != nil) {
  379. cell.Blend.Draw(x_draw, y_draw, cell.Flags)
  380. }
  381. }
  382. }
  383. // Let go of hold
  384. // al.HoldBitmapDrawing(false)
  385. }
  386. func (pane * Pane) DrawOneShadowOn(cell * Cell, pane_below * Pane,
  387. tx, ty int, x, y float32) {
  388. tile := cell.Tile
  389. if (tile == nil) { return; }
  390. if (tile.Shadow == 0) { return; }
  391. shadow_color := al.MapRGBA(0, 0, 0, 128)
  392. edge_tile := pane.Tile(tx + 1, ty - 1)
  393. aid_tile := pane.Tile(tx + 1, ty)
  394. shadow_trapezium := false
  395. if (edge_tile != nil) && edge_tile.IsWall() {
  396. shadow_trapezium = true
  397. // here the shadow is at trapezium, not a parallelogram.
  398. }
  399. /* Tile sizes... */
  400. tw := float32(pane.Tileset.TileW)
  401. th := float32(pane.Tileset.TileH)
  402. /* Only cast a shadow to the east if no solid tile next to self.
  403. * Shadow is a parallelogram to simplify overlaps.
  404. */
  405. if (aid_tile == nil) || !aid_tile.IsWall() {
  406. low_tile := pane_below.Tile(tx + 1, ty)
  407. if (low_tile != nil) && (low_tile.ShadowMask != 1) {
  408. polygon := [8]float32 {
  409. x + tw , y ,
  410. x + tw , y + th ,
  411. x + tw * 1.5 , y + th * 0.5 ,
  412. x + tw * 1.5 , y - th * 0.5 ,
  413. }
  414. if (shadow_trapezium) {
  415. polygon[7] = y
  416. }
  417. al.DrawFilledPolygon(polygon[0:8], 0, shadow_color)
  418. }
  419. }
  420. aid_tile = pane.Tile(tx, ty-1)
  421. /* Only cast a shadow to the north if no solid tile above to self.
  422. * Shadow is a parallelogram to simplify overlaps.
  423. */
  424. if (aid_tile == nil) || !aid_tile.IsWall() {
  425. low_tile := pane_below.Tile(tx, ty - 1)
  426. if (low_tile != nil) && (low_tile.ShadowMask != 1) {
  427. polygon := [8]float32 {
  428. x + tw , y ,
  429. x + tw , y ,
  430. x + tw * 1.5 , y - th * 0.5 ,
  431. x + tw * 0.5 , y - th * 0.5 ,
  432. }
  433. if (shadow_trapezium) {
  434. polygon[4] = x + tw
  435. }
  436. al.DrawFilledPolygon(polygon[0:8], 0, shadow_color)
  437. }
  438. }
  439. }
  440. /** Draws the shadows that tile pane pane casts onto the pane pane_below
  441. * with the camera delimiting the view.
  442. * On a classic tile map the bottom is to the south, so this function draws
  443. * "classic" shadows cast as if the sun were in the south-west,
  444. * with the shadows pointing north-east.
  445. */
  446. func (pane * Pane) DrawShadowsOn(pane_below * Pane, camera * physics.Camera) {
  447. gridwide := pane.GridW
  448. gridhigh := pane.GridH
  449. tilewide := pane.Tileset.TileW
  450. tilehigh := pane.Tileset.TileH
  451. x := int(camera.X)
  452. y := int(camera.Y)
  453. tx_start := x / tilewide
  454. ty_start := y / tilehigh
  455. tx_delta := 1 + (int(camera.W) / tilewide)
  456. ty_delta := 1 + (int(camera.H) / tilehigh)
  457. tx_stop := tx_start + tx_delta
  458. ty_stop := ty_start + ty_delta
  459. tx_index := 0
  460. ty_index := 0
  461. // realwide := pane.PixelW
  462. // realhigh := pane.PixelH
  463. // drawflag := 0
  464. // al.HoldBitmapDrawing(true)
  465. if tx_start < 0 { tx_start = 0; }
  466. if ty_start < 0 { ty_start = 0; }
  467. if tx_stop > gridwide { tx_stop = gridwide; }
  468. if ty_stop > gridhigh { ty_stop = gridhigh; }
  469. y_draw := float32(-y + (ty_start * tilehigh))
  470. for ty_index = ty_start; ty_index < ty_stop; ty_index++ {
  471. y_draw += float32(tilehigh)
  472. x_draw := float32(-x + (tx_start * tilewide))
  473. row := pane.Cells[ty_index]
  474. for tx_index = tx_start ; tx_index < tx_stop; tx_index++ {
  475. x_draw += float32(tilewide)
  476. cell := &row[tx_index]
  477. pane.DrawOneShadowOn(cell, pane_below, tx_index, ty_index, x_draw, y_draw)
  478. }
  479. }
  480. // Let go of hold
  481. // al.HoldBitmapDrawing(false)
  482. }
  483. /** Updates the tile pane. Curently does nothing, but this may change. */
  484. func (pane * Pane) Update(dt float64) {
  485. if pane.Tileset != nil {
  486. pane.Tileset.Update(dt)
  487. }
  488. }
  489. /** Gets a tile from a the tilepane's tile set by it's tile id. **/
  490. func (pane * Pane) TileFromSet(index int) * Tile {
  491. set := pane.Tileset
  492. if nil == set {
  493. return nil;
  494. }
  495. return set.Tile(index)
  496. }
  497. type BlendOffset struct {
  498. tx int
  499. ty int
  500. }
  501. var BlendOffsets [8]BlendOffset = [8]BlendOffset{
  502. {-1, -1}, /* TILE_BLEND_NORTHWEST 0 */
  503. { 0, -1}, /* TILE_BLEND_NORTH 1 */
  504. { 1, -1}, /* TILE_BLEND_NORTHEAST 2 */
  505. {-1, 0}, /* TILE_BLEND_WEST 3 */
  506. { 1, 0}, /* TILE_BLEND_EAST 4 */
  507. {-1, 1}, /* TILE_BLEND_SOUTHWEST 5 */
  508. { 0, 1}, /* TILE_BLEND_SOUTH 6 */
  509. { 1, 1}, /* TILE_BLEND_SOUTHEAST 7 */
  510. }
  511. func (pane * Pane) InitBlendTile(index, tx, ty int, tile * Tile) bool {
  512. blend := pane.Blend(tx, ty)
  513. if blend != nil {
  514. blend.Destroy()
  515. pane.SetBlend(tx, ty, nil)
  516. }
  517. target := al.TargetBitmap()
  518. tile_prio := tile.Blend
  519. for i:= 0; i < len(BlendOffsets) ; i++ {
  520. offset := BlendOffsets[i]
  521. txn := tx + offset.tx
  522. tyn := ty + offset.ty
  523. aid_tile := pane.Tile(txn, tyn)
  524. if aid_tile == nil { continue; }
  525. aid_prio := aid_tile.Blend
  526. if aid_prio <= tile_prio { continue; }
  527. blend_bmp := al.CreateBitmap(pane.Tileset.TileW, pane.Tileset.TileH /* , al.CONVERT_BITMAP */)
  528. if blend_bmp == nil { return false; }
  529. al.SetTargetBitmap(blend_bmp)
  530. al.ClearToColor(al.MapRGBA(0,0,0,0))
  531. PrepareBlend(blend_bmp, tile, aid_tile, i);
  532. }
  533. al.SetTargetBitmap(target)
  534. return true
  535. }
  536. const (
  537. MASK_SIDE_W = 16
  538. MASK_SIDE_H = 16
  539. MASK_CORNER_W = 16
  540. MASK_CORNER_H = 16
  541. MASK_W = 8
  542. MASK_H = 8
  543. )
  544. func (pane * Pane) InitMasks() {
  545. // load the masks into the pane
  546. for blend_type := 0; blend_type < BLEND_TYPE_MAX ; blend_type++ {
  547. fin1 := fmt.Sprintf("/image/masks/corner_mask_%d.png", blend_type)
  548. fin2 := fmt.Sprintf("/image/masks/side_mask_%d.png", blend_type)
  549. bmp1 := fifi.LoadBitmap(fin1)
  550. bmp2 := fifi.LoadBitmap(fin2)
  551. BlendMasks[blend_type][BLEND_CORNER] = bmp1
  552. BlendMasks[blend_type][BLEND_SIDE] = bmp2
  553. }
  554. }
  555. func (pane * Pane) InitBlend(index int) bool {
  556. if pane == nil { return false }
  557. if pane.Blends == nil { return false }
  558. if index > 4 { return false }
  559. tx := 0
  560. ty := 0
  561. w := pane.GridW
  562. h := pane.GridH
  563. for ty = 0 ; ty < h; ty++ {
  564. for tx = 0; tx < w; tx++ {
  565. tile := pane.Tile(tx, ty)
  566. if tile == nil { continue; }
  567. if tile.Blend < 1 { continue; }
  568. pane.InitBlendTile(index, tx, ty, tile)
  569. }
  570. }
  571. return true
  572. }