pane.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  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/camera"
  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. Shadows [][8]float32 // Slice of shadow polygons.
  153. }
  154. /**
  155. * A Pane is a layer of tiles for use in a tile map or tiled
  156. * background. A pane consists of individual tiles from the same
  157. * tile set. Different panes may have different tile sets.
  158. */
  159. type Pane struct {
  160. Tileset * Set
  161. Cells [][]Cell
  162. GridW int
  163. GridH int
  164. PixelW int
  165. PixelH int
  166. // This bitmap is the atlas used for blends. XXX: Not implemented yet.
  167. Blends * al.Bitmap
  168. Name string
  169. };
  170. /** Initializes a tile pane.
  171. * The pane will not clean up the tile set itself!
  172. */
  173. func (pane * Pane) Init(set * Set, gridw, gridh int, name string) (* Pane) {
  174. pane.Tileset = set
  175. pane.GridW = gridw
  176. pane.GridH = gridh
  177. pane.PixelW = pane.GridW * set.TileW
  178. pane.PixelH = pane.GridW * set.TileH
  179. pane.Name = name
  180. pane.Cells = make([][]Cell, pane.GridH)
  181. for i := range (pane.Cells) {
  182. pane.Cells[i] = make([]Cell, pane.GridW)
  183. }
  184. return pane
  185. }
  186. func NewPane(set * Set, gridw, gridh int, name string) (pane * Pane) {
  187. pane = &Pane{}
  188. return pane.Init(set, gridw, gridh, name)
  189. }
  190. func (pane * Pane) Outside(gridx, gridy int) bool {
  191. return ((gridx < 0) || (gridy < 0)) ||
  192. ((gridx >= pane.GridW) || (gridy >= pane.GridH))
  193. }
  194. func (pane * Pane) Cell(gridx, gridy int) * Cell {
  195. if pane.Outside(gridx, gridy) {
  196. return nil
  197. }
  198. return & pane.Cells[gridy][gridx]
  199. }
  200. func (pane * Pane) Tile(gridx, gridy int) * Tile {
  201. if pane.Outside(gridx, gridy) {
  202. return nil
  203. }
  204. return pane.Cells[gridy][gridx].Tile
  205. }
  206. func (pane * Pane) Blend(gridx, gridy int) * al.Bitmap {
  207. if pane.Outside(gridx, gridy) {
  208. return nil
  209. }
  210. return pane.Cells[gridy][gridx].Blend
  211. }
  212. func (pane * Pane) SetTile(gridx, gridy int, tile * Tile) * Tile {
  213. if pane.Outside(gridx, gridy) {
  214. return nil
  215. }
  216. pane.Cells[gridy][gridx].Tile = tile
  217. return tile
  218. }
  219. func (pane * Pane) SetTileIndex(gridx, gridy, index int) * Tile {
  220. return pane.SetTile(gridx, gridy, pane.Tileset.Tile(index))
  221. }
  222. func (pane * Pane) SetBlend(gridx, gridy int, blend * al.Bitmap) * al.Bitmap {
  223. if pane.Outside(gridx, gridy) {
  224. return nil
  225. }
  226. if nil != pane.Cells[gridy][gridx].Blend {
  227. pane.Cells[gridy][gridx].Blend.Destroy()
  228. }
  229. pane.Cells[gridy][gridx].Blend = blend
  230. return blend
  231. }
  232. func (pane * Pane) SetFlags(gridx, gridy, flags int) int {
  233. if pane.Outside(gridx, gridy) {
  234. return -1
  235. }
  236. pane.Cells[gridy][gridx].Flags = flags
  237. return flags
  238. }
  239. func (pane * Pane) SetTileRect(gridx, gridy, gridw, gridh int, tile * Tile) * Tile {
  240. for jj := gridy ; jj < (gridy + gridh) ; jj++ {
  241. for ii := gridx ; ii < (gridx + gridh) ; ii++ {
  242. pane.SetTile(ii, jj, tile)
  243. }
  244. }
  245. return tile
  246. }
  247. func (pane * Pane) Fill(tile * Tile) * Tile {
  248. return pane.SetTileRect(0, 0, pane.GridW, pane.GridH, nil)
  249. }
  250. func (cell * Cell) AddShadowPolygon(polygon [8]float32) {
  251. cell.Shadows = append(cell.Shadows, polygon)
  252. }
  253. func (cell * Cell) DeleteShadowPolygons() {
  254. cell.Shadows = nil
  255. }
  256. type DrawIterator func (cell * Cell, x, y float32, tx, ty int)
  257. /* Draws the tiles of the pane using an iterator function.
  258. * This must be done in one call because changing the source bitmap is less optimal.
  259. * You must hold bitmap drawing yourself if applicable.
  260. */
  261. func (pane * Pane) DrawIterate(camera * camera.Camera, iter DrawIterator) {
  262. gridwide := pane.GridW
  263. gridhigh := pane.GridH
  264. tilewide := pane.Tileset.TileW
  265. tilehigh := pane.Tileset.TileH
  266. x := int(camera.X)
  267. y := int(camera.Y)
  268. tx_start := x / tilewide
  269. ty_start := y / tilehigh
  270. tx_delta := 1 + (int(camera.W) / tilewide)
  271. ty_delta := 1 + (int(camera.H) / tilehigh)
  272. tx_stop := tx_start + tx_delta
  273. ty_stop := ty_start + ty_delta
  274. tx_index := 0
  275. ty_index := 0
  276. // realwide := pane.PixelW
  277. // realhigh := pane.PixelH
  278. // drawflag := 0
  279. if tx_start < 0 { tx_start = 0; }
  280. if ty_start < 0 { ty_start = 0; }
  281. if tx_stop > gridwide { tx_stop = gridwide; }
  282. if ty_stop > gridhigh { ty_stop = gridhigh; }
  283. y_draw := float32(-y + (ty_start * tilehigh))
  284. for ty_index = ty_start; ty_index < ty_stop; ty_index++ {
  285. y_draw += float32(tilehigh)
  286. x_draw := float32(-x + (tx_start * tilewide))
  287. row := pane.Cells[ty_index]
  288. for tx_index = tx_start ; tx_index < tx_stop; tx_index++ {
  289. x_draw += float32(tilewide)
  290. cell := &row[tx_index]
  291. iter(cell, x_draw, y_draw, tx_index, ty_index)
  292. }
  293. }
  294. }
  295. /* Draws the tiles of the pane. This must be done in one call because
  296. * changing the source bitmap is less optimal. */
  297. func (pane * Pane) DrawTiles(camera * camera.Camera) {
  298. gridwide := pane.GridW
  299. gridhigh := pane.GridH
  300. tilewide := pane.Tileset.TileW
  301. tilehigh := pane.Tileset.TileH
  302. x := int(camera.X)
  303. y := int(camera.Y)
  304. tx_start := x / tilewide
  305. ty_start := y / tilehigh
  306. tx_delta := 1 + (int(camera.W) / tilewide)
  307. ty_delta := 1 + (int(camera.H) / tilehigh)
  308. tx_stop := tx_start + tx_delta
  309. ty_stop := ty_start + ty_delta
  310. tx_index := 0
  311. ty_index := 0
  312. // realwide := pane.PixelW
  313. // realhigh := pane.PixelH
  314. // drawflag := 0
  315. al.HoldBitmapDrawing(true)
  316. if tx_start < 0 { tx_start = 0; }
  317. if ty_start < 0 { ty_start = 0; }
  318. if tx_stop > gridwide { tx_stop = gridwide; }
  319. if ty_stop > gridhigh { ty_stop = gridhigh; }
  320. y_draw := float32(-y + (ty_start * tilehigh))
  321. for ty_index = ty_start; ty_index < ty_stop; ty_index++ {
  322. y_draw += float32(tilehigh)
  323. x_draw := float32(-x + (tx_start * tilewide))
  324. row := pane.Cells[ty_index]
  325. for tx_index = tx_start ; tx_index < tx_stop; tx_index++ {
  326. x_draw += float32(tilewide)
  327. cell := row[tx_index]
  328. if (cell.Tile != nil) {
  329. cell.Tile.Draw(x_draw, y_draw, cell.Flags)
  330. }
  331. }
  332. }
  333. // Let go of hold
  334. al.HoldBitmapDrawing(false)
  335. }
  336. /* Draws the blends of the pane. This must be done in one call because
  337. * changing the source bitmap is less optimal. */
  338. func (pane * Pane) DrawBlends(camera * camera.Camera) {
  339. gridwide := pane.GridW
  340. gridhigh := pane.GridH
  341. tilewide := pane.Tileset.TileW
  342. tilehigh := pane.Tileset.TileH
  343. x := int(camera.X)
  344. y := int(camera.Y)
  345. tx_start := x / tilewide
  346. ty_start := y / tilehigh
  347. tx_delta := 1 + (int(camera.W) / tilewide)
  348. ty_delta := 1 + (int(camera.H) / tilehigh)
  349. tx_stop := tx_start + tx_delta
  350. ty_stop := ty_start + ty_delta
  351. tx_index := 0
  352. ty_index := 0
  353. // realwide := pane.PixelW
  354. // realhigh := pane.PixelH
  355. // drawflag := 0
  356. // al.HoldBitmapDrawing(true)
  357. if tx_start < 0 { tx_start = 0; }
  358. if ty_start < 0 { ty_start = 0; }
  359. if tx_stop > gridwide { tx_stop = gridwide; }
  360. if ty_stop > gridhigh { ty_stop = gridhigh; }
  361. y_draw := float32(-y + (ty_start * tilehigh))
  362. for ty_index = ty_start; ty_index < ty_stop; ty_index++ {
  363. y_draw += float32(tilehigh)
  364. x_draw := float32(-x + (tx_start * tilewide))
  365. row := pane.Cells[ty_index]
  366. for tx_index = tx_start ; tx_index < tx_stop; tx_index++ {
  367. x_draw += float32(tilewide)
  368. cell := row[tx_index]
  369. if (cell.Blend != nil) {
  370. cell.Blend.Draw(x_draw, y_draw, cell.Flags)
  371. }
  372. }
  373. }
  374. // Let go of hold
  375. // al.HoldBitmapDrawing(false)
  376. }
  377. func (pane * Pane) DrawOneShadowOn(cell * Cell, pane_below * Pane,
  378. tx, ty int, x, y float32) {
  379. tile := cell.Tile
  380. if (tile == nil) { return; }
  381. if (tile.Shadow == 0) { return; }
  382. shadow_color := al.MapRGBA(0, 0, 0, 128)
  383. edge_tile := pane.Tile(tx + 1, ty - 1)
  384. aid_tile := pane.Tile(tx + 1, ty)
  385. shadow_trapezium := false
  386. if (edge_tile != nil) && edge_tile.IsWall() {
  387. shadow_trapezium = true
  388. // here the shadow is at trapezium, not a parallelogram.
  389. }
  390. /* Tile sizes... */
  391. tw := float32(pane.Tileset.TileW)
  392. th := float32(pane.Tileset.TileH)
  393. /* Only cast a shadow to the east if no solid tile next to self.
  394. * Shadow is a parallelogram to simplify overlaps.
  395. */
  396. if (aid_tile == nil) || !aid_tile.IsWall() {
  397. low_tile := pane_below.Tile(tx + 1, ty)
  398. if (low_tile != nil) && (low_tile.ShadowMask != 1) {
  399. polygon := [8]float32 {
  400. x + tw , y ,
  401. x + tw , y + th ,
  402. x + tw * 1.5 , y + th * 0.5 ,
  403. x + tw * 1.5 , y - th * 0.5 ,
  404. }
  405. if (shadow_trapezium) {
  406. polygon[7] = y
  407. }
  408. al.DrawFilledPolygon(polygon[0:8], 0, shadow_color)
  409. }
  410. }
  411. aid_tile = pane.Tile(tx, ty-1)
  412. /* Only cast a shadow to the north if no solid tile above to self.
  413. * Shadow is a parallelogram to simplify overlaps.
  414. */
  415. if (aid_tile == nil) || !aid_tile.IsWall() {
  416. low_tile := pane_below.Tile(tx, ty - 1)
  417. if (low_tile != nil) && (low_tile.ShadowMask != 1) {
  418. polygon := [8]float32 {
  419. x + tw , y ,
  420. x + tw , y ,
  421. x + tw * 1.5 , y - th * 0.5 ,
  422. x + tw * 0.5 , y - th * 0.5 ,
  423. }
  424. if (shadow_trapezium) {
  425. polygon[4] = x + tw
  426. }
  427. al.DrawFilledPolygon(polygon[0:8], 0, shadow_color)
  428. }
  429. }
  430. }
  431. /** Draws the shadows that tile pane pane casts onto the pane pane_below
  432. * with the camera delimiting the view.
  433. * On a classic tile map the bottom is to the south, so this function draws
  434. * "classic" shadows cast as if the sun were in the south-west,
  435. * with the shadows pointing north-east.
  436. */
  437. func (pane * Pane) DrawShadowsOn(pane_below * Pane, camera * camera.Camera) {
  438. gridwide := pane.GridW
  439. gridhigh := pane.GridH
  440. tilewide := pane.Tileset.TileW
  441. tilehigh := pane.Tileset.TileH
  442. x := int(camera.X)
  443. y := int(camera.Y)
  444. tx_start := x / tilewide
  445. ty_start := y / tilehigh
  446. tx_delta := 1 + (int(camera.W) / tilewide)
  447. ty_delta := 1 + (int(camera.H) / tilehigh)
  448. tx_stop := tx_start + tx_delta
  449. ty_stop := ty_start + ty_delta
  450. tx_index := 0
  451. ty_index := 0
  452. // realwide := pane.PixelW
  453. // realhigh := pane.PixelH
  454. // drawflag := 0
  455. // al.HoldBitmapDrawing(true)
  456. if tx_start < 0 { tx_start = 0; }
  457. if ty_start < 0 { ty_start = 0; }
  458. if tx_stop > gridwide { tx_stop = gridwide; }
  459. if ty_stop > gridhigh { ty_stop = gridhigh; }
  460. y_draw := float32(-y + (ty_start * tilehigh))
  461. for ty_index = ty_start; ty_index < ty_stop; ty_index++ {
  462. y_draw += float32(tilehigh)
  463. x_draw := float32(-x + (tx_start * tilewide))
  464. row := pane.Cells[ty_index]
  465. for tx_index = tx_start ; tx_index < tx_stop; tx_index++ {
  466. x_draw += float32(tilewide)
  467. cell := &row[tx_index]
  468. pane.DrawOneShadowOn(cell, pane_below, tx_index, ty_index, x_draw, y_draw)
  469. }
  470. }
  471. // Let go of hold
  472. // al.HoldBitmapDrawing(false)
  473. }
  474. /** Updates the tile pane. Curently does nothing, but this may change. */
  475. func (pane * Pane) Update(dt float64) {
  476. if pane.Tileset != nil {
  477. pane.Tileset.Update(dt)
  478. }
  479. }
  480. /** Gets a tile from a the tilepane's tile set by it's tile id. **/
  481. func (pane * Pane) TileFromSet(index int) * Tile {
  482. set := pane.Tileset
  483. if nil == set {
  484. return nil;
  485. }
  486. return set.Tile(index)
  487. }
  488. type BlendOffset struct {
  489. tx int
  490. ty int
  491. }
  492. var BlendOffsets [8]BlendOffset = [8]BlendOffset{
  493. {-1, -1}, /* TILE_BLEND_NORTHWEST 0 */
  494. { 0, -1}, /* TILE_BLEND_NORTH 1 */
  495. { 1, -1}, /* TILE_BLEND_NORTHEAST 2 */
  496. {-1, 0}, /* TILE_BLEND_WEST 3 */
  497. { 1, 0}, /* TILE_BLEND_EAST 4 */
  498. {-1, 1}, /* TILE_BLEND_SOUTHWEST 5 */
  499. { 0, 1}, /* TILE_BLEND_SOUTH 6 */
  500. { 1, 1}, /* TILE_BLEND_SOUTHEAST 7 */
  501. }
  502. func (pane * Pane) InitBlendTile(index, tx, ty int, tile * Tile) bool {
  503. blend := pane.Blend(tx, ty)
  504. if blend != nil {
  505. blend.Destroy()
  506. pane.SetBlend(tx, ty, nil)
  507. }
  508. target := al.TargetBitmap()
  509. tile_prio := tile.Blend
  510. for i:= 0; i < len(BlendOffsets) ; i++ {
  511. offset := BlendOffsets[i]
  512. txn := tx + offset.tx
  513. tyn := ty + offset.ty
  514. aid_tile := pane.Tile(txn, tyn)
  515. if aid_tile == nil { continue; }
  516. aid_prio := aid_tile.Blend
  517. if aid_prio <= tile_prio { continue; }
  518. blend_bmp := al.CreateBitmap(pane.Tileset.TileW, pane.Tileset.TileH /* , al.CONVERT_BITMAP */)
  519. if blend_bmp == nil { return false; }
  520. al.SetTargetBitmap(blend_bmp)
  521. al.ClearToColor(al.MapRGBA(0,0,0,0))
  522. PrepareBlend(blend_bmp, tile, aid_tile, i);
  523. }
  524. al.SetTargetBitmap(target)
  525. return true
  526. }
  527. const (
  528. MASK_SIDE_W = 16
  529. MASK_SIDE_H = 16
  530. MASK_CORNER_W = 16
  531. MASK_CORNER_H = 16
  532. MASK_W = 8
  533. MASK_H = 8
  534. )
  535. func (pane * Pane) InitMasks() {
  536. // load the masks into the pane
  537. for blend_type := 0; blend_type < BLEND_TYPE_MAX ; blend_type++ {
  538. fin1 := fmt.Sprintf("/image/masks/corner_mask_%d.png", blend_type)
  539. fin2 := fmt.Sprintf("/image/masks/side_mask_%d.png", blend_type)
  540. bmp1 := fifi.LoadBitmap(fin1)
  541. bmp2 := fifi.LoadBitmap(fin2)
  542. BlendMasks[blend_type][BLEND_CORNER] = bmp1
  543. BlendMasks[blend_type][BLEND_SIDE] = bmp2
  544. }
  545. }
  546. func (pane * Pane) InitBlend(index int) bool {
  547. if pane == nil { return false }
  548. if pane.Blends == nil { return false }
  549. if index > 4 { return false }
  550. tx := 0
  551. ty := 0
  552. w := pane.GridW
  553. h := pane.GridH
  554. for ty = 0 ; ty < h; ty++ {
  555. for tx = 0; tx < w; tx++ {
  556. tile := pane.Tile(tx, ty)
  557. if tile == nil { continue; }
  558. if tile.Blend < 1 { continue; }
  559. pane.InitBlendTile(index, tx, ty, tile)
  560. }
  561. }
  562. return true
  563. }