Extraer shaders a archivos .metal separados para mejor organización
- Crear directorio data/shaders/ para organizar todos los shaders MSL - Extraer shaders embebidos a archivos individuales: * background.metal - Shader de fondo degradado * triangle.metal - Shader de triángulo multicolor * sprite.metal - Shader de sprites con vertex color tinting * crt.metal - Shader CRT post-processing completo - Modificar main.cpp para cargar shaders desde archivos: * Usar stringWithContentsOfFile para leer código fuente * Compilar dinámicamente con newLibraryWithSource * Manejo robusto de errores de lectura y compilación - Eliminar 351 líneas de strings embebidos de main.cpp - Mantener funcionalidad completa: CRT + sprites + fondo + triángulo Beneficios: - Shaders editables sin recompilar ejecutable - Mejor organización y mantenimiento del código - Syntax highlighting completo en editores - Reutilización de shaders en otros proyectos - Desarrollo más ágil de efectos visuales 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
40
data/shaders/background.metal
Normal file
40
data/shaders/background.metal
Normal file
@@ -0,0 +1,40 @@
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
|
||||
struct VertexOut {
|
||||
float4 position [[position]];
|
||||
float4 color;
|
||||
};
|
||||
|
||||
vertex VertexOut background_vertex_main(uint vertexID [[vertex_id]]) {
|
||||
VertexOut out;
|
||||
|
||||
// Quad de pantalla completa en coordenadas NDC
|
||||
float2 positions[6] = {
|
||||
float2(-1.0, -1.0), // Bottom left
|
||||
float2( 1.0, -1.0), // Bottom right
|
||||
float2(-1.0, 1.0), // Top left
|
||||
float2( 1.0, -1.0), // Bottom right
|
||||
float2( 1.0, 1.0), // Top right
|
||||
float2(-1.0, 1.0) // Top left
|
||||
};
|
||||
|
||||
// Gradiente de púrpura oscuro arriba a azul cyan abajo
|
||||
float4 colors[6] = {
|
||||
float4(0.2, 0.6, 0.8, 1.0), // Bottom left - cyan claro
|
||||
float4(0.2, 0.6, 0.8, 1.0), // Bottom right - cyan claro
|
||||
float4(0.3, 0.1, 0.5, 1.0), // Top left - púrpura oscuro
|
||||
float4(0.2, 0.6, 0.8, 1.0), // Bottom right - cyan claro
|
||||
float4(0.3, 0.1, 0.5, 1.0), // Top right - púrpura oscuro
|
||||
float4(0.3, 0.1, 0.5, 1.0) // Top left - púrpura oscuro
|
||||
};
|
||||
|
||||
out.position = float4(positions[vertexID], 0.0, 1.0);
|
||||
out.color = colors[vertexID];
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
fragment float4 background_fragment_main(VertexOut in [[stage_in]]) {
|
||||
return in.color;
|
||||
}
|
||||
158
data/shaders/crt.metal
Normal file
158
data/shaders/crt.metal
Normal file
@@ -0,0 +1,158 @@
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
|
||||
// Parámetros del CRT shader
|
||||
#define CURVATURE_X 0.05
|
||||
#define CURVATURE_Y 0.1
|
||||
#define MASK_BRIGHTNESS 0.80
|
||||
#define SCANLINE_WEIGHT 6.0
|
||||
#define SCANLINE_GAP_BRIGHTNESS 0.12
|
||||
#define BLOOM_FACTOR 3.5
|
||||
#define INPUT_GAMMA 2.4
|
||||
#define OUTPUT_GAMMA 2.2
|
||||
|
||||
// Features habilitadas
|
||||
#define SCANLINES
|
||||
#define MULTISAMPLE
|
||||
#define GAMMA
|
||||
// #define FAKE_GAMMA
|
||||
// #define CURVATURE
|
||||
// #define SHARPER
|
||||
#define MASK_TYPE 2
|
||||
|
||||
struct CRTVertexOut {
|
||||
float4 position [[position]];
|
||||
float2 texCoord;
|
||||
};
|
||||
|
||||
vertex CRTVertexOut crt_vertex_main(uint vertexID [[vertex_id]]) {
|
||||
CRTVertexOut out;
|
||||
|
||||
// Fullscreen quad con coordenadas de textura
|
||||
float2 positions[6] = {
|
||||
float2(-1.0, -1.0), // Bottom left
|
||||
float2( 1.0, -1.0), // Bottom right
|
||||
float2(-1.0, 1.0), // Top left
|
||||
float2( 1.0, -1.0), // Bottom right
|
||||
float2( 1.0, 1.0), // Top right
|
||||
float2(-1.0, 1.0) // Top left
|
||||
};
|
||||
|
||||
float2 texCoords[6] = {
|
||||
float2(0.0, 1.0), // Bottom left
|
||||
float2(1.0, 1.0), // Bottom right
|
||||
float2(0.0, 0.0), // Top left
|
||||
float2(1.0, 1.0), // Bottom right
|
||||
float2(1.0, 0.0), // Top right
|
||||
float2(0.0, 0.0) // Top left
|
||||
};
|
||||
|
||||
out.position = float4(positions[vertexID], 0.0, 1.0);
|
||||
out.texCoord = texCoords[vertexID];
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
float CalcScanLineWeight(float dist) {
|
||||
return max(1.0 - dist * dist * SCANLINE_WEIGHT, SCANLINE_GAP_BRIGHTNESS);
|
||||
}
|
||||
|
||||
float CalcScanLine(float dy, float filterWidth) {
|
||||
float scanLineWeight = CalcScanLineWeight(dy);
|
||||
#ifdef MULTISAMPLE
|
||||
scanLineWeight += CalcScanLineWeight(dy - filterWidth);
|
||||
scanLineWeight += CalcScanLineWeight(dy + filterWidth);
|
||||
scanLineWeight *= 0.3333333;
|
||||
#endif
|
||||
return scanLineWeight;
|
||||
}
|
||||
|
||||
fragment float4 crt_fragment_main(CRTVertexOut in [[stage_in]],
|
||||
texture2d<float> sceneTexture [[texture(0)]],
|
||||
sampler sceneSampler [[sampler(0)]]) {
|
||||
float2 TextureSize = float2(320.0, 240.0); // Resolución virtual del CRT
|
||||
float filterWidth = (768.0 / 240.0) / 3.0;
|
||||
|
||||
float2 texcoord = in.texCoord;
|
||||
|
||||
// Convertir a píxeles
|
||||
float2 texcoordInPixels = texcoord * TextureSize;
|
||||
|
||||
#ifdef SHARPER
|
||||
float2 tempCoord = floor(texcoordInPixels) + 0.5;
|
||||
float2 coord = tempCoord / TextureSize;
|
||||
float2 deltas = texcoordInPixels - tempCoord;
|
||||
float scanLineWeight = CalcScanLine(deltas.y, filterWidth);
|
||||
float2 signs = sign(deltas);
|
||||
deltas.x *= 2.0;
|
||||
deltas = deltas * deltas;
|
||||
deltas.y = deltas.y * deltas.y;
|
||||
deltas.x *= 0.5;
|
||||
deltas.y *= 8.0;
|
||||
deltas /= TextureSize;
|
||||
deltas *= signs;
|
||||
float2 tc = coord + deltas;
|
||||
#else
|
||||
float tempY = floor(texcoordInPixels.y) + 0.5;
|
||||
float yCoord = tempY / TextureSize.y;
|
||||
float dy = texcoordInPixels.y - tempY;
|
||||
float scanLineWeight = CalcScanLine(dy, filterWidth);
|
||||
float signY = sign(dy);
|
||||
dy = dy * dy;
|
||||
dy = dy * dy;
|
||||
dy *= 8.0;
|
||||
dy /= TextureSize.y;
|
||||
dy *= signY;
|
||||
float2 tc = float2(texcoord.x, yCoord + dy);
|
||||
#endif
|
||||
|
||||
// Samplear la textura de escena
|
||||
float3 colour = sceneTexture.sample(sceneSampler, tc).rgb;
|
||||
|
||||
#ifdef SCANLINES
|
||||
#ifdef GAMMA
|
||||
#ifdef FAKE_GAMMA
|
||||
colour = colour * colour;
|
||||
#else
|
||||
colour = pow(colour, float3(INPUT_GAMMA));
|
||||
#endif
|
||||
#endif
|
||||
scanLineWeight *= BLOOM_FACTOR;
|
||||
colour *= scanLineWeight;
|
||||
|
||||
#ifdef GAMMA
|
||||
#ifdef FAKE_GAMMA
|
||||
colour = sqrt(colour);
|
||||
#else
|
||||
colour = pow(colour, float3(1.0 / OUTPUT_GAMMA));
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Shadow mask
|
||||
#if MASK_TYPE == 0
|
||||
return float4(colour, 1.0);
|
||||
#else
|
||||
#if MASK_TYPE == 1
|
||||
float whichMask = fract((in.position.x * 1.0001) * 0.5);
|
||||
float3 mask;
|
||||
if (whichMask < 0.5) {
|
||||
mask = float3(MASK_BRIGHTNESS, 1.0, MASK_BRIGHTNESS);
|
||||
} else {
|
||||
mask = float3(1.0, MASK_BRIGHTNESS, 1.0);
|
||||
}
|
||||
#elif MASK_TYPE == 2
|
||||
float whichMask = fract((in.position.x * 1.0001) * 0.3333333);
|
||||
float3 mask = float3(MASK_BRIGHTNESS, MASK_BRIGHTNESS, MASK_BRIGHTNESS);
|
||||
if (whichMask < 0.3333333) {
|
||||
mask.x = 1.0;
|
||||
} else if (whichMask < 0.6666666) {
|
||||
mask.y = 1.0;
|
||||
} else {
|
||||
mask.z = 1.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return float4(colour * mask, 1.0);
|
||||
#endif
|
||||
}
|
||||
29
data/shaders/sprite.metal
Normal file
29
data/shaders/sprite.metal
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
|
||||
struct SpriteVertexIn {
|
||||
float2 position [[attribute(0)]];
|
||||
float4 color [[attribute(1)]];
|
||||
float2 texCoord [[attribute(2)]];
|
||||
};
|
||||
|
||||
struct SpriteVertexOut {
|
||||
float4 position [[position]];
|
||||
float4 color;
|
||||
float2 texCoord;
|
||||
};
|
||||
|
||||
vertex SpriteVertexOut sprite_vertex_main(SpriteVertexIn in [[stage_in]]) {
|
||||
SpriteVertexOut out;
|
||||
out.position = float4(in.position, 0.0, 1.0);
|
||||
out.color = in.color;
|
||||
out.texCoord = in.texCoord;
|
||||
return out;
|
||||
}
|
||||
|
||||
fragment float4 sprite_fragment_main(SpriteVertexOut in [[stage_in]],
|
||||
texture2d<float> spriteTexture [[texture(0)]],
|
||||
sampler textureSampler [[sampler(0)]]) {
|
||||
float4 textureColor = spriteTexture.sample(textureSampler, in.texCoord);
|
||||
return textureColor * in.color; // Multiplicar textura por color de vértice para tinting
|
||||
}
|
||||
33
data/shaders/triangle.metal
Normal file
33
data/shaders/triangle.metal
Normal file
@@ -0,0 +1,33 @@
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
|
||||
struct VertexOut {
|
||||
float4 position [[position]];
|
||||
float4 color;
|
||||
};
|
||||
|
||||
vertex VertexOut triangle_vertex_main(uint vertexID [[vertex_id]]) {
|
||||
VertexOut out;
|
||||
|
||||
// Triángulo simple en coordenadas normalized device coordinates
|
||||
float2 positions[3] = {
|
||||
float2( 0.0, 0.5), // Top
|
||||
float2(-0.5, -0.5), // Bottom left
|
||||
float2( 0.5, -0.5) // Bottom right
|
||||
};
|
||||
|
||||
float4 colors[3] = {
|
||||
float4(1, 0, 0, 1), // Red
|
||||
float4(0, 1, 0, 1), // Green
|
||||
float4(0, 0, 1, 1) // Blue
|
||||
};
|
||||
|
||||
out.position = float4(positions[vertexID], 0.0, 1.0);
|
||||
out.color = colors[vertexID];
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
fragment float4 triangle_fragment_main(VertexOut in [[stage_in]]) {
|
||||
return in.color;
|
||||
}
|
||||
400
source/main.cpp
400
source/main.cpp
@@ -104,404 +104,102 @@ int main(int argc, char* argv[]) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Shaders para fondo degradado
|
||||
NSString* backgroundVertexShaderSource = @R"(
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
|
||||
struct VertexOut {
|
||||
float4 position [[position]];
|
||||
float4 color;
|
||||
};
|
||||
|
||||
vertex VertexOut background_vertex_main(uint vertexID [[vertex_id]]) {
|
||||
VertexOut out;
|
||||
|
||||
// Quad de pantalla completa en coordenadas NDC
|
||||
float2 positions[6] = {
|
||||
float2(-1.0, -1.0), // Bottom left
|
||||
float2( 1.0, -1.0), // Bottom right
|
||||
float2(-1.0, 1.0), // Top left
|
||||
float2( 1.0, -1.0), // Bottom right
|
||||
float2( 1.0, 1.0), // Top right
|
||||
float2(-1.0, 1.0) // Top left
|
||||
};
|
||||
|
||||
// Gradiente de púrpura oscuro arriba a azul cyan abajo
|
||||
float4 colors[6] = {
|
||||
float4(0.2, 0.6, 0.8, 1.0), // Bottom left - cyan claro
|
||||
float4(0.2, 0.6, 0.8, 1.0), // Bottom right - cyan claro
|
||||
float4(0.3, 0.1, 0.5, 1.0), // Top left - púrpura oscuro
|
||||
float4(0.2, 0.6, 0.8, 1.0), // Bottom right - cyan claro
|
||||
float4(0.3, 0.1, 0.5, 1.0), // Top right - púrpura oscuro
|
||||
float4(0.3, 0.1, 0.5, 1.0) // Top left - púrpura oscuro
|
||||
};
|
||||
|
||||
out.position = float4(positions[vertexID], 0.0, 1.0);
|
||||
out.color = colors[vertexID];
|
||||
|
||||
return out;
|
||||
}
|
||||
)";
|
||||
|
||||
NSString* backgroundFragmentShaderSource = @R"(
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
|
||||
struct VertexOut {
|
||||
float4 position [[position]];
|
||||
float4 color;
|
||||
};
|
||||
|
||||
fragment float4 background_fragment_main(VertexOut in [[stage_in]]) {
|
||||
return in.color;
|
||||
}
|
||||
)";
|
||||
|
||||
// Shaders para triángulo
|
||||
NSString* triangleVertexShaderSource = @R"(
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
|
||||
struct VertexOut {
|
||||
float4 position [[position]];
|
||||
float4 color;
|
||||
};
|
||||
|
||||
vertex VertexOut triangle_vertex_main(uint vertexID [[vertex_id]]) {
|
||||
VertexOut out;
|
||||
|
||||
// Triángulo simple en coordenadas normalized device coordinates
|
||||
float2 positions[3] = {
|
||||
float2( 0.0, 0.5), // Top
|
||||
float2(-0.5, -0.5), // Bottom left
|
||||
float2( 0.5, -0.5) // Bottom right
|
||||
};
|
||||
|
||||
float4 colors[3] = {
|
||||
float4(1, 0, 0, 1), // Red
|
||||
float4(0, 1, 0, 1), // Green
|
||||
float4(0, 0, 1, 1) // Blue
|
||||
};
|
||||
|
||||
out.position = float4(positions[vertexID], 0.0, 1.0);
|
||||
out.color = colors[vertexID];
|
||||
|
||||
return out;
|
||||
}
|
||||
)";
|
||||
|
||||
NSString* triangleFragmentShaderSource = @R"(
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
|
||||
struct VertexOut {
|
||||
float4 position [[position]];
|
||||
float4 color;
|
||||
};
|
||||
|
||||
fragment float4 triangle_fragment_main(VertexOut in [[stage_in]]) {
|
||||
return in.color;
|
||||
}
|
||||
)";
|
||||
|
||||
// Shaders para sprites con textura y color
|
||||
NSString* spriteVertexShaderSource = @R"(
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
|
||||
struct SpriteVertexIn {
|
||||
float2 position [[attribute(0)]];
|
||||
float4 color [[attribute(1)]];
|
||||
float2 texCoord [[attribute(2)]];
|
||||
};
|
||||
|
||||
struct SpriteVertexOut {
|
||||
float4 position [[position]];
|
||||
float4 color;
|
||||
float2 texCoord;
|
||||
};
|
||||
|
||||
vertex SpriteVertexOut sprite_vertex_main(SpriteVertexIn in [[stage_in]]) {
|
||||
SpriteVertexOut out;
|
||||
out.position = float4(in.position, 0.0, 1.0);
|
||||
out.color = in.color;
|
||||
out.texCoord = in.texCoord;
|
||||
return out;
|
||||
}
|
||||
)";
|
||||
|
||||
NSString* spriteFragmentShaderSource = @R"(
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
|
||||
struct SpriteVertexOut {
|
||||
float4 position [[position]];
|
||||
float4 color;
|
||||
float2 texCoord;
|
||||
};
|
||||
|
||||
fragment float4 sprite_fragment_main(SpriteVertexOut in [[stage_in]],
|
||||
texture2d<float> spriteTexture [[texture(0)]],
|
||||
sampler textureSampler [[sampler(0)]]) {
|
||||
float4 textureColor = spriteTexture.sample(textureSampler, in.texCoord);
|
||||
return textureColor * in.color; // Multiplicar textura por color de vértice para tinting
|
||||
}
|
||||
)";
|
||||
|
||||
// Shaders para CRT post-processing (fullscreen quad)
|
||||
NSString* crtVertexShaderSource = @R"(
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
|
||||
struct CRTVertexOut {
|
||||
float4 position [[position]];
|
||||
float2 texCoord;
|
||||
};
|
||||
|
||||
vertex CRTVertexOut crt_vertex_main(uint vertexID [[vertex_id]]) {
|
||||
CRTVertexOut out;
|
||||
|
||||
// Fullscreen quad con coordenadas de textura
|
||||
float2 positions[6] = {
|
||||
float2(-1.0, -1.0), // Bottom left
|
||||
float2( 1.0, -1.0), // Bottom right
|
||||
float2(-1.0, 1.0), // Top left
|
||||
float2( 1.0, -1.0), // Bottom right
|
||||
float2( 1.0, 1.0), // Top right
|
||||
float2(-1.0, 1.0) // Top left
|
||||
};
|
||||
|
||||
float2 texCoords[6] = {
|
||||
float2(0.0, 1.0), // Bottom left
|
||||
float2(1.0, 1.0), // Bottom right
|
||||
float2(0.0, 0.0), // Top left
|
||||
float2(1.0, 1.0), // Bottom right
|
||||
float2(1.0, 0.0), // Top right
|
||||
float2(0.0, 0.0) // Top left
|
||||
};
|
||||
|
||||
out.position = float4(positions[vertexID], 0.0, 1.0);
|
||||
out.texCoord = texCoords[vertexID];
|
||||
|
||||
return out;
|
||||
}
|
||||
)";
|
||||
|
||||
// CRT Fragment Shader - Migrado de GLSL a MSL
|
||||
NSString* crtFragmentShaderSource = @R"(
|
||||
#include <metal_stdlib>
|
||||
using namespace metal;
|
||||
|
||||
// Parámetros del CRT shader
|
||||
#define CURVATURE_X 0.05
|
||||
#define CURVATURE_Y 0.1
|
||||
#define MASK_BRIGHTNESS 0.80
|
||||
#define SCANLINE_WEIGHT 6.0
|
||||
#define SCANLINE_GAP_BRIGHTNESS 0.12
|
||||
#define BLOOM_FACTOR 3.5
|
||||
#define INPUT_GAMMA 2.4
|
||||
#define OUTPUT_GAMMA 2.2
|
||||
|
||||
// Features habilitadas
|
||||
#define SCANLINES
|
||||
#define MULTISAMPLE
|
||||
#define GAMMA
|
||||
// #define FAKE_GAMMA
|
||||
// #define CURVATURE
|
||||
// #define SHARPER
|
||||
#define MASK_TYPE 2
|
||||
|
||||
struct CRTVertexOut {
|
||||
float4 position [[position]];
|
||||
float2 texCoord;
|
||||
};
|
||||
|
||||
float CalcScanLineWeight(float dist) {
|
||||
return max(1.0 - dist * dist * SCANLINE_WEIGHT, SCANLINE_GAP_BRIGHTNESS);
|
||||
}
|
||||
|
||||
float CalcScanLine(float dy, float filterWidth) {
|
||||
float scanLineWeight = CalcScanLineWeight(dy);
|
||||
#ifdef MULTISAMPLE
|
||||
scanLineWeight += CalcScanLineWeight(dy - filterWidth);
|
||||
scanLineWeight += CalcScanLineWeight(dy + filterWidth);
|
||||
scanLineWeight *= 0.3333333;
|
||||
#endif
|
||||
return scanLineWeight;
|
||||
}
|
||||
|
||||
fragment float4 crt_fragment_main(CRTVertexOut in [[stage_in]],
|
||||
texture2d<float> sceneTexture [[texture(0)]],
|
||||
sampler sceneSampler [[sampler(0)]]) {
|
||||
float2 TextureSize = float2(320.0, 240.0); // Resolución virtual del CRT
|
||||
float filterWidth = (768.0 / 240.0) / 3.0;
|
||||
|
||||
float2 texcoord = in.texCoord;
|
||||
|
||||
// Convertir a píxeles
|
||||
float2 texcoordInPixels = texcoord * TextureSize;
|
||||
|
||||
#ifdef SHARPER
|
||||
float2 tempCoord = floor(texcoordInPixels) + 0.5;
|
||||
float2 coord = tempCoord / TextureSize;
|
||||
float2 deltas = texcoordInPixels - tempCoord;
|
||||
float scanLineWeight = CalcScanLine(deltas.y, filterWidth);
|
||||
float2 signs = sign(deltas);
|
||||
deltas.x *= 2.0;
|
||||
deltas = deltas * deltas;
|
||||
deltas.y = deltas.y * deltas.y;
|
||||
deltas.x *= 0.5;
|
||||
deltas.y *= 8.0;
|
||||
deltas /= TextureSize;
|
||||
deltas *= signs;
|
||||
float2 tc = coord + deltas;
|
||||
#else
|
||||
float tempY = floor(texcoordInPixels.y) + 0.5;
|
||||
float yCoord = tempY / TextureSize.y;
|
||||
float dy = texcoordInPixels.y - tempY;
|
||||
float scanLineWeight = CalcScanLine(dy, filterWidth);
|
||||
float signY = sign(dy);
|
||||
dy = dy * dy;
|
||||
dy = dy * dy;
|
||||
dy *= 8.0;
|
||||
dy /= TextureSize.y;
|
||||
dy *= signY;
|
||||
float2 tc = float2(texcoord.x, yCoord + dy);
|
||||
#endif
|
||||
|
||||
// Samplear la textura de escena
|
||||
float3 colour = sceneTexture.sample(sceneSampler, tc).rgb;
|
||||
|
||||
#ifdef SCANLINES
|
||||
#ifdef GAMMA
|
||||
#ifdef FAKE_GAMMA
|
||||
colour = colour * colour;
|
||||
#else
|
||||
colour = pow(colour, float3(INPUT_GAMMA));
|
||||
#endif
|
||||
#endif
|
||||
scanLineWeight *= BLOOM_FACTOR;
|
||||
colour *= scanLineWeight;
|
||||
|
||||
#ifdef GAMMA
|
||||
#ifdef FAKE_GAMMA
|
||||
colour = sqrt(colour);
|
||||
#else
|
||||
colour = pow(colour, float3(1.0 / OUTPUT_GAMMA));
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Shadow mask
|
||||
#if MASK_TYPE == 0
|
||||
return float4(colour, 1.0);
|
||||
#else
|
||||
#if MASK_TYPE == 1
|
||||
float whichMask = fract((in.position.x * 1.0001) * 0.5);
|
||||
float3 mask;
|
||||
if (whichMask < 0.5) {
|
||||
mask = float3(MASK_BRIGHTNESS, 1.0, MASK_BRIGHTNESS);
|
||||
} else {
|
||||
mask = float3(1.0, MASK_BRIGHTNESS, 1.0);
|
||||
}
|
||||
#elif MASK_TYPE == 2
|
||||
float whichMask = fract((in.position.x * 1.0001) * 0.3333333);
|
||||
float3 mask = float3(MASK_BRIGHTNESS, MASK_BRIGHTNESS, MASK_BRIGHTNESS);
|
||||
if (whichMask < 0.3333333) {
|
||||
mask.x = 1.0;
|
||||
} else if (whichMask < 0.6666666) {
|
||||
mask.y = 1.0;
|
||||
} else {
|
||||
mask.z = 1.0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return float4(colour * mask, 1.0);
|
||||
#endif
|
||||
}
|
||||
)";
|
||||
|
||||
// Compilar shaders CRT
|
||||
// Cargar shaders CRT desde archivo
|
||||
NSError* error = nil;
|
||||
id<MTLLibrary> crtVertexLibrary = [device newLibraryWithSource:crtVertexShaderSource options:nil error:&error];
|
||||
if (!crtVertexLibrary || error) {
|
||||
|
||||
NSString* crtShaderPath = @"data/shaders/crt.metal";
|
||||
NSString* crtShaderSource = [NSString stringWithContentsOfFile:crtShaderPath encoding:NSUTF8StringEncoding error:&error];
|
||||
if (!crtShaderSource || error) {
|
||||
if (error) {
|
||||
std::cout << "Failed to compile CRT vertex shader: " << [[error localizedDescription] UTF8String] << std::endl;
|
||||
std::cout << "Failed to read CRT shader file: " << [[error localizedDescription] UTF8String] << std::endl;
|
||||
} else {
|
||||
std::cout << "Failed to read CRT shader file: data/shaders/crt.metal" << std::endl;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
id<MTLLibrary> crtFragmentLibrary = [device newLibraryWithSource:crtFragmentShaderSource options:nil error:&error];
|
||||
if (!crtFragmentLibrary || error) {
|
||||
id<MTLLibrary> crtLibrary = [device newLibraryWithSource:crtShaderSource options:nil error:&error];
|
||||
if (!crtLibrary || error) {
|
||||
if (error) {
|
||||
std::cout << "Failed to compile CRT fragment shader: " << [[error localizedDescription] UTF8String] << std::endl;
|
||||
std::cout << "Failed to compile CRT shader: " << [[error localizedDescription] UTF8String] << std::endl;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
id<MTLFunction> crtVertexFunction = [crtVertexLibrary newFunctionWithName:@"crt_vertex_main"];
|
||||
id<MTLFunction> crtFragmentFunction = [crtFragmentLibrary newFunctionWithName:@"crt_fragment_main"];
|
||||
id<MTLFunction> crtVertexFunction = [crtLibrary newFunctionWithName:@"crt_vertex_main"];
|
||||
id<MTLFunction> crtFragmentFunction = [crtLibrary newFunctionWithName:@"crt_fragment_main"];
|
||||
|
||||
// Compilar shaders de fondo
|
||||
id<MTLLibrary> backgroundVertexLibrary = [device newLibraryWithSource:backgroundVertexShaderSource options:nil error:&error];
|
||||
if (!backgroundVertexLibrary || error) {
|
||||
// Cargar shaders de fondo desde archivo
|
||||
NSString* backgroundShaderPath = @"data/shaders/background.metal";
|
||||
NSString* backgroundShaderSource = [NSString stringWithContentsOfFile:backgroundShaderPath encoding:NSUTF8StringEncoding error:&error];
|
||||
if (!backgroundShaderSource || error) {
|
||||
if (error) {
|
||||
std::cout << "Failed to compile background vertex shader: " << [[error localizedDescription] UTF8String] << std::endl;
|
||||
std::cout << "Failed to read background shader file: " << [[error localizedDescription] UTF8String] << std::endl;
|
||||
} else {
|
||||
std::cout << "Failed to read background shader file: data/shaders/background.metal" << std::endl;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
id<MTLLibrary> backgroundFragmentLibrary = [device newLibraryWithSource:backgroundFragmentShaderSource options:nil error:&error];
|
||||
if (!backgroundFragmentLibrary || error) {
|
||||
id<MTLLibrary> backgroundLibrary = [device newLibraryWithSource:backgroundShaderSource options:nil error:&error];
|
||||
if (!backgroundLibrary || error) {
|
||||
if (error) {
|
||||
std::cout << "Failed to compile background fragment shader: " << [[error localizedDescription] UTF8String] << std::endl;
|
||||
std::cout << "Failed to compile background shader: " << [[error localizedDescription] UTF8String] << std::endl;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
id<MTLFunction> backgroundVertexFunction = [backgroundVertexLibrary newFunctionWithName:@"background_vertex_main"];
|
||||
id<MTLFunction> backgroundFragmentFunction = [backgroundFragmentLibrary newFunctionWithName:@"background_fragment_main"];
|
||||
id<MTLFunction> backgroundVertexFunction = [backgroundLibrary newFunctionWithName:@"background_vertex_main"];
|
||||
id<MTLFunction> backgroundFragmentFunction = [backgroundLibrary newFunctionWithName:@"background_fragment_main"];
|
||||
|
||||
// Compilar shaders de triángulo
|
||||
id<MTLLibrary> triangleVertexLibrary = [device newLibraryWithSource:triangleVertexShaderSource options:nil error:&error];
|
||||
if (!triangleVertexLibrary || error) {
|
||||
// Cargar shaders de triángulo desde archivo
|
||||
NSString* triangleShaderPath = @"data/shaders/triangle.metal";
|
||||
NSString* triangleShaderSource = [NSString stringWithContentsOfFile:triangleShaderPath encoding:NSUTF8StringEncoding error:&error];
|
||||
if (!triangleShaderSource || error) {
|
||||
if (error) {
|
||||
std::cout << "Failed to compile triangle vertex shader: " << [[error localizedDescription] UTF8String] << std::endl;
|
||||
std::cout << "Failed to read triangle shader file: " << [[error localizedDescription] UTF8String] << std::endl;
|
||||
} else {
|
||||
std::cout << "Failed to read triangle shader file: data/shaders/triangle.metal" << std::endl;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
id<MTLLibrary> triangleFragmentLibrary = [device newLibraryWithSource:triangleFragmentShaderSource options:nil error:&error];
|
||||
if (!triangleFragmentLibrary || error) {
|
||||
id<MTLLibrary> triangleLibrary = [device newLibraryWithSource:triangleShaderSource options:nil error:&error];
|
||||
if (!triangleLibrary || error) {
|
||||
if (error) {
|
||||
std::cout << "Failed to compile triangle fragment shader: " << [[error localizedDescription] UTF8String] << std::endl;
|
||||
std::cout << "Failed to compile triangle shader: " << [[error localizedDescription] UTF8String] << std::endl;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
id<MTLFunction> triangleVertexFunction = [triangleVertexLibrary newFunctionWithName:@"triangle_vertex_main"];
|
||||
id<MTLFunction> triangleFragmentFunction = [triangleFragmentLibrary newFunctionWithName:@"triangle_fragment_main"];
|
||||
id<MTLFunction> triangleVertexFunction = [triangleLibrary newFunctionWithName:@"triangle_vertex_main"];
|
||||
id<MTLFunction> triangleFragmentFunction = [triangleLibrary newFunctionWithName:@"triangle_fragment_main"];
|
||||
|
||||
// Compilar shaders de sprites
|
||||
id<MTLLibrary> spriteVertexLibrary = [device newLibraryWithSource:spriteVertexShaderSource options:nil error:&error];
|
||||
if (!spriteVertexLibrary || error) {
|
||||
// Cargar shaders de sprites desde archivo
|
||||
NSString* spriteShaderPath = @"data/shaders/sprite.metal";
|
||||
NSString* spriteShaderSource = [NSString stringWithContentsOfFile:spriteShaderPath encoding:NSUTF8StringEncoding error:&error];
|
||||
if (!spriteShaderSource || error) {
|
||||
if (error) {
|
||||
std::cout << "Failed to compile sprite vertex shader: " << [[error localizedDescription] UTF8String] << std::endl;
|
||||
std::cout << "Failed to read sprite shader file: " << [[error localizedDescription] UTF8String] << std::endl;
|
||||
} else {
|
||||
std::cout << "Failed to read sprite shader file: data/shaders/sprite.metal" << std::endl;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
id<MTLLibrary> spriteFragmentLibrary = [device newLibraryWithSource:spriteFragmentShaderSource options:nil error:&error];
|
||||
if (!spriteFragmentLibrary || error) {
|
||||
id<MTLLibrary> spriteLibrary = [device newLibraryWithSource:spriteShaderSource options:nil error:&error];
|
||||
if (!spriteLibrary || error) {
|
||||
if (error) {
|
||||
std::cout << "Failed to compile sprite fragment shader: " << [[error localizedDescription] UTF8String] << std::endl;
|
||||
std::cout << "Failed to compile sprite shader: " << [[error localizedDescription] UTF8String] << std::endl;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
id<MTLFunction> spriteVertexFunction = [spriteVertexLibrary newFunctionWithName:@"sprite_vertex_main"];
|
||||
id<MTLFunction> spriteFragmentFunction = [spriteFragmentLibrary newFunctionWithName:@"sprite_fragment_main"];
|
||||
id<MTLFunction> spriteVertexFunction = [spriteLibrary newFunctionWithName:@"sprite_vertex_main"];
|
||||
id<MTLFunction> spriteFragmentFunction = [spriteLibrary newFunctionWithName:@"sprite_fragment_main"];
|
||||
|
||||
// Crear pipeline de fondo
|
||||
MTLRenderPipelineDescriptor* backgroundPipelineDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
|
||||
|
||||
Reference in New Issue
Block a user