Mat4 :: #type,distinct Vec(4 * 4, float);

m4 :: (r0: Vec4, r1: Vec4, r2: Vec4, r3: Vec4) -> Mat4 #expand {
   return .{
      components = .[
         r0.x, r0.y, r0.z, r0.w,
         r1.x, r1.y, r1.z, r1.w,
         r2.x, r2.y, r2.z, r2.w,
         r3.x, r3.y, r3.z, r3.w,
      ],
   };
}

m4_identity :: #bake_arguments m4d(diag = 1);

m4d :: (diag: float) -> Mat4 #expand {
   res: Mat4;
   res[0][0] = diag;
   res[1][1] = diag;
   res[2][2] = diag;
   res[3][3] = diag;
   return res;
}

operator [] :: inline (m: Mat4, idx: int) -> Vec4 #expand {
   bounds_check_index(idx * 4, m.N);
   return (m.components[idx * 4]).(*Vec4).*;
}

operator *[] :: inline (m: *Mat4, $$idx: int) -> *Vec4 #no_abc {
   N :: Mat4.{}.N; // @note(judah): dumb workaround for not being able to access pointer type field constants
   bounds_check_index(idx * 4, N);
   return (*m.components[idx * 4]).(*Vec4);
}

operator []= :: inline (m: *Mat4, $$idx: int, value: Vec4) #no_abc {
   N :: Mat4.{}.N;
   bounds_check_index(idx * 4, N);

   ptr := (*m.components[idx * 4]).(*Vec4);
   ptr.*= value;
}

