I have a program that has a public static array of sf::RenderWindows, a non copyable window from the sfml library. Anyway when I try to push_back to the vector I get a error because it is not copy able. I have tried doing it with refrances and pointers and well and always get some sort of error. If I try to use refrances i get like 20 errors saying pointer to refrance is illegal and if I try to use pointers constructors like .draw and .clear "Don't exist". If there is a way to use something like push_back that just doesn't copy that would be great if not I'll give my code when I try with both refrances and pointers.
Refrances
static vector <MakeKey::NewKey> KeyArray;
static vector <sf::RenderWindow&> WindowArray;
static void StepWindows(sf::RenderWindow & window, MakeKey::NewKey key)
{
sf::Clock clock;
MakeTopWindow(window);
setShape(window, key.Img);
window.clear(sf::Color::Transparent);
window.draw(key.Sprite);
window.display();
if (clock.getElapsedTime().asMicroseconds() > 1000)
{
window.setPosition(MakeKey::Gravity(window, key));
}
}
Refrances when i push_back
MakeKey::KeyArray.push_back(Key);
MakeKey::WindowArray.push_back(window);
Pointers
static vector <MakeKey::NewKey> KeyArray;
static vector <sf::RenderWindow*> WindowArray;
static void StepWindows(sf::RenderWindow & window, MakeKey::NewKey key)
{
sf::Clock clock;
MakeTopWindow(window);
setShape(window, key.Img);
window.clear(sf::Color::Transparent);
window.draw(key.Sprite);
window.display();
if (clock.getElapsedTime().asMicroseconds() > 1000)
{
window.setPosition(MakeKey::Gravity(window, key));
}
}
Pointers when i push_back
MakeKey::KeyArray.push_back(Key);
MakeKey::WindowArray.push_back(&window);
//The error here is that is 2 undefined external symbol because I declaired both arrays as static but if they are not static I get a error on where I push_back saying refrance must be relative to specific class.
Thanks
My entire class because someone wanted it - still getting linker error but im trying to figure that out.
static class MakeKey
{
public:
typedef struct KeyStruct {
sf::Image Img;
sf::Texture Tex;
sf::Sprite Sprite;
typedef struct Velocety {
static int x;
static int y;
};
typedef struct Acceleration {
static int x;
static int y;
};
typedef struct HitSide {
static bool x()
{
typedef struct Side {
static bool left(sf::RenderWindow window, sf::Image image) {
int XPos{ window.getPosition().x };
if (XPos > (sf::VideoMode::getDesktopMode().width - image.getSize().x - 1))
return true;
return false;
}
static bool right(sf::RenderWindow window, sf::Image image)
{
int XPos{ window.getPosition().x };
if (XPos < 1 + image.getSize().x)
return true;
return false;
}
};
}
static bool y(sf::RenderWindow window, sf::Image image)
{
typedef struct Side {
static bool top(sf::RenderWindow window, sf::Image image) {
int YPos = window.getPosition().y;
if (YPos > (sf::VideoMode::getDesktopMode().width - image.getSize().y - 1))
return true;
return false;
}
static bool bottom(sf::RenderWindow window, sf::Image image)
{
int YPos = window.getPosition().y;
if (YPos < 1 + image.getSize().y)
return true;
return false;
}
};
}
};
static sf::Clock OffGroundClock;
}NewKey;
static sf::Vector2i Gravity(sf::RenderWindow * window, MakeKey::NewKey Key)
{
int XPos = window->getPosition().x;
int YPos = window->getPosition().y;
cout << "Gravity Debug Starting\n" << XPos << " and " << YPos << endl;
YPos += 2;
if (YPos < 1 + Key.Img.getSize().y)
YPos = 1 + Key.Img.getSize().y;
if (YPos > (sf::VideoMode::getDesktopMode().height - Key.Img.getSize().y - 1))
YPos = (YPos = sf::VideoMode::getDesktopMode().height - Key.Img.getSize().y);
if (XPos < 1 + Key.Img.getSize().x)
XPos = (1 + Key.Img.getSize().x);
if (XPos > (sf::VideoMode::getDesktopMode().width - Key.Img.getSize().x - 1))
XPos = sf::VideoMode::getDesktopMode().width - Key.Img.getSize().x;
cout << XPos << " and " << YPos << endl;
return sf::Vector2i(XPos, YPos);
}
/*void Step() {
velocity.x += acceleration.x;
velocity.y += acceleration.y;
}*/
static bool setShape(sf::RenderWindow * window, const sf::Image& image)
{
HWND hwnd = window->getSystemHandle();
const sf::Uint8* pixelData = image.getPixelsPtr();
HRGN hRegion = CreateRectRgn(0, 0, image.getSize().x, image.getSize().y);
// Determine the visible region
for (unsigned int y = 0; y < image.getSize().y; y++)
{
for (unsigned int x = 0; x < image.getSize().x; x++)
{
if (pixelData[y * image.getSize().x * 4 + x * 4 + 3] == 0)
{
HRGN hRegionPixel = CreateRectRgn(x, y, x + 1, y + 1);
CombineRgn(hRegion, hRegion, hRegionPixel, RGN_XOR);
DeleteObject(hRegionPixel);
}
}
}
SetWindowRgn(hwnd, hRegion, true);
DeleteObject(hRegion);
return true;
}
static sf::Vector2i RandSpawn(sf::Image image)
{
cout << "Desktop Demensions:" << sf::VideoMode::getDesktopMode().width << " by " << sf::VideoMode::getDesktopMode().height << endl;
cout << "Starting Relocation Debug" << endl;
std::random_device rand;
int RandX = (rand() % sf::VideoMode::getDesktopMode().width) - image.getSize().x;
int RandY = (rand() % sf::VideoMode::getDesktopMode().height) - image.getSize().y;
if (RandX < 1 + image.getSize().x)
cout << "Image X Size: " << image.getSize().x << endl << "RandX: " << RandX << endl;
RandX = image.getSize().x;
cout << "Image X Size: " << image.getSize().x << endl << "RandX: " << RandX << endl;
if (RandY < 1 + image.getSize().y)
cout << "Image Y Size: " << image.getSize().y << endl << "RandY: " << RandY << endl;
RandY = image.getSize().y;
cout << "Image Y Size: " << image.getSize().y << endl << "RandY: " << RandY << endl;
cout << "Randomly Relocated\n" << RandX << " and " << RandY << endl;
cout << "Relocation Debug Complete\n\n" << endl;
return sf::Vector2i(RandX, RandY);
}
static bool setTransparency(HWND hwnd, unsigned char alpha)
{
SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
SetLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA);
return true;
}
static void MakeTopWindow(sf::RenderWindow * windowPoint)
{
HWND hwndPoint = windowPoint->getSystemHandle();
SetWindowPos(hwndPoint, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}
static vector <MakeKey::NewKey> KeyArray;
static vector <sf::RenderWindow*> WindowArray;
static void StepWindows()
{
for (int i{ 0 }; i > MakeKey::KeyArray.size(); i++)
{
sf::Clock clock;
MakeTopWindow(WindowArray[i]);
setShape(WindowArray[i], KeyArray[i].Img);
WindowArray[i]->clear(sf::Color::Transparent);
WindowArray[i]->draw(KeyArray[i].Sprite);
WindowArray[i]->display();
if (clock.getElapsedTime().asMicroseconds() > 1000)
{
WindowArray[i]->setPosition(MakeKey::Gravity(WindowArray[i], KeyArray[i]));
}
}
}
static void DrawKey(string input)
{
MakeKey::NewKey Key;
if (input == "A")
Key.Img.loadFromFile("Assets/Images/A.png");
else if (input == "D")
Key.Img.loadFromFile("Assets/Images/D.png");
else if (input == "E")
Key.Img.loadFromFile("Assets/Images/E.png");
else if (input == "Q")
Key.Img.loadFromFile("Assets/Images/Q.png");
else if (input == "S")
Key.Img.loadFromFile("Assets/Images/S.png");
else if (input == "W")
Key.Img.loadFromFile("Assets/Images/W.png");
else if (input == "X")
Key.Img.loadFromFile("Assets/Images/X.png");
else if (input == "Z")
Key.Img.loadFromFile("Assets/Images/Z.png");
else if (input == "Esc")
Key.Img.loadFromFile("Assets/Images/esc.png");
Key.Tex.loadFromImage(Key.Img);
Key.Sprite.setTexture(Key.Tex);
//Open Window
sf::RenderWindow window(sf::VideoMode(Key.Img.getSize().x, Key.Img.getSize().y, 32), "Key", sf::Style::None);
window.setPosition(MakeKey::RandSpawn(Key.Img));
sf::RenderWindow* windowPoint = &window;
//Make Transparent
const unsigned char opacity = 1000;
setTransparency(window.getSystemHandle(), opacity);
setShape(windowPoint, Key.Img);
MakeKey::KeyArray.push_back(Key);
MakeKey::WindowArray.push_back(&window);
}
};
Main
int main()
{
sf::RenderWindow window(sf::VideoMode(100, 100, 32), "Main Window", sf::Style::None);
sf::RenderWindow* windowRef = &window;
while (window.isOpen())
{
sf::Event event;
while (window.pollEvent(event))
{
MakeKey::MakeTopWindow(windowRef);
//Key Presses
if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::A)
MakeKey::DrawKey("A");
else if (event.key.code == sf::Keyboard::D)
MakeKey::DrawKey("D");
else if (event.key.code == sf::Keyboard::E)
MakeKey::DrawKey("E");
else if (event.key.code == sf::Keyboard::Q)
MakeKey::DrawKey("Q");
else if (event.key.code == sf::Keyboard::S)
MakeKey::DrawKey("S");
else if (event.key.code == sf::Keyboard::W)
MakeKey::DrawKey("W");
else if (event.key.code == sf::Keyboard::X)
MakeKey::DrawKey("X");
else if (event.key.code == sf::Keyboard::Z)
MakeKey::DrawKey("Z");
else if (event.key.code == sf::Keyboard::Escape)
MakeKey::DrawKey("Esc");
}
//Close
if (event.type == sf::Event::Closed)
window.close();
}
MakeKey::StepWindows();
}
return EXIT_SUCCESS;
}
I'm pretty new to SFML networking and have been working on a pong clone for quite some time. I've written two programs: a client and a server. My problem is that the two don't seem to properly send/receive data between each other. I've checked and my ports properly bind and my packet isn't larger than the max datagram size. However, when I check the status of socket.send(...) against Socket::Done it finds that the data did not send. Is there something I'm doing wrong?
Client:
#include <SFML/Graphics.hpp>
#include <SFML/Network.hpp>
#include <ctime>
#include <iostream>
#include <sstream>
using namespace sf;
using namespace std;
template <typename T>
string NumberToString ( T Number )
{
stringstream ss;
ss << Number;
return ss.str();
}
int main()
{
cout << "Enter an IP address: ";
string address;
cin >> address;
IpAddress other = address;
//window
RenderWindow window(VideoMode(800, 600), "Pong");
//player 1
RectangleShape rect(Vector2f(40, 130));
rect.setPosition(40, 50);
rect.setFillColor(Color::Blue);
rect.setOutlineThickness(4);
rect.setOutlineColor(Color::Black);
//player 2
RectangleShape player2(Vector2f(40, 130));
player2.setPosition(520,50);
player2.setFillColor(Color(255, 0, 208));
player2.setOutlineThickness(4);
player2.setOutlineColor(Color::Black);
//ball
CircleShape ball(50, 50);
ball.setOrigin(ball.getRadius(), ball.getRadius());
ball.setPosition(400, 300);
ball.setFillColor(Color(255, 255, 0));
ball.setOutlineThickness(4);
ball.setOutlineColor(Color::Black);
//score
Uint16 score1;
Uint16 score2;
//socket
short unsigned int port = 54000;
UdpSocket socket;
if (socket.bind(port) != Socket::Done)
{
cout << "Error\n";
}
socket.setBlocking(false);
//text
Font font;
font.loadFromFile("SF Electrotome.ttf");
Text score;
score.setFont(font);
score.setColor(Color::Black);
score.setString("0 0");
score.setCharacterSize(16);
score.setPosition(300, 50);
//loop
bool running = true;
while (running) //game loop
{
Event ev;
while (window.pollEvent(ev)) //event loop
{
switch (ev.type)
{
case Event::Closed: //quit on click x
running = false;
break;
case Event::KeyPressed:
if (ev.key.code == Keyboard::Escape) //quit on escape
{
running = false;
}
break;
}
}
//get that sweet info
Packet received;
socket.receive(received, other, port);
float player1pos[2];
float player2pos[2];
float ballpos[2];
received >> player1pos[0] >> player1pos[1] >> player2pos[0] >> player2pos[1] >>
ballpos[0] >> ballpos[1] >> score1 >> score2;
rect.setPosition(player1pos[0], player1pos[1]);
player2.setPosition(player2pos[0], player2pos[1]);
ball.setPosition(ballpos[0], ballpos[1]);
//scores
score.setString(NumberToString(score1) + " " + NumberToString(score2));
//handle player input
if (Keyboard::isKeyPressed(Keyboard::Up))
{
if (rect.getPosition().y >= 0) //keep in bounds
{
Packet p;
Uint16 direction = 1;
p << direction;
socket.send(p, other, port);
}
} else if (Keyboard::isKeyPressed(Keyboard::Down)){
if (player2.getPosition().y + player2.getSize().y <= 600) //keep in bounds
{
Packet p;
Uint16 direction = 2;
p << direction;
socket.send(p, other, port);
}
}
//draw everything
window.clear(Color::White);
window.draw(rect);
window.draw(player2);
window.draw(ball);
window.draw(score);
window.display();
}
return 0;
}
Server:
#include <SFML/Graphics.hpp>
#include <SFML/Network.hpp>
#include <cstdlib>
#include <ctime>
#include <sstream>
#include <iostream>
using namespace sf;
using namespace std;
template <typename T>
string NumberToString ( T Number )
{
stringstream ss;
ss << Number;
return ss.str();
}
int main()
{
cout << "Enter an IP address: ";
string address;
cin >> address;
IpAddress other(address);
if (other == IpAddress::None)
{
cout << "Error loading ip";
}
srand(time(NULL));
//window
RenderWindow window(VideoMode(800, 600), "Pong");
//player 1
RectangleShape rect(Vector2f(40, 130));
rect.setPosition(40, 50);
rect.setFillColor(Color::Blue);
rect.setOutlineThickness(4);
rect.setOutlineColor(Color::Black);
//player 2
RectangleShape player2(Vector2f(40, 130));
player2.setPosition(720, 50);
player2.setFillColor(Color(255, 0, 208));
player2.setOutlineThickness(4);
player2.setOutlineColor(Color::Black);
//ball
CircleShape ball(50, 50);
ball.setOrigin(ball.getRadius(), ball.getRadius());
ball.setPosition(400, 300);
ball.setFillColor(Color(255, 255, 0));
ball.setOutlineThickness(4);
ball.setOutlineColor(Color::Black);
float randX = (rand() % 5 + 1);
float randY = (rand() % 5 + 1);
Vector2f ballVelocity(randX/15, randY/15);
//score
Uint16 score1 = 0;
Uint16 score2 = 0;
//text
Font font;
font.loadFromFile("SF Electrotome.ttf");
Text score;
score.setFont(font);
score.setColor(Color::Black);
score.setString("0 0");
score.setCharacterSize(16);
score.setPosition(350, 50);
//network socket
UdpSocket socket;
short unsigned int sendPort = 54000;
if (!(socket.bind(sendPort) == Socket::Done))
{
cout << "Error";
}
socket.setBlocking(false);
//loop
bool running = true;
while (running) //game loop
{
Event ev;
while (window.pollEvent(ev)) //event loop
{
switch (ev.type)
{
case Event::Closed: //quit on click x
running = false;
break;
case Event::KeyPressed:
if (ev.key.code == Keyboard::Escape) //quit on escape
{
running = false;
}
break;
}
}
//handle player input
if (Keyboard::isKeyPressed(Keyboard::Up))
{
if (rect.getPosition().y >= 0) //keep in bounds
{
rect.move(0, -0.2);
}
} else if (Keyboard::isKeyPressed(Keyboard::Down)){
if (rect.getPosition().y + rect.getSize().y <= 600) //keep in bounds
{
rect.move(0, 0.2);
}
}
//handle player 2 input
Uint16 direction;
IpAddress sender;
Packet received;
if ((socket.receive(received, other, sendPort)) != Socket::Done)
{
cout << "Error receiving data";
}
received >> direction;
if (sender == other)
{
switch (direction)
{
case 1:
player2.move(0, -0.2);
break;
case 2:
player2.move(0, 0.2);
break;
}
}
//handle ball direction changes
if ((ball.getPosition().y - ball.getRadius() <= 0) || (ball.getPosition().y + ball.getRadius() >= 600)) { //top or bottom
ballVelocity.y *= -1;
} else if ((ball.getPosition().x + ball.getRadius() >= 800)) { //right edge
ballVelocity.x *= -1;
score1 += 1;
} else if (ball.getPosition().x - ball.getRadius() <= 0) { //left edge
ballVelocity.x *= -1;
score2 += 1;
}
ball.move(ballVelocity);
//handle player/ball collisions
FloatRect player1Box = rect.getGlobalBounds();
FloatRect ballBox = ball.getGlobalBounds();
FloatRect player2Box = player2.getGlobalBounds();
if (player1Box.intersects(ballBox) || player2Box.intersects(ballBox))
{
ballVelocity.x *= -1;
}
//set score
score.setString(NumberToString(score1) + " " + NumberToString(score2));
//send everything over
Packet p;
p << rect.getPosition().x << rect.getPosition().y << player2.getPosition().x << player2.getPosition().y <<
ball.getPosition().x << ball.getPosition().y << score1 << score2;
socket.send(p, other, sendPort);
//draw everything
window.clear(Color::White);
window.draw(rect);
window.draw(player2);
window.draw(ball);
window.draw(score);
window.display();
}
return 0;
}
I've seen a few questions that are probably the same. I am still unable to make my code work after reading the answers. So I am sorry in advance if I am repeating the posts.
I managed to write this code :
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <string>
bool leftButtonDown = false, leftButtonUp = false;
cv::Mat img;
cv::Point cor1, cor2;
cv::Rect rect;
void mouseCall(int event, int x, int y, int, void*) {
if (event == cv::EVENT_LBUTTONDOWN) //finding first corner
{
leftButtonDown = true; cor1.x = x; cor1.y = y; std::cout << "Corner 1: " << cor1 << std::endl;
}
if (event == cv::EVENT_LBUTTONUP) {
if (abs(x - cor1.x)>20 && abs(y - cor1.y)>5) //finding second corner and checking whether the region is too small
{
leftButtonUp = true; cor2.x = x; cor2.y = y; std::cout << "Corner 2: " << cor2 << std::endl;
}
else { std::cout << "Select more than 5 pixels" << std::endl; }
}
if (leftButtonDown == true && leftButtonUp == false) //when the left button is clicked and let off
{ //draw a rectangle continuously
cv::Point pt; pt.x = x; pt.y = y;
cv::Mat temp_img = img.clone();
rectangle(temp_img, cor1, pt, cv::Scalar(0, 0, 255));
cv::imshow("Original", temp_img);
}
else if (event == cv::EVENT_MOUSEMOVE) //tracking mouse movement
{
std::cout << "Mouse moving over the window - position (" << x << ", " << y << ")" << std::endl;
}
if (leftButtonDown == true && leftButtonUp == true) //when the selection is done
{
rect.width = abs(cor1.x - cor2.x);
rect.height = abs(cor1.y - cor2.y);
rect.x = cv::min(cor1.x, cor2.x);
rect.y = cv::min(cor1.y, cor2.y);
cv::Mat cutTempImg(img, rect); //Selecting a ROI(region of interest) from the original img
cv::namedWindow("Cut Temporary Image");
cv::imshow("Cut Temporary Image", cutTempImg); //showing the cropped image
leftButtonDown = false;
leftButtonUp = false;
}
}
int main(){
img = cv::imread("image.jpg");
cv::namedWindow("Original");
cv::imshow("Original", img);
cv::setMouseCallback("Original", mouseCall); //setting the mouse callback for selecting the region with mouse
while (char(cv::waitKey(1) != 'q')) //waiting for the 'q' key to finish the execution
{
}
return 0;
}
And it is working fine. Now I want to make same code, with using class.(OOP)
But cv::setMouseCallback function is not letting me do that.
Can any one help me fix this?
My second code :
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <string>
class ResizeImage {
cv::Mat img;
cv::Point cor1, cor2;
cv::Rect rect;
std::string name;
public:
void setImg(cv::Mat img) { this->img = img; };
cv::Mat getImg() { return img; };
void setRect();
int getCoordinates1X() { return cor1.x; };
int getCoordinates1Y() { return cor1.y; };
int getCoordinates2X() { return cor2.x; };
int getCoordinates2Y() { return cor2.y; };
void setCoordinates1(int x, int y) { this->cor1.x = x; this->cor1.y = y; };
void setCoordinates2(int x, int y) { this->cor2.x = x; this->cor2.y = y; };
void mouseCall(int event, int x, int y, int flags, void* param);
void showImgOriginal();
void setImgName(std::string name) { this->name = name; };
std::string getImgName() { return name; };
};
void ResizeImage :: showImgOriginal() {
cv::namedWindow(name, CV_WINDOW_AUTOSIZE);
cv::imshow(name, img);
};
void ResizeImage::setRect() {
rect.width = abs(cor1.x - cor2.x);
rect.height = abs(cor1.y - cor2.y);
rect.x = cv::min(cor1.x, cor2.x);
rect.y = cv::min(cor1.y, cor2.y);
}
void ResizeImage::mouseCall(int event, int x, int y, int flags, void* param) {
if (event == cv::EVENT_LBUTTONDOWN) //finding first corner
{
leftButtonDown = true; setCoordinates1(x,y); std::cout << "Corner 1: " << getCoordinates1X()<<" "<<getCoordinates1Y() << std::endl;
}
if (event == cv::EVENT_LBUTTONUP) {
if (abs(x - cor1.x)>20 && abs(y - cor1.y)>5) //finding second corner and checking whether the region is too small
{
leftButtonUp = true; setCoordinates2(x, y); std::cout << "Corner 2: " << getCoordinates2X() << " " << getCoordinates2Y() << std::endl;
}
else { std::cout << "Select more than 5 pixels" << std::endl; }
}
if (leftButtonDown == true && leftButtonUp == false) //when the left button is down
{
cv::Point pt; pt.x = x; pt.y = y;
cv::Mat temp_img = img.clone();
rectangle(temp_img, cor1, pt, cv::Scalar(0, 0, 255)); //drawing a rectangle continuously
cv::imshow("Original", temp_img);
}
else if (event == cv::EVENT_MOUSEMOVE) //tracking mouse movement
{
std::cout << "Mouse moving over the window - position (" << x << ", " << y << ")" << std::endl;
}
if (leftButtonDown == true && leftButtonUp == true) //when the selection is done
{
setRect();
cv::Mat cutTempImg(img, rect); //Selecting a ROI(region of interest) from the original img
cv::namedWindow("Cut Temporary Image");
cv::imshow("Cut Temporary Image", cutTempImg); //showing the cropped image
leftButtonDown = false;
leftButtonUp = false;
}
}
int main(){
cv::Mat img = cv::imread("image.jpg");
ResizeImage img_;
img_.setImg(img);
img_.setImgName("original");
img_.showImgOriginal();
cv::setMouseCallback(img_.getImgName(),img_.mouseCall());
while (char(cv::waitKey(1) != 'q')) //waiting for the 'q' key to finish the execution
{
}
return 0;
}
Code after changes :
//Program is loading image, and showing it to user.
//User can use mouse to make a rectangle and cut the loaded image.
//Command line is tracking mouse movements and the coordinates of the rectangle.
//User can end the program using 'q'.
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <string>
bool leftButtonDown = false, leftButtonUp = false; //flags for mouse clicks
class ResizeImage {
cv::Mat img; //image to process
cv::Point cor1, cor2; //coordinates of selected rectangle
cv::Rect rect; //rectangle
std::string name; //windows name
public:
//////////////////////////////////////////////////////////////////////////////
ResizeImage() { std::cout << "Starting..."<<std::endl; }; //Constructor/Destructor
~ResizeImage() { std::cout << "Ending..." << std::endl; };
//////////////////////////////////////////////////////////////////////////////
void setImg(cv::Mat img) { this->img = img; };
void setImgName(std::string name) { this->name = name; }; //set functions
void setRect();
void setCoordinates1(int x, int y) { this->cor1.x = x; this->cor1.y = y; };
void setCoordinates2(int x, int y) { this->cor2.x = x; this->cor2.y = y; };
//////////////////////////////////////////////////////////////////////////////
int getCoordinates1X() { return cor1.x; }; //getfunctions
int getCoordinates1Y() { return cor1.y; };
int getCoordinates2X() { return cor2.x; };
int getCoordinates2Y() { return cor2.y; };
cv::Mat getImg() { return img; };
std::string getImgName() { return name; };
//////////////////////////////////////////////////////////////////////////////
static void mouseCall(int event, int x, int y, int flags, void* param); //static function
//////////////////////////////////////////////////////////////////////////////
void showImgOriginal(); //show function (priting image)
//////////////////////////////////////////////////////////////////////////////
};
void ResizeImage :: showImgOriginal() { //showing image
cv::namedWindow(name, CV_WINDOW_AUTOSIZE);
cv::imshow(name, img);
};
void ResizeImage::setRect() { //calculating selected rectangle
rect.width = abs(cor1.x - cor2.x);
rect.height = abs(cor1.y - cor2.y);
rect.x = cv::min(cor1.x, cor2.x);
rect.y = cv::min(cor1.y, cor2.y);
}
void ResizeImage::mouseCall(int event, int x, int y, int flags, void* param) {
if (event == cv::EVENT_LBUTTONDOWN) //finding first corner
{
leftButtonDown = true; ((ResizeImage*)param)->cor1.x = x; ((ResizeImage*)param)->cor1.y = y; //saving coordinates
std::cout << "Corner 1: " << ((ResizeImage*)param)->cor1.x << " " << ((ResizeImage*)param)->cor1.y << std::endl; //printing coordinates
}
if (event == cv::EVENT_LBUTTONUP) {
if (abs(x - ((ResizeImage*)param)->cor1.x)>20 && abs(y - ((ResizeImage*)param)->cor1.y)>10) //finding second corner and checking whether the region is too small
{
leftButtonUp = true; ((ResizeImage*)param)->cor2.x = x; ((ResizeImage*)param)->cor2.y = y; //saving coordinates
std::cout << "Corner 2: " << ((ResizeImage*)param)->cor2.x << " " << ((ResizeImage*)param)->cor2.y << std::endl; //printing coordinates
}
else { std::cout << "Select more than 10 pixels" << std::endl; } //warning if region is too small
}
if (leftButtonDown == true && leftButtonUp == false) //when the left button is down
{
cv::Point pt; pt.x = x; pt.y = y;
cv::Mat temp_img = ((ResizeImage*)param)->img.clone();
rectangle(temp_img, ((ResizeImage*)param)->cor1, pt, cv::Scalar(0, 0, 255)); //drawing a rectangle continuously
}
else if (event == cv::EVENT_MOUSEMOVE) //tracking mouse movement
{
std::cout << "Mouse moving over the window - position (" << x << ", " << y << ")" << std::endl;
}
if (leftButtonDown == true && leftButtonUp == true) //when the selection is done
{
((ResizeImage*)param)->setRect();
cv::Mat cutTempImg(((ResizeImage*)param)->img, ((ResizeImage*)param)->rect); //Selecting a ROI(region of interest) from the original img
cv::namedWindow("Cut Temporary Image");
cv::imshow("Cut Temporary Image", cutTempImg); //showing the cropped image
leftButtonDown = false;
leftButtonUp = false;
}
}
int main() {
cv::Mat img = cv::imread("image.jpg");
ResizeImage img_;
img_.setImg(img);
img_.setImgName("Original");
img_.showImgOriginal();
cv::setMouseCallback(img_.getImgName(),ResizeImage::mouseCall,&img_);
while (char(cv::waitKey(1) != 'q')) //waiting for the 'q' key to finish the execution
{
}
return 0;
}
If you want to use a class method as a callback, you should indeed declare the method as static. However, you also need to pass an object to the callback to be able to access non static members of your class such as cor1 or cor2.
Here is a minimal example of how you can achieve this:
class Call {
public:
Call(int i) : a(i){};
int a;
static void mouse(int event, int x, int y, int flags, void* param) {
std::cout << ((Call*)param)->a << std::endl;
}
};
cv::namedWindow("Call");
Call call(10);
cv::setMouseCallback("Call", Call::mouse, &call);
cv::imshow("Call", cv::Mat(100, 100, CV_8U, cv::Scalar(0)));
cv::waitKey();
I create a Call object and use its mouse method as the window callback while still passing the object to the call back.
You should make the function static:
static void mouseCall(int event, int x, int y, int flags, void* param);
and then:
cv::setMouseCallback(img_.getImgName(),ResizeImage::mouseCall);
I'm trying to implement a basic solution for trackball with openGL.
There are 2 rotations :
- around x axis (right direction) , linked with up/down mouse movement.
- around y axis (up direction) , linked with right/left mouse movement.
The cube is centered on 0, camera is on z axis. Axis are drawn : x in blue, y in green, z in red.
2 different groups of rotations:
90° around x by moving the mouse down. Z toward down, x right, y in front.
Then another rotation: 90° around z (z as displayed), mouse movement on the right. z towards the right direction, x up and y in front.
I process again, position start from scratch.
90° around y. y : up , z: right , x: in front
Another rotation of 90° around z. x: up , z: right : y : in front .
I identify a different behaviour between the second rotations.
For coherence, I was waiting that for the first operation, the second rotation was around z
Or for the second operation, the second rotation was around x axis.
Why ?
For me, the second operation has the goood rotations, that's the behaviour i would like to have.
Thank you for your help.
Below the code
cube.cpp :
#include <SDL/SDL.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <cstdlib>
#include <iostream>
#include "sdlglutils.h"
#include "trackballcamera.h"
using namespace std;
void Dessiner();
double angleZ = 0;
double angleX = 0;
double angleY = 0;
TrackBallCamera * camera;
int main(int argc, char *argv[])
{
cout<<"in main cube"<<endl;
freopen("CON", "w", stdout);
freopen("CON", "r", stdin);
freopen("CON", "w", stderr);
SDL_Event event;
SDL_Init(SDL_INIT_VIDEO);
atexit(SDL_Quit);
SDL_WM_SetCaption("SDL GL Application", NULL);
SDL_SetVideoMode(640, 480, 32, SDL_OPENGL);
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluPerspective(70,(double)640/480,1,1000);
glEnable(GL_DEPTH_TEST);
camera = new TrackBallCamera();
camera->setScrollSensivity(10);
Dessiner();
Uint32 last_time = SDL_GetTicks();
Uint32 current_time,ellapsed_time;
Uint32 start_time;
GLUquadric* params;
params = gluNewQuadric();
for (;;)
{
start_time = SDL_GetTicks();
while (SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_QUIT:
exit(0);
break;
case SDL_MOUSEBUTTONUP:
cout<<"SDL_MOUSEBUTTONUP"<<endl;
camera->OnMouseButton(event.button);
break;
case SDL_MOUSEBUTTONDOWN:
cout<<"SDL_MOUSEBUTTONDOWN"<<endl;
camera->OnMouseButton(event.button);
break;
case SDL_MOUSEMOTION:
camera->OnMouseMotion(event.motion);
break;
}
}
current_time = SDL_GetTicks();
ellapsed_time = current_time - last_time;
last_time = current_time;
//angleZ += 0.05 * ellapsed_time;
//angleX += 0.05 * ellapsed_time;
Dessiner();
ellapsed_time = SDL_GetTicks() - start_time;
if (ellapsed_time < 10)
{
SDL_Delay(10 - ellapsed_time);
}
}
return 0;
}
void dessinerRepere(unsigned int echelle = 10)
{
//glPushMatrix();
glScalef(echelle,echelle,echelle);
glBegin(GL_LINES);
glColor3ub(0,0,255);
glVertex3i(0,0,0);
glVertex3i(1,0,0);
glColor3ub(0,255,0);
glVertex3i(0,0,0);
glVertex3i(0,1,0);
glColor3ub(255,0,0);
glVertex3i(0,0,0);
glVertex3i(0,0,1);
glEnd();
//glPopMatrix();
}
void Dessiner()
{
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity( );
//gluLookAt(20,20,20,0,0,0,0,0,1);
camera->look(0,0,camera->getDistance()
,0,0,0
,0,1,0);
//glRotated(angleZ,0,0,1);
//glRotated(angleX,1,0,0);
glBegin(GL_QUADS);
glColor3ub(255,0,0); //face rouge
glVertex3d(1,1,1);
glVertex3d(1,1,-1);
glVertex3d(-1,1,-1);
glVertex3d(-1,1,1);
glColor3ub(0,255,0); //face verte
glVertex3d(1,-1,1);
glVertex3d(1,-1,-1);
glVertex3d(1,1,-1);
glVertex3d(1,1,1);
glColor3ub(0,0,255); //face bleue
glVertex3d(-1,-1,1);
glVertex3d(-1,-1,-1);
glVertex3d(1,-1,-1);
glVertex3d(1,-1,1);
glColor3ub(255,255,0); //face jaune
glVertex3d(-1,1,1);
glVertex3d(-1,1,-1);
glVertex3d(-1,-1,-1);
glVertex3d(-1,-1,1);
glColor3ub(0,255,255); //face cyan
glVertex3d(1,1,-1);
glVertex3d(1,-1,-1);
glVertex3d(-1,-1,-1);
glVertex3d(-1,1,-1);
glColor3ub(255,0,255); //face magenta
glVertex3d(1,-1,1);
glVertex3d(1,1,1);
glVertex3d(-1,1,1);
glVertex3d(-1,-1,1);
glEnd();
//glLoadIdentity( );
dessinerRepere();
glFlush();
SDL_GL_SwapBuffers();
}
trackballcamera.cpp :
#include "trackballcamera.h"
#include <GL/gl.h>
#include <GL/glu.h>
#include <cmath>
#include "trackballcamera.h"
#include "sdlglutils.h"
void TrackBallCamera::setDistance(const double & newDistance)
{
_distance = newDistance;
}
const double & TrackBallCamera::getDistance() const
{
return _distance;
}
TrackBallCamera::TrackBallCamera()
{
const char *hand1[] =
{
/* width height num_colors chars_per_pixel */
" 16 16 3 1 ",
/* colors */
"X c #000000",
". c #ffffff",
" c None",
/* pixels */
" XX ",
" XX X..XXX ",
" X..XX..X..X ",
" X..XX..X..X X ",
" X..X..X..XX.X",
" X..X..X..X..X",
" XX X.......X..X",
"X..XX..........X",
"X...X.........X ",
" X............X ",
" X...........X ",
" X..........X ",
" X.........X ",
" X.......X ",
" X......X ",
" X......X ",
"0,0"
};
const char *hand2[] =
{
/* width height num_colors chars_per_pixel */
" 16 16 3 1 ",
/* colors */
"X c #000000",
". c #ffffff",
" c None",
/* pixels */
" ",
" ",
" ",
" ",
" XX XX XX ",
" X..X..X..XX ",
" X........X.X ",
" X.........X ",
" XX.........X ",
" X...........X ",
" X...........X ",
" X..........X ",
" X.........X ",
" X.......X ",
" X......X ",
" X......X ",
"0,0"
};
_hand1 = cursorFromXPM(hand1);
_hand2 = cursorFromXPM(hand2);
SDL_SetCursor(_hand1);
_holdRotation = false;
_holdTranslation = false;
_angleX = 0;
_angleY = 0;
_angleZ = 0;
_transX = 0;
_transY = 0;
_transZ = 0;
_distance = 50;
_motionSensivity = 0.3;
//_scrollSensivity = 1;
_scrollSensivity = 10;
}
void TrackBallCamera::OnMouseMotion(const SDL_MouseMotionEvent & event)
{
printf("OnMouseMotion; _holdRotation:%d; _holdTranslation:%d\n", _holdRotation, _holdTranslation);
if (_holdRotation)
{
_angleY += event.xrel*_motionSensivity;
_angleX += event.yrel*_motionSensivity;
printf("_angleX:%lf; _angleY:%lf\n",_angleX,_angleY);
// if (_angleY > 90)
// _angleY = 90;
// else if (_angleY < -90)
// _angleY = -90;
}
if (_holdTranslation)
{
_transX += event.xrel*_motionSensivity;
_transY += event.yrel*_motionSensivity;
printf("_transZ:%lf, _transY:%lf\n",_transZ, _transY);
}
}
void TrackBallCamera::OnMouseButton(const SDL_MouseButtonEvent & event)
{
printf("OnMouseButton\n");
if (event.button == SDL_BUTTON_LEFT)
{
if ((_holdRotation)&&(event.type == SDL_MOUSEBUTTONUP))
{
_holdRotation = false;
SDL_SetCursor(_hand1);
}
else if ((!_holdRotation)&&(event.type == SDL_MOUSEBUTTONDOWN))
{
_holdRotation = true;
SDL_SetCursor(_hand2);
}
printf("_holdRotation:%d\n",_holdRotation);
}
else if (event.button == SDL_BUTTON_RIGHT)
{
if ((_holdTranslation)&&(event.type == SDL_MOUSEBUTTONUP))
{
_holdTranslation = false;
SDL_SetCursor(_hand1);
}
else if ((!_holdTranslation)&&(event.type == SDL_MOUSEBUTTONDOWN))
{
_holdTranslation = true;
SDL_SetCursor(_hand2);
}
}
else if ((event.button == SDL_BUTTON_WHEELUP)&&(event.type == SDL_MOUSEBUTTONDOWN))
{
printf("OK WHEELUP, _scrollSensivity:%lf; _distance:%lf\n", _scrollSensivity,_distance);
_distance -= _scrollSensivity;
//if (_distance < 0.1)
//_distance = 0.1;
printf("APRES WHEELUP, _distance:%lf\n", _distance);
}
else if ((event.button == SDL_BUTTON_WHEELDOWN)&&(event.type == SDL_MOUSEBUTTONDOWN))
{
printf("OK WHEELDOWN, _distance:%lf\n",_distance);
_distance += _scrollSensivity;
}
}
void TrackBallCamera::OnKeyboard(const SDL_KeyboardEvent & event)
{
if ((event.type == SDL_KEYDOWN)&&(event.keysym.sym == SDLK_HOME))
{
_angleY = 0;
_angleX = 0;
}
}
void TrackBallCamera::setMotionSensivity(double sensivity)
{
_motionSensivity = sensivity;
}
void TrackBallCamera::setScrollSensivity(double sensivity)
{
_scrollSensivity = sensivity;
}
TrackBallCamera::~TrackBallCamera()
{
SDL_FreeCursor(_hand1);
SDL_FreeCursor(_hand2);
SDL_SetCursor(NULL);
}
//camera->look(cloud.pointPosition[lastElement*3],0,75,cloud.pointPosition[lastElement*3],0,0,0,1,0);
void TrackBallCamera::look(const GLfloat& xPointOfView
,const GLfloat& yPointOfView
,const GLfloat& zPointOfView
,const GLfloat& xCenter
,const GLfloat& yCenter
,const GLfloat& zCenter
,const GLfloat& xVerticalVector
,const GLfloat& yVerticalVector
,const GLfloat& zVerticalVector
)
//void TrackBallCamera::look()
{
//gluLookAt(_distance,0,0,
//0,0,0,
//0,0,1);
//printf("look, xPointOfView:%lf\n",xPointOfView);
gluLookAt(xPointOfView,yPointOfView,zPointOfView,
xCenter,yCenter,zCenter,
xVerticalVector,yVerticalVector,zVerticalVector);
glRotated(_angleX,1,0,0);
glRotated(_angleY,0,1,0);
//glRotated(_angleZ,0,0,1);
//glTranslated(_transX,0,0);
//glTranslated(0,_transY,0);
//glTranslated(0,0,_transZ);
}
trackballcamera.h :
#ifndef TRACKBALLCAMERA_H
#define TRACKBALLCAMERA_H
#include <SDL/SDL.h>
#include <GL/gl.h>
class TrackBallCamera
{
public:
TrackBallCamera();
virtual void OnMouseMotion(const SDL_MouseMotionEvent & event);
virtual void OnMouseButton(const SDL_MouseButtonEvent & event);
virtual void OnKeyboard(const SDL_KeyboardEvent & event);
//virtual void look();
virtual void look(const GLfloat& xPointOfView
,const GLfloat& yPointOfView
,const GLfloat& zPointOfView
,const GLfloat& xCenter
,const GLfloat& yCenter
,const GLfloat& zCenter
,const GLfloat& xVerticalVector
,const GLfloat& yVerticalVector
,const GLfloat& zVerticalVector
);
virtual void setMotionSensivity(double sensivity);
virtual void setScrollSensivity(double sensivity);
void setDistance(const double & newDistance);
const double & getDistance() const ;
virtual ~TrackBallCamera();
protected:
double _motionSensivity;
double _scrollSensivity;
//bool _hold;
bool _holdRotation;
bool _holdTranslation;
double _distance;
double _angleX;
double _angleY;
double _angleZ;
double _transX;
double _transY;
double _transZ;
SDL_Cursor * _hand1;
SDL_Cursor * _hand2;
};
#endif //TRACKBALLCAMERA_H
sdlglutils.cpp :
#include "sdlglutils.h"
#include <SDL/SDL.h>
//#include <SDL/SDL_image.h>
#include <GL/glu.h>
#include <cstring>
#include <cstdlib>
SDL_Cursor * cursorFromXPM(const char * xpm[])
{
int i, row, col;
int width, height;
Uint8 * data;
Uint8 * mask;
int hot_x, hot_y;
SDL_Cursor * cursor = NULL;
sscanf(xpm[0], "%d %d", &width, &height);
data = (Uint8*)calloc(width/8*height,sizeof(Uint8));
mask = (Uint8*)calloc(width/8*height,sizeof(Uint8));
i = -1;
for ( row=0; row<height; ++row )
{
for ( col=0; col<width; ++col )
{
if ( col % 8 )
{
data[i] <<= 1;
mask[i] <<= 1;
}
else
{
++i;
data[i] = mask[i] = 0;
}
switch (xpm[4+row][col])
{
case 'X':
data[i] |= 0x01;
mask[i] |= 0x01;
break;
case '.':
mask[i] |= 0x01;
break;
case ' ':
break;
}
}
}
sscanf(xpm[4+row], "%d,%d", &hot_x, &hot_y);
//printf("data :%" PRIu8 "; mask:%" PRIu8 ";width:%d; height:%d; hot_x:%d; hot_y:%d\n", *data, *mask, width, height, hot_x, hot_y);
cursor = SDL_CreateCursor(data, mask, width, height, hot_x, hot_y);
free(data);
free(mask);
return cursor;
}
sdlglutils.h :
#ifndef SDLGLUTILS_H
#define SDLGLUTILS_H
#include <GL/gl.h>
#include <SDL/SDL.h>
SDL_Cursor * cursorFromXPM(const char * xpm[]);
#endif //SDLGLUTILS_H
You seem to be running into a classic problem with Euler Angles, the order of incremental rotations matters.
Furthermore for an intuitive Trackball behavior for 3D rotation, you need to consider that the model and global rotation axes are not aligned, and thus when you apply the trackball deltas to the global axes, the rotation might be in an unexpected direction. To remedy this, you need to do a coordinate transformation of the user input into global space, or compute a rotation matrix in user space, and transform that rotation matrix from model space into global space, so that the rendering does the right thing.