http://www.cnitblog.com/sword/archive/2007/04/21/26000.aspx
整个贴图过程分为4个步骤:
1. 删除地块
2. 拼接地块
3. 排序地块层
4. 更新地块
有2种类型的地形纹理:
根据上面这张排好索引的图片,加上效果图可以知道基本地块为:
1 | 2
8 | 16
然后是随机地块,数据如下:
s32 s_pBaseTexIndex_c[] = { 1, 2, 8, 16 };
s32 s_pRandTexIndex_c[] = { 0, 4, 5, 6, 7, 12, 13, 14, 15, 20, 21, 22, 23, 27, 28, 29, 30, 31 };
整个贴图算法都是基于上面这个基本索引而来.4个基本索引相加为27,是一个很特别的索引.
举2个例子:
1 | 2+1 1 | 3
8 | 16+8 = 8 | 24 =
1 | 2 1 | 2
8+1 | 16+2 = 9 | 18 =
一个格子最多可以贴4个地块,也就是4层地块,下面是基本数据定义.
// 地形顶点数据
struct TeVertex
{
f32 fHeight; ///< 地形高度值
Vector3f v3Normal; ///< 地形顶点法向量
};
// 地形地块纹理数据
struct TeTile
{
s8 Block[TE_TILE_COUNT]; ///< 纹理中的一块
u8 Texture[TE_TILE_COUNT]; ///< 纹理ID,255代表空
};
首先初始化一个32*32的地形数据:
m_pVertex = new TeVertex[32*32];
m_pTile = new TeTile[32*32];
for( i = 0; i < 32*32; ++i )
{
nBlock = s_pRandTexIndex_c[rand() % 18];
m_pVertex[i].fHeight = 0.0f;
m_pTile[i].Block[0] = nBlock;
m_pTile[i].Texture[0] = 0;
m_pTile[i].Block[1] = 0;
m_pTile[i].Texture[1] = 255;
m_pTile[i].Block[2] = 0;
m_pTile[i].Texture[2] = 255;
m_pTile[i].Block[3] = 0;
m_pTile[i].Texture[3] = 255;
}
在拼接之前首先是找出4个要拼接的格子,如图:
1. 删除地块
1-1: 如果当前地块第0层的纹理索引不为0并且Block索引是随机地块的话,格子的数据需要调整, 算法为用27减去除第0层外所有有效层的Block索引,最后的结果赋予第0层的Block.
1-2: 循环直到找出如果4个格子的某一层的Texture索引都相同,并找出所在的层,然后在做以下判断:
1-2-1: 如果这4个格子的这4层的Block索引都是随机地块索引,并且Texture索引比要贴的Texture索引大的话,则这4个格子的相应Block索引都要变为27减去基本索引. 然后回到2-1.
1-2-2: 1-2-1不成立的话,判断4个格子的Block是否可删除,条件是用当前地块的当前层的Block索引减去基本地块,如果是随机地块索引(除开0和27)则不合法,其余结果是合法的.
1-2-3: 将4个格子的对应层的Block索引都减去一个值.如果是Block索引是随机地块索引,则用27减去基本地块索引.否则用自身的Block索引减去基本索引值,如果减出来的结果是0的话, 则设置这个格子的这一层的Texture索引为255
2. 拼接地块
首先是找出要拼接纹理对应的层次,这中间涉及到调节层次数据,看下面的代码.接下来就是修改Block索引,主要的操作就是加上基本索引.在这中间涉及到的判断相当的多,还是看代码直接:),值得注意的是当设置的地块Block索引为27的时候需要特殊处理.
3. 排序地块层
这一步最简单,一共才4层,最简单的冒泡排序就行了:)
4. 更新地块
把一个地块中所有的地块索引相加,索引为随机地块的不参与,如果最后的结果为27那么需要对这个地块的数据做调整.如果这个格子的Texture索引不是0的话,把这个格子的第0层的Block索引设置为随机地块索引.如果是0的话,则第0层的Texture索引变为第1层的Texture索引,并且把第2层的数据复制到第1层,把第3层的数据复制到第2层,第3层的数据设置为空.
由于网上查不到相关的资料,上面这些都是我通过观察war3的编辑器总结出来的,希望可以给在做类似war3这种地形贴图的朋友一些帮助:),有不明白的地方可以在QQ(76537477)上联系我.
最后贴上我的效果图和核心代码:
算法的基本代码(为了简单明了,下面的代码是简化了的, 这里实在是不知道怎么排版啊)
#define TE_INVALID_TILE 255
#define TE_TILE_LEN 2.0f
#define TE_TEX_BASE 4 // 地形纹理基本变换数
#define TE_MAX_TEX 8 // 地形最多支持8种不同的纹理
#define TE_TEX_RAND_S 2 // 256的地形纹理最大变换数
#define TE_TEX_RAND_C 18 // 512的地形纹理最大变换数
#define TE_TEX_COUNT_S 16 // Simple
#define TE_TEX_COUNT_C 32 // Complex//-------------&-------------
// ---------------------------&-------------------------
void SetTile( const Vector3f & v3Pos )
{
if ( m_nSelectTexture < 0 || m_nSelectTexture >= m_vecTexture.Size() )
return ;
f32 fDis = TE_TILE_LEN / 2.0f ;
s32 nLDTile = (s32)((v3Pos.y - fDis) / TE_TILE_LEN) * m_nTileWid + (s32)((v3Pos.x - fDis) / TE_TILE_LEN);
s32 nRDTile = (s32)((v3Pos.y - fDis) / TE_TILE_LEN) * m_nTileWid + (s32)((v3Pos.x + fDis) / TE_TILE_LEN);
s32 nRUTile = (s32)((v3Pos.y + fDis) / TE_TILE_LEN) * m_nTileWid + (s32)((v3Pos.x + fDis) / TE_TILE_LEN);
s32 nLUTile = (s32)((v3Pos.y + fDis) / TE_TILE_LEN) * m_nTileWid + (s32)((v3Pos.x - fDis) / TE_TILE_LEN);
s32 i = 0 , nLDLayer = 0 , nRDLayer = 0 , nRULayer = 0 , nLULayer = 0 ;
s32 nLDBlock, nRDBlock, nRUBlock, nLUBlock;
BOOL bLDCheck = FALSE, bRDCheck = FALSE, bRUCheck = FALSE, bLUCheck = FALSE; // 更新当前周围的地块属性
UpdateTileAttribute( nLDTile, nRDTile, nRUTile, nLUTile ); // 找出对应的层
for ( i = 0 ; i < TE_LAYERS; ++ i )
{
if ( m_pTile[nLDTile].Texture[i] == m_nSelectTexture )
{
nLDLayer = i;
bLDCheck = TRUE;
}
else if ( ! bLDCheck && m_pTile[nLDTile].Texture[i] != TE_INVALID_TILE )
{
++ nLDLayer;
}
if ( m_pTile[nRDTile].Texture[i] == m_nSelectTexture )
{
nRDLayer = i;
bRDCheck = TRUE;
}
else if ( ! bRDCheck && m_pTile[nRDTile].Texture[i] != TE_INVALID_TILE )
{
++ nRDLayer;
}
if ( m_pTile[nRUTile].Texture[i] == m_nSelectTexture )
{
nRULayer = i;
bRUCheck = TRUE;
}
else if ( ! bRUCheck && m_pTile[nRUTile].Texture[i] != TE_INVALID_TILE )
{
++ nRULayer;
}
if ( m_pTile[nLUTile].Texture[i] == m_nSelectTexture )
{
nLULayer = i;
bLUCheck = TRUE;
}
else if ( ! bLUCheck && m_pTile[nLUTile].Texture[i] != TE_INVALID_TILE )
{
++ nLULayer;
}
}
if ( ! bLDCheck )
nLDLayer = AdjustTileLayer( nLDTile, 2 );
if ( ! bRDCheck )
nRDLayer = AdjustTileLayer( nRDTile, 3 );
if ( ! bRUCheck )
nRULayer = AdjustTileLayer( nRUTile, 1 );
if ( ! bLUCheck )
nLULayer = AdjustTileLayer( nLUTile, 0 );
s32 nLDTexture = m_pTile[nLDTile].Texture[nLDLayer];
if ( nLDTexture != TE_INVALID_TILE )
{
s32 nRDTexture = m_pTile[nRDTile].Texture[nRDLayer];
s32 nRUTexture = m_pTile[nRUTile].Texture[nRULayer];
s32 nLUTexture = m_pTile[nLUTile].Texture[nLULayer];
if ( nLDTexture == nRDTexture && nLDTexture == nRUTexture && nLDTexture == nLUTexture )
{
if ( (m_pTile[nLDTile].Texture[TE_LAYERS - 1 ] != TE_INVALID_TILE ||
m_pTile[nRDTile].Texture[TE_LAYERS - 1 ] != TE_INVALID_TILE ||
m_pTile[nRUTile].Texture[TE_LAYERS - 1 ] != TE_INVALID_TILE ||
m_pTile[nLUTile].Texture[TE_LAYERS - 1 ] != TE_INVALID_TILE) )
{
if ( (nLDTexture == m_nSelectTexture) &&
(m_pTile[nLDTile].Block[nLDLayer] == s_pBaseTexIndex_c[ 2 ] ||
m_pTile[nRDTile].Block[nRDLayer] == s_pBaseTexIndex_c[ 3 ] ||
m_pTile[nRUTile].Block[nRULayer] == s_pBaseTexIndex_c[ 1 ] ||
m_pTile[nLUTile].Block[nLULayer] == s_pBaseTexIndex_c[ 0 ] ) )
{
goto _SORT_LAYER;
} nLDBlock = m_pTile[nLDTile].Block[nLDLayer];
if ( m_pTile[nLDTile].Texture[nLDLayer] != 0 && (nLDBlock == 0 || ! IsValidRandBlock(nLDBlock)) )
nLDBlock = m_pTile[nLDTile].Block[nLDLayer] + s_pBaseTexIndex_c[ 2 ]; nRDBlock = m_pTile[nRDTile].Block[nRDLayer];
if ( m_pTile[nRDTile].Texture[nRDLayer] != 0 && (nRDBlock == 0 || ! IsValidRandBlock(nRDBlock)) )
nRDBlock = m_pTile[nRDTile].Block[nRDLayer] + s_pBaseTexIndex_c[ 3 ]; nRUBlock = m_pTile[nRUTile].Block[nRULayer];
if ( m_pTile[nRUTile].Texture[nRULayer] != 0 && (nRUBlock == 0 || ! IsValidRandBlock(nRUBlock)) )
nRUBlock = m_pTile[nRUTile].Block[nRULayer] + s_pBaseTexIndex_c[ 1 ]; nLUBlock = m_pTile[nLUTile].Block[nLULayer];
if ( m_pTile[nLUTile].Texture[nLULayer] != 0 && (nLUBlock == 0 || ! IsValidRandBlock(nLUBlock)) )
nLUBlock = m_pTile[nLUTile].Block[nLULayer] + s_pBaseTexIndex_c[ 0 ]; if ( IsValidBlock(nLDBlock) && IsValidTileBlock( nLDBlock ) )
SetTileAttribute( nLDTile, nLDLayer, nLDBlock );
if ( IsValidBlock(nRDBlock) && IsValidTileBlock( nRDBlock ) )
SetTileAttribute( nRDTile, nRDLayer, nRDBlock );
if ( IsValidBlock(nRUBlock) && IsValidTileBlock( nRUBlock ) )
SetTileAttribute( nRUTile, nRULayer, nRUBlock );
if ( IsValidBlock(nLUBlock) && IsValidTileBlock( nLUBlock ) )
SetTileAttribute( nLUTile, nLULayer, nLUBlock ); goto _SORT_LAYER;
}
else if ( m_pTile[nLDTile].Block[nLDLayer] + s_pBaseTexIndex_c[ 2 ] >= TE_TEX_COUNT_C ||
m_pTile[nRDTile].Block[nRDLayer] + s_pBaseTexIndex_c[ 3 ] >= TE_TEX_COUNT_C ||
m_pTile[nRUTile].Block[nRULayer] + s_pBaseTexIndex_c[ 1 ] >= TE_TEX_COUNT_C ||
m_pTile[nLUTile].Block[nLULayer] + s_pBaseTexIndex_c[ 0 ] >= TE_TEX_COUNT_C )
{
goto _SORT_LAYER;
}
}
}
nLDBlock = m_pTile[nLDTile].Block[nLDLayer] + s_pBaseTexIndex_c[ 2 ];
nRDBlock = m_pTile[nRDTile].Block[nRDLayer] + s_pBaseTexIndex_c[ 3 ];
nRUBlock = m_pTile[nRUTile].Block[nRULayer] + s_pBaseTexIndex_c[ 1 ];
nLUBlock = m_pTile[nLUTile].Block[nLULayer] + s_pBaseTexIndex_c[ 0 ]; if ( ! IsValidTileBlock( nLDBlock ) )
goto _SORT_LAYER; if ( ! IsValidTileBlock( nRDBlock ) )
goto _SORT_LAYER; if ( ! IsValidTileBlock( nRUBlock ) )
goto _SORT_LAYER; if ( ! IsValidTileBlock( nLUBlock ) )
goto _SORT_LAYER;SetTileAttribute( nLDTile, nLDLayer, nLDBlock );
SetTileAttribute( nRDTile, nRDLayer, nRDBlock );
SetTileAttribute( nRUTile, nRULayer, nRUBlock );
SetTileAttribute( nLUTile, nLULayer, nLUBlock );_SORT_LAYER:
SortLayerTile( nLDTile );
SortLayerTile( nRDTile );
SortLayerTile( nRUTile );
SortLayerTile( nLUTile );
} // -------------&-------------
// ---------------------------&-------------------------
s32 AdjustTileLayer( s32 nTile, s32 nIndex )
{
BOOL bCheck = FALSE, bFindLayer = FALSE;
s32 i, nMinLayer, nRetLayer = 0 ;
for ( i = 0 ; i < TE_LAYERS; ++ i )
{
if ( m_pTile[nTile].Texture[i] == TE_INVALID_TILE )
{
bCheck = TRUE;
m_pTile[nTile].Texture[i] = m_nSelectTexture;
if ( m_nSelectTexture == 0 )
m_pTile[nTile].Block[i] = 27 ;
break ;
}
}
if ( ! bCheck )
{
nMinLayer = 0 ; for ( i = 0 ; i < TE_LAYERS; ++ i )
{
if ( m_pTile[nTile].Texture[i] == m_nSelectTexture )
{
bFindLayer = TRUE;
m_pTile[nTile].Texture[i] = m_nSelectTexture;
break ;
}
}
if ( ! bFindLayer )
{
for ( i = 0 ; i < TE_LAYERS - 1 ; ++ i )
{
m_pTile[nTile].Texture[i] = m_pTile[nTile].Texture[i + 1 ];
m_pTile[nTile].Block[i] = m_pTile[nTile].Block[i + 1 ];
}
for ( i = 0 ; i < TE_LAYERS - 1 ; ++ i )
{
if ( m_pTile[nTile].Texture[i] == m_nSelectTexture )
{
m_pTile[nTile].Texture[TE_LAYERS - 1 ] = 0 ;
m_pTile[nTile].Block[TE_LAYERS - 1 ] = s_pRandTexIndex_c[rand() % TE_TEX_RAND_C]; goto _SPECIAL_LAYER;
}
} m_pTile[nTile].Texture[TE_LAYERS - 1 ] = m_nSelectTexture;
m_pTile[nTile].Block[TE_LAYERS - 1 ] = 0 ;
}
} _SPECIAL_LAYER:
// for( i = 0; i < TE_LAYERS; ++i )
// {
// if( m_pTile[nTile].Texture[i] < m_pTile[nTile].Texture[nMinLayer] )
// {
// nMinLayer = i;
// }
// }for( i = 0; i < TE_LAYERS; ++i )
{
if ( m_pTile[nTile].Texture[i] == m_nSelectTexture )
{
nRetLayer = i;
goto _LAYER_RETURN;
}
}
for ( i = 0 ; i < TE_LAYERS; ++ i )
{
if ( m_pTile[nTile].Texture[i] == TE_INVALID_TILE )
{
nRetLayer = i;
goto _LAYER_RETURN;
}
} nRetLayer = TE_LAYERS - 1 ;_LAYER_RETURN: return nRetLayer;
} // +-------------&-------------
// +---------------------------&-------------------------
void SortLayerTile( s32 nTile )
{
BOOL bBaseLayer = FALSE;
s32 nBaseLayer = - 1 ;
s32 i, j, nTex, nBlock; for ( i = 0 ; i < TE_LAYERS; ++ i )
{
for ( j = i + 1 ; j < TE_LAYERS; ++ j )
{
if ( m_pTile[nTile].Texture[i] > m_pTile[nTile].Texture[j] )
{
nTex = m_pTile[nTile].Texture[i];
nBlock = m_pTile[nTile].Block[i]; m_pTile[nTile].Texture[i] = m_pTile[nTile].Texture[j];
m_pTile[nTile].Block[i] = m_pTile[nTile].Block[j]; m_pTile[nTile].Texture[j] = nTex;
m_pTile[nTile].Block[j] = nBlock;
} }
} nBlock = 0 ;
for ( i = 0 ; i < TE_LAYERS; ++ i )
{
if ( ! IsValidRandBlock( m_pTile[nTile].Block[i] ) )
{
nBlock += m_pTile[nTile].Block[i];
}
} if ( nBlock == 27 )
{
if ( m_pTile[nTile].Texture[ 0 ] == 0 )
{
m_pTile[nTile].Texture[ 0 ] = m_pTile[nTile].Texture[ 1 ];
m_pTile[nTile].Block[ 0 ] = 27 ; for ( i = 1 ; i < TE_LAYERS - 1 ; ++ i )
{
m_pTile[nTile].Texture[i] = m_pTile[nTile].Texture[i + 1 ];
m_pTile[nTile].Block[i] = m_pTile[nTile].Block[i + 1 ];
} m_pTile[nTile].Texture[TE_LAYERS - 1 ] = TE_INVALID_TILE;
m_pTile[nTile].Block[TE_LAYERS - 1 ] = 0 ;
}
else
{
m_pTile[nTile].Block[ 0 ] = 27 ;
}
}
} // -------------&-------------
// ---------------------------&-------------------------
BOOL IsValidTileBlock( s32 nBlock ) const
{
s32 i = 0 ; if ( nBlock == 0 || nBlock == 27 )
return TRUE; for ( ; i < TE_TEX_RAND_C; ++ i )
{
if ( nBlock == s_pRandTexIndex_c[i] )
return FALSE;
} return TRUE;
} // -------------&-------------
// ---------------------------&-------------------------
BOOL IsValidRandBlock( s32 nBlock ) const
{
s32 i = 0 ;
for ( ; i < TE_TEX_RAND_C; ++ i )
{
if ( nBlock == s_pRandTexIndex_c[i] )
return TRUE;
} return FALSE;
} // +-------------&-------------
// +---------------------------&-------------------------
s32 CheckLayerTile( s32 nTile, s32 nTexture )
{
s32 i; for ( i = 0 ; i < TE_TILE_COUNT; ++ i )
{
if ( m_pTile[nTile].Texture[i] != TE_INVALID_TILE && m_pTile[nTile].Texture[i] == nTexture )
return i;
} return - 1 ;
} // +-------------&-------------
// +---------------------------&-------------------------
void UpdateTileAttribute( s32 nLDTile, s32 nRDTile, s32 nRUTile, s32 nLUTile )
{
s32 i, nBlock, nLDTexture;
s32 nLDLayer, nRDLayer, nRULayer, nLULayer; if ( IsValidRandBlock(m_pTile[nLDTile].Block[ 0 ]) && m_pTile[nLDTile].Texture[ 0 ] != 0 )
{
nBlock = 27 ;
for ( i = 1 ; i < TE_LAYERS; ++ i )
{
if ( m_pTile[nLDTile].Texture[i] != TE_INVALID_TILE )
{
nBlock -= m_pTile[nLDTile].Block[i];
}
} m_pTile[nLDTile].Block[ 0 ] = nBlock;
} if ( IsValidRandBlock(m_pTile[nRDTile].Block[ 0 ]) && m_pTile[nRDTile].Texture[ 0 ] != 0 )
{
nBlock = 27 ;
for ( i = 1 ; i < TE_LAYERS; ++ i )
{
if ( m_pTile[nRDTile].Texture[i] != TE_INVALID_TILE )
{
nBlock -= m_pTile[nRDTile].Block[i];
}
} m_pTile[nRDTile].Block[ 0 ] = nBlock;
} if ( IsValidRandBlock(m_pTile[nRUTile].Block[ 0 ]) && m_pTile[nRUTile].Texture[ 0 ] != 0 )
{
nBlock = 27 ;
for ( i = 1 ; i < TE_LAYERS; ++ i )
{
if ( m_pTile[nRUTile].Texture[i] != TE_INVALID_TILE )
{
nBlock -= m_pTile[nRUTile].Block[i];
}
} m_pTile[nRUTile].Block[ 0 ] = nBlock;
} if ( IsValidRandBlock(m_pTile[nLUTile].Block[ 0 ]) && m_pTile[nLUTile].Texture[ 0 ] != 0 )
{
nBlock = 27 ;
for ( i = 1 ; i < TE_LAYERS; ++ i )
{
if ( m_pTile[nLUTile].Texture[i] != TE_INVALID_TILE )
{
nBlock -= m_pTile[nLUTile].Block[i];
}
} m_pTile[nLUTile].Block[ 0 ] = nBlock;
} // 找出对应的层
for ( i = 0 ; i < TE_TILE_COUNT; ++ i )
{
nLDLayer = i;
nLDTexture = m_pTile[nLDTile].Texture[i]; if ( nLDTexture == m_nSelectTexture )
continue ; nRDLayer = CheckLayerTile( nRDTile, nLDTexture );
if ( nRDLayer == - 1 )
continue ; nRULayer = CheckLayerTile( nRUTile, nLDTexture );
if ( nRULayer == - 1 )
continue ; nLULayer = CheckLayerTile( nLUTile, nLDTexture );
if ( nLULayer == - 1 )
continue ; if ( IsValidRandBlock( m_pTile[nLDTile].Block[nLDLayer] ) &&
IsValidRandBlock( m_pTile[nRDTile].Block[nRDLayer] ) &&
IsValidRandBlock( m_pTile[nRUTile].Block[nRULayer] ) &&
IsValidRandBlock( m_pTile[nLUTile].Block[nLULayer] ) )
{
if ( m_nSelectTexture < nLDTexture )
{
m_pTile[nLDTile].Block[nLDLayer] = 27 - s_pBaseTexIndex_c[ 2 ];
m_pTile[nRDTile].Block[nRDLayer] = 27 - s_pBaseTexIndex_c[ 3 ];
m_pTile[nRUTile].Block[nRULayer] = 27 - s_pBaseTexIndex_c[ 1 ];
m_pTile[nLUTile].Block[nLULayer] = 27 - s_pBaseTexIndex_c[ 0 ];
}
continue ;
} if ( ! IsValidSubBlock( nLDTile, nLDLayer, 2 ) ||
! IsValidSubBlock( nRDTile, nRDLayer, 3 ) ||
! IsValidSubBlock( nRUTile, nRULayer, 1 ) ||
! IsValidSubBlock( nLUTile, nLULayer, 0 ) )
{
continue ;
} ChangeBlock( nLDTile, nLDLayer, 2 );
ChangeBlock( nRDTile, nRDLayer, 3 );
ChangeBlock( nRUTile, nRULayer, 1 );
ChangeBlock( nLUTile, nLULayer, 0 );
}
} // +-------------&-------------
// +---------------------------&-------------------------
BOOL IsValidSubBlock( s32 nTile, s32 nLayer, s32 nIndex )
{
s32 nBlock = m_pTile[nTile].Block[nLayer] - s_pBaseTexIndex_c[nIndex]; if ( ! IsValidBlock( nBlock ) )
return FALSE; if ( nBlock == 0 || ! IsValidRandBlock( nBlock ) )
return TRUE; return TRUE;
} // +-------------&-------------
// +---------------------------&-------------------------
void ChangeBlock( s32 nTile, s32 nLayer, s32 nIndex )
{
s32 nBlock = m_pTile[nTile].Block[nLayer]; if ( ! IsValidRandBlock( nBlock ) )
{
nBlock = nBlock - s_pBaseTexIndex_c[nIndex];
m_pTile[nTile].Block[nLayer] = nBlock; if ( nBlock == 0 )
{
m_pTile[nTile].Block[nLayer] = 0 ;
m_pTile[nTile].Texture[nLayer] = TE_INVALID_TILE;
}
}
else
{
m_pTile[nTile].Block[nLayer] = 27 - s_pBaseTexIndex_c[nIndex];
}
} // -------------&-------------
// ---------------------------&-------------------------
void SetTileAttribute( s32 nTile, s32 nLayer, s32 nBlock )
{
if ( nBlock == 27 )
{
// nBlock = s_pRandTexIndex_c[rand() % TE_TEX_RAND_C]; s32 i = 0;
for ( ; i < TE_TILE_COUNT; ++ i )
{
if ( m_pTile[nTile].Texture[i] < m_nSelectTexture )
{
m_pTile[nTile].Block[i] = 0 ;
m_pTile[nTile].Texture[i] = TE_INVALID_TILE;
}
} m_pTile[nTile].Texture[nLayer] = m_nSelectTexture;
} if ( ! IsValidBlock( nBlock ) )
{
nBlock = 0 ;
} if ( nBlock >= 32 )
{
nBlock = 27 ;
} m_pTile[nTile].Block[nLayer] = nBlock;
}