Color
❎ Create a image::Color structure containing three unsigned bytes named after the primary colors used in the led matrix: r, g and b.
❎ Since copying a Color (3 bytes) is cheap, make it automatically derive Copy (and Clone which is needed for Copy).
❎ The default initialization of the structure would set all integer fields to 0, which is a perfect default for a color as it represents black. Make Color automatically derive Default.
❎ Implement three public constants Color::RED, Color::GREEN and Color::BLUE initialized to the correct values for those three primary colors.
⚠️ If you put the code for your
imagemodule inside a file namesimage.rs, do not usepub mod image { … }inside this file. Otherwise, you will end up with aimage::imagemodule, which is not what you want. Theimage.rsmust contain the content of theimagemodule directly inside the file.
Gamma correction
The led matrix requires some gamma correction to represent colors as our eyes can see them. This gamma correction table works fine with our led matrix.
❎ Add a gamma module to the project containing the above-mentioned gamma table and a function pub fn gamma_correct(x: u8) -> u8 which returns the corresponding value in the table.
❎ Implement a pub fn gamma_correct(&self) -> Self method on Color which applies the gamma::gamma_correct correction to all components of a color.
Color multiplication and division
We would like to be able to take a color and make it more or less vibrant by multiplying or dividing it by a floating point value. Since we do not have access to the standard library, we will implement traits coming directly from core::ops instead of importing them from std::ops.
However, in no_std mode we do not have access to some standard operations on floating point operands, such as f32::round(). We will have to use an external crate such as micromath to get those operations.
❎ Add the micromath crate to your project, and use micromath::F32Ext in your image module to get common operations back.
❎ Implement the trait core::ops::Mul<f32> on Color and make it return another Color whose individual components are multiplied by the given floating point value. You might want to use a helper function to ensure that each component stays within the range of an u8. Make sure you properly round to the closest value. Also, f32::clamp() might be of some use.
❎ Implement the trait core::ops::Div<f32> on Color and make it return another Color whose individual components are divided by the given floating point value. Note that you can use the multiplication defined above to implement this more concisely.
That's it, our Color type is complete.
🦀 Note on traits, visibility, and namespace pollution
When you
use micromath::F32Ext;, you bring theF32Exttrait into the current namespace. This trait declares methods such asround(), and it is implemented on thef32type. So importingF32Extinto the current namespace makes theround()method available onf32values.But note that altough you do not use the
F32Extname explicitely in your code, you still "pollute" your namespace with this name. To prevent this, you might import theF32Exttrait but bind it to no name by renaming it to_:// Import the F32Ext trait without importing the F32Ext name use micromath::F32Ext as _;