C++ DirectX DrawText in multiple colors - c++

I use ID3DXFont interface to draw text and that perfectly suits my needs as long as complete string is in single color. Now I'd wish to draw a string but in multiple colors. For instance "abc", with a in red, b in yellow, etc.
I know that I could draw each letter on its own, giving a different Color parameter to DrawText each time. The only issue with this is that I do not know how many pixels should I offset after each letter because every letter has a different width. Hardcoding widths is not really a good solution.

The ID3DXFont interface doesn't allow you to draw multiple colors within a single invocation of DrawText. However, it can give you the bounding rectangles of any text that you wish to draw using the DT_CALCRECT flag, so you do not need to hardcode widths of particular glyphs within your font. This also means you can switch the font and/or size of the font without needing to modify your drawing code, or hardcoding new width. For example:
ID3DXFont* font = ...;
const char* strings[] = { "A", "i", "C" };
D3DCOLOR colors[] = { D3DCOLOR_ARGB(255, 255, 0, 0), D3DCOLOR_ARGB(255, 0, 255, 0), D3DCOLOR_ARGB(255, 0, 0, 255) };
RECT r = { 10,10,0,0}; // starting point
for (int i = 0; i < _countof(strings); ++i)
{
font->DrawText(NULL, strings[i], -1, &r, DT_CALCRECT, 0);
font->DrawText(NULL, strings[i], -1, &r, DT_NOCLIP, colors[i]);
r.left = r.right; // offset for next character.
}
Note: I have used 'i' instead of 'b' from your example, because it makes it apparent that the rectangles are correct, as 'i' is (generally) a very thin glyph. Also note that this assumes a single line of text. The calculated rectangle also includes height, so if you are doing multiple lines, you could also use the height of the calculated rectangle to offset the position.

Related

How to automatically adjust width for text with SDL2_TTF

I'm working on a score display for my simple 2d SDL_2 Game.
This is the part of my code where I display the speed (basically just score):
void Renderer::renderText(const char* text, SDL_Rect* destR)
{
SDL_Surface* surfaceText = TTF_RenderText_Solid(Renderer::font, text, { 255,255,255 });
SDL_Texture* textureText = SDL_CreateTextureFromSurface(renderer, surfaceText);
SDL_FreeSurface(surfaceText);
SDL_RenderCopy(renderer, textureText, NULL, destR);
SDL_DestroyTexture(textureText);
}
There is the obvious problem that if I have a width for the number "1", the text would be squished a lot of the number was "10000" etc as you would have to fit 5 characters into an SDL_Rect that is only 1 character wide.
I could multiply the width by the number of characters however that wouldn't be very accurate as different characters have different widths.
How would I solve this?
(I only answered this because I found out how and nobody else answered)
You can do something like this.
SDL_Rect destR = { x, y, 0, 0 };
TTF_SizeText(font, text, &destR.w, &destR.h);
Basically, TTF_SizeText enables you to get the native width and height from the text with font. Then you can just multiply the height and width as you wish.

What is a good way to store color?

I started to make "game of life" and I thought, what if I could have more states than 1 or 0.
But then I need different colors. I want the colors to be linked to a grid/object (the grid is a class).
What is a good/decent way to store color pallets for fast/easy access?
My current less than ideal solution was to have 4 pointers to memory for each red, green, blue and alpha value.
In my class I had a function to set the color of value v to rgba:
SetColor(v, r, g, b, a) //Set v to the appropriate color values
I would like to keep this function to easily modify a color.
What I use is something really simple: 4 floats
struct Color {
float r, g, b, a;
};
Then, you can have something like a color pallete:
// a Palette of 8 colors:
using palette_t = std::array<Color, 8>
palette_t myPalette { /* ... */ };
Then, in your grid or object class, you can reference the color with an index:
struct Grid {
// lot's of code
private:
std::size_t colorIndex = 0;
};
But then you asked how to have easy access to the color (I guess the easy access is from within the Grid class)
There is a lot of solution that can exists, and most will depend of your project structure. This is one idea many others. I hope it will inspire you.
You can store a function that return the right color:
struct Grid {
// lot's of code
private:
std::size_t colorIndex = 0;
std::function<Color(std::size_t)> color;
};
And then, have something that create your grid correctly:
struct GridCreator {
GridCreator(const palette_t& aPalette) : palette{aPalette} {}
Grid create(std::size_t color) const {
Grid grid;
// create the grid
grid.color = [this](std::size_t index) {
return palette[index];
};
return grid;
}
private:
const palette_t& palette;
};
Then you got free access to your color palette without directly knowing that the palette exists from the Grid class.
Have an array of colors:
std::vector<std::array<unsigned char, 4>> palette {
{255, 0, 0, 255}, // red
{0, 255, 0, 255}, // green
{0, 0, 255, 255}, // blue
};
Then for each field store the index in the array (of type size_t). Example:
auto id = field[5][2];
auto color = palette[id];
auto r = color[0], alpha = color[3];
Changing a color is as simple as:
palette[id] = {255, 0, 0, 127};
For adding new colors, use:
palette.push_back({255, 0, 0, 127}).
Alternatively, you can define a simple struct so that you can use color.r, color.alpha etc. and write a constructor for easy color creation.
Mind this example is C++11 code.
Enums are perfect for Colors kind of structure.
More code readability.
Better compiler-time optimizations.
enum Color { red, green, blue };
Color r = red;
switch(r)
{
case red : std::cout << "red\n"; break;
case green: std::cout << "green\n"; break;
case blue : std::cout << "blue\n"; break;
}
For your special case.
You can store color for each point as a single integer.
uint32_t point_color = field[5][2].color;
unsigned char* color = (unsigned char*)point_color[id];
auto r = color[0], alpha = color[3];
/////
void SetColor(uint32_t& point_color,unsigned char r,
unsigned char g,unsigned char b,unsigned char a){
point_color=r | (b*(1<<8)) | (g*(1<<16)) | (a*(1<<24));
}
Pros of this structure
lesser messy.
faster bit operations only.
lesser memory.
Your question is dualistic:
What is a good way to store color?
what is a good/decent way to store color pallets?
If you really only want to store a colour, my advise would be not to store the colours as references, but to store the RGB values in one INT32 inside a class where you can get and set the Reg / Green / Blue values. Compare this with how .NET does this.
The advantage of this method is that it does no more space than using pointers and it is fast in get / set / comparisons.
A color pallette is a collection of colours. This is quite often used if you want to switch all used colours into a different colour. For instance if you want all light-blue colours in to misty-blue colours, and all fire-red colours into brick-red.
This is used by defining a palette as a pre-defined sized array or RGB values. Historically a palette contains 16, 64, or 256 values, or sometimes 2 if you only want black/white pictures.
If you use a palette, every dot in your grid has an index in your palette array and your grid has a current pallette. The RGB value of point X of grid G is then G.CurrentPallette[X.PaletIndex]. Changing all colours of your grid at once means switching to a different palette: G.CurrentPalette = otherPalette. This is a really fast and efficient way of changing the colours in your grid
Whether to use the RGB method or the Palette method depends on what you want:
Do you only want to use a subset of all possible colours, and do you want to change the complete subset into a different subset: use the Palette method
Do you want to change the colour of dots with a certain state, for instance change all yellow dots to green, use the palette method: change the color yellow in your palette to green
However, if you only want to change individual dots on your grid it is probably more efficient to use the RGB method.
any color value has an interval from 0 through 255 so you need 3 unsigned char variables and another one for alph. we make a whole thing, mapping them an a struct:
typedef struct Color
{
unsigned char _ucRed;
unsigned char _ucGreen;
unsigned char _ucBlue;
unsigned char _ucAlpha;
}COLOR;

Drawing points of handwritten stroke using DrawEllipse (GDI+)

I'm working on an application that draws handwritten strokes. Strokes are internally stored as vectors of points and they can be transformed into std::vector<Gdiplus::Point>. Points are so close to each other, that simple drawing of each point should result into an image of continual stroke.
I'm using Graphics.DrawEllipse (GDI+) method to draw these points. Here's the code:
// prepare bitmap:
Bitmap *bitmap = new Gdiplus::Bitmap(w, h, PixelFormat32bppRGB);
Graphics graphics(bitmap);
// draw the white background:
SolidBrush myBrush(Color::White);
graphics.FillRectangle(&myBrush, 0, 0, w, h);
Pen blackPen(Color::Black);
blackPen.SetWidth(1.4f);
// draw stroke:
std::vector<Gdiplus::Point> stroke = getStroke();
for (UINT i = 0; i < stroke.size(); ++i)
{
// draw point:
graphics.DrawEllipse(&blackPen, stroke[i].X, stroke[i].Y, 2, 2);
}
At the end I just save this bitmap as a PNG image and sometimes the following problem occurs:
When I saw this "hole" in my stroke, I decided to draw my points again, but this time, by using ellipse with width and height set to 1 by using redPen with width set to 0.1f. So right after the code above I added the following code:
Pen redPen(Color::Red);
redPen.SetWidth(0.1f);
for (UINT i = 0; i < stroke.size(); ++i)
{
// draw point:
graphics.DrawEllipse(&redPen, stroke[i].X, stroke[i].Y, 1, 1);
}
And the new stoke I've got looked like this:
When I use Graphics.DrawRectangle instead of DrawEllipse while drawing this new red stroke, it never happens that this stroke (drawn by drawing rectangles) would have different width or holes in it:
I can't think of any possible reason, why drawing circles would result into this weird behaviour. How come that stroke is always continual and never deformed in any way when I use Graphics.DrawRectangle?
Could anyone explain, what's going on here? Am I missing something?
By the way I'm using Windows XP (e.g. in case it's a known bug). Any help will be appreciated.
I've made the wrong assumption that if I use Graphics.DrawEllipse to draw a circle with radius equal to 2px with pen of width about 2px, it will result in a filled circle with diameter about 4-5 px being drawn.
But I've found out that I actually can't rely on the width of the pen while drawing a circle this way. This method is meant only for drawing of border of this shape, thus for drawing filled ellipse it's much better to use Graphics.FillEllipse.
Another quite important fact to consider is that both of mentioned functions take as parameters coordinates that specify "upper-left corner of the rectangle that specifies the boundaries of the ellipse", so I should subtract half of the radius from both coordinates to make sure the original coordinates specify the middle of this circle.
Here's the new code:
// draw the white background:
SolidBrush whiteBrush(Color::White);
graphics.FillRectangle(&whiteBrush, 0, 0, w, h);
// draw stroke:
Pen blackBrush(Color::Black);
std::vector<Gdiplus::Point> stroke = getStroke();
for (UINT i = 0; i < stroke.size(); ++i)
graphics.FillEllipse(&blackBrush, stroke[i].X - 2, stroke[i].Y - 2, 4, 4);
// draw original points:
Pen redBrush(Color::Red);
std::vector<Gdiplus::Point> origStroke = getOriginalStroke();
for (UINT i = 0; i < origStroke.size(); ++i)
graphics.FillRectangle(&redBrush, origStroke[i].X, origStroke[i].Y, 1, 1);
which yields following result:
So in case someone will face the same problem as I did, the solution is:

C++/CLI Visual C++ 2010 Express - Drawing multiple ellipses

I want to draw multiple filled ellipses on/in some panel. Drawing single one isnt problem, i am using:
Color aColor = Color::FromArgb( 255, 0, 0 );
SolidBrush^ aBrush = gcnew SolidBrush(aColor);
Rectangle rect = Rectangle(x, y, 10, 10);
e->Graphics->FillEllipse(aBrush, rect);
It draws red ellipse bordered by rectangle, and fills it with red color. (assuming i will give x and y). The problem i met, is when I want to draw multiple ellipses like that, in RANDOM places. So i need to pass random x and y (using rand() % somenumber) but i am not sure, how can i pass these variables into the panel1_paint function and draw them when both numbers are randomized. Also, ofc i dont want the last ellipse to disappear when drawing new one. The only way is using global variables?
Any ideas?
Well, i tried as suggested, to use loop inside panel and i got that:
for(int i=0; i<ile_przeszkod; i++){
int x = rand() % 690; int y = rand() % 690;
Color aColor = Color::FromArgb( 255, 0, 0 );
SolidBrush^ aBrush = gcnew SolidBrush(aColor);
Rectangle rect = Rectangle(x, y, 10, 10);
e->Graphics->FillEllipse(aBrush, rect);
MessageBox::Show("x: "+x+ " y: " +y);
}
ile_przeszkod means how many of them i want to be drawn, and message box showes me what numbers it randomized so i am sure ellipses dont overlap. The problem is, after "invalidating" panel1 i see only 1 ellipse. :/ What should i do to see both of them?
all the x, y coordinates are random , so they don't depend on some other deciding procedure, So that need not to be passed to panel1_paint rather you can run a lpop and generate random number to use them as your x, y coordinates.

How do I create a color bar (TV test pattern)

I need to create a colorbar like THIS
I use a scaled array of floats between 0 and 1.
Now I want to compute the RGB color from this float. How to do it? Want to write it in C/c++ so I think I need 2 functions.
The first function to build the colorbar with one parameter like STEPSIZE and the second function need the value and must just return the array index of the colorbar.
I couldn't find it on google, so please help me.
What you are referring to here is the 100% EBU Color Bars (named after the standards body, the European Broadcasting Union). This is not the same as the full SMPTE RP 219-2002 color bars, which have other features including gradients and the PLUGE (Picture Line-Up Generation Equipment), described in the Wikipedia article on Color Bars.
The EBU Color Bars consist of 8 vertical bars of equal width. They are defined in the same way for both SD and HD formats. In the RGB color space, they alternate each of the red, green and blue channels at different rates (much like counting in binary) from 0 to 100% intensity. Counting down from white, in normalised RGB form (appearing left to right):
1, 1, 1: White
1, 1, 0: Yellow
0, 1, 1: Cyan
0, 1, 0: Green
1, 0, 1: Magenta
1, 0, 0: Red
0, 0, 1: Blue
0, 0, 0: Black
So the blue channel alternates every column, the red channel after two columns, and the green after four columns. This arrangement has the useful property that the luminance (Y in YCb'Cr' colour space) results in a downward stepping plot.
To render using 8-bit RGB (most commonly found in desktop systems), simply multiply the above values by 255. The EBU bars come in 75% and 100% variants, based on the intensity of the white column. The SMPTE color bars typically use 75% levels as a reference.
Here is some simple C code to generate 100% EBU color bars and save the result as a PGM file:
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
// PAL dimensions
static const unsigned kWidth = 720;
static const unsigned kHeight = 576;
typedef struct
{
uint8_t r;
uint8_t g;
uint8_t b;
} RGB;
int main(int argc, char* argv[])
{
const RGB BAR_COLOUR[8] =
{
{ 255, 255, 255 }, // 100% White
{ 255, 255, 0 }, // Yellow
{ 0, 255, 255 }, // Cyan
{ 0, 255, 0 }, // Green
{ 255, 0, 255 }, // Magenta
{ 255, 0, 0 }, // Red
{ 0, 0, 255 }, // Blue
{ 0, 0, 0 }, // Black
};
// Allocate frame buffer
size_t frameBytes = kWidth*kHeight*sizeof(RGB);
RGB* frame = malloc(frameBytes);
unsigned columnWidth = kWidth / 8;
// Generate complete frame
for (unsigned y = 0; y < kHeight; y++)
{
for (unsigned x = 0; x < kWidth; x++)
{
unsigned col_idx = x / columnWidth;
frame[y*kWidth+x] = BAR_COLOUR[col_idx];
}
}
// Save as PPM
FILE* fout = fopen("ebu_bars.ppm", "wb");
fprintf(fout, "P6\n%u %u\n255\n", kWidth, kHeight);
fwrite(frame, frameBytes, 1, fout);
fclose(fout);
free(frame);
return 0;
}
This should be readily adaptable to any other language. There's probably no need for using float unless you're implementing this on a GPU (in which case the algorithm would be quite different). There is much scope for optimization here; the code is written for clarity, not speed.
Note that while it is possible to generate a perfect digital representation of the color bars in a computer, this will not be safe for broadcast. The transitions between "perfect" color bars would require infinitely high bandwidth to accurately represent. So if the test image is to be transmitted via analog broadcast equipment, it must be bandwidth-limited by a low-pass filter (eg. ~4.3MHz for PAL). This is why you notice the "fuzzy" boundaries in between each column; these contain intermediate values between the pure colors.
Also note that it is not possible to accurately represent the SMPTE color bars in the RGB color space. This is because certain critical values are specified in the YCb'Cr' color space (notably in the PLUGE region) which are outside the gamut of RGB (either SD or HD). You can create something that approximates the values (eg. a very dark blue) but they are not correct. So unless you are representing the test frame in YCb'Cr', stick to EBU bars only (the upper 2/3).
RGB uses bytes, so assuming your array of floats is something like
float scaledColor[3]; // 0 = R, etc., all 0.0 < scaledColor[x] < 1.0
then you can do:
unsigned char r = (unsigned char)(255 * scaledColor[0]);
unsigned char g = (unsigned char)(255 * scaledColor[1]);
unsigned char b = (unsigned char)(255 * scaledColor[2]);
This will of course only work if the values in the floats are really in the range from 0.0 to 1.0.
The simplest solution:
const unsigned char* getColour(float x) /* 0 <= x < 1 */
{
static const unsigned char bar[][3] = {
{255,255,255},
{255,255,0},
// ... fill in all the colours ...
{0,0,0}
};
return bar[(int)(x*sizeof(bar))];
}
Then you can use it to generate bars of any width.
My google-fu turned up that you want the upper third of a SMPTE color bar pattern.
Wikipedia says:
In order from left to right, the colors are gray, yellow, cyan, green,
magenta, red, and blue.
So the easiest way is to simply hard code the respective RGB color codes if you only need those. The article also mentions how those colors can be generated but this seems a lot more difficult and isn't really worth the effort for seven colors.