SDL Sprite how to set sprite center of origin - 2d

I'm messing around in SDL trying to build a game and have noticed that when I blit a sprite to the screen the origin of the sprite is set to the top left corner, 0,0.
To get around this I've simply adjusted the sprite placement by 1/2 the sprites width but as a solution it feels kind of clunky - I want to build a platform game so surely the COO will need to be at the sprites feet for collision detection with the platforms - and I was wondering if SDL had any functions in place that would allow me to set the center of origin a bit like the sprite editor in construct2.
This is my drawing routine:
// Draws the hero sprite according to clipframe
void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL )
{
//Holds offsets
SDL_Rect offset;
//Get offsets
offset.x = x;
offset.y = y;
//Blit
SDL_BlitSurface( source, clip, destination, &offset );
}
My instantiation of it:
apply_surface(width /2 - heroSpriteSize /2, height /2 - heroSpriteSize /2, hero, buffer, &wait[frame]);

Related

How to size the texture to occupy only a portion of a QQuickItem UI

I have overriden updatePaintNode in the following way to draw an OpenGL texture on a QQuickItem derived class called MyQQuickItem here.
QSGNode *MyQQuickItem::updatePaintNode(QSGNode * oldNode, QQuickItem::UpdatePaintNodeData * /*updatePaintNodeData*/)
{
QSGSimpleTextureNode * textureNode = static_cast<QSGSimpleTextureNode *>(oldNode);
if (!textureNode) {
textureNode = new QSGSimpleTextureNode();
}
QSize size(800, 800);
// myTextureId is a GLuint here
textureNode.reset(window()->createTextureFromId(myTextureId, size));
textureNode->setTexture(my_texture);
textureNode->markDirty(QSGBasicGeometryNode::DirtyMaterial);
QSizeF myiewport = boundingRect().size();
qreal xOffset = 0;
qreal yOffset = 10;
textureNode->setRect(xOffset, yOffset, myViewport.width(), myViewport.height());
return textureNode;
}
This renders the texture content well but covers the whole of my MyQQuickItem UI.
How can reduce the bottom margin of the texture to say fit 80% of the height of MyQQuickItem.
I want to render the texture to a portion of MyQQuickItem & leave the rest blank or black? Is that possible within updatePaintNode.
Note that the texture size is not the UI window size here. My texture size is 800 by 800. Whereas the UI window size is different and depends on the screen.
I found the answer to this:
Changing myViewport.height() gives the required end in Y direction one wishes to set. Similarly, changing myViewport.width() gives the required end in X direction one wishes to set.
4 parameters in TextureNode's setRect can stretch & fit the texture in the way one wishes within a portion of the QQuickItem.

How to disable linear filtering for drawImage on canvas in javafx

I'm trying to draw scaled image on canvas in javafx. Using this code:
Image image = ...;
canvas.setWidth(scale * width);
canvas.setHeight(scale * height);
GraphicsContext gc = canvas.getGraphicsContext2D();
gc.drawImage(image, 0, 0, scale * width, scale * height);
// this gives same result
// gc.scale(scale, scale);
// gc.drawImage(editableImage, 0, 0, width, height);
It works really fast but makes blurred images like this:
This is not what I'd like to see. Instead I want to get this picture:
Which can be drawn by manually setting each pixel color with such code:
PixelReader reader = image.getPixelReader();
PixelWriter writer = gc.getPixelWriter();
for (int y = 0; y < scale * height; ++y) {
for (int x = 0; x < scale * width; ++x) {
writer.setArgb(x, y, reader.getArgb(x / scale, y / scale));
}
}
But I cannot use this approach as it's too slow. It took couple of seconds to draw 1Kb image scaled 8 times. So I ask if there's any way to disable this blurry effect for drawing on canvas?
UPD 10/07/2019:
Looks like the issue is fixed! Now GraphicsContext should have property "image smoothing" controlling this behavior.
INITIAL ANSWER
I guess I've found answer to my question. As this issue says that there's no way to specify filtering options in graphics context.
Description:
When drawing an image in a GraphicsContext using the drawImage()
method to enlarge a small image to a larger canvas, the image is being
interpolated (possibly using a bilinear or bicubic algorithm). But
there are times like when rendering color maps (temperature,
zooplancton, salinity, etc.) or some geographical data (population
concentration, etc.) where we want to have no interpolation at all
(ie: use the nearest neighbor algorithm instead) in order to represent
accurate data and shapes.
In Java2D, this is possible by setting the appropriate
RenderingHints.KEY_RENDERING on the Graphics2D at hand. Currently on
JavaFX's GraphicsContext there is no such way to specify how the image
is to be interpolated.
The same applies when shrinking images too.
This could be expanded to support a better form of smoothing for the
"smooth" value that is available in both Image and ImageView and that
does not seem to work very well currently (at least on Windows).
The issue was created in 2013 but it's still untouched so unlikely it will be resolved soon.

Set QGraphicsTextItem text contents of exact height and width

I am required to create text items with exact width and height of text contents.
The height of the text is the most important requirement.
The position of the text should be relative to the text itself.
I also have to be able to place it on canvas in an exact spot.
Assuming a (printable) canvas (on a larger QGraphicsScene), say 5 inch width and 1 inch height, my text should be able to stretch top-bottom-left-right - and be placed on canvas, not part in part out.
I am sub-classing QGraphicsTextItem for my item type. I am resizing it, using QTransform(), to required size - in inches or mm or pixels (72*in).
Also setting the document() margin to 0, and anything inside (like QTextBlockFormat margins) also to 0.
I have implemented a setItemSize(QSizeF sz) (with sz in pixels), that resizes the QGraphicsTextItem as required.
The sz is initialized using the item bounding rect.
Assuming no wrap, single line text (multi-line could be solved separately once this issue is resolved).
When adding the item to canvas, I still see a top and bottom margin - and this varies based on font choice.
I drew a rectangle around the item to see it.
The top/bottom distances depend on font choices.
I have tried to use font metrics to determine these distances (in paint() I have been drawing lines to try to determine the position and rectangle in which the text fits).
I would be happy to at least be able to determine correct size to use for upper case, no accents or special characters fonts (it would be a start, though naturally I would need to be able to use any characters).
But at least some way to determine the size and position (relative to the (0,0) of item) of the text content even in the simplest case.....
The font metrics tightBoundingRect() seems the most accurate for size, but it seems impossible to determine its position so that I can somehow create my items correctly, and maybe resize/shift them correctly to fit on canvas.
Here are some examples of my struggle to determine at least exact size and position of text, relative to the (0,0) of the item (assuming that once I do that, I am able to expose that info to outside or include the shift in the item transform on resize).
Notice that the size of the text advertised by font metrics does not always cover the text, and for different fonts I am not able to position the tight bounding rect (magenta) around the text itself. (I did multiple guesses, the code below is just one - the lines are trying to show different font metrics sizes).
The above were experiments in paint function of the text item inheriting QGraphicsTextItem:
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
// draw text
QGraphicsTextItem::paint(painter, option, widget);
QPen p;
p.setWidthF(0);
QFontMetricsF fm(this->font());
qreal ascent = fm.ascent(),
descent = fm.descent(),
hheight = fm.height();
QRectF r = QGraphicsTextItem::boundingRect();
QRectF rFont= fm.tightBoundingRect(toPlainText());
qreal xmax = r.right();
painter->save();
painter->setBrush(Qt::NoBrush);
// where is "ascent + descent"
p.setColor(Qt::green);
painter->setPen(p);
painter->drawLine(QPointF(2, ascent), QPointF(2, ascent + descent));
painter->drawLine(QPointF(2, ascent + descent), QPointF(xmax/2, ascent + descent));
// where is "height"
p.setColor(Qt::red);
painter->setPen(p);
painter->drawLine(QPointF(xmax/2, 0), QPointF(xmax/2, hheight));
painter->drawLine(QPointF(xmax/2, ascent + descent), QPointF(xmax, ascent + descent));
// where is "ascent"
p.setColor(Qt::yellow);
painter->setPen(p);
painter->drawLine(QPointF(6, 0), QPointF(6, ascent));
painter->drawLine(QPointF(6, ascent), QPointF(xmax, ascent));
// something that may look like top of the text
p.setColor(Qt::blue);
painter->setPen(p);
qreal yyy = ascent + rFont.y() + 1;
painter->drawLine(QPointF(5, yyy), QPointF(xmax, yyy));
// this should be useful... should be the natural offset
qreal yoffset = (r.height() - rFont.height()) / 2;
// qDebug() << yoffset << r << rFont;
//qreal y0 = (r.height() - fm.height())/2;
p.setColor(Qt::darkGreen);
painter->drawEllipse(10, yoffset, 1, 1);
// where is the font rect
p.setColor(Qt::magenta);
painter->setPen(p);
yoffset = (r.height() + rFont.height()) / 2;
painter->translate(0, yoffset);
painter->drawRect(rFont);
painter->restore();
}
I have also tried not using QGraphicsTextItem, but paint text inside a rectangle. The same thing happens.
(Qt 4.7 - 5.x)
This is not a good solution. This is an attempt to solve my own problem - in a first iteration - of setting text with given width and height, using font metrics.
Reasons for not being good -
Even after resize, text is smaller than desired, I don't understand why
The position is incorrect, based on font style the text can be above or below the canvas, meaning it gets clipped.
I resize it using a factor calculated from the item bounding rect size and the font metrics bounding rect (I used the tight bounding rect for more accurate size).
myText->setItemFontSize(12); // If I use font metrics I need to reset text size on every change, because resizing loses font info
QFontMetricsF fm(myText->font());
QRectF fmRect = fm.tightBoundingRect(myText.toPlainText().toUpper());
// without toUpper() the size is too small - even so it is a bit small
// I read tightBoundingRect is slow - but boundingRect and height and ascent all give values that result in even smaller size
//qreal absH = fm.ascent();
qreal absH = fmRect.height();
qreal absW = fmRect.width();
qreal absHeightRatio = myText->getItemSize().height() / absH;
qreal absWidthRatio = myText->getItemSize().width() / absW;
Then setting size:
myText->setItemSize(QSizeF(absWidthRatio * textLength, absHeightRatio * fontHeight));
// This function scales the `QTransform` on item
// but since I request a final position dependent on item size
// (including blank space around it) - it has no chance of being accurate.....
// This is where my next effort will go, figuring out how to get rid of the fluff
// around the item inside the scaling
The function for setting position: trying to center text:
// leftShift = 10, rightShift = 10 in example
myText->setPos(0,0);
QRectF r = myText->mapToScene(myText->boundingRect()).boundingRect();
QSizeF sz = r.size();
qreal w = sz.width();
qreal h = sz.height();
qreal cx = (m_docLength - w + leftShift - rightShift)/2 - r.left();
qreal cy = (m_docHeight - h)/2 - r.top();
myText->setPos(cx, cy);
The images below are for fontHeight = m_docHeight -
Desirable:
- either the entire size of text (ascent + descent) equals doc height, and text is centered vertically based on content
- or the upper case size text equals doc height and the descent is below document (text centered based on only upper case) - this would seem easier based on how QGraphicsTextItem seems to position it
Actual:
- the text is smaller no matter which parameters I use to scale, and centered based on upper case text
As shown above - I have no idea how I could center vertically based on content (so for edge-to-edge text the descent would fit in) - and in lieu of that, all I really want is edge-to-edge uppercase letters, but I can't seem able to achieve that.
Oh and these are for Arial type font - one of the best-behaved. Other fonts jump all over the place, either above or below the canvas. And for some fonts, the resulting text is actually smaller - which is inexplicable to me, because how can the tight bounding rectangle be smaller than the item bounding rectangle...
Still this is as far as I got to getting my text as close to "true" size and placed on a canvas that matches its size.

How to create Vector3 for all resolutions

I'm trying to fit my interface for all resolutions. I have this code
private void OnEnable() {
GameObject back = Instantiate(Background) as GameObject;
BoxCollider2D back_bc2d = back.GetComponent<BoxCollider2D>();
float x = ((Screen.currentResolution.width) / back_bc2d.size.x) / 2;
float y = (Screen.currentResolution.height / back_bc2d.size.y);
back.transform.localScale = new Vector3(x, y, back.transform.localScale.z);
Destroy(back_bc2d);
}
As you can see, I'm trying to create something like GUI.DrawTexture (I don't want to use GUI.DrawTexture because of some reasons)
My texture have to draw on a half screen.
But on different resolutions it doesn't work. What I'm doing wrong?
Screen resolution does not mean anything in world space, only the aspect ratio is important there. The in game geometry size is the same in every resolution, only the viewport may be wider showing more of it - this is how the camera works.
Also, you should not derive localScale used in world space from screen space coordinates - they don't work this way.
If you want to position some geometry in worldspace relative to the camera, use http://docs.unity3d.com/ScriptReference/Camera.ScreenToWorldPoint.html

QGraphicsItem : emulating an item origin which is not the top left corner

My application is using Qt.
I have a class which is inheriting QGraphicsPixmapItem.
When applying transformations on these items (for instance, rotations), the origin of the item (or the pivot point) is always the top left corner.
I'd like to change this origin, so that, for instance, when setting the position of the item, this would put actually change the center of the pixmap.
Or, if I'm applying a rotation, the rotation's origin would be the center of the pixmap.
I haven't found a way to do it straight out of the box with Qt, so I thougth of reimplementing itemChange() like this :
QVariant JGraphicsPixmapItem::itemChange(GraphicsItemChange Change, const QVariant& rValue)
{
switch (Change)
{
case QGraphicsItem::ItemPositionHasChanged:
// Emulate a pivot point in the center of the image
this->translate(this->boundingRect().width() / 2,
this->boundingRect().height() / 2);
break;
case QGraphicsItem::ItemTransformHasChanged:
break;
}
return QGraphicsItem::itemChange(Change, rValue);
}
I thought this would work, as Qt's doc mentions that the position of an item and its transform matrix are two different concepts.
But it is not working.
Any idea ?
You're overthinking it. QGraphicsPixmapItem already has this functionality built in. See the setOffset method.
So to set the item origin at its centre, just do setOffset( -0.5 * QPointF( width(), height() ) ); every time you set the pixmap.
The Qt-documentation about rotating:
void QGraphicsItem::rotate ( qreal angle )
Rotates the current item
transformation angle degrees clockwise
around its origin. To translate around
an arbitrary point (x, y), you need to
combine translation and rotation with
setTransform().
Example:
// Rotate an item 45 degrees around (0, 0).
item->rotate(45);
// Rotate an item 45 degrees around (x, y).
item->setTransform(QTransform().translate(x, y).rotate(45).translate(-x, -y));
You need to create a rotate function, that translate the object to the parent's (0, 0) corner do the rotation and move the object to the original location.

Resources