Skip to content

Fix Color.FromHSV hue progression and parameter normalization#9170

Merged
SimonDarksideJ merged 6 commits intoMonoGame:developfrom
AristurtleDev:fix/color-fromhsv
Jan 16, 2026
Merged

Fix Color.FromHSV hue progression and parameter normalization#9170
SimonDarksideJ merged 6 commits intoMonoGame:developfrom
AristurtleDev:fix/color-fromhsv

Conversation

@AristurtleDev
Copy link
Contributor

Description

Fixes two bugs in Color.FromHSV()

  1. Fixes fractional hue calculation within color wheel segments. The fractional position f within each 60deg segment was calcualted as int f = (int)(h / 60.0f) - i, which always resulted in a 0 due to integer arithmetic. Changed to float f = (h % 60.0f) / 60.0f to correctly calcualte fractional position within [0,1] range.
  2. Removed incorrect normalization of saturation and value parameters. The documentation for the method states that these values should be in the [0,1] range. By normalizing them by dividing by 100, this causes colors to be nearly black in all cases (e.g. passing s=1.0, v=1.0 would result in RGB values of 2 instead of 255)

Additionally, Color.FromHSV(), Color.FromHSL() were changed to static methods. These are factory methods for creating a Color value from a different structure, it doesn't make sense to have them as instance members that require an instance before using.

Breaking Changes

Since Color.FromHSV() and Color.FromHSL() are changed to static factory methods, this would be considered a breaking change as it changes the public API that already existed. Not sure if you want to keep this change since it's technically a breaking change or we can obsolete the existing ones with a warning and forward them to the new static ones, then remove the instance methods in a future release where breaking changes are good.

Related Issues

The fractional position `f` within each 60deg segment was always 0 due to using integer maths.
The documentation for these values state that they are in the [0,1] range.  When supplying a value such as 0.5, then the division would do 0.5/100 = 0.005 which is incorrect.

`s` and `v` are also linear values in HSV, so clamping makes sense for them. `h` is a cyclical value, so should be allowed to wrap if not in [0,360] range
Copy link
Contributor

@ThomasFOG ThomasFOG left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good to me, thanks! Breaking changes are indeed totally fine as this is very new and unrelated to XNA compatibility.

@SimonDarksideJ SimonDarksideJ merged commit 28a59a0 into MonoGame:develop Jan 16, 2026
15 of 16 checks passed
@AristurtleDev AristurtleDev deleted the fix/color-fromhsv branch January 16, 2026 15:06
CartBlanche pushed a commit that referenced this pull request Jan 22, 2026
## Description

Fixes two bugs in `Color.FromHSV()`

1. Fixes fractional hue calculation within color wheel segments. The
fractional position `f` within each 60deg segment was calcualted as `int
f = (int)(h / 60.0f) - i`, which always resulted in a `0` due to integer
arithmetic. Changed to `float f = (h % 60.0f) / 60.0f` to correctly
calcualte fractional position within [0,1] range.
2. Removed incorrect normalization of saturation and value parameters.
The documentation for the method states that these values should be in
the [0,1] range. By normalizing them by dividing by 100, this causes
colors to be nearly black in all cases (e.g. passing `s=1.0, v=1.0`
would result in RGB values of `2` instead of `255`)

Additionally, `Color.FromHSV()`, `Color.FromHSL()` were changed to
`static` methods. These are factory methods for creating a `Color` value
from a different structure, it doesn't make sense to have them as
instance members that require an instance before using.

## Breaking Changes

Since `Color.FromHSV()` and `Color.FromHSL()` are changed to static
factory methods, this would be considered a breaking change as it
changes the public API that already existed. Not sure if you want to
keep this change since it's technically a breaking change or we can
obsolete the existing ones with a warning and forward them to the new
static ones, then remove the instance methods in a future release where
breaking changes are good.

## Related Issues
- Closes #9131
viniciusjarina pushed a commit to codefoco/MonoGame that referenced this pull request Jan 29, 2026
…me#9170)

## Description

Fixes two bugs in `Color.FromHSV()`

1. Fixes fractional hue calculation within color wheel segments. The
fractional position `f` within each 60deg segment was calcualted as `int
f = (int)(h / 60.0f) - i`, which always resulted in a `0` due to integer
arithmetic. Changed to `float f = (h % 60.0f) / 60.0f` to correctly
calcualte fractional position within [0,1] range.
2. Removed incorrect normalization of saturation and value parameters.
The documentation for the method states that these values should be in
the [0,1] range. By normalizing them by dividing by 100, this causes
colors to be nearly black in all cases (e.g. passing `s=1.0, v=1.0`
would result in RGB values of `2` instead of `255`)

Additionally, `Color.FromHSV()`, `Color.FromHSL()` were changed to
`static` methods. These are factory methods for creating a `Color` value
from a different structure, it doesn't make sense to have them as
instance members that require an instance before using.

## Breaking Changes

Since `Color.FromHSV()` and `Color.FromHSL()` are changed to static
factory methods, this would be considered a breaking change as it
changes the public API that already existed. Not sure if you want to
keep this change since it's technically a breaking change or we can
obsolete the existing ones with a warning and forward them to the new
static ones, then remove the instance methods in a future release where
breaking changes are good.

## Related Issues
- Closes MonoGame#9131
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Color.FromHSV() is missing components

4 participants