pane.go 21 KB

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