123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684 |
- package tile
- import "fmt"
- import "gitlab.com/beoran/al5go/al"
- // import "gitlab.com/beoran/ebsgo/engine/geometry/point"
- import "gitlab.com/beoran/ebsgo/engine/physics"
- import "gitlab.com/beoran/ebsgo/engine/fifi"
- import "gitlab.com/beoran/ebsgo/monolog"
- /* Tile blending direction constants. */
- const (
- BLEND_NORTHWEST = 0
- BLEND_NORTH = 1
- BLEND_NORTHEAST = 2
- BLEND_WEST = 3
- BLEND_EAST = 4
- BLEND_SOUTHWEST = 5
- BLEND_SOUTH = 6
- BLEND_SOUTHEAST = 7
- BLEND_DIRECTION_MAX = 8
- )
- /* Tile blending shapes */
- const (
- BLEND_CORNER = 0
- BLEND_SIDE = 1
- BLEND_SHAPE_MAX = 2
- )
- /* Tile blending types. */
- const (
- BLEND_SHARP = 0
- BLEND_GRADUAL = 1
- BLEND_FUZZY = 2
- BLEND_FUZZY_GRADUAL = 3
- BLEND_TYPE_MAX = 3 // XXX data for type FUZZY_GRADUAL is missing...
- )
- const BLEND_BITMAPS_MAX = 255
- /* A cache of generated generic blending masks. */
- var BlendMasks [BLEND_TYPE_MAX][BLEND_SHAPE_MAX]*al.Bitmap
- /* Lookup array with info on how the mask should be applied, i. e. flipped. */
- var BlendFlags [BLEND_DIRECTION_MAX]int = [BLEND_DIRECTION_MAX] int{
- 0,
- 0,
- al.FLIP_HORIZONTAL,
- 0,
- al.FLIP_HORIZONTAL,
- al.FLIP_VERTICAL,
- al.FLIP_VERTICAL,
- al.FLIP_HORIZONTAL | al.FLIP_VERTICAL,
- }
- /* Lookup array with info on which "side" mask should be used. */
- var BlendSides [BLEND_DIRECTION_MAX]int = [BLEND_DIRECTION_MAX]int {
- BLEND_CORNER,
- BLEND_SIDE ,
- BLEND_CORNER,
- BLEND_SIDE ,
- BLEND_SIDE ,
- BLEND_CORNER,
- BLEND_SIDE ,
- BLEND_CORNER,
- }
- /* Lookup array with info on how the mask should be turned, i. e. rotated. */
- var BlendAngles [BLEND_DIRECTION_MAX]float32 = [BLEND_DIRECTION_MAX]float32 {
- 0.0,
- 0.0,
- 0.0,
- 3 * al.PI / 2.0,
- al.PI / 2.0,
- 0.0,
- 0.0,
- 0.0,
- }
- /*
-
- ## Implementation of automatic overlapping ##
-
- In the simple case where there are only 2 different kinds of tiles,
- then for a tile somewhere in the map, that tile has 8 neighbours, and thus
- there are 8**2 or 256 different possible layouts of these neighbours around that
- single tile, and 256 different blends would be needed.
-
- Of course, this is a staggering amount for hand drawn graphics, and even for
- automatically generated mask images, this takes up a hefty chunk of memory,
- so some kind of simplification is needed.
-
- The first simplification is the use of the tile's blend value as a blend *priority*
- value. The tile with the lower blend priority will be blended with the
- tile with the higher blend priority blending over it. Tiles with equal blend
- priority will simply not blend. This reduces the possibilities because in
- cases where 3 or more tyle types must blend, without priorities,
- the number of possible blends would become even larger.
-
- Let's consider the possibilities takng symmetry in account. If only 2 tiles
- that will blend are adjacent, there are 8 possibilities. However there are 4
- symmetric rotations of the 2 cases of the 2 tiles being either side-to-side
- or corner to corner. In case of side-to side, the blend should go rougmly like
- this: (scaled down to 8x8
-
- ..........OOOOOOOO ................OO
- ..........OOOOOOOO ..............OOOO
- ..........OOOOOOOO ............OOOOOO
- ..........OOOOOOOO ............OOOOOO
- ..........OOOOOOOO => ............OOOOOO
- ..........OOOOOOOO ............OOOOOO
- ..........OOOOOOOO ...........OOOOOOO
- ..........OOOOOOOO ..........OOOOOOOO
-
- And corner to corner:
-
- OOOOOOOO OOOOOOOO
- OOOOOOOO OOOOOOOO
- OOOOOOOO OOOOOOOO
- OOOOOOOO OOOOOOOO
- OOOOOOOO => OOOOOOOO
- OOOOOOOO OOOOOOOO
- OOOOOOOO .OOOOOOO
- OOOOOOOO ..OOOOOO
- .......... ..........
- .......... ..........
- .......... ..........
- .......... ..........
- .......... => ..........
- .......... ..........
- .......... ..........
- .......... ..........
-
- If the masks are judiciouly chosen, and all align correctly,
- then it will suffice to have just 2 mask images which get rotated as needed,
- one mask for the side to side, and one for corner to corner.
- Each of the masks follows a strict pattern, that is, the side by side
- has a \__/ - like shape were the depth of the overlap is at most 1/4th of the
- tile height. (Or is it 1/3, let's check it out).
-
- Then, for every overlapping tile, an overlap bitmap can be generated
- when loading the tile layer it is in, and that bitmap can then be used to
- draw the tile in stead of the original bitmap.
- ## Implementation of automatic shadows ##
- Every cell in the tile pane contains a slice of shadow polygons,
- that is set up before rendering. This should in the future be used in stead of
- the current live polygons generated at draw time but this will require
- an approach where a camera transform is applied whilst drawing in stead of
- the current situation where we use the camera info directly to calculate
- the draw positions.
- */
- func PrepareBlend(blend * al.Bitmap, tile * Tile, blentile * Tile, direction int ) * al.Bitmap {
- side := BlendSides[direction]
- angle := BlendAngles[direction]
- flags := BlendFlags[direction]
- maskid:= tile.BlendMask
- mask := BlendMasks[maskid][side]
- if mask == nil {
- return nil
- } else {
- tile.DrawMaskedTo(blend, mask, angle, flags)
- return blend
- }
- }
- /**
- * A Cell is an individual part of a pane. It contains a tile,
- * a blend bitmap, two shadow polygons, and rendering flags.
- */
- type Cell struct {
- * Tile
- Blend * al.Bitmap
- Flags int
- Rotate float32
- Shadows [][8]float32 // Slice of shadow polygons.
- }
- /**
- * A Pane is a layer of tiles for use in a tile map or tiled
- * background. A pane consists of individual tiles from the same
- * tile set. Different panes may have different tile sets.
- */
- type Pane struct {
- Tileset * Set
- Cells [][]Cell
- GridW int
- GridH int
- PixelW int
- PixelH int
- // This bitmap is the atlas used for blends. XXX: Not implemented yet.
- Blends * al.Bitmap
- Name string
- };
- /* First group id of the tile set of the plane. */
- func (pane * Pane) FirstGID() int {
- if pane.Tileset == nil {
- return 0
- } else {
- return pane.Tileset.FirstGID
- }
- }
- /** Initializes a tile pane.
- * The pane will not clean up the tile set itself!
- */
- func (pane * Pane) Init(set * Set, gridw, gridh int, name string) (* Pane) {
- pane.Tileset = set
- pane.GridW = gridw
- pane.GridH = gridh
- pane.PixelW = pane.GridW * set.TileW
- pane.PixelH = pane.GridW * set.TileH
- pane.Name = name
- pane.Cells = make([][]Cell, pane.GridH)
- for i := range (pane.Cells) {
- pane.Cells[i] = make([]Cell, pane.GridW)
- }
- return pane
- }
- func NewPane(set * Set, gridw, gridh int, name string) (pane * Pane) {
- pane = &Pane{}
- return pane.Init(set, gridw, gridh, name)
- }
-
- func (pane * Pane) Outside(gridx, gridy int) bool {
- return ((gridx < 0) || (gridy < 0)) ||
- ((gridx >= pane.GridW) || (gridy >= pane.GridH))
- }
- func (pane * Pane) Cell(gridx, gridy int) * Cell {
- if pane.Outside(gridx, gridy) {
- return nil
- }
- return & pane.Cells[gridy][gridx]
- }
- func (pane * Pane) Tile(gridx, gridy int) * Tile {
- if pane.Outside(gridx, gridy) {
- return nil
- }
- return pane.Cells[gridy][gridx].Tile
- }
- func (pane * Pane) Blend(gridx, gridy int) * al.Bitmap {
- if pane.Outside(gridx, gridy) {
- return nil
- }
- return pane.Cells[gridy][gridx].Blend
- }
- func (pane * Pane) SetTile(gridx, gridy int, tile * Tile) * Tile {
- if pane.Outside(gridx, gridy) {
- return nil
- }
- pane.Cells[gridy][gridx].Tile = tile
- return tile
- }
- func (pane * Pane) SetTileIndex(gridx, gridy, index int) * Tile {
- return pane.SetTile(gridx, gridy, pane.Tileset.Tile(index))
- }
- func (pane * Pane) SetBlend(gridx, gridy int, blend * al.Bitmap) * al.Bitmap {
- if pane.Outside(gridx, gridy) {
- return nil
- }
- if nil != pane.Cells[gridy][gridx].Blend {
- pane.Cells[gridy][gridx].Blend.Destroy()
- }
- pane.Cells[gridy][gridx].Blend = blend
- return blend
- }
- func (pane * Pane) SetFlags(gridx, gridy int, flags int) int {
- if pane.Outside(gridx, gridy) {
- return -1
- }
- pane.Cells[gridy][gridx].Flags = flags
- return flags
- }
- func (pane * Pane) SetTileRect(gridx, gridy, gridw, gridh int, tile * Tile) * Tile {
- for jj := gridy ; jj < (gridy + gridh) ; jj++ {
- for ii := gridx ; ii < (gridx + gridh) ; ii++ {
- pane.SetTile(ii, jj, tile)
- }
- }
- return tile
- }
- func (pane * Pane) Fill(tile * Tile) * Tile {
- return pane.SetTileRect(0, 0, pane.GridW, pane.GridH, nil)
- }
- func (cell * Cell) AddShadowPolygon(polygon [8]float32) {
- cell.Shadows = append(cell.Shadows, polygon)
- }
- func (cell * Cell) DeleteShadowPolygons() {
- cell.Shadows = nil
- }
- type DrawIterator func (cell * Cell, x, y float32, tx, ty int)
- /* Draws the tiles of the pane using an iterator function.
- * This must be done in one call because changing the source bitmap is less optimal.
- * You must hold bitmap drawing yourself if applicable.
- */
- func (pane * Pane) DrawIterate(camera * physics.Camera, iter DrawIterator) {
- gridwide := pane.GridW
- gridhigh := pane.GridH
- tilewide := pane.Tileset.TileW
- tilehigh := pane.Tileset.TileH
- x := int(camera.X)
- y := int(camera.Y)
- tx_start := x / tilewide
- ty_start := y / tilehigh
- tx_delta := 1 + (int(camera.W) / tilewide)
- ty_delta := 1 + (int(camera.H) / tilehigh)
- tx_stop := tx_start + tx_delta
- ty_stop := ty_start + ty_delta
- tx_index := 0
- ty_index := 0
- // realwide := pane.PixelW
- // realhigh := pane.PixelH
- // drawflag := 0
- if tx_start < 0 { tx_start = 0; }
- if ty_start < 0 { ty_start = 0; }
- if tx_stop > gridwide { tx_stop = gridwide; }
- if ty_stop > gridhigh { ty_stop = gridhigh; }
- y_draw := float32(-y + (ty_start * tilehigh))
- for ty_index = ty_start; ty_index < ty_stop; ty_index++ {
- y_draw += float32(tilehigh)
- x_draw := float32(-x + (tx_start * tilewide))
- row := pane.Cells[ty_index]
- for tx_index = tx_start ; tx_index < tx_stop; tx_index++ {
- x_draw += float32(tilewide)
- cell := &row[tx_index]
- iter(cell, x_draw, y_draw, tx_index, ty_index)
- }
- }
- }
- /* Draws the tiles of the pane. This must be done in one call because
- * changing the source bitmap is less optimal. */
- func (pane * Pane) DrawTiles(camera * physics.Camera) {
- gridwide := pane.GridW
- gridhigh := pane.GridH
- tilewide := pane.Tileset.TileW
- tilehigh := pane.Tileset.TileH
- x := int(camera.X)
- y := int(camera.Y)
- tx_start := x / tilewide
- ty_start := y / tilehigh
- tx_delta := 1 + (int(camera.W) / tilewide)
- ty_delta := 1 + (int(camera.H) / tilehigh)
- tx_stop := tx_start + tx_delta
- ty_stop := ty_start + ty_delta
- tx_index := 0
- ty_index := 0
- // realwide := pane.PixelW
- // realhigh := pane.PixelH
- // drawflag := 0
- al.HoldBitmapDrawing(true)
- if tx_start < 0 { tx_start = 0; }
- if ty_start < 0 { ty_start = 0; }
- if tx_stop > gridwide { tx_stop = gridwide; }
- if ty_stop > gridhigh { ty_stop = gridhigh; }
- y_draw := float32(-y + (ty_start * tilehigh))
- for ty_index = ty_start; ty_index < ty_stop; ty_index++ {
- y_draw += float32(tilehigh)
- x_draw := float32(-x + (tx_start * tilewide))
- row := pane.Cells[ty_index]
- for tx_index = tx_start ; tx_index < tx_stop; tx_index++ {
- x_draw += float32(tilewide)
- cell := row[tx_index]
- if (cell.Tile != nil) {
- cell.Tile.Draw(x_draw, y_draw, cell.Flags)
- }
- }
- }
- // Let go of hold
- al.HoldBitmapDrawing(false)
- }
- /* Draws the blends of the pane. This must be done in one call because
- * changing the source bitmap is less optimal. */
- func (pane * Pane) DrawBlends(camera * physics.Camera) {
- gridwide := pane.GridW
- gridhigh := pane.GridH
- tilewide := pane.Tileset.TileW
- tilehigh := pane.Tileset.TileH
- x := int(camera.X)
- y := int(camera.Y)
- tx_start := x / tilewide
- ty_start := y / tilehigh
- tx_delta := 1 + (int(camera.W) / tilewide)
- ty_delta := 1 + (int(camera.H) / tilehigh)
- tx_stop := tx_start + tx_delta
- ty_stop := ty_start + ty_delta
- tx_index := 0
- ty_index := 0
- // realwide := pane.PixelW
- // realhigh := pane.PixelH
- // drawflag := 0
- // al.HoldBitmapDrawing(true)
- if tx_start < 0 { tx_start = 0; }
- if ty_start < 0 { ty_start = 0; }
- if tx_stop > gridwide { tx_stop = gridwide; }
- if ty_stop > gridhigh { ty_stop = gridhigh; }
- y_draw := float32(-y + (ty_start * tilehigh))
- for ty_index = ty_start; ty_index < ty_stop; ty_index++ {
- y_draw += float32(tilehigh)
- x_draw := float32(-x + (tx_start * tilewide))
- row := pane.Cells[ty_index]
- for tx_index = tx_start ; tx_index < tx_stop; tx_index++ {
- x_draw += float32(tilewide)
- cell := row[tx_index]
- if (cell.Blend != nil) {
- cell.Blend.Draw(x_draw, y_draw, cell.Flags)
- }
- }
- }
- // Let go of hold
- // al.HoldBitmapDrawing(false)
- }
- func (pane * Pane) DrawOneShadowOn(cell * Cell, pane_below * Pane,
- tx, ty int, x, y float32) {
- tile := cell.Tile
- if (tile == nil) { return; }
- if (tile.Shadow == 0) { return; }
- shadow_color := al.MapRGBA(0, 0, 0, 128)
- edge_tile := pane.Tile(tx + 1, ty - 1)
- aid_tile := pane.Tile(tx + 1, ty)
- shadow_trapezium := false
- if (edge_tile != nil) && edge_tile.IsWall() {
- shadow_trapezium = true
- // here the shadow is at trapezium, not a parallelogram.
- }
-
- /* Tile sizes... */
- tw := float32(pane.Tileset.TileW)
- th := float32(pane.Tileset.TileH)
-
-
- /* Only cast a shadow to the east if no solid tile next to self.
- * Shadow is a parallelogram to simplify overlaps.
- */
- if (aid_tile == nil) || !aid_tile.IsWall() {
- low_tile := pane_below.Tile(tx + 1, ty)
- if (low_tile != nil) && (low_tile.ShadowMask != 1) {
- polygon := [8]float32 {
- x + tw , y ,
- x + tw , y + th ,
- x + tw * 1.5 , y + th * 0.5 ,
- x + tw * 1.5 , y - th * 0.5 ,
- }
-
- if (shadow_trapezium) {
- polygon[7] = y
- }
- al.DrawFilledPolygon(polygon[0:8], 0, shadow_color)
- }
- }
-
- aid_tile = pane.Tile(tx, ty-1)
- /* Only cast a shadow to the north if no solid tile above to self.
- * Shadow is a parallelogram to simplify overlaps.
- */
-
- if (aid_tile == nil) || !aid_tile.IsWall() {
- low_tile := pane_below.Tile(tx, ty - 1)
- if (low_tile != nil) && (low_tile.ShadowMask != 1) {
- polygon := [8]float32 {
- x + tw , y ,
- x + tw , y ,
- x + tw * 1.5 , y - th * 0.5 ,
- x + tw * 0.5 , y - th * 0.5 ,
- }
-
- if (shadow_trapezium) {
- polygon[4] = x + tw
- }
- al.DrawFilledPolygon(polygon[0:8], 0, shadow_color)
- }
- }
- }
- /** Draws the shadows that tile pane pane casts onto the pane pane_below
- * with the camera delimiting the view.
- * On a classic tile map the bottom is to the south, so this function draws
- * "classic" shadows cast as if the sun were in the south-west,
- * with the shadows pointing north-east.
- */
- func (pane * Pane) DrawShadowsOn(pane_below * Pane, camera * physics.Camera) {
- gridwide := pane.GridW
- gridhigh := pane.GridH
- tilewide := pane.Tileset.TileW
- tilehigh := pane.Tileset.TileH
- x := int(camera.X)
- y := int(camera.Y)
- tx_start := x / tilewide
- ty_start := y / tilehigh
- tx_delta := 1 + (int(camera.W) / tilewide)
- ty_delta := 1 + (int(camera.H) / tilehigh)
- tx_stop := tx_start + tx_delta
- ty_stop := ty_start + ty_delta
- tx_index := 0
- ty_index := 0
- // realwide := pane.PixelW
- // realhigh := pane.PixelH
- // drawflag := 0
- // al.HoldBitmapDrawing(true)
- if tx_start < 0 { tx_start = 0; }
- if ty_start < 0 { ty_start = 0; }
- if tx_stop > gridwide { tx_stop = gridwide; }
- if ty_stop > gridhigh { ty_stop = gridhigh; }
- y_draw := float32(-y + (ty_start * tilehigh))
- for ty_index = ty_start; ty_index < ty_stop; ty_index++ {
- y_draw += float32(tilehigh)
- x_draw := float32(-x + (tx_start * tilewide))
- row := pane.Cells[ty_index]
- for tx_index = tx_start ; tx_index < tx_stop; tx_index++ {
- x_draw += float32(tilewide)
- cell := &row[tx_index]
- pane.DrawOneShadowOn(cell, pane_below, tx_index, ty_index, x_draw, y_draw)
- }
- }
- // Let go of hold
- // al.HoldBitmapDrawing(false)
- }
- /** Updates the tile pane. Curently does nothing, but this may change. */
- func (pane * Pane) Update(dt float64) {
- if pane.Tileset != nil {
- pane.Tileset.Update(dt)
- }
- }
- /** Gets a tile from a the tilepane's tile set by it's tile id. **/
- func (pane * Pane) TileFromSet(index int) * Tile {
- set := pane.Tileset
- if nil == set {
- return nil;
- }
- return set.Tile(index)
- }
- type BlendOffset struct {
- tx int
- ty int
- }
- var BlendOffsets [8]BlendOffset = [8]BlendOffset{
- {-1, -1}, /* TILE_BLEND_NORTHWEST 0 */
- { 0, -1}, /* TILE_BLEND_NORTH 1 */
- { 1, -1}, /* TILE_BLEND_NORTHEAST 2 */
- {-1, 0}, /* TILE_BLEND_WEST 3 */
- { 1, 0}, /* TILE_BLEND_EAST 4 */
- {-1, 1}, /* TILE_BLEND_SOUTHWEST 5 */
- { 0, 1}, /* TILE_BLEND_SOUTH 6 */
- { 1, 1}, /* TILE_BLEND_SOUTHEAST 7 */
- }
- func (pane * Pane) InitBlendTile(index, tx, ty int, tile * Tile) bool {
- // SetBlend calls Destoy() on the bitmap automagically
- pane.SetBlend(tx, ty, nil)
-
- target := al.TargetBitmap()
- tile_prio := tile.Blend
- for i:= 0; i < len(BlendOffsets) ; i++ {
- offset := BlendOffsets[i]
- txn := tx + offset.tx
- tyn := ty + offset.ty
- aid_tile := pane.Tile(txn, tyn)
- if aid_tile == nil { continue; }
- aid_prio := aid_tile.Blend
- if aid_prio <= tile_prio { continue; }
- blend_bmp := al.CreateBitmap(pane.Tileset.TileW, pane.Tileset.TileH /* , al.CONVERT_BITMAP */)
- if blend_bmp == nil { return false; }
- al.SetTargetBitmap(blend_bmp)
- al.ClearToColor(al.MapRGBA(0,0,0,0))
- PrepareBlend(blend_bmp, tile, aid_tile, i);
- }
-
- al.SetTargetBitmap(target)
- return true
- }
- const (
- MASK_SIDE_W = 16
- MASK_SIDE_H = 16
- MASK_CORNER_W = 16
- MASK_CORNER_H = 16
- MASK_W = 8
- MASK_H = 8
- )
- func InitBlendMasks() {
- // load the masks into the pane
- for blend_type := 0; blend_type < BLEND_TYPE_MAX ; blend_type++ {
- fin1 := fmt.Sprintf("/image/masks/corner_mask_%d.png", blend_type)
- fin2 := fmt.Sprintf("/image/masks/side_mask_%d.png", blend_type)
-
- bmp1 := fifi.LoadBitmap(fin1)
- bmp2 := fifi.LoadBitmap(fin2)
- BlendMasks[blend_type][BLEND_CORNER] = bmp1
- BlendMasks[blend_type][BLEND_SIDE] = bmp2
- if bmp1 == nil {
- monolog.Error("Could not load blend mask %d %d", blend_type, BLEND_CORNER)
- }
- if bmp2 == nil {
- monolog.Error("Could not load blend mask %d %d", blend_type, BLEND_SIDE)
- }
- }
- }
- func (pane * Pane) InitBlend(index int) bool {
- if pane == nil { return false }
- if pane.Blends == nil { return false }
- w := pane.GridW
- h := pane.GridH
- for ty := 0 ; ty < h; ty++ {
- for tx := 0; tx < w; tx++ {
- tile := pane.Tile(tx, ty)
- if tile == nil { continue; }
- if tile.Blend < 1 { continue; }
- monolog.Info("Will it blend? %d %d %d", tx, ty, tile.Blend)
- pane.InitBlendTile(index, tx, ty, tile)
- }
- }
- return true
- }
- func (pane * Pane) Close() {
- // No need to close tile set, the map will close them.
- w := pane.GridW
- h := pane.GridH
- for ty := 0 ; ty < h; ty++ {
- for tx := 0; tx < w; tx++ {
- pane.SetBlend(tx, ty, nil)
- }
- }
-
- if pane.Blends != nil {
- pane.Blends.Destroy()
- pane.Blends = nil
- }
- }
|