Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- const std = @import("std");
- const warn = std.debug.warn;
- const assert = std.debug.assert;
- const File = std.os.File;
- const ASCII = std.ASCII;
- const TypeId = @import("builtin").TypeId;
- const TypeInfo = @import("builtin").TypeInfo;
- /// clamps a value into the given range [min;max]
- fn clamp(comptime T: type, v: T, min: T, max: T) T {
- if (v < min) {
- return min;
- } else {
- if (v > max) {
- return max;
- } else {
- return v;
- }
- }
- }
- fn Color(comptime T: type) type {
- return packed struct {
- const Self = @This();
- const Component = T;
- R: Component,
- G: Component,
- B: Component,
- fn equals(self: Self, b: Self) bool {
- return self.R == b.R and self.G == b.G and self.B == b.B;
- }
- };
- }
- /// convert any numeric type into range [0;1]
- /// integers will be mapped from "min" to "max", floats will be clamped.
- fn map_to_uniform(comptime T: type, value: T) f128 {
- switch (@typeInfo(T)) {
- TypeId.Int => |t| {
- if (t.is_signed) {
- const min = @intToFloat(f128, -(1 << (t.bits - 1)));
- const max = @intToFloat(f128, (1 << (t.bits - 1)));
- return (@intToFloat(f128, value) - min) / (max - min);
- } else {
- const max = @intToFloat(f128, (1 << t.bits) - 1);
- return @intToFloat(f128, value) / max;
- }
- },
- TypeId.Float => |t| {
- return value;
- },
- else => @panic("Unsupported type " ++ @typeName(T)),
- }
- }
- /// convert range [0;1] to any numeric type
- /// integers will be mapped into rang "min" to "max", floats will be clamped
- fn map_from_uniform(comptime T: type, value: f128) T {
- switch (@typeInfo(T)) {
- TypeId.Int => |t| {
- if (t.is_signed) {
- const min = @intToFloat(f128, -(1 << (t.bits - 1)));
- const max = @intToFloat(f128, (1 << (t.bits - 1)));
- return @floatToInt(T, (max - min) * value + min);
- } else {
- const max = @intToFloat(f128, (1 << t.bits) - 1);
- return @floatToInt(T, max * value);
- }
- },
- TypeId.Float => |t| {
- return @floatCast(T, value);
- },
- else => @panic("Unsupported type " ++ @typeName(T)),
- }
- }
- /// Maps a color from one type to another.
- fn mapColor(comptime TIn: type, comptime TOut: type, c: TIn) TOut {
- if (TIn == TOut)
- return c;
- var r = map_to_uniform(TIn.Component, c.R);
- var g = map_to_uniform(TIn.Component, c.G);
- var b = map_to_uniform(TIn.Component, c.B);
- r = clamp(f128, r, 0.0, 1.0);
- g = clamp(f128, g, 0.0, 1.0);
- b = clamp(f128, b, 0.0, 1.0);
- return TOut{
- .R = map_from_uniform(TOut.Component, r),
- .G = map_from_uniform(TOut.Component, g),
- .B = map_from_uniform(TOut.Component, b),
- };
- }
- test "mapColor" {
- // test will run with comptime, but won't link without it. (lld: error: undefined symbol: __divtf3)
- comptime {
- var c_u8 = Color(u8) { .R = 0xFF, .G = 0x00, .B = 0x00 };
- var c_f32 = Color(f32) { .R = 1.0, .G = 0.0, .B = 0.0 };
- assert(mapColor(@typeOf(c_u8), @typeOf(c_f32), c_u8).equals(c_f32));
- assert(mapColor(@typeOf(c_f32), @typeOf(c_u8), c_f32).equals(c_u8));
- }
- }
- fn render() Color(f32) {
- return Color(f32){ .R = 0, .G = 0, .B = 0 };
- }
- pub fn main() void {
- /// comptime will yield a compiler error (error: evaluation exceeded 1000 backwards branches)
- /// no comptime will result in stack overflow.
- // comptime
- {
- var y: usize = 0;
- while (y < 240) : (y += 1) {
- var x: usize = 0;
- while (x < 320) : (x += 1) {
- const val = render();
- const mapped = mapColor(@typeOf(val), Color(u8), val);
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement