I am interested in simple rect clipping in Directx9.
On the top picture you see what I get.
I want to get what is on the bottom picture without changing the coordinates and/or viewport.
Meaning, I will draw the entire circle but Directx9 will just clip it.
It would be preferable that clip rect will be given in WINDOW coordinates, so it will not be affected by current state transformations.
In additions, it should affect everything going from now on to window, including polygons, sprites, textures, text etc.
Can somone suggest how to do this?
You're describing a scissor test, which is built into the directx device.
See Scissor Test
More specifically, you just set the rectangle in screen coordinates using SetScissorRect
And then enable the scissor test by calling
device->SetRenderState( D3DRS_SCISSORTESTENABLE , TRUE );
I had the same question a month ago and I came up with a solution myself after trying to locate a clipping method, so I had to develop my own... This should work:
void Clip(LPDIRECT3DDEVICE9 device, LPDIRECT3DSURFACE9 surface, LPDIRECT3DSURFACE9 backbuffer, int x, int y, int width, int height, int destX, int destY, int destWidth, int destHeight)
{
RECT source;
if (x >= destX && (x+width) <= (destX+destWidth))
{
source.left = 0;
source.right = width;
}
else if ( (x >= destX && x <= (destX+destWidth)) && ((x+width) > (destX+destWidth)))
{
source.left = 0;
source.right = width - ((x+width) - (destX+destWidth));
source.right = abs(source.right);
}
else if (x < destX && (x+width) < (destX+destWidth))
{
source.left = abs(x);
source.right = width;
}
else if ( (x < destX) && ((x+width) > (destX+destWidth)))
{
source.left = abs(x);
source.right = source.left + (destWidth);
}
else
{
return;
}
if (y >= destY && (y+height) <= (destY+destHeight))
{
source.top = 0;
source.bottom = height;
}
else if ( (y >= destY && y <= (destY+destHeight)) && ((y+height) > (destY+destHeight)) )
{
source.top = 0;
source.bottom = height - ((y+height) - (destY+destHeight));
source.bottom = abs(source.bottom);
}
else if (y < destY && (y+height) > destY && (y+height) <= (destY+destHeight))
{
source.top = abs(y);
source.bottom = height;
}
else if ( (y < destY) && ((y+height) > (destY+destHeight)))
{
source.top = abs(y);
source.bottom = source.top + (destHeight);
}
else
{
return;
}
RECT destination;
if (x >= destX && (x+width) <= (destX+destWidth))
{
destination.left = x;
destination.right = x + width;
}
else if ( (x >= destX && x <= (destX+destWidth)) && ((x+width) > (destX+destWidth)))
{
destination.left = x;
destination.right = (destX+destWidth);
}
else if ( (x < destX) && ((x+width) < (destX+destWidth)) && ((x+width) >= x))
{
destination.left = destX;
destination.right = width - abs(x);
}
else if ( (x < destX) && ((x+width) > (destX+destWidth)))
{
destination.left = destX;
destination.right = (destX+destWidth);
}
else
{
return;
}
if (y >= destY && (y+height) <= (destY+destHeight))
{
destination.top = y;
destination.bottom = y + height;
}
else if ( (y >= destY && y <= (destY+destHeight)) && (y+height) > (destY+destHeight))
{
destination.top = y;
destination.bottom = (destY+destHeight);
}
else if (y < destY && (y+height) > destY && (y+height) <= (destY+destHeight))
{
destination.top = destY;
destination.bottom = height - abs(y);
}
else if ( (y < destY) && ((y+height) > (destY+destHeight)))
{
destination.top = destY;
destination.bottom = (destY+destHeight);
}
else
{
return;
}
device->StretchRect(surface, &source, backbuffer, &destination, D3DTEXF_NONE);
DeleteObject(&source);
DeleteObject(&destination);
};
Related
I'm making a program, that moves a dot, from the startx, starty to endx, endy.
But it moves continuously, even after the x and the y are bigger than endx and endy.
Here is the code:
int x, y;
x = startx; y = starty;
if(startx<goalx){
if (starty < goaly) {
while (startx < goalx || starty < goaly) {
x += sqrt(2)*speedx;
y += sqrt(2)*speedy;
}
}
else {
while (startx < goalx || starty > goaly) {
x += sqrt(2)*speedx;
y -= sqrt(2)*speedy;
}
}
}
else {
if (starty < goaly) {
while (startx > goalx || starty < goaly) {
x -= sqrt(2)*speedx;
y += sqrt(2)*speedy;
}
}
else {
while (startx > goalx || starty > goaly) {
x -= sqrt(2)*speedx;
y -= sqrt(2)*speedy;
}
}
}
cout << x << ", " << y << endl;
startx, starty, goalx and goaly are user inputs.
The control structures depend on startx and starty but these are never changing. Supposedly x and y should be used instead.
try this
int x, y;
x = startx; y = starty;
int xInc = sqrt(2) * speedx;
int yInc = sqrt(2) * speedy;
if(x < goalx && y < goaly)
{
while(x < goalx || y < goaly)
{
x += xInc;
y += yInc;
}
}
else if(x < goalx && y > goaly)
{
while(x < goalx || y > goaly)
{
x += xInc;
y -= yInc;
}
}
else if(x > goalx && y < goaly)
{
while(x > goalx || y < goaly)
{
x -= xInc;
y += yInc;
}
}
else if(x > goalx && y > goaly)
{
while(x > goalx || y > goaly)
{
x -= xInc;
y -= yInc;
}
}
I'm fighting with this for like few days, and I have no idea, how to do that, so I'd like to ask you for help. I've got no idea how collision should look like right here, so player could jump through 'down zone' of the block, and stay right on the block.
block.cpp
bool block::CollidingWithPlayer(character& player) {
for (int i = 1; i < MAX_BLOCKS; i++) {
if (player.x + player.width >= coordinateX[i] && player.x <= coordinateX[i] + width[i] && player.y + player.height >= coordinateY[i] && player.y <= coordinateY[i] + block_height) {
player.onGround = true;
return true;
}
}
}
character.cpp
void character::startJump(map& Map, character& player) {
if (onGround)
{
vel[1] = -11.0;
onGround = false;
}
}
void character::updateJump(block& Block, character& player) {
if (!onGround) {
Block.CollidingWithPlayer(player);
vel[1] += 0.5;
y += vel[1];
x += vel[0];
}
if (y > 460){
y = 460;
vel[1] = 0.0;
onGround = true;
vel[0] = 0.0;
}
if ((x + width >= START_OF_RIGHT_WALL && x <= WALL_WIDTH + START_OF_RIGHT_WALL) || (x + width >= START_OF_LEFT_WALL &&x <= START_OF_LEFT_WALL + WALL_WIDTH)){
vel[0] *= -1;
bound = true;
if (direction == 1)
direction = 2;
else if (direction == 2)
direction = 1;
}
}
I need to create a frameless Qt Windows app that supports resizing.
If I use
setWindowFlags(Qt::FramelessWindowHint);
then I can resize only from bottom-right corner (like with the size grip, I guess QMainWindow includes it somehow?).
Is there any easy way to make it resizable from all sides like a normal window? Maybe something platform-specific (Windows)?
Solved it using WM_NCHITTEST, based on code from https://bugreports.qt.io/browse/QTBUG-40578 (bug report not related to this).
.h
class MainWindow : public QMainWindow
{
Q_OBJECT
......
protected:
bool nativeEvent(const QByteArray& eventType, void* message, long* result) override;
};
.cpp
bool MainWindow::nativeEvent(const QByteArray& eventType, void* message, long* result)
{
MSG* msg = static_cast<MSG*>(message);
if (msg->message == WM_NCHITTEST)
{
if (isMaximized())
{
return false;
}
*result = 0;
const LONG borderWidth = 8;
RECT winrect;
GetWindowRect(reinterpret_cast<HWND>(winId()), &winrect);
// must be short to correctly work with multiple monitors (negative coordinates)
short x = msg->lParam & 0x0000FFFF;
short y = (msg->lParam & 0xFFFF0000) >> 16;
bool resizeWidth = minimumWidth() != maximumWidth();
bool resizeHeight = minimumHeight() != maximumHeight();
if (resizeWidth)
{
//left border
if (x >= winrect.left && x < winrect.left + borderWidth)
{
*result = HTLEFT;
}
//right border
if (x < winrect.right && x >= winrect.right - borderWidth)
{
*result = HTRIGHT;
}
}
if (resizeHeight)
{
//bottom border
if (y < winrect.bottom && y >= winrect.bottom - borderWidth)
{
*result = HTBOTTOM;
}
//top border
if (y >= winrect.top && y < winrect.top + borderWidth)
{
*result = HTTOP;
}
}
if (resizeWidth && resizeHeight)
{
//bottom left corner
if (x >= winrect.left && x < winrect.left + borderWidth &&
y < winrect.bottom && y >= winrect.bottom - borderWidth)
{
*result = HTBOTTOMLEFT;
}
//bottom right corner
if (x < winrect.right && x >= winrect.right - borderWidth &&
y < winrect.bottom && y >= winrect.bottom - borderWidth)
{
*result = HTBOTTOMRIGHT;
}
//top left corner
if (x >= winrect.left && x < winrect.left + borderWidth &&
y >= winrect.top && y < winrect.top + borderWidth)
{
*result = HTTOPLEFT;
}
//top right corner
if (x < winrect.right && x >= winrect.right - borderWidth &&
y >= winrect.top && y < winrect.top + borderWidth)
{
*result = HTTOPRIGHT;
}
}
if (*result != 0)
return true;
QWidget *action = QApplication::widgetAt(QCursor::pos());
if (action == this){
*result = HTCAPTION;
return true;
}
}
return false;
}
implementation from Qt: Resize borderless widget did not work well: sometimes the window is moved during resizing (even in the first version without dragging)
I'm working on a project that is creating a painting program using OpenGL and GLUT on C++.
So far I have a color menu on the left side and now I am trying to make a tool menu on the right side but I can't figure out how to get it on the right.
This is what i have so far:
int inwindow(int x, int y)
{
return (x > WLEFT && x < WRIGHT && y > WBOTTOM && y < WTOP);
}
static float colormenu[][8] = {{Red}, {Orange}, {Yellow}, {Green}, {Cyan}, {Blue}, {Purple}, {Black}};
int incolormenu(int x, int y)
{
return (x >= 0 && x <= MENUWIDTH && y >= 0 && y <= HEIGHT);
}
int colormenuindex(int x, int y)
{
if(!incolormenu(x, y))
return -1;
else
return(y / BOXHEIGHT);
}
static float toolmenu[][6] = {{Pencil}, {Line}, {Box}, {Rectangle}, {Circle}, {FCircle}};
int intoolmenu(int x, int y)
{
return (x >= 0 && x <= MENUWIDTH && y >= 0 && y <= HEIGHT);
}
int toolmenuindex(int x, int y)
{
if(!intoolmenu(x, y))
return -1;
else
return(y / BOXHEIGHT);
}
void drawSketch()
{
int i;
glClearColor(Grey, 1);
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(Black);
for(i = 0; i < NCOLORS; i++)
{
glColor3f(colormenu[i][R], colormenu[i][G], colormenu[i][B]);
glRecti(1, BOXHEIGHT * i + 1, MENUWIDTH - 1, BOXHEIGHT * (i + 1) - 1);
}
for(i = 0; i < NCOLORS; i++)
{
glColor3f(toolmenu[i][Pencil], toolmenu[i][Line], toolmenu[i][Box]);
glRasterPos3f(0.2, -0.8, -1.5);
}
glFlush();
}
Not sure if you are willing to use a third party solution but I've used the following project with really good results.
NanoGUI Github Project
I've implemented tilemap collision into my game, it works but the problem comes when I'm colliding on one axis and trying to move on the other. I can't slide along the wall.
in Player.cpp
void Player::update(float delta, std::vector<Tile>& tiles) {
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W) || sf::Keyboard::isKeyPressed(sf::Keyboard::Up) || sf::Joystick::getAxisPosition(0, sf::Joystick::Y) < -20) {
newPos.y -= speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A) || sf::Keyboard::isKeyPressed(sf::Keyboard::Left) || sf::Joystick::getAxisPosition(0, sf::Joystick::X) < -20) {
newPos.x -= speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S) || sf::Keyboard::isKeyPressed(sf::Keyboard::Down) || sf::Joystick::getAxisPosition(0, sf::Joystick::Y) > 20) {
newPos.y += speed * delta;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D) || sf::Keyboard::isKeyPressed(sf::Keyboard::Right) || sf::Joystick::getAxisPosition(0, sf::Joystick::X) > 20) {
newPos.x += speed * delta;
}
sf::Vector2f oldPos = sprite.getPosition();
move(delta, newPos);
for (int i = 0; i < tiles.size(); i++) {
if (Collision::PixelPerfectTest(sprite, tiles[i].sprite) && tiles[i].collision) {
sprite.setPosition(oldPos);
newPos = oldPos;
}
}
}
void Player::move(float delta, sf::Vector2f position) {
sprite.setPosition(position);
}
In Collision.cpp
bool PixelPerfectTest(const sf::Sprite& Object1, const sf::Sprite& Object2, sf::Uint8 AlphaLimit) {
sf::FloatRect Intersection;
if (Object1.getGlobalBounds().intersects(Object2.getGlobalBounds(), Intersection)) {
sf::IntRect O1SubRect = Object1.getTextureRect();
sf::IntRect O2SubRect = Object2.getTextureRect();
sf::Uint8* mask1 = Bitmasks.GetMask(Object1.getTexture());
sf::Uint8* mask2 = Bitmasks.GetMask(Object2.getTexture());
// Loop through our pixels
for (int i = Intersection.left; i < Intersection.left + Intersection.width; i++) {
for (int j = Intersection.top; j < Intersection.top + Intersection.height; j++) {
sf::Vector2f o1v = Object1.getInverseTransform().transformPoint(i, j);
sf::Vector2f o2v = Object2.getInverseTransform().transformPoint(i, j);
// Make sure pixels fall within the sprite's subrect
if (o1v.x > 0 && o1v.y > 0 && o2v.x > 0 && o2v.y > 0 &&
o1v.x < O1SubRect.width && o1v.y < O1SubRect.height &&
o2v.x < O2SubRect.width && o2v.y < O2SubRect.height) {
if (Bitmasks.GetPixel(mask1, Object1.getTexture(), (int)(o1v.x) + O1SubRect.left, (int)(o1v.y) + O1SubRect.top) > AlphaLimit &&
Bitmasks.GetPixel(mask2, Object2.getTexture(), (int)(o2v.x) + O2SubRect.left, (int)(o2v.y) + O2SubRect.top) > AlphaLimit)
return true;
}
}
}
}
return false;
}
That's because your collision test is all or nothing. I would do extra collision tests to see if the x or y new position is valid or not, something like:
if (tiles[i].collision && Collision::PixelPerfectTest(sprite, tiles[i].sprite))
{
sf::Vector2f checkPosX = newPos;
sf::Vector2f checkPosY = newPos;
checkPosX.y = oldPos.y;
checkPosY.x = oldPos.x;
sprite.setPosition(checkPosX);
if (!Collision::PixelPerfectTest(sprite, tiles[i].sprite))
{
newPos = checkPosX;
}
else
{
sprite.setPosition(checkPosY);
if (!Collision::PixelPerfectTest(sprite, tiles[i].sprite))
{
newPos = checkPosY;
}
else
{
sprite.setPosition(oldPos);
newPos = oldPos;
}
}
}
As an aside, if you do test tiles[i].collision first you will skip the more expensive PixelPerfectTest() test for non-collision tiles due to the expression short-circuiting.