Skip to content

Commit

Permalink
adds iOS fade in pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
zimmermannubique committed Feb 5, 2024
1 parent 52b50c3 commit dad152a
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 36 deletions.
74 changes: 51 additions & 23 deletions ios/graphics/Model/Polygon/PolygonPatternGroup2d.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@ final class PolygonPatternGroup2d: BaseGraphicsObject {
private var textureCoordinatesBuffer: MTLBuffer?

private var stencilState: MTLDepthStencilState?
private var renderPassStencilState: MTLDepthStencilState?

private var texture: MTLTexture?

private var screenPixelFactor: Float = 0
var customScreenPixelFactor = SIMD2<Float>([0.0, 0.0])

var posOffset = SIMD2<Float>([0.0, 0.0])


init(shader: MCShaderProgramInterface, metalContext: MetalContext) {
guard let shader = shader as? PolygonPatternGroupShader else {
Expand All @@ -39,25 +43,9 @@ final class PolygonPatternGroup2d: BaseGraphicsObject {
label: "PolygonPatternGroup2d")
}

private func setupStencilStates() {
let ss2 = MTLStencilDescriptor()
ss2.stencilCompareFunction = .equal
ss2.stencilFailureOperation = .zero
ss2.depthFailureOperation = .keep
ss2.depthStencilPassOperation = .keep
ss2.readMask = 0b1111_1111
ss2.writeMask = 0b0000_0000

let s2 = MTLDepthStencilDescriptor()
s2.frontFaceStencil = ss2
s2.backFaceStencil = ss2

stencilState = device.makeDepthStencilState(descriptor: s2)
}

override func render(encoder: MTLRenderCommandEncoder,
context: RenderingContext,
renderPass _: MCRenderPassConfig,
renderPass pass: MCRenderPassConfig,
mvpMatrix: Int64,
isMasked: Bool,
screenPixelAsRealMeterFactor: Double) {
Expand All @@ -70,7 +58,9 @@ final class PolygonPatternGroup2d: BaseGraphicsObject {
let indicesBuffer,
let opacitiesBuffer,
let textureCoordinatesBuffer,
let texture else { return }
let texture else {
return
}

#if DEBUG
encoder.pushDebugGroup(label)
Expand All @@ -81,26 +71,47 @@ final class PolygonPatternGroup2d: BaseGraphicsObject {

if isMasked {
if stencilState == nil {
setupStencilStates()
self.stencilState = self.maskStencilState()
}

encoder.setDepthStencilState(stencilState)
encoder.setStencilReferenceValue(0b1100_0000)
}

if pass.isPassMasked {
if renderPassStencilState == nil {
renderPassStencilState = self.renderPassMaskStencilState()
}

encoder.setDepthStencilState(renderPassStencilState)
encoder.setStencilReferenceValue(0b1100_0000)
}

shader.setupProgram(context)
shader.preRender(context)

encoder.setVertexBuffer(verticesBuffer, offset: 0, index: 0)
if let matrixPointer = UnsafeRawPointer(bitPattern: Int(mvpMatrix)) {
encoder.setVertexBytes(matrixPointer, length: 64, index: 1)
}
if customScreenPixelFactor.x != 0 {
encoder.setVertexBytes(&customScreenPixelFactor, length: MemoryLayout<SIMD2<Float>>.stride, index: 2)

// scale factors for shaders
var pixelFactor : Float = Float(screenPixelAsRealMeterFactor)

if self.shader.fadeInPattern {
var scaleFactors = SIMD2<Float>([pixelFactor, pixelFactor])
encoder.setVertexBytes(&scaleFactors, length: MemoryLayout<SIMD2<Float>>.stride, index: 2)
encoder.setVertexBytes(&posOffset, length: MemoryLayout<SIMD2<Float>>.stride, index: 3)

scaleFactors = customScreenPixelFactor.x != 0 ? customScreenPixelFactor : SIMD2<Float>([pixelFactor, pixelFactor])
encoder.setFragmentBytes(&pixelFactor, length: MemoryLayout<Float>.stride, index: 2)
encoder.setFragmentBytes(&scaleFactors, length: MemoryLayout<SIMD2<Float>>.stride, index: 3)
} else {
var factors = SIMD2<Float>([screenPixelAsRealMeterFactor, screenPixelAsRealMeterFactor])
encoder.setVertexBytes(&factors, length: MemoryLayout<SIMD2<Float>>.stride, index: 2)
var scaleFactors = customScreenPixelFactor.x != 0 ? customScreenPixelFactor : SIMD2<Float>([pixelFactor, pixelFactor])
encoder.setVertexBytes(&scaleFactors, length: MemoryLayout<SIMD2<Float>>.stride, index: 2)
}

// texture
encoder.setFragmentTexture(texture, index: 0)
encoder.setFragmentSamplerState(sampler, index: 0)

Expand Down Expand Up @@ -135,6 +146,23 @@ extension PolygonPatternGroup2d: MCPolygonPatternGroup2dInterface {
self.indicesCount = Int(indices.elementCount)
self.verticesBuffer = verticesBuffer
self.indicesBuffer = indicesBuffer

if let p = UnsafeRawPointer(bitPattern: Int(vertices.address)) {
var minX = Float.greatestFiniteMagnitude
var minY = Float.greatestFiniteMagnitude

for i in 0..<vertices.elementCount {
if i % 3 == 0 {
let x = (p + 4 * Int(i)).load(as: Float.self)
let y = (p + 4 * (Int(i) + 1)).load(as: Float.self)
minX = min(x, minX)
minY = min(y, minY)
}
}

self.posOffset.x = minX;
self.posOffset.y = minY;
}
}
}

Expand Down
13 changes: 10 additions & 3 deletions ios/graphics/Pipelines/PipelineLibrary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ public enum PipelineType: String, CaseIterable, Codable {
case lineGroupShader
case polygonGroupShader
case polygonPatternGroupShader
case polygonPatternFadeInGroupShader
case colorShader
case roundColorShader
case clearStencilShader
Expand All @@ -137,6 +138,7 @@ public enum PipelineType: String, CaseIterable, Codable {
case .lineGroupShader: return "Line Group shader"
case .polygonGroupShader: return "Polygon Group shader"
case .polygonPatternGroupShader: return "Polygon Group Pattern shader"
case .polygonPatternFadeInGroupShader: return "Polygon Group Pattern (fade in) shader"
case .colorShader: return "Color shader"
case .roundColorShader: return "Round color shader"
case .clearStencilShader: return "Clear stencil shader"
Expand All @@ -155,6 +157,7 @@ public enum PipelineType: String, CaseIterable, Codable {
case .lineGroupShader: return "lineGroupVertexShader"
case .polygonGroupShader: return "polygonGroupVertexShader"
case .polygonPatternGroupShader: return "polygonPatternGroupVertexShader"
case .polygonPatternFadeInGroupShader: return "polygonPatternGroupVertexShader"
case .colorShader: return "colorVertexShader"
case .roundColorShader: return "colorVertexShader"
case .clearStencilShader: return "stencilClearVertexShader"
Expand All @@ -173,6 +176,7 @@ public enum PipelineType: String, CaseIterable, Codable {
case .lineGroupShader: return "lineGroupFragmentShader"
case .polygonGroupShader: return "polygonGroupFragmentShader"
case .polygonPatternGroupShader: return "polygonPatternGroupFragmentShader"
case .polygonPatternFadeInGroupShader: return "polygonPatternGroupFadeInFragmentShader"
case .colorShader: return "colorFragmentShader"
case .roundColorShader: return "roundColorFragmentShader"
case .clearStencilShader: return "stencilClearFragmentShader"
Expand All @@ -186,9 +190,12 @@ public enum PipelineType: String, CaseIterable, Codable {

var vertexDescriptor: MTLVertexDescriptor {
switch self {
case .lineGroupShader: return LineVertex.descriptor
case .polygonGroupShader, .polygonPatternGroupShader: return PolygonVertex.descriptor
default: return Vertex.descriptor
case .lineGroupShader:
return LineVertex.descriptor
case .polygonGroupShader, .polygonPatternGroupShader, .polygonPatternFadeInGroupShader:
return PolygonVertex.descriptor
default:
return Vertex.descriptor
}
}
}
Expand Down
78 changes: 74 additions & 4 deletions ios/graphics/Shader/Metal/PolygonGroupShader.metal
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@ struct PolygonPatternGroupVertexOut {
vertex PolygonPatternGroupVertexOut
polygonPatternGroupVertexShader(const PolygonGroupVertexIn vertexIn [[stage_in]],
constant float4x4 &mvpMatrix [[buffer(1)]],
constant float2 &scalingFactor [[buffer(2)]])
{
float2 pixelPosition = vertexIn.position.xy * float2(1 / scalingFactor.x, 1 / scalingFactor.y);
constant float2 &scalingFactor [[buffer(2)]],
constant float2 &posOffset [[buffer(3)]]) {
float2 pixelPosition = (vertexIn.position.xy - posOffset) * float2(1.0 / scalingFactor.x, 1 / scalingFactor.y);

PolygonPatternGroupVertexOut out {
PolygonPatternGroupVertexOut out {
.position = mvpMatrix * float4(vertexIn.position.xy, 0.0, 1.0),
.stylingIndex = vertexIn.stylingIndex,
.pixelPosition = pixelPosition
Expand Down Expand Up @@ -91,3 +91,73 @@ polygonPatternGroupFragmentShader(PolygonPatternGroupVertexOut in [[stage_in]],

return float4(color.r * a, color.g * a, color.b * a, a);
}

fragment float4
polygonPatternGroupFadeInFragmentShader(PolygonPatternGroupVertexOut in [[stage_in]],
texture2d<float> texture0 [[ texture(0)]],
sampler textureSampler [[sampler(0)]],
constant float *opacity [[buffer(0)]],
constant float *texureCoordinates [[buffer(1)]],
constant float &screenPixelAsRealMeterFactor [[buffer(2)]],
constant float2 &scalingFactor [[buffer(3)]])
{

int offset = int(in.stylingIndex * 5);
const float2 uvOrig = float2(texureCoordinates[offset], texureCoordinates[offset + 1]);
const float2 uvSize = float2(texureCoordinates[offset + 2], texureCoordinates[offset + 3]);
const int combined = int(texureCoordinates[offset + 4]);
const float2 pixelSize = float2(combined & 0xFF, combined >> 16);

const float scalingFactorFactor = (scalingFactor.x / screenPixelAsRealMeterFactor) - 1.0;
const float2 spacing = pixelSize * scalingFactorFactor;
const float2 totalSize = pixelSize + spacing;
const float2 adjustedPixelPosition = in.pixelPosition + totalSize * 0.5; // in other project pixelSize
float2 uvTot = fmod(adjustedPixelPosition, totalSize);

const int yIndex = int(adjustedPixelPosition.y / totalSize.y) % 2;

if(yIndex != 0 && uvTot.y <= pixelSize.y) {
uvTot.x = fmod(adjustedPixelPosition.x + totalSize.x * 0.5, totalSize.x);
}

float4 resultColor = float4(0.0,0.0,0.0,0.0);

if(uvTot.x > pixelSize.x || uvTot.y > pixelSize.y) {
if(uvTot.x > pixelSize.x && uvTot.y < pixelSize.y) {
// topRight
const float2 spacingTexSize = float2(spacing.x, spacing.x);
float relative = uvTot.y - (pixelSize.y - spacing.x) / 2;
if(relative > 0.0 && relative < spacing.x) {
float xPos = uvTot.x - pixelSize.x;
float2 uv = fmod(float2(xPos, relative) / spacingTexSize + float2(1.0,1.0), float2(1.0,1.0));

const float2 texUv = uvOrig + uvSize * uv;
resultColor = texture0.sample(textureSampler, texUv);
}
} else {
uvTot.x = fmod(adjustedPixelPosition.x + spacing.x * 0.5, totalSize.x);
if(uvTot.x > pixelSize.x && uvTot.y > pixelSize.y) {
// bottom right
const float2 uv = fmod((uvTot - pixelSize) / spacing + float2(1.0, 1.0), float2(1.0,1.0));
const float2 texUv = uvOrig + uvSize * uv;
resultColor = texture0.sample(textureSampler, texUv);
} else {
// bottom left
const float2 spacingTexSize = float2(spacing.y, spacing.y);
const float relativeX = uvTot.x - (pixelSize.x - spacing.x) / 2.0;

if(relativeX > 0.0 && relativeX < spacing.y) {
const float2 uv = fmod(float2(relativeX, uvTot.y - pixelSize.y) / spacingTexSize + float2(1.0, 1.0), float2(1.0,1.0));
const float2 texUv = uvOrig + uvSize * uv;
resultColor = texture0.sample(textureSampler, texUv);
}
}
}
} else {
const float2 uv = fmod(uvTot / pixelSize + float2(1.0,1.0), float2(1.0,1.0));
const float2 texUv = uvOrig + uvSize * uv;
resultColor = texture0.sample(textureSampler, texUv);
}

return resultColor;
}
20 changes: 16 additions & 4 deletions ios/graphics/Shader/PolygonPatternGroupShader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,25 @@ import Metal
import UIKit

class PolygonPatternGroupShader: BaseShader {
override init() {
// MARK: - Variables

let fadeInPattern : Bool

// MARK: - Init

init(fadeInPattern: Bool) {
self.fadeInPattern = fadeInPattern
super.init()
}

// MARK: - Setup

override func setupProgram(_: MCRenderingContextInterface?) {
if pipeline == nil {
pipeline = MetalContext.current.pipelineLibrary.value(Pipeline(type: .polygonPatternGroupShader, blendMode: blendMode).json)
}
guard pipeline == nil else { return }

let t : PipelineType = fadeInPattern ? .polygonPatternFadeInGroupShader : .polygonPatternGroupShader
let pl = Pipeline(type: t, blendMode: blendMode)
pipeline = MetalContext.current.pipelineLibrary.value(pl.json)
}

override func preRender(encoder: MTLRenderCommandEncoder, context: RenderingContext) {
Expand Down
4 changes: 2 additions & 2 deletions ios/graphics/Shader/ShaderFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ class ShaderFactory: MCShaderFactoryInterface {
PolygonGroupShader()
}

func createPolygonPatternGroupShader() -> MCPolygonPatternGroupShaderInterface? {
PolygonPatternGroupShader()
func createPolygonPatternGroupShader(_ fadeInPattern: Bool) -> MCPolygonPatternGroupShaderInterface? {
PolygonPatternGroupShader(fadeInPattern: fadeInPattern)
}

func createColorCircleShader() -> MCColorCircleShaderInterface? {
Expand Down

0 comments on commit dad152a

Please sign in to comment.