Float * Color vs Color * Float

Why is it considered a compiler error for a float times a color? A color times a float works just fine.

Looks like there needs to be an operator that takes in a float first. Can you file an issue for this?

I added it as an issue. Unless this is some C# concept I’m lacking knowledge on.

1 Like

Might as well just add all these extensions seems like they are getting added over time anyways,

Scale(.5f)
ScaleRGB(.5f)

With extensions it kinda makes it questionable if they shouldn’t just be extensions.
Less bloat to the whole library if you use your own extension methods on a case by case basis.
That said some of these i use a awful lot.

You can put this in a project or standard helper class ect.

  namespace Microsoft.Xna.Framework
  {
    public static class MgExt
    {
        public static Vector3 ToVector3(this Vector4 v)
        {
            return new Vector3(v.X, v.Y, v.Z);
        }
        public static Vector4 ToVector4(this Vector3 v)
        {
            return new Vector4(v.X, v.Y, v.Z, 1f);
        }
        public static Vector4 ToVector4(this Vector3 v, float w)
        {
            return new Vector4(v.X, v.Y, v.Z, w);
        }
        public static Rectangle FromLocSize(this Rectangle r, Vector2 xy, Vector2 size)
        {
            return new Rectangle(xy.ToPoint(), size.ToPoint());
        }
        public static Rectangle FromLocStartEnd(this Rectangle r, Vector2 s, Vector2 e)
        {
            return new Rectangle(s.ToPoint(), (e - s).ToPoint());
        }
        public static Vector2 ToVector2(this Rectangle rectangle)
        {
            return new Vector2(rectangle.X, rectangle.Y);
        }
        public static Vector2 SizeToVector2(this Rectangle rectangle)
        {
            return new Vector2(rectangle.Width, rectangle.Height);
        }
        public static Vector2 CenterToVector2(this Rectangle rectangle)
        {
            return new Vector2(rectangle.Center.X, rectangle.Center.Y);
        }
        public static Color ToColor(this Vector4 v)
        {
            return new Color((byte)(v.X *255f), (byte)(v.Y * 255f), (byte)(v.Z * 255f), (byte)(v.W * 255f));
        }
        public static Color ToColor(this Vector4 v, float wAlpha)
        {
           return new Color((byte)(v.X * 255f), (byte)(v.Y * 255f), (byte)(v.Z * 255f), (byte)(wAlpha * 255f));
        }
        public static Color Scale(this Color c, float s)
        {
            var n = c.ToVector4() * s;
            return n.ToColor();
        }
        public static Color ScaleRGB(this Color c, float s)
        {
            var v = c.ToVector4();
            return new Color((byte)(s *v.X * 255f), (byte)(s* v.Y * 255f), (byte)(s* v.Z * 255f), (byte)(v.W * 255f));
        }
        public static Color Scale(this Color c, Vector4 s)
        {
            var n = c.ToVector4() * s;
            return n.ToColor();
        }
        public static Color InvertedColor(this Color c)
        {
            return new Color(255 - c.R, 255 - c.G, 255 - c.B, c.A);
        }
        public static Color ChangeAlpha(this Color c, float a)
        {
            return new Color(c, a);
        }
        public static Color Interpolate(this Color a, Color b, float t)
        {
            float i = 1f - t;
            return new Color
                (
                (byte)(a.R * i + b.R * t),
                (byte)(a.G * i + b.G * t),
                (byte)(a.B * i + b.B * t),
                (byte)(a.A * i + b.A * t)
                );
        }
        /// <summary>
        /// Creates a world with a target.
        /// </summary>
        public static Matrix CreateWorldToTarget(this Matrix m, Vector3 position, Vector3 targetPosition, Vector3 up)
        {
            return Matrix.CreateWorld(position, targetPosition - position, up);
        }
/// <summary>
        /// Allows a position to be inflected against a unit normal and any position on its surface plane. 
        /// This is useful in mirroring positions across a plane. 
        /// When for example, you want to find in a water reflection cameras inflected position.
        /// E.G. a position opposite the surface on a light to surface reflection vector.
        /// </summary>
        public static Vector3 InflectPositionFromPlane(this Vector3 theCameraPostion, Vector3 thePlanesSurfaceNormal, Vector3 anyPositionOnThatSurfacePlane)
        {
            // the dot product also gives the length, when placed againsts a unit normal. 
            // so any unit n * a distance is the distance to that normals plane no matter the normals direction. 
            // i didn't know that relation was so straight forward till now.
            float camToPlaneDist = Vector3.Dot(thePlanesSurfaceNormal, theCameraPostion - anyPositionOnThatSurfacePlane);
            return theCameraPostion - thePlanesSurfaceNormal * camToPlaneDist * 2;
        }
/// <summary>
        /// Takes a screen position Point and reurns a ray in world space using viewport . unproject(...) , 
        /// The near and far are the z plane depth values used and found in your projection matrix.
        /// </summary>
        public static Ray GetScreenPointAsRayInto3dWorld(this Point screenPosition, Matrix projectionMatrix, Matrix viewMatrix, Matrix world, float near, float far, GraphicsDevice device)
        {
            return GetScreenVector2AsRayInto3dWorld(screenPosition.ToVector2(), projectionMatrix, viewMatrix, world, near, far, device);
        }

        /// <summary>
        /// far cannot be more then 1.0f
        /// Takes a screen position Vector2 and returns a ray in world space using viewport . unproject(...) , 
        /// The near and far are the z plane depth values used and found in your projection matrix.
        /// </summary>
        public static Ray GetScreenVector2AsRayInto3dWorld(this Vector2 screenPosition, Matrix projectionMatrix, Matrix viewMatrix, Matrix world, float near, float far, GraphicsDevice device)
        {
            Vector3 farScreenPoint = new Vector3(screenPosition.X, screenPosition.Y, far); // the projection matrice's far plane value.
            Vector3 nearScreenPoint = new Vector3(screenPosition.X, screenPosition.Y, near); // must be more then zero.
            Vector3 nearWorldPoint = device.Viewport.Unproject(nearScreenPoint, projectionMatrix, viewMatrix, world);
            Vector3 farWorldPoint = device.Viewport.Unproject(farScreenPoint, projectionMatrix, viewMatrix, world);
            Vector3 worldRaysNormal = Vector3.Normalize(farWorldPoint - nearWorldPoint);

            return new Ray(nearWorldPoint, worldRaysNormal);
        }
        // so lazy
        public static int ToInt(this float value)
        {
            return (int)(value);
        }
}
}

I have more but these are in my primary extensions.

Definitely not, thanks for bringing this up! It’s a problem in MonoGame’s code. I made a PR for this, which you can follow here.

1 Like

What about when you don’t want the alpha to change.
Is that correct c = c * .5f that’s probably why it wasn’t added in the first place.

Considering that this operator is not added yet and no one has complained…

Color c = Color.White * Color.Black;

Seems like its a given that we better add another overloaded operator.

    [System.Runtime.Serialization.DataContractAttribute]
    [DebuggerDisplay("{DebugDisplayString,nq}")]
    public struct Color : IEquatable<Color>
    {
        ...
        public static Color operator *(Color value, float scale);
        public static bool operator ==(Color a, Color b);
        public static bool operator !=(Color a, Color b);

it then follows these are missing…

public static Color operator *(Color value1, Color value2);
public static Color operator *(Color value, Vector3 scale);
public static Color operator *(Vector3 scale, Color value);
public static Color operator *(Color value, Vector4 scale);
public static Color operator *(Vector4 scale, Color value);

What about /
Color c = Color.White /2f;

We can do it for the compareitors as well.
Color != Vector3 ,
Color == Vector4

Is one overload for that and parenthesis reasonably not enough?
Is there a rule of thumb for this should there be one ?

Just saying i don’t think my point is that invalid.

This sort of thing could lead to code bloat in time if its done all over and reversing it is a breaking change.

This topic and my PR concern only color multiplication. I feel it’s reasonable to allow that operator in either order.

Divide is a nice convenience that can be achieved by also multiplying. Ex. Color.White / 2f is the same as Color.White * .5f.

I’m afraid I’m not quite following what you’re getting at with the equality operator between Colors, as it already includes them. MonoGame currently stores Colors as a packed value, and the alpha is non pre-multiplied. Excerpt from the source:

// Stored as RGBA with R in the least significant octet:
// |-------|-------|-------|-------
// A       B       G       R
private uint _packedValue;

The Vector4 overloads are likely not there because XNA did not have them. If you think your suggestions would improve the API then feel free to submit a PR.

Divide is a nice convenience that can be achieved by also multiplying. Ex. Color.White / 2f is the same as Color.White * .5f.

so is (Color.White * .5f) the same as .5f * Color.White;

so would this be but its not in there and this is the Color class.

Color c = Color.White * Color.Black;

The equality between operators could be used as a convience to check for equality against just the rgb vs a vector3 just like division is just as valid as multiplication. Or left is as valid as right multiplication.

Im just saying it’s something to think about in the future once its added its breaking to remove.

This is not completely correct. Color can represent either premultiplied and non-premultiplied RGBA data. Most users will use premultiplied alpha because that’s what the default blend state uses, but you can’t tell if a color is intended to be interpreted as premultiplied or not just from its value. I think that premultiplied being the default also explains why multiplication works the way it does (i.e. why it was designed that way by the XNA team). Multiply Color.White by 0.5f and you get premultiplied half-transparent white. This way multiplication with a value in the [0 1] range makes semantic sense, you multiply by an alpha value. In my opinion you can’t say the same for division and multiplication by another color. I.e. what does it mean to multiply Black and White together? What should the result be? What would you expect?

1 Like