i would like to implement 'drawing modes' (in my own graphics library).
That is drawing with AND, OR, etc
However i am storing colors using floats, each channel between 0 and 1.0
Do i have to first convert each color channel to 0-255 before i can use the AND, OR, etc drawing modes? and then convert back to float (0.0-1.0) ?
Or is there another way of doing it?
thanks
I believe the question is not clear enough. AND, OR, etc. are boolean operators. Many languages support bitwise versions as well. So, you first need to define what exactly is the meaning of AND-ing or OR-ing two color values. What is Red AND Green? Is it Black?
If the answer to the above question is positive, then you probably want to apply these operators in the bitwise sense on the (integer) RGB representation of your colors. In this case, you do need to:
1. Convert the floats to (8-bit or other resolution) integers
2. Pack the 3 channels (or 4 with Alpha) into one word (probably 32-bit integer)
3. Apply the bitwise operator
4. Unpack the channels and convert back to floats.
Note that in conversion of floats to int you first need to multiply your float value by MAX_COLOR (255 in your example), and then cast. Otherwise, you end up with all channels being 0. Opposite when you convert back to floats, first cast then divide by MAX_COLOR to normalize your values.
Related
QColor can return rgba values of type int (32-bit signed integer). Why is that? The color values range from 0-255, don't they? Is there any situation where this might not be the case?
I'm considering to implicitly cast each of the rgba values returned by QColor.red()/green()/blue()/alpha() to quint8. It seems to work but I don't know if this will lead to problems in some cases. Any ideas?
I assume you are talking about QColor::rgba() which returns a QRgb.
QRgb is an alias to unsigned int. In these 32 bits all fours channels are encoded as #AARRGGBB, 8 bits each one (0-255, as you mentioned). So, a color like alpha=32, red=255, blue=127, green=0 would be 0x20FF7F00 (553615104 in decimal).
Now, regarding your question about casting to quint8, there should be no problem since each channel is guaranteed to be in the range 0..255 (reference). In general, Qt usually uses int as a general integer and do not pay too much attention to the width of the data type, unless in some specific situations (like when it is necessary for a given memory access, for example). So, do not worry about that.
Now, if these operations are done frequently in a high performance context, think about retrieving the 32 bits once using QColor::rgba and then extract the components from it. You can access the individual channels using bitwise operations, or through the convenience functions qAlpha, qRed, qBlue and qGreen.
For completeness, just to mention that the sibbling QColor::rgb method returns the same structure but the alpha channel is opaque (0xFF). You also have QColor::rgba64, which returns a QRgba64. It uses 16 bits per channel, for higher precision. You have the 64 bits equivalents to qAlpha, etc, as qAlpha64 and so on.
I'm trying to understand glVertexAttribPointer, and I noticed that it accepts many more types than those that have an equivalent in GLSL. So to write down everything I know so far, I made this diagram matching all the types (except for the packed ones, which don't matter, and GL_FIXED, which I don't understand.
Blue nodes represent the type in GLSL, while yellow nodes represent the symbolic constants passed to glVertexAttribPointer.
Red nodes represent some kind of conversion between types.
Each yellow node is only directly connected to one blue node, what seems to be its main representation in GLSL, but some can be converted to some other form.
So I guess my question is: Are the relationships in this diagram correct, and how does GL_FIXED fit into it?
No.
You cannot feed a VS int, uint, or double input variable (or vectors of these) from a call to glVertexAttribPointer. This function only feeds float types. If you use non-normalized integers with this function, then they will be cast to floats as if by a standard cast operation (255 becomes 255.0f). GL_FIXED is just another floating-point representation, where a 32-bit integer is treated as a 16.16 fixed-point value. Naturally, this will be converted to a floating-point number when fed to the VS.
To feed the VS integers, you must use glVertexAttribIPointer. To feed doubles, you must use glVertexAttribLPointer.
bool types cannot be input variables of any kind.
The OpenGL documentation says very little about these two functions. When it would make sense to use glTexParameterIiv instead of glTexParameteriv or even glTexParameterfv?
If the values for GL_TEXTURE_BORDER_COLOR are specified with glTexParameterIiv or glTexParameterIuiv, the values are stored unmodified with an internal data type of integer. If specified with glTexParameteriv, they are converted to floating point with the following equation: f=(2c+1)/(2b−1). If specified with glTexParameterfv, they are stored unmodified as floating-point values.
You sort of answered your own question with the snippet you pasted. Traditional textures are fixed-point (unsigned normalized, where values like 255 are converted to 1.0 through normalization), but GL 3.0 introduced integral (signed / unsigned integer) texture types (where integer values stay integers).
If you had an integer texture and wanted to assign a border color (for use with the GL_CLAMP_TO_BORDER wrap mode), you would use one variant of those two functions (depending on whether you want signed or unsigned).
You cannot filter integer textures, but you can still have texture coordinate wrap behavior. Since said textures are integer and glTexParameteriv (...) normalizes the color values it is passed, an extra function had to be created to keep the color data integer.
You will find this same sort of thing with glVertexAttribIPointer (...) and so forth; adding support for integer data (as opposed to simply converting integer data to floating-point) to the GL pipeline required a lot of new commands.
What is the advantage or need of integer and SNORM textures? when do we use (-1,0) range for textures?
Any example where we need specifically integer or SNORM textures?
According to https://www.opengl.org/registry/specs/EXT/texture_snorm.txt,
signed normalized integer texture formats are used to represent a floating-point values in the range [-1.0, 1.0] with an exact value of floating point zero.
It is nice for storing noise, especially Perlin.
Better than float textures because no bits wasted on the exponent.
Unfortunately, as of GL4.4 none of the snorm formats can be rendered to.
You can use the unorm formats and *2-1 for the same effect, although there may be issues with getting an exact 0.
I have some code that is acting up and I suspect it's because I'm operating on the wrong types of data or converting between them poorly.
It is mixing cv::Mat objects of types CV_8U (which is what is created when reading a jpg as grayscale with cv::imread), CV_32F, and CV_32S.
What are the differences between these data types, and what do I need to be sure of when converting between them?
CV_8U is unsigned 8bit/pixel - ie a pixel can have values 0-255, this is the normal range for most image and video formats.
CV_32F is float - the pixel can have any value between 0-1.0, this is useful for some sets of calculations on data - but it has to be converted into 8bits to save or display by multiplying each pixel by 255.
CV_32S is a signed 32bit integer value for each pixel - again useful of you are doing integer maths on the pixels, but again needs converting into 8bits to save or display. This is trickier since you need to decide how to convert the much larger range of possible values (+/- 2billion!) into 0-255
Basically they just describe what the individual components are:
CV_8U: 1-byte unsigned integer (unsigned char).
CV_32S: 4-byte signed integer (int).
CV_32F: 4-byte floating point (float).
What you always have to keep in mind is that you cannot just cast them from one into the other (or it probably won't do what you want), especially between differently sized types.
So always make sure you use real conversion functions for converting between them, like cv::convert or cv::Mat::convertTo. Don't just try to access the elements of e.g. a cv::Mat of CV_8U type using e.g. cv::Mat::at<float> or cv::Mat_<float>.
Or if you just want to convert individual elements and don't want to create a new matrix of the other type, access the elements using the appropriate function (in the example cv::Mat::at<unsigned char>) and convert the result to float.
Likewise is there also a difference between the number of components and a cv::Mat of CV_8UC3 type is different from an image of CV_8UC1 type and should (usually) not be accessed by cv::Mat::at<unsigned char>, but by cv::Mat::at<cv::Vec3b>.
EDIT: Seeing Martin's answer it may be that you are aware of this all and his explanations are more what you have been looking for.