1#line 0 "examples/mtlViewer/mtlViewer.metal"
2
3//
4//   Copyright 2013 Pixar
5//
6//   Licensed under the Apache License, Version 2.0 (the "Apache License")
7//   with the following modification; you may not use this file except in
8//   compliance with the Apache License and the following modification to it:
9//   Section 6. Trademarks. is deleted and replaced with:
10//
11//   6. Trademarks. This License does not grant permission to use the trade
12//      names, trademarks, service marks, or product names of the Licensor
13//      and its affiliates, except as required to comply with Section 4(c) of
14//      the License and to reproduce the content of the NOTICE file.
15//
16//   You may obtain a copy of the Apache License at
17//
18//       http://www.apache.org/licenses/LICENSE-2.0
19//
20//   Unless required by applicable law or agreed to in writing, software
21//   distributed under the Apache License with the above modification is
22//   distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
23//   KIND, either express or implied. See the Apache License for the specific
24//   language governing permissions and limitations under the Apache License.
25//
26
27#include <metal_stdlib>
28using namespace metal;
29
30#if OSD_IS_ADAPTIVE
31static_assert(!OSD_ENABLE_SCREENSPACE_TESSELLATION || !USE_PTVS_FACTORS, "USE_PTVS_FACTORS cannot be enabled if OSD_ENABLE_SCREENSPACE_TESSELLATION is enabled");
32#endif
33
34#define SHADING_TYPE_MATERIAL 0
35#define SHADING_TYPE_FACE_VARYING_COLOR 1
36#define SHADING_TYPE_PATCH_TYPE 2
37#define SHADING_TYPE_PATCH_DEPTH 3
38#define SHADING_TYPE_PATCH_COORD 4
39#define SHADING_TYPE_NORMAL 5
40
41struct PerFrameConstants {
42    float4x4 ModelViewMatrix;
43    float4x4 ProjectionMatrix;
44    float4x4 ModelViewProjectionMatrix;
45    float4x4 ModelViewInverseMatrix;
46    float TessLevel;
47};
48
49struct OutputVertex {
50    float4 positionOut [[position]];
51    float3 position;
52    float3 normal;
53#if SHADING_TYPE == SHADING_TYPE_PATCH_TYPE || SHADING_TYPE == SHADING_TYPE_PATCH_DEPTH || SHADING_TYPE == SHADING_TYPE_PATCH_COORD || SHADING_TYPE_FACE_VARYING_COLOR
54    float3 patchColor;
55#endif
56};
57
58struct SolidColorVertex {
59    float4 positionOut [[position]];
60
61    half4 getColor() const {
62        return unpack_unorm4x8_to_half(_color);
63    }
64
65    void setColor(half4 color) {
66        _color = pack_half_to_unorm4x8(color);
67    }
68
69private:
70    uint _color [[flat, user(color)]];
71};
72
73struct PackedInputVertex {
74    packed_float3 position;
75};
76
77struct Light {
78    float3 Position;
79    float3 ambient;
80    float3 diffuse;
81    float3 specular;
82};
83
84float3 lighting(float3 diffuseColor, const constant Light* lightData, float3 eyePos, float3 eyeN)
85{
86
87    float3 color(0);
88    for(int i = 0; i < 2; i++)
89    {
90        const auto l = lightData[i].Position;
91        const auto h = normalize(l + float3(0,0,1));
92        const auto d = max(0.0, dot(eyeN, l));
93        const auto s = powr(max(0.0, dot(eyeN, h)), 500.0f);
94
95        color += lightData[i].ambient
96        + d * lightData[i].diffuse * diffuseColor
97        + s * lightData[i].specular;
98    }
99
100    return color;
101}
102
103
104const constant float4 patchColors[] = {
105    float4(1.0f,  1.0f,  1.0f,  1.0f),   // regular
106    float4(0.0f,  1.0f,  1.0f,  1.0f),   // regular pattern 0
107    float4(0.0f,  0.5f,  1.0f,  1.0f),   // regular pattern 1
108    float4(0.0f,  0.5f,  0.5f,  1.0f),   // regular pattern 2
109    float4(0.5f,  0.0f,  1.0f,  1.0f),   // regular pattern 3
110    float4(1.0f,  0.5f,  1.0f,  1.0f),   // regular pattern 4
111
112    float4(1.0f,  0.5f,  0.5f,  1.0f),   // single crease
113    float4(1.0f,  0.70f,  0.6f,  1.0f),  // single crease pattern 0
114    float4(1.0f,  0.65f,  0.6f,  1.0f),  // single crease pattern 1
115    float4(1.0f,  0.60f,  0.6f,  1.0f),  // single crease pattern 2
116    float4(1.0f,  0.55f,  0.6f,  1.0f),  // single crease pattern 3
117    float4(1.0f,  0.50f,  0.6f,  1.0f),  // single crease pattern 4
118
119    float4(0.8f,  0.0f,  0.0f,  1.0f),   // boundary
120    float4(0.0f,  0.0f,  0.75f, 1.0f),   // boundary pattern 0
121    float4(0.0f,  0.2f,  0.75f, 1.0f),   // boundary pattern 1
122    float4(0.0f,  0.4f,  0.75f, 1.0f),   // boundary pattern 2
123    float4(0.0f,  0.6f,  0.75f, 1.0f),   // boundary pattern 3
124    float4(0.0f,  0.8f,  0.75f, 1.0f),   // boundary pattern 4
125
126    float4(0.0f,  1.0f,  0.0f,  1.0f),   // corner
127    float4(0.5f,  1.0f,  0.5f,  1.0f),   // corner pattern 0
128    float4(0.5f,  1.0f,  0.5f,  1.0f),   // corner pattern 1
129    float4(0.5f,  1.0f,  0.5f,  1.0f),   // corner pattern 2
130    float4(0.5f,  1.0f,  0.5f,  1.0f),   // corner pattern 3
131    float4(0.5f,  1.0f,  0.5f,  1.0f),   // corner pattern 4
132
133    float4(1.0f,  1.0f,  0.0f,  1.0f),   // gregory
134    float4(1.0f,  1.0f,  0.0f,  1.0f),   // gregory
135    float4(1.0f,  1.0f,  0.0f,  1.0f),   // gregory
136    float4(1.0f,  1.0f,  0.0f,  1.0f),   // gregory
137    float4(1.0f,  1.0f,  0.0f,  1.0f),   // gregory
138    float4(1.0f,  1.0f,  0.0f,  1.0f),   // gregory
139
140    float4(1.0f,  0.5f,  0.0f,  1.0f),   // gregory boundary
141    float4(1.0f,  0.5f,  0.0f,  1.0f),   // gregory boundary
142    float4(1.0f,  0.5f,  0.0f,  1.0f),   // gregory boundary
143    float4(1.0f,  0.5f,  0.0f,  1.0f),   // gregory boundary
144    float4(1.0f,  0.5f,  0.0f,  1.0f),   // gregory boundary
145    float4(1.0f,  0.5f,  0.0f,  1.0f),   // gregory boundary
146
147    float4(1.0f,  0.7f,  0.3f,  1.0f),   // gregory basis
148    float4(1.0f,  0.7f,  0.3f,  1.0f),   // gregory basis
149    float4(1.0f,  0.7f,  0.3f,  1.0f),   // gregory basis
150    float4(1.0f,  0.7f,  0.3f,  1.0f),   // gregory basis
151    float4(1.0f,  0.7f,  0.3f,  1.0f),   // gregory basis
152    float4(1.0f,  0.7f,  0.3f,  1.0f)    // gregory basis
153};
154
155float4
156getAdaptivePatchColor(int3 patchParam
157#if OSD_PATCH_ENABLE_SINGLE_CREASE
158                      , float2 vSegments
159#else
160#endif
161                      )
162{
163
164
165    int patchType = 0;
166
167    int edgeCount = popcount(OsdGetPatchBoundaryMask(patchParam));
168    if (edgeCount == 1) {
169        patchType = 2; // BOUNDARY
170    }
171    if (edgeCount > 1) {
172        patchType = 3; // CORNER
173    }
174
175#if OSD_PATCH_ENABLE_SINGLE_CREASE
176    // check this after boundary/corner since single crease patch also has edgeCount.
177    if (vSegments.y > 0) {
178        patchType = 1;
179    }
180#elif OSD_PATCH_GREGORY
181    patchType = 4;
182#elif OSD_PATCH_GREGORY_BOUNDARY
183    patchType = 5;
184#elif OSD_PATCH_GREGORY_BASIS
185    patchType = 6;
186#elif OSD_PATCH_GREGORY_TRIANGLE
187    patchType = 6;
188#endif
189
190    int pattern = popcount(OsdGetPatchTransitionMask(patchParam));
191
192    return patchColors[6*patchType + pattern];
193}
194
195float4
196getAdaptiveDepthColor(int3 patchParam)
197{
198    //  Represent depth with repeating cycle of four colors:
199    const float4 depthColors[4] = {
200        float4(0.0f,  0.5f,  0.5f,  1.0f),
201        float4(1.0f,  1.0f,  1.0f,  1.0f),
202        float4(0.0f,  1.0f,  1.0f,  1.0f),
203        float4(0.5f,  1.0f,  0.5f,  1.0f)
204    };
205    return depthColors[OsdGetPatchRefinementLevel(patchParam) & 3];
206}
207
208#if OSD_IS_ADAPTIVE
209#if USE_STAGE_IN
210#if OSD_PATCH_REGULAR || OSD_PATCH_BOX_SPLINE_TRIANGLE
211struct ControlPoint
212{
213    float3 P [[attribute(0)]];
214#if OSD_PATCH_ENABLE_SINGLE_CREASE
215    float3 P1 [[attribute(1)]];
216    float3 P2 [[attribute(2)]];
217#if !USE_PTVS_SHARPNESS
218    float2 vSegments [[attribute(3)]];
219#endif
220#endif
221};
222#elif OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY
223struct ControlPoint
224{
225    float3 P [[attribute(0)]];
226    float3 Ep [[attribute(1)]];
227    float3 Em [[attribute(2)]];
228    float3 Fp [[attribute(3)]];
229    float3 Fm [[attribute(4)]];
230};
231#elif OSD_PATCH_GREGORY_BASIS || OSD_PATCH_GREGORY_TRIANGLE
232struct ControlPoint
233{
234    float3 position [[attribute(0)]];
235};
236#endif
237
238struct PatchInput
239{
240    patch_control_point<ControlPoint> cv;
241#if !USE_PTVS_FACTORS
242    float4 tessOuterLo [[attribute(5)]];
243    float4 tessOuterHi [[attribute(6)]];
244#endif
245    int3 patchParam [[attribute(10)]];
246};
247#endif
248
249#if OSD_PATCH_REGULAR || OSD_PATCH_GREGORY_BASIS || OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY
250typedef MTLQuadTessellationFactorsHalf PatchTessFactors;
251#elif OSD_PATCH_BOX_SPLINE_TRIANGLE || OSD_PATCH_GREGORY_TRIANGLE
252typedef MTLTriangleTessellationFactorsHalf PatchTessFactors;
253#endif
254
255
256//----------------------------------------------------------
257// OSD Kernel
258//----------------------------------------------------------
259//The user of OSD should define this kernel which serves as the landing point for all patch computation
260//This compute function should just be copied and pasted, modifying the section under "User Vertex Transform"
261//Or the entire function may be moddified as needed (for example to add a patch index buffer)
262kernel void compute_main(
263    const constant PerFrameConstants& frameConsts [[buffer(FRAME_CONST_BUFFER_INDEX)]],
264    unsigned thread_position_in_grid [[thread_position_in_grid]],
265    unsigned thread_position_in_threadgroup [[thread_position_in_threadgroup]],
266    unsigned threadgroup_position_in_grid [[threadgroup_position_in_grid]],
267    OsdPatchParamBufferSet osdBuffers, //This struct contains all of the buffers needed by OSD
268    device PatchTessFactors* patchTessellationFactors [[buffer(PATCH_TESSFACTORS_INDEX)]]
269#if OSD_USE_PATCH_INDEX_BUFFER
270    ,device unsigned* patchIndex [[buffer(OSD_PATCH_INDEX_BUFFER_INDEX)]]
271    ,device MTLDrawPatchIndirectArguments* drawIndirectCommands [[buffer(OSD_DRAWINDIRECT_BUFFER_INDEX)]]
272#endif
273)
274{
275
276    //----------------------------------------------------------
277    // OSD Kernel Setup
278    //----------------------------------------------------------
279
280    #define PATCHES_PER_THREADGROUP (THREADS_PER_THREADGROUP / THREADS_PER_PATCH)
281    int const primitiveID = thread_position_in_grid / THREADS_PER_PATCH;
282    int const primitiveIDInTG = thread_position_in_threadgroup / THREADS_PER_PATCH;
283    int const vertexIndex = threadgroup_position_in_grid * PATCHES_PER_THREADGROUP * CONTROL_POINTS_PER_PATCH +
284                            thread_position_in_threadgroup * CONTROL_POINTS_PER_THREAD;
285    int const vertexIndexInTG = thread_position_in_threadgroup * CONTROL_POINTS_PER_THREAD;
286    int const invocationID = (thread_position_in_threadgroup * VERTEX_CONTROL_POINTS_PER_THREAD) % (THREADS_PER_PATCH*VERTEX_CONTROL_POINTS_PER_THREAD);
287
288    //Contains the shared patchParam value used by all threads that act upon a single patch
289    //the .z (sharpness) field is set to -1 (NAN) if that patch should be culled to signal other threads to return.
290    threadgroup int3 patchParam[PATCHES_PER_THREADGROUP];
291    threadgroup PatchVertexType patchVertices[PATCHES_PER_THREADGROUP * CONTROL_POINTS_PER_PATCH];
292
293    //----------------------------------------------------------
294    // OSD Vertex Transform
295    //----------------------------------------------------------
296    {
297        patchParam[primitiveIDInTG] = OsdGetPatchParam(primitiveID, osdBuffers.patchParamBuffer);
298
299        for (unsigned threadOffset = 0; threadOffset < CONTROL_POINTS_PER_THREAD; ++threadOffset)
300        {
301            if (vertexIndexInTG + threadOffset < PATCHES_PER_THREADGROUP * CONTROL_POINTS_PER_PATCH)
302            {
303                const auto vertexId = osdBuffers.indexBuffer[(vertexIndex + threadOffset)];
304                const auto v = osdBuffers.vertexBuffer[vertexId];
305
306                threadgroup auto& patchVertex = patchVertices[vertexIndexInTG + threadOffset];
307
308                //----------------------------------------------------------
309                // User Vertex Transform
310                //----------------------------------------------------------
311
312                OsdComputePerVertex(float4(v.position,1), patchVertex, vertexId, frameConsts.ModelViewProjectionMatrix, osdBuffers);
313            }
314        }
315    }
316
317#if NEEDS_BARRIER
318    threadgroup_barrier(mem_flags::mem_threadgroup);
319#endif
320
321    //----------------------------------------------------------
322    // OSD Patch Cull
323    //----------------------------------------------------------
324    {
325        auto patch = patchVertices + primitiveIDInTG * CONTROL_POINTS_PER_PATCH;
326
327        if (!OsdCullPerPatchVertex(patch, frameConsts.ModelViewMatrix))
328        {
329#if !OSD_USE_PATCH_INDEX_BUFFER
330#if OSD_PATCH_REGULAR || OSD_PATCH_GREGORY_BASIS || OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY
331            patchTessellationFactors[primitiveID].edgeTessellationFactor[0] = 0.0h;
332            patchTessellationFactors[primitiveID].edgeTessellationFactor[1] = 0.0h;
333            patchTessellationFactors[primitiveID].edgeTessellationFactor[2] = 0.0h;
334            patchTessellationFactors[primitiveID].edgeTessellationFactor[3] = 0.0h;
335            patchTessellationFactors[primitiveID].insideTessellationFactor[0] = 0.0h;
336            patchTessellationFactors[primitiveID].insideTessellationFactor[1] = 0.0h;
337#elif OSD_PATCH_BOX_SPLINE_TRIANGLE || OSD_PATCH_GREGORY_TRIANGLE
338            patchTessellationFactors[primitiveID].edgeTessellationFactor[0] = 0.0h;
339            patchTessellationFactors[primitiveID].edgeTessellationFactor[1] = 0.0h;
340            patchTessellationFactors[primitiveID].edgeTessellationFactor[2] = 0.0h;
341            patchTessellationFactors[primitiveID].insideTessellationFactor = 0.0h;
342#endif
343#endif
344
345            patchParam[primitiveIDInTG].z = -1;
346#if !NEEDS_BARRIER
347            return;
348#endif
349        }
350    }
351
352#if NEEDS_BARRIER
353    threadgroup_barrier(mem_flags::mem_threadgroup);
354#endif
355
356    //----------------------------------------------------------
357    // OSD Patch Compute
358    //----------------------------------------------------------
359    if (patchParam[primitiveIDInTG].z != -1)
360    {
361        for (unsigned threadOffset = 0; threadOffset < VERTEX_CONTROL_POINTS_PER_THREAD; ++threadOffset)
362        {
363            if (invocationID + threadOffset < VERTEX_CONTROL_POINTS_PER_PATCH)
364            {
365                OsdComputePerPatchVertex(
366                    patchParam[primitiveIDInTG],
367                    invocationID + threadOffset,
368                    primitiveID,
369                    invocationID + threadOffset + primitiveID * VERTEX_CONTROL_POINTS_PER_PATCH,
370                    patchVertices + primitiveIDInTG * CONTROL_POINTS_PER_PATCH,
371                    osdBuffers
372                    );
373            }
374        }
375    }
376
377#if NEEDS_BARRIER
378    threadgroup_barrier(mem_flags::mem_device_and_threadgroup);
379#endif
380
381    //----------------------------------------------------------
382    // OSD Tessellation Factors
383    //----------------------------------------------------------
384    if (invocationID == 0)
385    {
386
387#if OSD_USE_PATCH_INDEX_BUFFER
388        const auto patchId = atomic_fetch_add_explicit((device atomic_uint*)&drawIndirectCommands->patchCount, 1, memory_order_relaxed);
389        patchIndex[patchId] = primitiveID;
390#else
391        const auto patchId = primitiveID;
392#endif
393
394        OsdComputePerPatchFactors(
395            patchParam[primitiveIDInTG],
396            frameConsts.TessLevel,
397            primitiveID,
398            frameConsts.ProjectionMatrix,
399            frameConsts.ModelViewMatrix,
400            osdBuffers,
401            patchVertices + primitiveIDInTG * CONTROL_POINTS_PER_PATCH,
402            patchTessellationFactors[patchId]
403            );
404    }
405}
406
407#if SHADING_TYPE == SHADING_TYPE_FACE_VARYING_COLOR
408float3
409interpolateFaceVaryingColor(
410        int                       patch_id,
411        float2                    uv,
412        const device float*       fvarData,
413        const device int*         fvarIndices,
414        const device packed_int3* fvarPatchParams,
415        const constant int*       fvarPatchArrays)
416{
417    OsdPatchArray fvarPatchArray = OsdPatchArrayInit(
418        fvarPatchArrays[0],
419        fvarPatchArrays[1],
420        fvarPatchArrays[2],
421        fvarPatchArrays[3],
422        fvarPatchArrays[4],
423        fvarPatchArrays[5]);
424    OsdPatchParam fvarParam = OsdPatchParamInit(
425        fvarPatchParams[patch_id][0],
426        fvarPatchParams[patch_id][1],
427        fvarPatchParams[patch_id][2]);
428
429    int fvarPatchType = OsdPatchParamIsRegular(fvarParam)
430                        ? fvarPatchArray.regDesc
431                        : fvarPatchArray.desc;
432
433    float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20];
434    int numPoints = OsdEvaluatePatchBasisNormalized(fvarPatchType, fvarParam,
435                uv.x, uv.y, wP, wDu, wDv, wDuu, wDuv, wDvv);
436
437    int primOffset = patch_id * fvarPatchArray.stride;
438
439    float2 interpUV = float2(0);
440    for (int i = 0; i < numPoints; ++i) {
441        int index = fvarIndices[primOffset + i] * 2 /* OSD_FVAR_WIDTH */ + 0 /* fvarOffset */;
442        float2 cv = float2(fvarData[index + 0], fvarData[index + 1]);
443        interpUV += wP[i] * cv;
444    }
445
446    return float3(interpUV, 0);
447}
448#endif
449
450#if OSD_PATCH_REGULAR || OSD_PATCH_GREGORY_BASIS || OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY
451[[patch(quad, VERTEX_CONTROL_POINTS_PER_PATCH)]]
452#elif OSD_PATCH_BOX_SPLINE_TRIANGLE || OSD_PATCH_GREGORY_TRIANGLE
453[[patch(triangle, VERTEX_CONTROL_POINTS_PER_PATCH)]]
454#endif
455vertex OutputVertex vertex_main(
456    const constant PerFrameConstants& frameConsts [[buffer(FRAME_CONST_BUFFER_INDEX)]],
457#if USE_STAGE_IN
458    const PatchInput patchInput [[stage_in]],
459#else
460    const OsdVertexBufferSet patchInput,
461#endif
462    const device float*       osdFaceVaryingData        [[buffer(OSD_FVAR_DATA_BUFFER_INDEX)]],
463    const device int*         osdFaceVaryingIndices     [[buffer(OSD_FVAR_INDICES_BUFFER_INDEX)]],
464    const device packed_int3* osdFaceVaryingPatchParams [[buffer(OSD_FVAR_PATCHPARAM_BUFFER_INDEX)]],
465    const constant int*       osdFaceVaryingPatchArrays [[buffer(OSD_FVAR_PATCH_ARRAYS_BUFFER_INDEX)]],
466#if OSD_PATCH_REGULAR || OSD_PATCH_GREGORY_BASIS || OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY
467    float2 position_in_patch [[position_in_patch]],
468#elif OSD_PATCH_BOX_SPLINE_TRIANGLE || OSD_PATCH_GREGORY_TRIANGLE
469    float3 position_in_patch [[position_in_patch]],
470#endif
471    uint patch_id [[patch_id]]
472    )
473{
474    OutputVertex out;
475
476#if USE_STAGE_IN
477    int3 patchParam = patchInput.patchParam;
478#else
479    int3 patchParam = patchInput.patchParamBuffer[patch_id];
480#endif
481
482    int refinementLevel = OsdGetPatchRefinementLevel(patchParam);
483    float tessLevel = min(frameConsts.TessLevel, (float)OSD_MAX_TESS_LEVEL) /
484        exp2((float)refinementLevel - 1);
485
486    auto patchVertex = OsdComputePatch(tessLevel, position_in_patch, patch_id, patchInput);
487
488    out.position = (frameConsts.ModelViewMatrix * float4(patchVertex.position, 1.0f)).xyz;
489    out.positionOut = frameConsts.ModelViewProjectionMatrix * float4(patchVertex.position, 1.0f);
490
491    out.normal = mul(frameConsts.ModelViewMatrix, patchVertex.normal);
492#if SHADING_TYPE == SHADING_TYPE_PATCH_TYPE
493#if OSD_PATCH_ENABLE_SINGLE_CREASE
494    out.patchColor = getAdaptivePatchColor(patchParam, patchVertex.vSegments).xyz;
495#else
496    out.patchColor = getAdaptivePatchColor(patchParam).xyz;
497#endif
498#elif SHADING_TYPE == SHADING_TYPE_PATCH_DEPTH
499    out.patchColor = getAdaptiveDepthColor(patchParam).xyz;
500#elif SHADING_TYPE == SHADING_TYPE_NORMAL
501#elif SHADING_TYPE == SHADING_TYPE_PATCH_COORD
502    out.patchColor = patchVertex.patchCoord.xyz;
503#elif SHADING_TYPE == SHADING_TYPE_FACE_VARYING_COLOR
504    out.patchColor = interpolateFaceVaryingColor(
505        patch_id,
506        patchVertex.tessCoord.xy,
507        osdFaceVaryingData,
508        osdFaceVaryingIndices,
509        osdFaceVaryingPatchParams,
510        osdFaceVaryingPatchArrays);
511#endif
512
513    return out;
514}
515#endif
516
517#if OSD_PATCH_REGULAR
518const constant unsigned BSplineControlLineIndices[] = {
519    0, 1, //Outer lines
520    1, 2,
521    2, 3,
522    3, 7,
523    7, 11,
524    11, 15,
525    15, 14,
526    14, 13,
527    13, 12,
528    12, 8,
529    8, 4,
530    4, 0,
531
532    //Inner lines
533    5, 6,
534    6, 10,
535    10, 9,
536    9, 5,
537
538    //TL edge lines
539    1, 5,
540    4, 5,
541
542    //TR edge lines
543    2, 6,
544    6, 7,
545
546    //BL edge lines
547    8, 9,
548    9, 13,
549
550    //BR edge lines
551    10, 14,
552    10, 11
553};
554
555vertex SolidColorVertex vertex_lines(
556    const device unsigned* indicesBuffer [[buffer(INDICES_BUFFER_INDEX)]],
557    const device OsdPerPatchVertexBezier* osdPerPatchVertexBezier [[buffer(OSD_PERPATCHVERTEX_BUFFER_INDEX)]],
558    const constant PerFrameConstants& frameConsts [[buffer(FRAME_CONST_BUFFER_INDEX)]],
559    uint vertex_id [[vertex_id]]
560    )
561{
562    const auto idx_size = sizeof(BSplineControlLineIndices) / sizeof(BSplineControlLineIndices[0]);
563    const auto idx = vertex_id % idx_size;
564    const auto patch_id = vertex_id / idx_size;
565
566    const auto in = osdPerPatchVertexBezier[patch_id * VERTEX_CONTROL_POINTS_PER_PATCH + BSplineControlLineIndices[idx]];
567
568    SolidColorVertex out;
569
570    out.positionOut = frameConsts.ModelViewProjectionMatrix * float4(in.P, 1.0);
571    out.positionOut.z -= 0.001;
572
573    if(idx > 22) {
574        out.setColor(half4(0,1,0,1));
575    }
576    else
577    {
578        out.setColor(half4(1,0,0,1));
579    }
580
581    return out;
582}
583#endif
584
585#if OSD_PATCH_GREGORY_BASIS || OSD_PATCH_GREGORY || OSD_PATCH_GREGORY_BOUNDARY
586const constant uint GregoryBasisControlLineIndices[] = {
587    //Outer Edge
588    0, 2,
589    2, 16,
590    16, 15,
591    15, 17,
592    17, 11,
593    11, 10,
594    10, 12,
595    12, 6,
596    6, 5,
597    5, 7,
598    7, 1,
599    1, 0,
600
601    //Outside-Inside Edges
602    1, 3,
603    2, 4,
604    16, 18,
605    17, 19,
606    11, 13,
607    12, 14,
608    6, 8,
609    7, 9,
610
611    //Inner Edge
612    3, 4,
613    4, 18,
614    18, 19,
615    19, 13,
616    13, 14,
617    14, 8,
618    8, 9,
619    9, 3,
620};
621
622
623vertex SolidColorVertex vertex_lines(
624#ifdef OSD_PATCH_GREGORY_BASIS
625    const device unsigned* indicesBuffer [[buffer(INDICES_BUFFER_INDEX)]],
626    const device PackedInputVertex* vertexBuffer [[buffer(VERTEX_BUFFER_INDEX)]],
627#else
628    const device PackedInputVertex* vertexBuffer [[buffer(OSD_PERPATCHVERTEX_BUFFER_INDEX)]],
629#endif
630    const constant PerFrameConstants& frameConsts [[buffer(FRAME_CONST_BUFFER_INDEX)]],
631    uint vertex_id [[vertex_id]]
632    )
633{
634    const auto idx_size = sizeof(GregoryBasisControlLineIndices) / sizeof(GregoryBasisControlLineIndices[0]);
635    const auto idx = vertex_id % idx_size;
636    const auto patch_id = vertex_id / idx_size;
637
638#ifdef OSD_PATCH_GREGORY_BASIS
639    const auto in = vertexBuffer[indicesBuffer[patch_id * VERTEX_CONTROL_POINTS_PER_PATCH + GregoryBasisControlLineIndices[idx]]];
640#else
641    const auto in = vertexBuffer[patch_id * 20 + GregoryBasisControlLineIndices[idx]];
642#endif
643    SolidColorVertex out;
644
645    out.positionOut = frameConsts.ModelViewProjectionMatrix * float4(in.position, 1.0);
646    out.positionOut.z -= 0.001;
647
648    if(idx > 22) {
649        out.setColor(half4(0,1,0,1));
650    }
651    else
652    {
653        out.setColor(half4(1,0,0,1));
654    }
655
656    return out;
657}
658#endif
659
660#if OSD_PATCH_QUADS || OSD_PATCH_TRIANGLES
661
662#if OSD_PATCH_QUADS
663const constant uint triangleIdx[6] = {
664    0, 2, 1, 3, 2, 0
665};
666#endif
667
668vertex OutputVertex vertex_main(
669    device unsigned* indicesBuffer [[buffer(INDICES_BUFFER_INDEX)]],
670    device PackedInputVertex* vertexBuffer [[buffer(VERTEX_BUFFER_INDEX)]],
671    const constant PerFrameConstants& frameConsts [[buffer(FRAME_CONST_BUFFER_INDEX)]],
672    const device float2* osdFaceVaryingData[[buffer(OSD_FVAR_DATA_BUFFER_INDEX)]],
673    const device int* osdFaceVaryingIndices[[buffer(OSD_FVAR_INDICES_BUFFER_INDEX)]],
674    uint vertex_id [[vertex_id]]
675    )
676{
677#if OSD_PATCH_QUADS
678    const auto quadId = vertex_id / 6;
679#else
680    const auto primID = vertex_id / 3;
681#endif
682
683#if OSD_PATCH_QUADS
684    float3 p0 = vertexBuffer[indicesBuffer[quadId * 4 + 0]].position;
685    float3 p1 = vertexBuffer[indicesBuffer[quadId * 4 + 1]].position;
686    float3 p2 = vertexBuffer[indicesBuffer[quadId * 4 + 2]].position;
687    float3 position = vertexBuffer[indicesBuffer[quadId * 4 + triangleIdx[vertex_id % 6]]].position;
688    float2 uv = osdFaceVaryingData[osdFaceVaryingIndices[quadId * 4 + triangleIdx[vertex_id % 6]]].xy;
689#else
690    float3 p0 = vertexBuffer[indicesBuffer[primID * 3 + 0]].position;
691    float3 p1 = vertexBuffer[indicesBuffer[primID * 3 + 1]].position;
692    float3 p2 = vertexBuffer[indicesBuffer[primID * 3 + 2]].position;
693    float3 position = vertexBuffer[indicesBuffer[vertex_id]].position;
694    float2 uv = osdFaceVaryingData[osdFaceVaryingIndices[vertex_id]].xy;
695#endif
696
697    float3 normal = normalize(cross(p2 - p1, p0 - p1));
698
699
700    OutputVertex out;
701    out.position = (frameConsts.ModelViewMatrix * float4(position, 1.0)).xyz;
702    out.positionOut = frameConsts.ModelViewProjectionMatrix * float4(position, 1.0);
703    out.normal = (frameConsts.ModelViewMatrix * float4(normal, 0.0)).xyz;
704
705#if SHADING_TYPE == SHADING_TYPE_PATCH_TYPE || SHADING_TYPE == SHADING_TYPE_PATCH_DEPTH || SHADING_TYPE == SHADING_TYPE_PATCH_COORD
706    out.patchColor = out.normal;
707#elif SHADING_TYPE == SHADING_TYPE_FACE_VARYING_COLOR
708    out.patchColor.rg = uv;
709#endif
710
711    return out;
712}
713
714vertex SolidColorVertex vertex_lines(
715    device unsigned* indicesBuffer [[buffer(INDICES_BUFFER_INDEX)]],
716    device PackedInputVertex* vertexBuffer [[buffer(VERTEX_BUFFER_INDEX)]],
717    const constant PerFrameConstants& frameConsts [[buffer(FRAME_CONST_BUFFER_INDEX)]],
718    uint vertex_id [[vertex_id]]
719    )
720{
721#if OSD_PATCH_QUADS
722    const auto quadId = vertex_id / 6;
723#else
724    const auto primID = vertex_id / 3;
725#endif
726
727#if OSD_PATCH_QUADS
728    float3 position = vertexBuffer[indicesBuffer[quadId * 4 + triangleIdx[vertex_id % 6]]].position;
729#else
730    float3 position = vertexBuffer[indicesBuffer[vertex_id]].position;
731#endif
732
733    SolidColorVertex out;
734    out.positionOut = frameConsts.ModelViewProjectionMatrix * float4(position, 1.0);
735
736    return out;
737}
738#endif
739
740fragment half4 fragment_solidcolor(SolidColorVertex in [[stage_in]])
741{
742    return in.getColor();
743}
744
745
746fragment float4 fragment_main(OutputVertex in [[stage_in]],
747                              const constant Light* lightData [[buffer(0)]],
748                              const constant PerFrameConstants& frameConsts [[buffer(1)]],
749                              const constant float4& shade [[buffer(2)]])
750{
751    float4 color;
752
753#if SHADING_TYPE == SHADING_TYPE_MATERIAL
754    const float3 diffuseColor = float3(0.4f, 0.4f, 0.8f);
755#elif SHADING_TYPE == SHADING_TYPE_PATCH_TYPE || SHADING_TYPE == SHADING_TYPE_PATCH_DEPTH
756    const float3 diffuseColor = in.patchColor;
757#endif
758#if SHADING_TYPE == SHADING_TYPE_NORMAL
759    color.xyz = normalize(in.normal) * 0.5 + 0.5;
760#elif SHADING_TYPE == SHADING_TYPE_PATCH_COORD || SHADING_TYPE == SHADING_TYPE_FACE_VARYING_COLOR
761    color.xyz = lighting(1.0, lightData, in.position, normalize(in.normal));
762    int checker = int(floor(20*in.patchColor.r)+floor(20*in.patchColor.g))&1;
763    color.xyz *= float3(in.patchColor.rg*checker, 1-checker);
764    color.xyz = pow(color.xyz, 1/2.2);
765#else
766    color.xyz = lighting(diffuseColor, lightData, in.position, normalize(in.normal));
767#endif
768    color.w = 1;
769    return max(color,shade);
770}
771