MetalConverter320/ConverterIIGS320.playground/Resources/Shaders.metal

116 lines
3.5 KiB
Metal

//
// Shaders.metal
//
// Created by Mark Lim Pak Mun on 06/12/2018.
// Copyright © Incremental Innovation 2018 . All rights reserved.
//
// File for Metal kernel and shader functions
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
// Vertex shader outputs and per-fragment inputs.
typedef struct
{
float2 position;
float2 texCoord;
} Vertex;
typedef struct
{
float4 position [[position]]; // in clip space
float2 texCoord;
} RasterizerData;
vertex RasterizerData
vertexShader( uint vertexID [[ vertex_id ]],
const device Vertex *vertices [[ buffer(0)]])
{
RasterizerData out;
float2 position = vertices[vertexID].position;
// convert incoming position into clip space
out.position.xy = position;
out.position.z = 0.0;
out.position.w = 1.0;
// pass thru to the fragment shader
out.texCoord = vertices[vertexID].texCoord;
return out;
}
// Fragment function
fragment half4
fragmentShader(RasterizerData in [[stage_in]],
texture2d<half> colorTexture [[ texture(0) ]])
{
constexpr sampler textureSampler (mag_filter::linear,
min_filter::linear);
// Sample the texture and return the color to colorSample
const half4 colorSample = colorTexture.sample(textureSampler,
in.texCoord);
// We return the color of the texture
return colorSample;
}
/// ============ kernel function ============
#define bytesPerScanLine 160
#define sizeOfColorTable 16 // in terms of 16-bit words
/*
Converts a IIGS "pixel" to an ordinary rgba pixel.
*/
kernel void convert320(const device uchar *iigsBitmap [[buffer(0)]],
const device uchar *scbs [[buffer(1)]],
const device ushort *colorTables [[buffer(2)]],
texture2d<half, access::write> output [[texture(0)]],
uint2 gid [[thread_position_in_grid]])
{
uint width = output.get_width();
uint height = output.get_height();
if ((gid.x >= width) || (gid.y >= height))
{
// Return early if the pixel is out of bounds
return;
}
uint col = gid.x; // 0 - 319 for standard Apple IIGS 320x200 graphics
uint row = gid.y; // 0 - 199
uint whichColorTable = scbs[row] & 0x0f; // 0 - 15
uint bitmapIndex = row * bytesPerScanLine + col/2;
uchar pixels = iigsBitmap[bitmapIndex]; // 2 IIGS 4-bit "pixels"/byte
uint whichColorEntry; // 0 - 15
if (col % 2) {
// odd column # - pixel #1 (bits 0-3)
whichColorEntry = pixels & 0x0f;
}
else {
// even column # - pixel #0 (bits 4-7)
whichColorEntry = (pixels >> 4) & 0x0f;
}
uint colorTableIndex = sizeOfColorTable*whichColorTable + whichColorEntry;
ushort color = colorTables[colorTableIndex];
ushort red = (color & 0x0f00) >> 8; // 0 - 15
ushort green = (color & 0x00f0) >> 4;
ushort blue = (color & 0x000f);
// Scale the values [0,15] to [0,255]
red *= 17; // 0, 17, 34, ... , 238, 255
green *= 17;
blue *= 17;
// Compute the rbga8888 colour of the pixel ...
half4 color4 = half4(red, green, blue, 255);
// ... and scale its values to [0, 1.0]
color4 *= 1/255.0;
// Write the pixel to the texture.
output.write(color4, gid);
}