rendering rects on iOS

This commit is contained in:
Ronja Enseleit 2023-07-02 18:50:35 +02:00
parent fca5628279
commit 8ca95fbeab
16 changed files with 481 additions and 231 deletions

View File

@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
FB239F6B2A51983C0084874D /* IOSAssetManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = FB239F6A2A51983C0084874D /* IOSAssetManager.mm */; };
FB239F6F2A519BE00084874D /* assets in Resources */ = {isa = PBXBuildFile; fileRef = FB239F6E2A519BE00084874D /* assets */; };
FBA9A7502A50790A00F960DA /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = FBA9A74F2A50790A00F960DA /* AppDelegate.m */; };
FBA9A7532A50790A00F960DA /* MetalViewDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = FBA9A7522A50790A00F960DA /* MetalViewDelegate.mm */; };
FBA9A7562A50790A00F960DA /* GameViewController.mm in Sources */ = {isa = PBXBuildFile; fileRef = FBA9A7552A50790A00F960DA /* GameViewController.mm */; };
@ -27,6 +29,9 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
FB239F692A5197830084874D /* IOSAssetManager.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.h; path = IOSAssetManager.h; sourceTree = "<group>"; };
FB239F6A2A51983C0084874D /* IOSAssetManager.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = IOSAssetManager.mm; sourceTree = "<group>"; };
FB239F6E2A519BE00084874D /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; path = assets; sourceTree = "<group>"; };
FBA9A7342A5078B800F960DA /* AssetManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AssetManager.h; path = cpp/AssetManager.h; sourceTree = "<group>"; };
FBA9A7352A5078B800F960DA /* Font.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Font.cpp; path = cpp/Font.cpp; sourceTree = "<group>"; };
FBA9A7372A5078B800F960DA /* Hash.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Hash.h; path = cpp/Hash.h; sourceTree = "<group>"; };
@ -127,6 +132,8 @@
FBA9A7622A50790A00F960DA /* main.m */,
FBA9A76C2A5096C500F960DA /* MetalGfxInterface.h */,
FBA9A76F2A5098E800F960DA /* MetalGfxInterface.mm */,
FB239F692A5197830084874D /* IOSAssetManager.h */,
FB239F6A2A51983C0084874D /* IOSAssetManager.mm */,
);
path = m;
sourceTree = "<group>";
@ -152,6 +159,7 @@
FBC6DF7A2A50782C00CA10E7 = {
isa = PBXGroup;
children = (
FB239F6E2A519BE00084874D /* assets */,
FBA9A7462A5078DC00F960DA /* m */,
FBA9A7332A50789900F960DA /* cpp */,
FBA9A74C2A50790A00F960DA /* Products */,
@ -217,6 +225,7 @@
buildActionMask = 2147483647;
files = (
FBA9A7612A50790A00F960DA /* LaunchScreen.storyboard in Resources */,
FB239F6F2A519BE00084874D /* assets in Resources */,
FBA9A75E2A50790A00F960DA /* Assets.xcassets in Resources */,
FBA9A75C2A50790A00F960DA /* Main.storyboard in Resources */,
);
@ -235,6 +244,7 @@
FBA9A76B2A5079BC00F960DA /* Texture.cpp in Sources */,
FBA9A7762A50A58000F960DA /* Renderer.cpp in Sources */,
FBA9A7682A50795000F960DA /* StringRepository.cpp in Sources */,
FB239F6B2A51983C0084874D /* IOSAssetManager.mm in Sources */,
FBA9A7702A5098E800F960DA /* MetalGfxInterface.mm in Sources */,
FBA9A7532A50790A00F960DA /* MetalViewDelegate.mm in Sources */,
FBA9A76A2A50795700F960DA /* Hash.cpp in Sources */,

View File

@ -20,5 +20,116 @@
landmarkType = "0">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "230CC0C2-A8D1-4213-8AE3-3C387755A129"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "m/MetalViewDelegate.mm"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "55"
endingLineNumber = "55"
landmarkName = "-_loadMetalWithView:"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "FB626E75-87DB-404F-90BE-27B364652473"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "m/MetalViewDelegate.mm"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "63"
endingLineNumber = "63"
landmarkName = "-_loadMetalWithView:"
landmarkType = "7">
<Locations>
<Location
uuid = "FB626E75-87DB-404F-90BE-27B364652473 - 54c402e8093d4dff"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
symbolName = "-[MetalViewDelegate _loadMetalWithView:]"
moduleName = "KDE"
usesParentBreakpointCondition = "Yes"
urlString = "file:///Users/ronjaenseleit/Documents/KDE/app/src/main/m/MetalViewDelegate.mm"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "70"
endingLineNumber = "70"
offsetFromSymbolStart = "132">
</Location>
<Location
uuid = "FB626E75-87DB-404F-90BE-27B364652473 - 54c402e8093d4dff"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
symbolName = "-[MetalViewDelegate _loadMetalWithView:]"
moduleName = "KDE"
usesParentBreakpointCondition = "Yes"
urlString = "file:///Users/ronjaenseleit/Documents/KDE/app/src/main/m/MetalViewDelegate.mm"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "70"
endingLineNumber = "70"
offsetFromSymbolStart = "116">
</Location>
<Location
uuid = "FB626E75-87DB-404F-90BE-27B364652473 - 54c402e8093d4cd4"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
symbolName = "-[MetalViewDelegate _loadMetalWithView:]"
moduleName = "KDE"
usesParentBreakpointCondition = "Yes"
urlString = "file:///Users/ronjaenseleit/Documents/KDE/app/src/main/m/MetalViewDelegate.mm"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "63"
endingLineNumber = "63"
offsetFromSymbolStart = "116">
</Location>
</Locations>
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "ABBF5C68-10CF-4FF5-BB6F-D86C5D352BB2"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "cpp/AssetManager.cpp"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "20"
endingLineNumber = "20"
landmarkName = "AssetManager::loadTexture(path, p_texture)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "7C88C504-1B41-4373-879B-61403D971D39"
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "m/MetalViewDelegate.mm"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "281"
endingLineNumber = "281"
landmarkName = "-mtkView:drawableSizeWillChange:"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>

View File

@ -171,6 +171,7 @@ void Renderer::addFontRect(float x,
void Renderer::renderFrame(float width, float height)
{
// This is done automatically under iOS and does not require a call.
#if defined(_WIN32) || defined(__ANDROID__)
openGLGfxRenderFrame((OpenGLGfx*)m_gfx, width, height);
#endif
@ -179,7 +180,7 @@ void Renderer::renderFrame(float width, float height)
void Renderer::getTextureSize(KDEStringHandle texture, unsigned int* w, unsigned int* h)
{
#ifdef __APPLE__
// TODO
#else
openGLGfxGetTextureSize((OpenGLGfx*)m_gfx, texture, w, h);
#endif

View File

@ -176,6 +176,8 @@ public:
unsigned int* w,
unsigned int* h);
void* getGfx() { return m_gfx; }
private:
Renderer(void* gfx);
~Renderer();

View File

@ -1,5 +1,10 @@
#include "Texture.h"
#include "Profiling.h"
#include "Renderer.h"
#ifdef __APPLE__
#include "../m/MetalGfxInterface.h"
#endif
#if defined(__ANDROID__) || defined(_WIN32)
Texture::Texture() : m_texture(0) {}
@ -69,6 +74,35 @@ void Texture::bind() const
glBindTexture(GL_TEXTURE_2D, m_texture);
}
#else
Texture::Texture() : m_texture(nullptr) {}
Texture::Texture(unsigned int width, unsigned int height, const void* data)
: width_px(width), height_px(height)
{
m_texture = metalGfxCreateTexture(Renderer::ptr->getGfx(), data, width, height, MetalGfxTextureFormat_RGBA);
}
Texture::Texture(unsigned int width, unsigned int height, const void* data, int dummy)
: width_px(width), height_px(height)
{
m_texture = metalGfxCreateTexture(Renderer::ptr->getGfx(), data, width, height, MetalGfxTextureFormat_Red);
}
void Texture::destroy()
{
metalGfxDestroyTexture(m_texture);
m_texture = nullptr;
}
void Texture::bind() const
{
/* This is a no-op under metal? */
}
#endif
void Texture::getTextureSize(unsigned int* w, unsigned int* h)
{
ZoneScoped;
@ -79,29 +113,3 @@ void Texture::getTextureSize(unsigned int* w, unsigned int* h)
*h = height_px;
}
}
#else
Texture::Texture() {}
Texture::Texture(unsigned int width, unsigned int height, const void* data)
{
}
Texture::Texture(unsigned int width, unsigned int height, const void* data, int dummy)
{
}
void Texture::destroy()
{
}
void Texture::bind() const
{
}
void Texture::getTextureSize(unsigned int* w, unsigned int* h)
{
}
#endif

View File

@ -37,9 +37,15 @@ public:
unsigned int* w,
unsigned int* h);
#ifdef __APPLE__
void* getObj() { return m_texture; }
#endif
private:
#if defined(_WIN32) || defined(__ANDROID__)
GLuint m_texture;
#elif defined(__APPLE__)
void* m_texture;
#endif
int width_px;

View File

@ -9,6 +9,7 @@
#import "MetalViewDelegate.h"
#include "../cpp/Renderer.h"
#include "IOSAssetManager.h"
@implementation GameViewController
{
@ -33,10 +34,9 @@
return;
}
IOSAssetManager::create();
_renderer = [[MetalViewDelegate alloc] initWithMetalKitView:_view];
[_renderer mtkView:_view drawableSizeWillChange:_view.bounds.size];
_view.delegate = _renderer;
Renderer::create((__bridge void*)_renderer);

View File

@ -0,0 +1,17 @@
#ifndef KRIMI_DINNER_ENGINE_IOSAssetManager_h
#define KRIMI_DINNER_ENGINE_IOSAssetManager_h
#include "../cpp/AssetManager.h"
class IOSAssetManager : public AssetManager
{
public:
static void create();
bool loadFile(const char* path, FileBuffer* p_file_buffer) override;
void releaseFileBuffer(FileBuffer& fb) override;
};
#endif

View File

@ -0,0 +1,35 @@
#include "IOSAssetManager.h"
#import <Foundation/Foundation.h>
#include <stdlib.h>
#include <string.h>
void IOSAssetManager::create()
{
ptr = new IOSAssetManager;
}
bool IOSAssetManager::loadFile(const char* path, FileBuffer* p_file_buf)
{
NSString* search_path = [NSString stringWithUTF8String:path];
NSString* full_path = [[NSBundle mainBundle] pathForResource:search_path ofType:@"" inDirectory:@"assets"];
NSData* content = [[NSFileManager defaultManager] contentsAtPath: full_path];
NSUInteger length = [content length];
void *buf = malloc((size_t)length);
if (!buf)
return false;
[content getBytes: buf length: length];
p_file_buf->data = buf;
p_file_buf->size = (size_t)length;
p_file_buf->internal = NULL;
return true;
}
void IOSAssetManager::releaseFileBuffer(FileBuffer& fb)
{
free((void*)fb.data);
memset(&fb, 0, sizeof(fb));
}

View File

@ -8,4 +8,14 @@ void metalGfxPushRect(void* metalGfxObj, KDERect rect, KDEStringHandle texture);
void metalGfxPushFontRect(void* metalGfxObj, KDERect rect, float char_height, KDEStringHandle font, KDEStringHandle key);
typedef enum MetalGfxTextureFormat
{
MetalGfxTextureFormat_RGBA,
MetalGfxTextureFormat_Red,
} MetalGfxTextureFormat;
void* metalGfxCreateTexture(void* metalGfxObj, const void* pixels, unsigned int width, unsigned int height, MetalGfxTextureFormat format);
void metalGfxDestroyTexture(void* textureObj);
#endif

View File

@ -1,5 +1,8 @@
#import <Foundation/Foundation.h>
#import "MetalViewDelegate.h"
#import <MetalKit/MetalKit.h>
#import "MetalGfxInterface.h"
void metalGfxPushRect(void* metalGfxObj, KDERect rect, KDEStringHandle texture)
{
@ -10,3 +13,17 @@ void metalGfxPushFontRect(void* metalGfxObj, KDERect rect, float char_height, KD
{
[(__bridge id)metalGfxObj pushRect:rect withFont:font withCharHeight:char_height withKey:key];
}
void* metalGfxCreateTexture(void* metalGfxObj, const void* pixels, unsigned int width, unsigned int height, MetalGfxTextureFormat format)
{
MTLPixelFormat pxFormat = (format == MetalGfxTextureFormat_RGBA)
? MTLPixelFormatRGBA8Uint
: MTLPixelFormatR8Uint;
return (__bridge_retained void*)[(__bridge id)metalGfxObj createTexture:pixels width:width height:height format:pxFormat];
}
void metalGfxDestroyTexture(void* textureObj)
{
id<MTLTexture> texture = (__bridge_transfer id)textureObj;
// Texture should be dropped here
}

View File

@ -20,5 +20,7 @@
-(void)pushRect:(KDERect)rect withFont:(KDEStringHandle)font withCharHeight:(float)char_height withKey:(KDEStringHandle)key;
-(nonnull id<MTLTexture>)createTexture:(nonnull const void*)data width:(unsigned int)width height:(unsigned int)height format:(MTLPixelFormat)format;
@end

View File

@ -1,12 +1,7 @@
//
// Renderer.m
// KDE
//
// Created by Ronja Enseleit on 01.07.23.
//
#import <simd/simd.h>
#import <ModelIO/ModelIO.h>
#include <vector>
#include <map>
#import "MetalViewDelegate.h"
@ -14,6 +9,7 @@
#import "ShaderTypes.h"
#include "../cpp/Renderer.h"
#include "IOSAssetManager.h"
static const NSUInteger MaxBuffersInFlight = 3;
@ -26,16 +22,21 @@ static const NSUInteger MaxBuffersInFlight = 3;
id <MTLBuffer> _dynamicUniformBuffer[MaxBuffersInFlight];
id <MTLRenderPipelineState> _pipelineState;
id <MTLDepthStencilState> _depthState;
id <MTLTexture> _colorMap;
id <MTLTexture> _dummyTexture;
MTLVertexDescriptor *_mtlVertexDescriptor;
uint8_t _uniformBufferIndex;
vector_float2 _resolution;
matrix_float4x4 _projectionMatrix;
uint8_t _bufferIndex;
float _rotation;
id<MTLBuffer> _vertexBuffers[MaxBuffersInFlight];
// In number of rects
size_t _vertexBufferCapacities[MaxBuffersInFlight];
MTKMesh *_mesh;
std::vector<KDERect> _drawRects;
std::vector<id<MTLTexture>> _drawTextures;
std::map<KDEStringHandle, Texture> _textures;
}
-(nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)view;
@ -46,7 +47,6 @@ static const NSUInteger MaxBuffersInFlight = 3;
_device = view.device;
_inFlightSemaphore = dispatch_semaphore_create(MaxBuffersInFlight);
[self _loadMetalWithView:view];
[self _loadAssets];
}
return self;
@ -60,28 +60,40 @@ static const NSUInteger MaxBuffersInFlight = 3;
view.colorPixelFormat = MTLPixelFormatBGRA8Unorm_sRGB;
view.sampleCount = 1;
_resolution = vector2((float)[view drawableSize].width, (float)[view drawableSize].height);
_mtlVertexDescriptor = [[MTLVertexDescriptor alloc] init];
_mtlVertexDescriptor.attributes[VertexAttributePosition].format = MTLVertexFormatFloat3;
_mtlVertexDescriptor.attributes[VertexAttributePosition].offset = 0;
_mtlVertexDescriptor.attributes[VertexAttributePosition].bufferIndex = BufferIndexMeshPositions;
_mtlVertexDescriptor.attributes[VertexAttributeDstP0].format = MTLVertexFormatFloat2;
_mtlVertexDescriptor.attributes[VertexAttributeDstP0].offset = 0;
_mtlVertexDescriptor.attributes[VertexAttributeDstP0].bufferIndex = BufferIndexRects;
_mtlVertexDescriptor.attributes[VertexAttributeTexcoord].format = MTLVertexFormatFloat2;
_mtlVertexDescriptor.attributes[VertexAttributeTexcoord].offset = 0;
_mtlVertexDescriptor.attributes[VertexAttributeTexcoord].bufferIndex = BufferIndexMeshGenerics;
_mtlVertexDescriptor.attributes[VertexAttributeDstP1].format = MTLVertexFormatFloat2;
_mtlVertexDescriptor.attributes[VertexAttributeDstP1].offset = offsetof(KDERect, dst_p1_x);
_mtlVertexDescriptor.attributes[VertexAttributeDstP1].bufferIndex = BufferIndexRects;
_mtlVertexDescriptor.layouts[BufferIndexMeshPositions].stride = 12;
_mtlVertexDescriptor.layouts[BufferIndexMeshPositions].stepRate = 1;
_mtlVertexDescriptor.layouts[BufferIndexMeshPositions].stepFunction = MTLVertexStepFunctionPerVertex;
_mtlVertexDescriptor.attributes[VertexAttributeSrcP0].format = MTLVertexFormatFloat2;
_mtlVertexDescriptor.attributes[VertexAttributeSrcP0].offset = offsetof(KDERect, src_p0_x);
_mtlVertexDescriptor.attributes[VertexAttributeSrcP0].bufferIndex = BufferIndexRects;
_mtlVertexDescriptor.layouts[BufferIndexMeshGenerics].stride = 8;
_mtlVertexDescriptor.layouts[BufferIndexMeshGenerics].stepRate = 1;
_mtlVertexDescriptor.layouts[BufferIndexMeshGenerics].stepFunction = MTLVertexStepFunctionPerVertex;
_mtlVertexDescriptor.attributes[VertexAttributeSrcP1].format = MTLVertexFormatFloat2;
_mtlVertexDescriptor.attributes[VertexAttributeSrcP1].offset = offsetof(KDERect, src_p1_x);
_mtlVertexDescriptor.attributes[VertexAttributeSrcP1].bufferIndex = BufferIndexRects;
_mtlVertexDescriptor.attributes[VertexAttributeColor].format = MTLVertexFormatFloat4;
_mtlVertexDescriptor.attributes[VertexAttributeColor].offset = offsetof(KDERect, r);
_mtlVertexDescriptor.attributes[VertexAttributeColor].bufferIndex = BufferIndexRects;
_mtlVertexDescriptor.attributes[VertexAttributeExpandR].format = MTLVertexFormatInt;
_mtlVertexDescriptor.attributes[VertexAttributeExpandR].offset = offsetof(KDERect, expand_r);
_mtlVertexDescriptor.attributes[VertexAttributeExpandR].bufferIndex = BufferIndexRects;
_mtlVertexDescriptor.layouts[BufferIndexRects].stride = sizeof(KDERect);
_mtlVertexDescriptor.layouts[BufferIndexRects].stepRate = 1;
_mtlVertexDescriptor.layouts[BufferIndexRects].stepFunction = MTLVertexStepFunctionPerInstance;
id<MTLLibrary> defaultLibrary = [_device newDefaultLibrary];
id <MTLFunction> vertexFunction = [defaultLibrary newFunctionWithName:@"vertexShader"];
id <MTLFunction> fragmentFunction = [defaultLibrary newFunctionWithName:@"fragmentShader"];
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
@ -103,7 +115,7 @@ static const NSUInteger MaxBuffersInFlight = 3;
MTLDepthStencilDescriptor *depthStateDesc = [[MTLDepthStencilDescriptor alloc] init];
depthStateDesc.depthCompareFunction = MTLCompareFunctionLess;
depthStateDesc.depthWriteEnabled = YES;
depthStateDesc.depthWriteEnabled = NO;
_depthState = [_device newDepthStencilStateWithDescriptor:depthStateDesc];
for(NSUInteger i = 0; i < MaxBuffersInFlight; i++)
@ -112,64 +124,20 @@ static const NSUInteger MaxBuffersInFlight = 3;
options:MTLResourceStorageModeShared];
_dynamicUniformBuffer[i].label = @"UniformBuffer";
_vertexBufferCapacities[i] = 256;
_vertexBuffers[i] = [_device newBufferWithLength:sizeof(Rect) * _vertexBufferCapacities[i]
options:MTLResourceStorageModeShared];
}
_commandQueue = [_device newCommandQueue];
// Create the dummy texture (1x1 px white)
uint8_t bytes[4] = { 255, 255, 255, 255 };
_dummyTexture = [self createTexture:bytes width:1 height:1 format:MTLPixelFormatRGBA8Uint];
}
- (void)_loadAssets
{
/// Load assets into metal objects
NSError *error;
MTKMeshBufferAllocator *metalAllocator = [[MTKMeshBufferAllocator alloc]
initWithDevice: _device];
MDLMesh *mdlMesh = [MDLMesh newBoxWithDimensions:(vector_float3){4, 4, 4}
segments:(vector_uint3){2, 2, 2}
geometryType:MDLGeometryTypeTriangles
inwardNormals:NO
allocator:metalAllocator];
MDLVertexDescriptor *mdlVertexDescriptor =
MTKModelIOVertexDescriptorFromMetal(_mtlVertexDescriptor);
mdlVertexDescriptor.attributes[VertexAttributePosition].name = MDLVertexAttributePosition;
mdlVertexDescriptor.attributes[VertexAttributeTexcoord].name = MDLVertexAttributeTextureCoordinate;
mdlMesh.vertexDescriptor = mdlVertexDescriptor;
_mesh = [[MTKMesh alloc] initWithMesh:mdlMesh
device:_device
error:&error];
if(!_mesh || error)
{
NSLog(@"Error creating MetalKit mesh %@", error.localizedDescription);
}
MTKTextureLoader* textureLoader = [[MTKTextureLoader alloc] initWithDevice:_device];
NSDictionary *textureLoaderOptions =
@{
MTKTextureLoaderOptionTextureUsage : @(MTLTextureUsageShaderRead),
MTKTextureLoaderOptionTextureStorageMode : @(MTLStorageModePrivate)
};
_colorMap = [textureLoader newTextureWithName:@"ColorMap"
scaleFactor:1.0
bundle:nil
options:textureLoaderOptions
error:&error];
if(!_colorMap || error)
{
NSLog(@"Error creating texture %@", error.localizedDescription);
}
}
- (void)_updateGameState
- (NSUInteger)_updateGameState
{
// Demo code
static float x = 1.f;
@ -188,21 +156,27 @@ static const NSUInteger MaxBuffersInFlight = 3;
}
#endif
Renderer::ptr->addRect(100, 100, 500, 500, 0.3f, 0.3f, 0.3f, 1.f);
Renderer::ptr->addRect(100, 100, 500, 500, 1.f, 1.f, 1.f, 1.f, StringRepository::global->internString("smiley_PNG42.png"));
//Renderer::ptr->addRect(m_smiley_pos.x, m_smiley_pos.y, 500, 500, 0.f, x * x, 1.f - x * x, 1.f, m_smiley);
// Upload rects
if (_drawRects.size() > _vertexBufferCapacities[_bufferIndex]) {
size_t newCap = ((_drawRects.size() + 63) / 64) * 64;
_vertexBuffers[_bufferIndex] = [_device newBufferWithLength:sizeof(KDERect) * newCap
options:MTLResourceStorageModeShared];
_vertexBufferCapacities[_bufferIndex] = newCap;
}
memcpy(_vertexBuffers[_bufferIndex].contents,
_drawRects.data(),
_drawRects.size() * sizeof(KDERect));
NSUInteger rectCount = (NSUInteger)_drawRects.size();
_drawRects.clear();
/// Update any game state before encoding renderint commands to our drawable
Uniforms * uniforms = (Uniforms*)_dynamicUniformBuffer[_uniformBufferIndex].contents;
Uniforms * uniforms = (Uniforms*)_dynamicUniformBuffer[_bufferIndex].contents;
uniforms->resolution = _resolution;
uniforms->projectionMatrix = _projectionMatrix;
vector_float3 rotationAxis = {1, 1, 0};
matrix_float4x4 modelMatrix = matrix4x4_rotation(_rotation, rotationAxis);
matrix_float4x4 viewMatrix = matrix4x4_translation(0.0, 0.0, -8.0);
uniforms->modelViewMatrix = matrix_multiply(viewMatrix, modelMatrix);
_rotation += .01;
return rectCount;
}
- (void)drawInMTKView:(nonnull MTKView *)view
@ -211,7 +185,7 @@ static const NSUInteger MaxBuffersInFlight = 3;
dispatch_semaphore_wait(_inFlightSemaphore, DISPATCH_TIME_FOREVER);
_uniformBufferIndex = (_uniformBufferIndex + 1) % MaxBuffersInFlight;
_bufferIndex = (_bufferIndex + 1) % MaxBuffersInFlight;
id <MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
commandBuffer.label = @"MyCommand";
@ -222,7 +196,7 @@ static const NSUInteger MaxBuffersInFlight = 3;
dispatch_semaphore_signal(block_sema);
}];
[self _updateGameState];
NSUInteger rectCount = [self _updateGameState];
/// Delay getting the currentRenderPassDescriptor until absolutely needed. This avoids
/// holding onto the drawable and blocking the display pipeline any longer than necessary
@ -231,47 +205,63 @@ static const NSUInteger MaxBuffersInFlight = 3;
if(renderPassDescriptor != nil)
{
/// Final pass rendering code here
id <MTLRenderCommandEncoder> renderEncoder =
[commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
renderEncoder.label = @"MyRenderEncoder";
[renderEncoder pushDebugGroup:@"DrawBox"];
[renderEncoder pushDebugGroup:@"DrawRects"];
[renderEncoder setFrontFacingWinding:MTLWindingCounterClockwise];
[renderEncoder setCullMode:MTLCullModeBack];
[renderEncoder setCullMode:MTLCullModeNone];
[renderEncoder setRenderPipelineState:_pipelineState];
[renderEncoder setDepthStencilState:_depthState];
[renderEncoder setVertexBuffer:_dynamicUniformBuffer[_uniformBufferIndex]
[renderEncoder setVertexBuffer:_dynamicUniformBuffer[_bufferIndex]
offset:0
atIndex:BufferIndexUniforms];
[renderEncoder setFragmentBuffer:_dynamicUniformBuffer[_uniformBufferIndex]
[renderEncoder setFragmentBuffer:_dynamicUniformBuffer[_bufferIndex]
offset:0
atIndex:BufferIndexUniforms];
for (NSUInteger bufferIndex = 0; bufferIndex < _mesh.vertexBuffers.count; bufferIndex++)
{
MTKMeshBuffer *vertexBuffer = _mesh.vertexBuffers[bufferIndex];
if((NSNull*)vertexBuffer != [NSNull null])
{
[renderEncoder setVertexBuffer:vertexBuffer.buffer
offset:vertexBuffer.offset
atIndex:bufferIndex];
}
}
[renderEncoder setVertexBuffer:_vertexBuffers[_bufferIndex]
offset:0
atIndex:BufferIndexRects];
[renderEncoder setFragmentTexture:_colorMap
size_t start = 0;
id<MTLTexture> currentTexture = _drawTextures[0];
while (start < rectCount) {
for (size_t i = start; i < rectCount; ++i) {
id<MTLTexture> texture = _drawTextures[i];
if (texture != currentTexture) {
size_t count = i - start;
[renderEncoder setFragmentTexture:currentTexture
atIndex:TextureIndexColor];
for(MTKSubmesh *submesh in _mesh.submeshes)
{
[renderEncoder drawIndexedPrimitives:submesh.primitiveType
indexCount:submesh.indexCount
indexType:submesh.indexType
indexBuffer:submesh.indexBuffer.buffer
indexBufferOffset:submesh.indexBuffer.offset];
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle
vertexStart:0
vertexCount:6
instanceCount:count
baseInstance:start];
start = i;
currentTexture = texture;
break;
}
else if (i == rectCount - 1) {
// just draw it
const size_t count = rectCount - start;
[renderEncoder setFragmentTexture:currentTexture
atIndex:TextureIndexColor];
[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle
vertexStart:0
vertexCount:6
instanceCount:count
baseInstance:start];
start = rectCount;
break;
}
}
}
[renderEncoder popDebugGroup];
@ -280,6 +270,7 @@ static const NSUInteger MaxBuffersInFlight = 3;
[commandBuffer presentDrawable:view.currentDrawable];
}
_drawTextures.clear();
[commandBuffer commit];
}
@ -287,62 +278,66 @@ static const NSUInteger MaxBuffersInFlight = 3;
- (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size
{
/// Respond to drawable size or orientation changes here
float aspect = size.width / (float)size.height;
_projectionMatrix = matrix_perspective_right_hand(65.0f * (M_PI / 180.0f), aspect, 0.1f, 100.0f);
_resolution.x = (float)size.width;
_resolution.y = (float)size.height;
}
- (void)pushRect:(KDERect)rect withTexture:(KDEStringHandle)texture
{
// TODO
Texture tex;
if (texture != 0) {
if (_textures.find(texture) == _textures.end()) {
if (!AssetManager::ptr->loadTexture(StringRepository::global->getString(texture), &tex)) {
NSLog(@"Failed to load a texture");
return;
}
_textures.insert(std::make_pair(texture, tex));
}
else {
tex = _textures[texture];
}
_drawTextures.push_back((__bridge id)tex.getObj());
}
else {
_drawTextures.push_back(_dummyTexture);
}
_drawRects.push_back(rect);
}
- (void)pushRect:(KDERect)rect withFont:(KDEStringHandle)font withCharHeight:(float)char_height withKey:(KDEStringHandle)key
{
// TODO
Texture tex;
if (key != 0) {
if (_textures.find(key) == _textures.end()) {
if (!AssetManager::ptr->loadFontBitmap(StringRepository::global->getString(font), char_height, &tex)) {
NSLog(@"Failed to load font");
return;
}
_textures.insert(std::make_pair(key, tex));
}
else {
tex = _textures[key];
}
_drawTextures.push_back((__bridge id)tex.getObj());
}
else {
_drawTextures.push_back(_dummyTexture);
}
_drawRects.push_back(rect);
}
#pragma mark Matrix Math Utilities
matrix_float4x4 matrix4x4_translation(float tx, float ty, float tz)
-(id<MTLTexture>)createTexture:(nonnull const void*)data width:(unsigned int)width height:(unsigned int)height format:(MTLPixelFormat)format;
{
return (matrix_float4x4) {{
{ 1, 0, 0, 0 },
{ 0, 1, 0, 0 },
{ 0, 0, 1, 0 },
{ tx, ty, tz, 1 }
}};
}
MTLTextureDescriptor* desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:format width:(NSUInteger)width height:(NSUInteger)height mipmapped:NO];
static matrix_float4x4 matrix4x4_rotation(float radians, vector_float3 axis)
{
axis = vector_normalize(axis);
float ct = cosf(radians);
float st = sinf(radians);
float ci = 1 - ct;
float x = axis.x, y = axis.y, z = axis.z;
MTLRegion region = { {0, 0, 0}, {width, height, 1}};
return (matrix_float4x4) {{
{ ct + x * x * ci, y * x * ci + z * st, z * x * ci - y * st, 0},
{ x * y * ci - z * st, ct + y * y * ci, z * y * ci + x * st, 0},
{ x * z * ci + y * st, y * z * ci - x * st, ct + z * z * ci, 0},
{ 0, 0, 0, 1}
}};
}
matrix_float4x4 matrix_perspective_right_hand(float fovyRadians, float aspect, float nearZ, float farZ)
{
float ys = 1 / tanf(fovyRadians * 0.5);
float xs = ys / aspect;
float zs = farZ / (nearZ - farZ);
return (matrix_float4x4) {{
{ xs, 0, 0, 0 },
{ 0, ys, 0, 0 },
{ 0, 0, zs, -1 },
{ 0, 0, nearZ * zs, 0 }
}};
id<MTLTexture> texture = [_device newTextureWithDescriptor: desc];
NSUInteger bytesPerRow = 4 * width;
[texture replaceRegion:region mipmapLevel:0 withBytes:data bytesPerRow:bytesPerRow];
return texture;
}
@end

View File

@ -23,15 +23,18 @@ typedef NSInteger EnumBackingType;
typedef NS_ENUM(EnumBackingType, BufferIndex)
{
BufferIndexMeshPositions = 0,
BufferIndexMeshGenerics = 1,
BufferIndexUniforms = 2
BufferIndexRects = 0,
BufferIndexUniforms = 1
};
typedef NS_ENUM(EnumBackingType, VertexAttribute)
{
VertexAttributePosition = 0,
VertexAttributeTexcoord = 1,
VertexAttributeDstP0 = 0,
VertexAttributeDstP1 = 1,
VertexAttributeSrcP0 = 2,
VertexAttributeSrcP1 = 3,
VertexAttributeColor = 4,
VertexAttributeExpandR = 5
};
typedef NS_ENUM(EnumBackingType, TextureIndex)
@ -41,8 +44,7 @@ typedef NS_ENUM(EnumBackingType, TextureIndex)
typedef struct
{
matrix_float4x4 projectionMatrix;
matrix_float4x4 modelViewMatrix;
vector_float2 resolution;
} Uniforms;
#endif /* ShaderTypes_h */

View File

@ -17,37 +17,71 @@ using namespace metal;
typedef struct
{
float3 position [[attribute(VertexAttributePosition)]];
float2 texCoord [[attribute(VertexAttributeTexcoord)]];
float2 dstP0 [[attribute(VertexAttributeDstP0)]];
float2 dstP1 [[attribute(VertexAttributeDstP1)]];
float2 srcP0 [[attribute(VertexAttributeSrcP0)]];
float2 srcP1 [[attribute(VertexAttributeSrcP1)]];
float4 color [[attribute(VertexAttributeColor)]];
int expandR [[attribute(VertexAttributeExpandR)]];
} Vertex;
typedef struct
{
float4 position [[position]];
float4 color;
float2 texCoord;
int expandR;
} ColorInOut;
constant float2 vertices[6] = {
{-1.0, -1.0},
{+1.0, -1.0},
{-1.0, +1.0},
{+1.0, -1.0},
{+1.0, +1.0},
{-1.0, +1.0}
};
vertex ColorInOut vertexShader(Vertex in [[stage_in]],
constant Uniforms & uniforms [[ buffer(BufferIndexUniforms) ]])
constant Uniforms & uniforms [[ buffer(BufferIndexUniforms) ]],
uint vertex_id [[vertex_id]])
{
ColorInOut out;
float4 position = float4(in.position, 1.0);
out.position = uniforms.projectionMatrix * uniforms.modelViewMatrix * position;
out.texCoord = in.texCoord;
float2 v = vertices[vertex_id];
float2 dstHalfSize = (in.dstP1 - in.dstP0) / 2.0;
float2 dstCenter = (in.dstP0 + in.dstP1) / 2.0;
float2 dstPos = v * dstHalfSize + dstCenter;
//dstPos.y = uniforms.resolution.y - dstPos.y;
out.position = float4(2.0 * (dstPos.x / uniforms.resolution.x) - 1.0,
2.0 * (dstPos.y / uniforms.resolution.y) - 1.0,
0.0,
1.0);
out.color = in.color;
out.position.y *= -1.0;
float2 srcHalfSize = (in.srcP1 - in.srcP0) / 2.0;
float2 srcCenter = (in.srcP0 + in.srcP1) / 2.0;
float2 srcPos = v * srcHalfSize + srcCenter;
out.texCoord = srcPos;
out.expandR = in.expandR;
return out;
}
fragment float4 fragmentShader(ColorInOut in [[stage_in]],
constant Uniforms & uniforms [[ buffer(BufferIndexUniforms) ]],
texture2d<half> colorMap [[ texture(TextureIndexColor) ]])
texture2d<uint> colorMap [[ texture(TextureIndexColor) ]])
{
constexpr sampler colorSampler(mip_filter::linear,
mag_filter::linear,
min_filter::linear);
half4 colorSample = colorMap.sample(colorSampler, in.texCoord.xy);
float4 colorSample = float4(colorMap.sample(colorSampler, in.texCoord.xy)) / 255.0 * in.color;
return float4(colorSample);
if (in.expandR == 1)
colorSample = colorSample.rrrr;
return colorSample;
}