Rotate The Rectangle in GDI - winapi

I am using the windows GDI API ExtTextOut function to draw text like this:
ExtTextOut(hDC, 2000, 2000, 0, &stRect, PrintText, TextOutLen, aiCharCellDistances);
I am trying to rotate the text, and I do rotate the text. But when I fill the rectangle with colors, I found that the rectangle didn't rotate with the text.
Is there any way to rotate the rectangle with the text? Or is there a better way to do this?
P.S.: My goal is to draw text in the rectangle (like text area) and can rotate it in any angle, and set background color, border line, line break, align right, etc.
Thanks!

It's not 100% clear what you want, but I think you want to draw some text and rectangle rotated at the same angle? If so, it's probably easiest to use SetWorldTransform to do the job.
Here's some code doing it with MFC:
double factor = (2.0f * 3.1416f)/360.0f;
double rot = 45.0f * factor;
// Create a matrix for the transform we want (read the docs for details)
XFORM xfm = { 0.0f };
xfm.eM11 = (float)cos(rot);
xfm.eM12 = (float)sin(rot);
xfm.eM21 = (float)-sin(rot);
xfm.eM22 = (float)cos(rot);
pDC->SetGraphicsMode(GM_ADVANCED);
pDC->SetWorldTransform(&xfm); // Tell Windows to use that transform matrix
pDC->SetBkMode(TRANSPARENT);
CRect rect{ 290, 190, 450, 230 };
CBrush red;
red.CreateSolidBrush(RGB(255, 0, 0));
pDC->FillRect(rect, &red); // Draw a red rectangle behind the text
pDC->TextOut(300, 200, L"This is a string"); // And draw the text at the same angle
For the most part, doing this without MFC just means changing pDC->foo(args) to foo(dc, args).
The result looks like this:
Note that in this case, you do not need to specify rotation (at all--either lfRotation or lfEscapement) for the font you use. You just draw like it was normal text, and the world transform handles all the rotation.

Related

How can I display text always in front on a 3D plot?

I have a complex 3D plot with some text on rollover. It's already a bit cluttered so I'd like to have the text always be in front of all the plot parts. Like here:
Right now, when I hover over some points in the background, the text is sometimes hidden behind plot components, like here:
How can I force the text to always be in the front and facing the camera (which it already is right now).?
Use pushMatrix()/popMatrix() to isolate coordinate spaces: one for the 3D graphics, another for the 2D elements on top:
void setup(){
size(300, 300, P3D);
sphereDetail(9);
noFill();
stroke(255);
textSize(21);
textAlign(CENTER);
}
void draw(){
background(0);
// 3D
pushMatrix();
translate(width * 0.5, height * 0.5, 0);
rotateX(map(mouseY, 0, height, -PI, PI));
rotateY(map(mouseX, 0, width, PI, -PI));
sphere(150);
popMatrix();
// 2D
pushMatrix();
text((int)frameRate, mouseX, mouseY);
popMatrix();
}
(The indenting is not required, just visually emphasising coordinate space nesting.
The last push/pop may not be needed for such as simple example, but is useful if you have more 2D/3D things happening on top of what's already been drawn)
For more info checkout the 2D Transformations Tutorial.
Additionally you might find the PeasyCam library useful.
To draw 2D text on top you'd do something like:
camera.beginHUD();
// draw 2D overlays here
camera.endHUD(); // back to 3D

Natural Color Mixing in Processing

I am trying to naturally mix green tint on one photo (elephant) and red tint on another photo (ship) by placing the two opaque and tinted photos on top of one another. While both photos appear with equal prominence, when the program is run and both colors can be observed, the red tint (because it is the last tint applied) is more dominant and there is no discernable yellow color in the image no matter which tint is applied first. If anyone knows how to naturally mix colors in processing I would love to hear your advice. I also do not want to simply apply a yellow tint as the last tint. Thanks!
PImage elephant;
PImage ship;
void setup(){
size(695,473);
elephant = loadImage("elephantRider.png");
ship = loadImage("ship.jpg");
ship.filter(OPAQUE);
elephant.filter(OPAQUE);
}
void draw(){
background(255);
tint(0,255,0, 127);
image(elephant, 0,0);
tint(255,0,0,127);
image(ship, 0,0);
}
Think of Processing as painting. What you're doing now is a little bit like drawing one color to the screen, and then drawing another color on top of the first color.
Instead, what you want to do is mix the two colors together before you draw the result to the screen. Think of this as mixing two paints together to make a new color.
You can do this by taking the average of the two colors, something like this:
PImage img;
void setup() {
size(695, 473);
img = loadImage("image.jpg");
}
void draw() {
background(255);
//green
tint(0, 255, 0, 127);
image(img, width/2, height/2, 50, 50);
float blendedRed = (0 + 255) / 2;
float blendedGreen = (255 + 0) / 2;
float blendedBlue = (0 + 0) / 2;
// blended
tint(blendedRed, blendedGreen, blendedBlue, 127);
image(img, mouseX, mouseY, 50, 50);
}
This example is a little contrived because the averages are pretty trivial, but this approach should work for any color.
If you want something more advanced, note that color averaging is a pretty advanced topic. Googling "color averaging" is probably a good start.

How to make the blend mode MULTIPLY not make all the image black in p5js

I have this codepen: https://codepen.io/giorgiomartini/pen/OjQpKd?editors=0010
Where I paint some shapes and some text, now I want to add a radial overlay between the shapes and the text.
So I created a drawgradient function and call it between the shapes and the text:
function drawGradient() {
blendMode(MULTIPLY)
for (let r = canvasX; r > 0; --r) {
let lightnes = map(r,0,canvasX,255,0)
fill(0, 0, lightnes)
ellipse(0, 0, r*1.8, r*2)
}
}
I want this gradient to have a multiply blend mode, so that it makes the whole thing a bit darker where the pixels are darker in the gradient.
But all i get is a full black overlay...
In photoshop or gimp, if you add a black and white radial gradient with a multiply blend mode it makes the background darker where there are darker pixles in the gradient.. but here in p5js it just makes everything black.
any ideas what am I doing wrong?
This is the mouseClicked function, and at the bottom, you can see the gradient function being called:
function mouseClicked(){
blendMode(BLEND)
const colsArray = randomColor({luminosity: 'light', format: 'hsl',count: 4})
background(colsArray[0])
translate(width/2, height/2)
////////////////////////////////////////////////////////////////// amt initial range
const arrayOfRandomNumsOfFirstProbStepX = createArrayOfRandomNums(amtOfSpotsInFirstProb,startProbStep,firstProbStepX)
const arrayOfRandomNumsOfFirstProbStepY = createArrayOfRandomNums(amtOfSpotsInFirstProb,startProbStep,firstProbStepY)
const arrayOfRandomNumsOfSecondProbStepX = createArrayOfRandomNums(amtOfSpotsInSecondProb,startProbStep,secondProbStepX)
const arrayOfRandomNumsOfSecondProbStepY = createArrayOfRandomNums(amtOfSpotsInSecondProb,startProbStep,secondProbStepY)
drawLinesAtRandomspots(6,random(50),colsArray)
//args => element, arrayOfRandomNumsOfProbStepX, arrayOfRandomNumsOfProbStepY, elmntSizeMin, elmntSizeMax,rot, colors
drawElmntsOnSomeProbabilityStep('ellipse',arrayOfRandomNumsOfFirstProbStepX, arrayOfRandomNumsOfFirstProbStepY , 10, 80, true, colsArray )
drawElmntsOnSomeProbabilityStep('rect',arrayOfRandomNumsOfSecondProbStepX, arrayOfRandomNumsOfSecondProbStepY, 5, 30, true, colsArray)
drawGradient()
addText()
}
Placing clear() at the beginning of the draw() function will clear the pixels within a buffer. This lets you use blendMode(MULTIPLY) without your overlapping shapes turning black after the first few frames.
If the effect you're going for is a linear gradient, it seems a little weird that you're drawing a bunch of ellipses to the screen.
ellipse(0, 0, r*1.8, r*2)
What do you expect this line to do?
Instead, I would think it would make more sense if you would draw a series of lines, a little bit darker or lighter each time. Here's an example:
function drawGradient() {
blendMode(MULTIPLY);
for (let lineX = 0; lineX < width; lineX++) {
let lightness = map(lineX, 0, width, 0, 255);
stroke(0, lightness)
line(lineX, 0, lineX, height)
}
}
This creates a horizontal gradient that fades from light to dark.
Edit: If you want a radial gradient, right now you're drawing a ton of dark circles on top of each other, so they're "stacking" to just become entirely black. You need to do a combination of drawing fewer circles (every 10 pixels instead of every 1 pixel, for example) and drawing them lighter. Here's an example:
function drawGradient() {
blendMode(MULTIPLY);
for (let r = 600; r > 0; r-=10) {
let lightness = map(r, 0, 600, 20, 0);
fill(0, lightness);
noStroke();
ellipse(0, 0, r, r);
}
}
This code draws circles every 10 pixels, and the darkest circle has an alpha of 20 instead of 255. This causes a much lighter gradient. You'll have to play with the exact values to get the effect you're going for.
If you have a follow-up question, please post a MCVE instead of your whole project. Just a couple of hard-coded shapes and a single gradient function would be enough, as long as we can run it. As of now your code is a little hard to debug because it contains a bunch of stuff not directly related to the problem. Good luck.

Flip image with different size width smooth transition

I'm trying to flip some animations in LibGDX, but because they are of different width, the animation plays weird. Here's the problem:
(the red dot marks the X/Y coordinate {0,0})
As you can see, when the animation plays "left" when you punch, the feet starts way behind than were it was, but when you punch right, the animations plays fine because the origin of both animations is the left corner, so the transition is smooth.
The only way I think of achieving what I want is to see what animation is playing and adjust the coordinates accordingly.
This is the code:
public static float draw(Batch batch, Animation animation, float animationState,
float delta,
int posX, int posY, boolean flip) {
animationState += delta;
TextureRegion r = animation.getKeyFrame(animationState, true);
float width = r.getRegionWidth() * SCALE;
float height = r.getRegionHeight() * SCALE;
if (flip) {
batch.draw(r, posX + width, posY, -width, height);
} else {
batch.draw(r, posX, posY, width, height);
}
return animationState;
}
Any suggestion is welcome as how to approach this.
Use some other batch.draw option (with other parameters). You can set "origin" parameters. It's like a hot spot...center of the image... So if you i.e. rotate, rotation will be done around that hot spot.
https://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g2d/Batch.html
I didn't use it for flipping, but it should work the same way. But if it doesn't then you have to adjust coordinates on your own, make some list with X offset for every frame and add it for flipped images.
Other solution would be to have wider frame images and keep center of the character always match the center of the image. That way your images will be wider then they have to - you'll have some empty space, but for sane number of frame it's acceptable.

HTML5 Canvas Image Rotation

I have a canvas where i have drawn a series of images onto it that can be dragged and dropped around, each image is a seperate entity.
I need to, depending on where the image is dropped rotate that image so that it looks appropiate, imaging dragging a triangle around a circle, the base line needs to always point outwards.
I thought i would be able to rotate the image and then draw that on the canvas, but what i seem to find when searching on the internet is that the canvas rotates each time - is it possible to rotate the image only and then place it on the canvas?
Many Thanks!
Yes you can, but it's not as simple as setting a rotation attribute. The way canvas works you can't rotate individual items specifically, only the whole canvas.
To rotate a single item, you'll need to rotate the canvas, place the item, and then rotate the canvas back to it's original orientation.
This question has a few examples: How do I rotate a single object on an html 5 canvas?
Before placing the image on the canvas, create a buffer canvas, place image there, rotate it and then port to main canvas.
var canvas = document.getElementById('test_canvas');
var ctx = canvas.getContext('2d');
var buffer = document.createElement('canvas');
buffer.width = buffer.height = 60;
var bctx = buffer.getContext('2d');
bctx.translate(30, 30);
bctx.rotate(0.5);
bctx.fillStyle = 'rgb(255, 0, 0)';
bctx.fillRect(-15, -15, 30, 30);
ctx.fillStyle = 'rgb(0, 255, 0)';
ctx.fillRect(30, 30, 30, 30);
ctx.drawImage(buffer, 50, 50);
You can check this code at JSFiddle I've setup - http://jsfiddle.net/dzenkovich/UdaUA/2/
Note you'll need to keep a close eye at the rotation point and buffer canvas size for this to work.
For more info check out this article I've found http://creativejs.com/2012/01/day-10-drawing-rotated-images-into-canvas/

Resources