Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: louwers <649392+louwers@users.noreply.github.com> Co-authored-by: Bart Louwers <bart@emeel.net>
198 lines
7.3 KiB
Objective-C
198 lines
7.3 KiB
Objective-C
#if !MLN_RENDER_BACKEND_METAL
|
|
|
|
/* OPENGL Custom Layer example implementation */
|
|
#import "CustomStyleLayerExample.h"
|
|
#import <GLKit/GLKit.h>
|
|
|
|
@implementation CustomStyleLayerExample {
|
|
GLuint _program;
|
|
GLuint _vertexShader;
|
|
GLuint _fragmentShader;
|
|
GLuint _buffer;
|
|
GLuint _aPos;
|
|
}
|
|
|
|
- (void)didMoveToMapView:(MLNMapView *)mapView {
|
|
static const GLchar *vertexShaderSource = "#version 300 es\nlayout (location = 0) in vec2 a_pos; void main() { gl_Position = vec4(a_pos, 1, 1); }";
|
|
static const GLchar *fragmentShaderSource = "#version 300 es\nout highp vec4 fragColor; void main() { fragColor = vec4(0, 0.5, 0, 0.5); }";
|
|
|
|
_program = glCreateProgram();
|
|
_vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
|
_fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
|
|
|
|
glShaderSource(_vertexShader, 1, &vertexShaderSource, NULL);
|
|
glCompileShader(_vertexShader);
|
|
glAttachShader(_program, _vertexShader);
|
|
glShaderSource(_fragmentShader, 1, &fragmentShaderSource, NULL);
|
|
glCompileShader(_fragmentShader);
|
|
glAttachShader(_program, _fragmentShader);
|
|
glLinkProgram(_program);
|
|
_aPos = glGetAttribLocation(_program, "a_pos");
|
|
|
|
GLfloat triangle[] = { 0, 0.5, 0.5, -0.5, -0.5, -0.5 };
|
|
glGenBuffers(1, &_buffer);
|
|
glBindBuffer(GL_ARRAY_BUFFER, _buffer);
|
|
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(GLfloat), triangle, GL_STATIC_DRAW);
|
|
}
|
|
|
|
- (void)drawInMapView:(MLNMapView *)mapView withContext:(MLNStyleLayerDrawingContext)context {
|
|
glUseProgram(_program);
|
|
glBindBuffer(GL_ARRAY_BUFFER, _buffer);
|
|
glEnableVertexAttribArray(_aPos);
|
|
glVertexAttribPointer(_aPos, 2, GL_FLOAT, GL_FALSE, 0, NULL);
|
|
glDisable(GL_STENCIL_TEST);
|
|
glDisable(GL_DEPTH_TEST);
|
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
|
|
}
|
|
|
|
- (void)willMoveFromMapView:(MLNMapView *)mapView {
|
|
if (!_program) {
|
|
return;
|
|
}
|
|
|
|
glDeleteBuffers(1, &_buffer);
|
|
glDetachShader(_program, _vertexShader);
|
|
glDetachShader(_program, _fragmentShader);
|
|
glDeleteShader(_vertexShader);
|
|
glDeleteShader(_fragmentShader);
|
|
glDeleteProgram(_program);
|
|
}
|
|
|
|
@end
|
|
|
|
#else // MLN_RENDER_BACKEND_METAL:
|
|
|
|
/* Metal Custom Layer example implementation */
|
|
#import "CustomStyleLayerExample.h"
|
|
|
|
@implementation CustomStyleLayerExample {
|
|
// The render pipeline state
|
|
id<MTLRenderPipelineState> _pipelineState;
|
|
id<MTLDepthStencilState> _depthStencilStateWithoutStencil;
|
|
}
|
|
|
|
- (void)didMoveToMapView:(MLNMapView *)mapView {
|
|
MLNBackendResource* resource = [mapView backendResource];
|
|
|
|
NSString *shaderSource = @
|
|
" #include <metal_stdlib>\n"
|
|
" using namespace metal;\n"
|
|
" typedef struct\n"
|
|
" {\n"
|
|
" vector_float2 position;\n"
|
|
" vector_float4 color;\n"
|
|
" } Vertex;\n"
|
|
" struct RasterizerData\n"
|
|
" {\n"
|
|
" float4 position [[position]];\n"
|
|
" float4 color;\n"
|
|
" };\n"
|
|
" vertex RasterizerData\n"
|
|
" vertexShader(uint vertexID [[vertex_id]],\n"
|
|
" constant Vertex *vertices [[buffer(0)]],\n"
|
|
" constant vector_uint2 *viewportSizePointer [[buffer(1)]])\n"
|
|
" {\n"
|
|
" RasterizerData out;\n"
|
|
" float2 pixelSpacePosition = vertices[vertexID].position.xy;\n"
|
|
" vector_float2 viewportSize = vector_float2(*viewportSizePointer);\n"
|
|
" out.position = vector_float4(0.0, 0.0, 0.0, 1.0);\n"
|
|
" out.position.xy = pixelSpacePosition / (viewportSize / 2.0);\n"
|
|
" out.color = vertices[vertexID].color;\n"
|
|
" return out;\n"
|
|
" }\n"
|
|
" fragment float4 fragmentShader(RasterizerData in [[stage_in]])\n"
|
|
" {\n"
|
|
" return in.color;\n"
|
|
" }\n";
|
|
|
|
|
|
NSError *error = nil;
|
|
id<MTLDevice> _device = resource.device;
|
|
id<MTLLibrary> library = [_device newLibraryWithSource:shaderSource options:nil error:&error];
|
|
NSAssert(library, @"Error compiling shaders: %@", error);
|
|
id<MTLFunction> vertexFunction = [library newFunctionWithName:@"vertexShader"];
|
|
id<MTLFunction> fragmentFunction = [library newFunctionWithName:@"fragmentShader"];
|
|
|
|
// Configure a pipeline descriptor that is used to create a pipeline state.
|
|
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
|
pipelineStateDescriptor.label = @"Simple Pipeline";
|
|
pipelineStateDescriptor.vertexFunction = vertexFunction;
|
|
pipelineStateDescriptor.fragmentFunction = fragmentFunction;
|
|
pipelineStateDescriptor.colorAttachments[0].pixelFormat = resource.mtkView.colorPixelFormat;
|
|
pipelineStateDescriptor.depthAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
|
|
pipelineStateDescriptor.stencilAttachmentPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
|
|
|
|
_pipelineState = [_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor
|
|
error:&error];
|
|
NSAssert(_pipelineState, @"Failed to create pipeline state: %@", error);
|
|
|
|
// Notice that we don't configure the stencilTest property, leaving stencil testing disabled
|
|
MTLDepthStencilDescriptor *depthStencilDescriptor = [[MTLDepthStencilDescriptor alloc] init];
|
|
depthStencilDescriptor.depthCompareFunction = MTLCompareFunctionAlways; // Or another value as needed
|
|
depthStencilDescriptor.depthWriteEnabled = NO;
|
|
|
|
_depthStencilStateWithoutStencil = [_device newDepthStencilStateWithDescriptor:depthStencilDescriptor];
|
|
|
|
}
|
|
|
|
- (void)preDrawInMapView:(MLNMapView *)mapView withContext:(MLNStyleLayerDrawingContext)context {
|
|
id<MTLCommandBuffer> commandBuffer = self.commandBuffer;
|
|
|
|
id<MTLBlitCommandEncoder> blitEncoder = [commandBuffer blitCommandEncoder];
|
|
[blitEncoder endEncoding];
|
|
}
|
|
|
|
- (void)drawInMapView:(MLNMapView *)mapView withContext:(MLNStyleLayerDrawingContext)context {
|
|
// Use the supplied render command encoder to encode commands
|
|
id<MTLCommandBuffer> commandBuffer = self.commandBuffer;
|
|
id<MTLRenderCommandEncoder> renderEncoder = self.renderEncoder;
|
|
MTLRenderPassDescriptor *renderPassDesc = self.renderPassDesc;
|
|
if(renderEncoder != nil)
|
|
{
|
|
MLNBackendResource* resource = [mapView backendResource];
|
|
|
|
vector_uint2 _viewportSize;
|
|
_viewportSize.x = resource.mtkView.drawableSize.width;
|
|
_viewportSize.y = resource.mtkView.drawableSize.height;
|
|
|
|
typedef struct
|
|
{
|
|
vector_float2 position;
|
|
vector_float4 color;
|
|
} Vertex;
|
|
|
|
static const Vertex triangleVertices[] =
|
|
{
|
|
// 2D positions, RGBA colors
|
|
{ { 250, -250 }, { 1, 0, 0, 1 } },
|
|
{ { -250, -250 }, { 0, 1, 0, 1 } },
|
|
{ { 0, 250 }, { 0, 0, 1, 1 } },
|
|
};
|
|
|
|
[renderEncoder setRenderPipelineState:_pipelineState];
|
|
[renderEncoder setDepthStencilState:_depthStencilStateWithoutStencil];
|
|
|
|
// Pass in the parameter data.
|
|
[renderEncoder setVertexBytes:triangleVertices
|
|
length:sizeof(triangleVertices)
|
|
atIndex:0];
|
|
|
|
[renderEncoder setVertexBytes:&_viewportSize
|
|
length:sizeof(_viewportSize)
|
|
atIndex:1];
|
|
|
|
// Draw the triangle.
|
|
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle
|
|
vertexStart:0
|
|
vertexCount:3];
|
|
}
|
|
}
|
|
|
|
- (void)willMoveFromMapView:(MLNMapView *)mapView {
|
|
// Clean up
|
|
}
|
|
|
|
@end
|
|
|
|
#endif
|