View difference between Paste ID: iu481NRh and nH1SJsR5
SHOW: | | - or go back to the newest paste.
1
const std = @import("std");
2
const warn = std.debug.warn;
3
const assert = std.debug.assert;
4
5
const File = std.os.File;
6
const ASCII = std.ASCII;
7
8
const TypeId = @import("builtin").TypeId;
9
const TypeInfo = @import("builtin").TypeInfo;
10
11
/// clamps a value into the given range [min;max]
12
fn clamp(comptime T: type, v: T, min: T, max: T) T {
13
    if (v < min) {
14
        return min;
15
    } else {
16
        if (v > max) {
17
            return max;
18
        } else {
19
            return v;
20
        }
21
    }
22
}
23
24
fn Color(comptime T: type) type {
25
    return packed struct {
26
        const Self = @This();
27
        const Component = T;
28
29
        R: Component,
30
        G: Component,
31
        B: Component,
32
33
        fn equals(self: Self, b: Self) bool {
34
            return self.R == b.R and self.G == b.G and self.B == b.B;
35
        }
36
    };
37
}
38
39
/// convert any numeric type into range [0;1]
40
/// integers will be mapped from "min" to "max", floats will be clamped.
41
fn map_to_uniform(comptime T: type, value: T) f128 {
42
    switch (@typeInfo(T)) {
43
        TypeId.Int => |t| {
44
            if (t.is_signed) {
45
                const min = @intToFloat(f128, -(1 << (t.bits - 1)));
46
                const max = @intToFloat(f128, (1 << (t.bits - 1)));
47
                return (@intToFloat(f128, value) - min) / (max - min);
48
            } else {
49
                const max = @intToFloat(f128, (1 << t.bits) - 1);
50
                return @intToFloat(f128, value) / max;
51
            }
52
        },
53
        TypeId.Float => |t| {
54
            return value;
55
        },
56
        else => @panic("Unsupported type " ++ @typeName(T)),
57
    }
58
}
59
60
/// convert range [0;1] to any numeric type
61
/// integers will be mapped into rang "min" to "max", floats will be clamped
62
fn map_from_uniform(comptime T: type, value: f128) T {
63
    switch (@typeInfo(T)) {
64
        TypeId.Int => |t| {
65
            if (t.is_signed) {
66
                const min = @intToFloat(f128, -(1 << (t.bits - 1)));
67
                const max = @intToFloat(f128, (1 << (t.bits - 1)));
68
                return @floatToInt(T, (max - min) * value + min);
69
            } else {
70
                const max = @intToFloat(f128, (1 << t.bits) - 1);
71
                return @floatToInt(T, max * value);
72
            }
73
        },
74
        TypeId.Float => |t| {
75
            return @floatCast(T, value);
76
        },
77
        else => @panic("Unsupported type " ++ @typeName(T)),
78
    }
79
}
80
81
/// Maps a color from one type to another.
82
fn mapColor(comptime TIn: type, comptime TOut: type, c: TIn) TOut {
83
    if (TIn == TOut)
84
        return c;
85
86
    var r = map_to_uniform(TIn.Component, c.R);
87
    var g = map_to_uniform(TIn.Component, c.G);
88
    var b = map_to_uniform(TIn.Component, c.B);
89
90
    r = clamp(f128, r, 0.0, 1.0);
91
    g = clamp(f128, g, 0.0, 1.0);
92
    b = clamp(f128, b, 0.0, 1.0);
93
94
    return TOut{
95
        .R = map_from_uniform(TOut.Component, r),
96
        .G = map_from_uniform(TOut.Component, g),
97
        .B = map_from_uniform(TOut.Component, b),
98
    };
99
}
100
101
test "mapColor" {
102
    // test will run with comptime, but won't link without it. (lld: error: undefined symbol: __divtf3)
103
    comptime {
104
        var c_u8 = Color(u8) { .R = 0xFF, .G = 0x00, .B = 0x00 };
105
        var c_f32 = Color(f32) { .R = 1.0, .G = 0.0, .B = 0.0 };
106
107
        assert(mapColor(@typeOf(c_u8), @typeOf(c_f32), c_u8).equals(c_f32));
108
        assert(mapColor(@typeOf(c_f32), @typeOf(c_u8), c_f32).equals(c_u8));
109
    }
110
}
111
112
fn render() Color(f32) {
113
    return Color(f32){ .R = 0, .G = 0, .B = 0 };
114
}
115
116
pub fn main() void {
117
    /// comptime will yield a compiler error (error: evaluation exceeded 1000 backwards branches)
118
    /// no comptime will result in stack overflow.
119
    // comptime
120
    {
121
      var y: usize = 0;
122
      while (y < 240) : (y += 1) {
123
          var x: usize = 0;
124
          while (x < 320) : (x += 1) {
125
              const val = render();
126
127
              const mapped = mapColor(@typeOf(val), Color(u8), val);
128
          }
129
      }
130
    }
131
}