Objective-cでMetalを使用してテクスチャを表示しよう

Metalを使用して、テクスチャ表示する覚書
「Objective-cでMetalを使用して三角形を描画しよう」を参照
https://qiita.com/sanoh/items/cfc7ecb057b7588c2a52
■Step1：シェーダー変更
---
まずはShaderType.h を追加します。
![スクリーンショット 2018-11-30 12.26.44.png](https://qiita-image-store.s3.amazonaws.com/0/122121/6c4cf599-dd67-0f2c-1f20-d7253076cd30.png)

```c:ShaderType.h
#ifndef ShaderType_h
#define ShaderType_h

#ifdef __METAL_VERSION__
#define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type
#define NSInteger metal::int32_t
#else
#import <Foundation/Foundation.h>
#endif

#include <simd/simd.h>

typedef NS_ENUM(NSInteger, BufferIndex)
{
    BufferIndexMeshPositions = 0
};

typedef NS_ENUM(NSInteger, TextureIndex)
{
    TextureIndexColor    = 0,
};

#endif /* ShaderType_h */
```
Shader.Metal を編集

```:Shader.Metal
#include <metal_stdlib>
#include <simd/simd.h>
#import "ShaderType.h"

using namespace metal;

struct Vertex {
    float2 position;
    float2 texCoord;
};

struct ColorInOut{
    float4  position [[position]];
    float2  texCoord;
};

vertex ColorInOut myVertexShader(constant Vertex *vertices [[buffer(BufferIndexMeshPositions)]],
                                 uint vid [[vertex_id]]) {
    ColorInOut  out;

    out.position    = float4(vertices[vid].position, 0.0, 1.0);
    out.texCoord    = vertices[vid].texCoord;
    return out;
}

fragment half4 myFragmentShader(ColorInOut vert [[stage_in]],
                                texture2d<half> colorMap     [[ texture(TextureIndexColor) ]]) {
    constexpr sampler defaultSampler;
    half4 imageColor = colorMap.sample(defaultSampler, vert.texCoord.xy);
    return imageColor;
}
```
■Steop2:MetalRenderer.mを編集します。
---

```swift:MetalRenderer.m
#import "MetalRenderer.h"
#import "ShaderType.h"

static const NSUInteger MaxBuffersInFlight = 3;

@implementation MetalRenderer
{
    dispatch_semaphore_t _in_flight_semaphore;
    id <MTLDevice> _device;
    id <MTLCommandQueue> _command_queue;

    id <MTLRenderPipelineState> _pipeline_state;
    id <MTLBuffer>   _buffer_position;

    id <MTLTexture> _color_image;   //＜新規＞
}

-(nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)view;
{
    //頂点情報＜変更＞
    float vertices_array[]={
        +0.0, +1.0, 0.0, 0.0,
        -1.0, -1.0, 1.0, 0.0,
        +1.0, -1.0, 1.0, 1.0,
    };
    if(self= [super init])
    {
        _device = view.device;
        _in_flight_semaphore = dispatch_semaphore_create(MaxBuffersInFlight);
        _command_queue = [_device newCommandQueue];
        view.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
        //  頂点情報の登録
        NSInteger size = sizeof(vertices_array);
        _buffer_position=[_device newBufferWithBytes:vertices_array
                                              length:size
                                             options:MTLResourceOptionCPUCacheModeDefault];
        //  シェーダーの登録
        id <MTLLibrary> library = [_device newDefaultLibrary];
        MTLRenderPipelineDescriptor *descriptor = [[MTLRenderPipelineDescriptor alloc] init];
        descriptor.vertexFunction = [library newFunctionWithName:@"myVertexShader"];
        descriptor.fragmentFunction = [library newFunctionWithName:@"myFragmentShader"];
        descriptor.colorAttachments[0].pixelFormat=MTLPixelFormatBGRA8Unorm;
        NSError *error = NULL;
        _pipeline_state = [_device newRenderPipelineStateWithDescriptor:descriptor 
                                                                  error:&error];
        if (!_pipeline_state)
        {
            NSLog(@"Failed to created pipeline state, error %@", error);
        }
        //  テクスチャ読込+登録＜新規＞
        MTKTextureLoader* textureLoader = [[MTKTextureLoader alloc] initWithDevice:_device];
        NSDictionary *textureLoaderOptions =
        @{
          MTKTextureLoaderOptionTextureUsage       : @(MTLTextureUsageShaderRead),
          MTKTextureLoaderOptionTextureStorageMode : @(MTLStorageModePrivate)
          };
        _color_image = [textureLoader newTextureWithName:@"colorImage"
                                             scaleFactor:1.0
                                                  bundle:nil
                                                 options:textureLoaderOptions
                                                   error:&error];
        if(!_color_image || error)
        {
            NSLog(@"Error creating texture %@", error.localizedDescription);
        }
    }
    return self;
}

- (void)drawInMTKView:(nonnull MTKView *)view
{
    dispatch_semaphore_wait(_in_flight_semaphore, DISPATCH_TIME_FOREVER);

    id <MTLCommandBuffer> command_buffer = [_command_queue commandBuffer];
    __block dispatch_semaphore_t block_sema = _in_flight_semaphore;
    [command_buffer addCompletedHandler:^(id<MTLCommandBuffer> buffer)
     {
         dispatch_semaphore_signal(block_sema);
     }];
    MTLRenderPassDescriptor* render_pass_descriptor = view.currentRenderPassDescriptor;
    render_pass_descriptor.colorAttachments[0].loadAction=MTLLoadActionClear;
    render_pass_descriptor.colorAttachments[0].storeAction=MTLStoreActionStore;
    render_pass_descriptor.colorAttachments[0].clearColor=MTLClearColorMake(1.0, 0.0, 0.0, 1.0);
    if(render_pass_descriptor != nil)
    {
        id <MTLRenderCommandEncoder> render_encoder = [command_buffer renderCommandEncoderWithDescriptor:render_pass_descriptor];
        //   テクスチャの設定
        [render_encoder setFragmentTexture:_color_image
                                   atIndex:TextureIndexColor];
        //  モデルの設定
        [render_encoder setRenderPipelineState:_pipeline_state];
        [render_encoder setVertexBuffer:_buffer_position
                                 offset:0
                                atIndex:BufferIndexMeshPositions];
        [render_encoder drawPrimitives:MTLPrimitiveTypeTriangle
                           vertexStart:0
                           vertexCount:3];

        [render_encoder endEncoding];
        [command_buffer presentDrawable:view.currentDrawable];
    }
    [command_buffer commit];
}

- (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size
{
}

@end
```
■Steop3:テクスチャをアセットに登録
---
 「Assets.xcassets」に右クリックでメニューを出し「New Texture Set」を選択します。
![スクリーンショット 2018-11-30 12.29.06.png](https://qiita-image-store.s3.amazonaws.com/0/122121/1c8e6db3-638e-0887-62cd-add8707fb2bc.png)
「Texture」が作成されます。
![スクリーンショット 2018-11-30 12.29.13.png](https://qiita-image-store.s3.amazonaws.com/0/122121/5db807ef-a6c9-01c8-fb7a-6d55b6af549f.png)
今回用意したテクスチャ（Pngファイル）
![color.png](https://qiita-image-store.s3.amazonaws.com/0/122121/05ee14ff-4fb3-973a-6b10-37075f585a2b.png)
テクスチャを「All Universel」にドラッグ＆ドロップし名前を「colorImage」に変更します。
![スクリーンショット 2018-11-30 12.29.45.png](https://qiita-image-store.s3.amazonaws.com/0/122121/3cd5aa1b-a7eb-ce4f-c4de-73684a861bc9.png)

■Setp4：実行
---
iOsは実機で実行してくださいMacの場合は以下のようになります。
![スクリーンショット 2018-11-30 12.30.01.png](https://qiita-image-store.s3.amazonaws.com/0/122121/23765721-76a1-32d9-0dba-a00e4695ba19.png)