2013-04-25 2 views
0

Как и многие программы, которые делают черепичную карту, как в игре Terraria, и превращают карту в единую картину всей карты, я пытаюсь сделать что-то подобное. Проблема в том, что мои текстуры блоков находятся в одном большом атласе текстуры и на которые ссылается индекс, и у меня возникают проблемы с получением данных о цвете из одного блока и помещением их в правильное место в большей текстуре.Размещение меньшего Texture2D в более крупном

Это мой код.

Получение исходного кода из индекса (этот код работает):

public static Rectangle GetSourceForIndex(int index, Texture2D tex) 
    { 
     int dim = tex.Width/TEXTURE_MAP_DIM; 

     int startx = index % TEXTURE_MAP_DIM; 
     int starty = index/TEXTURE_MAP_DIM; 

     return new Rectangle(startx * dim, starty * dim, dim, dim); 
    } 

Получение текстуру на индекс (где начинаются проблемы):

public static Texture2D GetTextureAtIndex(int index, Texture2D tex) 
    { 
     Rectangle source = GetSourceForIndex(index, tex); 
     Texture2D texture = new Texture2D(_device, source.Width, source.Height); 

     Color[] colors = new Color[tex.Width * tex.Height]; 
     tex.GetData<Color>(colors); 
     Color[] colorData = new Color[source.Width * source.Height]; 

     for (int x = 0; x < source.Width; x++) 
     { 
      for (int y = 0; y < source.Height; y++) 
      { 
       colorData[x + y * source.Width] = colors[x + source.X + (y + source.Y) * tex.Width]; 
      } 
     } 

     texture.SetData<Color>(colorData); 
     return texture; 
    } 

Ввод текстуры в общую картину (это совершенно неправильно, я уверен):

private void doSave() 
    { 
     int texWidth = this._rWidth * Region.REGION_DIM * 16; 
     int texHeight = this._rHeight * Region.REGION_DIM * 16; 

     Texture2D picture = new Texture2D(Game.GraphicsDevice, texWidth, texHeight); 
     Color[] pictureData = new Color[picture.Width * picture.Height]; 

     for (int blockX = 0; blockX < texWidth/16; blockX++) 
     { 
      for (int blockY = 0; blockY < texHeight/16; blockY++) 
      { 
       Block b = this.GetBlockAt(blockX, blockY); 
       Texture2D toCopy = TextureManager.GetTextureAtIndex(b.GetIndexBasedOnMetadata(b.GetMetadataForSurroundings(this, blockX, blockY)), b.GetTextureFile()); 
       Color[] copyData = new Color[toCopy.Width * toCopy.Height]; 
       Rectangle source = new Rectangle(blockX * 16, blockY * 16, 16, 16); 
       toCopy.GetData<Color>(copyData); 

       for (int x = 0; x < source.Width; x++) 
       { 
        for (int y = 0; y < source.Height; y++) 
        { 
         pictureData[x + source.X + (y + source.Y) * picture.Width] = copyData[x + y * source.Width]; 
        } 
       } 
      } 
     } 

     picture.SetData<Color>(pictureData); 

     string fileName = "picture" + DateTime.Now.ToString(@"MM\-dd\-yyyy-h\-mm-tt"); 
     FileStream stream = File.Open(this.GetSavePath() + @"Pictures\" + fileName, FileMode.OpenOrCreate); 
     picture.SaveAsPng(stream, picture.Width, picture.Height); 

Я не могу найти никаких хороших описаний по h ow для правильного преобразования между текстурой и одномерной матрицей цветов. Было бы намного легче, если бы я знал, как легко и правильно разместить квадрат цветов в большую двухмерную текстуру.

TL; DR: Как вы помещаете меньшую текстуру в большую текстуру?

+1

Вы пытаетесь что-то сделать в режиме реального времени здесь? Или вы просто хотите собрать большую текстуру для последующего использования в приложении реального времени. Потому что я предполагаю, что вы действительно хотите собрать плитки во время выполнения. Помещение всех ваших плиток в большую текстуру убивает все преимущества плитки. – Lucius

+0

Когда вы рисуете плитки, вы можете использовать параметр spritebatch Source rectangle – Cyral

+0

Я делаю большую картинку, потому что я думал, что было бы интересно иметь возможность получить изображение всего вашего мира. В игре все еще используется система на основе плитки. Его чисто для удовольствия, он вообще не работает. Мне нужно знать, как работает система Texture2D, чтобы скомпилировать одно изображение из всей карты. – sm81095

ответ

0

Создайте RenderTarget2D размер наибольшей текстуры и установите ее в активную. Нарисуйте большую текстуру, затем нарисуйте меньшую. Установите ссылку на исходную текстуру на RenderTarget2D, на который вы только что нарисовали.

int texWidth = this._rWidth * Region.REGION_DIM * 16; 
int texHeight = this._rHeight * Region.REGION_DIM * 16; 

_renderTarget = new RenderTarget2D(GraphicsDevice, texWidth, texHeight); 
GraphicsDevice.SetRenderTarget(_renderTarget); 
GraphicsDevice.Clear(Color.Transparent); 

_spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque); 

for (int blockX = 0; blockX < texWidth/16; blockX++) 
{ 
    for (int blockY = 0; blockY < texHeight/16; blockY++) 
    { 
     _spriteBatch.Draw(
      TextureManager.GetTextureAtIndex(b.GetIndexBasedOnMetadata(b.GetMetadataForSurroundings(this, blockX, blockY)), b.GetTextureFile()), 
     new Rectangle(blockX * 16, blockY * 16, 16, 16), 
     Color.White); 
    } 
} 

_spriteBatch.End() 

GraphicsDevice.SetRenderTarget(null); 
var picture = _renderTarget; 
+0

Я попытался использовать ваш метод, но я получаю ошибку «Framebuffer Incomplete» на строке «GraphicsDevice.SetRenderTarget (renderTarget)». – sm81095

+0

Какая платформа для разработки? И работает ли она с чистым XNA, а не с моногеймом? – ClassicThunder

+0

Кажется, это может быть ошибка в моногаме https://monogame.codeplex.com/discussions/406741. – ClassicThunder

Смежные вопросы