Using Cocos2d-x 3.4 on Windows7.
How to change "MenuItemImage" image on mouse cursor focus? (on Windows)
** I want "mouse over(hover) effect" to MenuItemImage. **
I know, how to create "not touch" or "clicking" button.
auto button = MenuItemImage::create(
"button_normal.png",
"button_pressed.png",
[](Ref* ref){
// do anything if clicking
});
auto menuButton = Menu::create(button, NULL);
auto winSize = Director::getInstance()->getWinSize();
menuButton->setPosition(Vec2(winSize.width / 2.0, winSize.height / 2.0));
this->addChild(menuButton);
But this method is not change image on focus.
Create a EventListenerMouse to look for mouse over event.
//
// MouseOverMenuItem.h
// MouseOver
//
// Created by Baris Atamer on 3/15/15.
//
//
#ifndef __MouseOver__MouseOverMenuItem__
#define __MouseOver__MouseOverMenuItem__
#include "cocos2d.h"
USING_NS_CC;
class MouseOverMenuItem : public MenuItemImage
{
public:
~MouseOverMenuItem();
static MouseOverMenuItem * create(const std::string &normalImage, const std::string &selectedImage, const std::string &disabledImage, const ccMenuCallback& callback);
protected:
EventListenerMouse* mouseListener;
private:
void onMouseMove(Event *event);
void setMouseListener();
};
#endif /* defined(__MouseOver__MouseOverMenuItem__) */
//
// MouseOverMenuItem.cpp
// MouseOver
//
// Created by Baris Atamer on 3/15/15.
//
//
#include "MouseOverMenuItem.h"
MouseOverMenuItem::~MouseOverMenuItem()
{
_eventDispatcher->removeEventListener(mouseListener);
}
MouseOverMenuItem* MouseOverMenuItem::create(const std::string &normalImage, const std::string &selectedImage, const std::string &disabledImage, const ccMenuCallback &callback)
{
MouseOverMenuItem *ret = new (std::nothrow) MouseOverMenuItem();
if (ret && ret->initWithNormalImage(normalImage, selectedImage, disabledImage, callback))
{
ret->setMouseListener();
ret->autorelease();
return ret;
}
CC_SAFE_DELETE(ret);
return nullptr;
}
void MouseOverMenuItem::onMouseMove(Event *event)
{
EventMouse* e = (EventMouse*)event;
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 locationInNode = convertToNodeSpace(Vec2(e->getCursorX(), e->getCursorY() + visibleSize.height ));
Rect r = Rect(0,0, getContentSize().width, getContentSize().height);
// Show selected image if mouse over
r.containsPoint(locationInNode) ? selected() : unselected();
}
void MouseOverMenuItem::setMouseListener()
{
// Create a mouse listener
mouseListener = EventListenerMouse::create();
mouseListener->onMouseMove = CC_CALLBACK_1(MouseOverMenuItem::onMouseMove, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(mouseListener, this);
}
Usage :
auto button = MouseOverMenuItem::create("button_normal.png", "button_pressed.png", "", [](Ref* ref){
// do anything if clicking
log("click!");
});
button->setPosition(Vec2(winSize.width*.5, winSize.height*.5) );
// create menu, it's an autorelease object
auto menu = Menu::create(button, NULL);
menu->setPosition(Vec2::ZERO);
this->addChild(menu, 1);
try MenuItemImage add to Menu.
auto button = MenuItemImage::create ...
auto menu = Menu::create(button , nullptr);
addChild(menu);
Related
There are over 20 Layers like Layer01.cpp, Layer02.cpp, Layer03.cpp ...
and there is a tableview named "itemSlots" in HelloWorld.cpp.
When user touch dragon button in Layer01,
a banana sprite in HelloWorld.cpp will be dissappeared,
and a poop appear in itemSlots.
That is all I want to do and I thought it is quite simple.
I made Layers and tableview also, like below,
but still couldn't find a way to make interact between button and sprite
which are made in different cpps.
Layer01.h
#ifndef __LAYER01__H__
#define __LAYER01__H__
#include "cocos2d.h"
#include "ui/CocosGUI.h"
class Layer01 : public cocos2d::LayerColor
{
public:
Layer01();
virtual bool init();
cocos2d::ui::Button* dragon;
void touchDragon();
private:
};
#endif
Layer01.cpp
#include "Layer01.h"
USING_NS_CC;
Layer01::Layer01()
{
bool bOk = initWithColor(Color4B::BLACK, 750, 400);
if (bOk == true) {
this->autorelease();
init();
};
}
bool Layer01::init()
{
scene01 = Sprite::create("images/scene01.jpg");
scene01->setScale(this->getContentSize().width/sc02a->getContentSize().width);
scene01->setAnchorPoint(Point::ZERO);
scene01->setPosition(Point::ZERO);
this->addChild(scene01);
dragon = ui::Button::create("images/dragon.png", "images/dragon.png", "");
dragon->setContentSize(Size(50, 50));
dragon->setPosition(Point(250,300));
dragon->addClickEventListener(CC_CALLBACK_0(Layer01::touchDragon, this));
this->addChild(dragon);
return true;
}
void Layer01::touchDragon()
{
/*
layer01->removeChild(banana);
auto poopCell = itemSlots->cellAtIndex(2);
poopCell->addChild(poop);
*/
}
HelloWorld.h
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
#include "Layer01.h"
#include "ui/CocosGUI.h"
#include "cocos-ext.h"
#include "CustomTableViewCell.h"
class HelloWorld : public cocos2d::Layer,
public cocos2d::extension::TableViewDataSource,
public cocos2d::extension::TableViewDelegate
{
public:
static cocos2d::Scene* createScene();
virtual bool init();
CREATE_FUNC(HelloWorld);
cocos2d::Sprite* banana;
cocos2d::Sprite* poop;
cocos2d::extension::TableView* itemSlots;
virtual void tableCellTouched(cocos2d::extension::TableView* table,
cocos2d::extension::TableViewCell* cell);
virtual cocos2d::Size tableCellSizeForIndex
(cocos2d::extension::TableView* table, ssize_t idx);
virtual cocos2d::extension::TableViewCell* tableCellAtIndex
(cocos2d::extension::TableView* table, ssize_t idx);
virtual ssize_t numberOfCellsInTableView(cocos2d::extension::TableView* view);
};
#endif // __HELLOWORLD_SCENE_H__
HelloWorld.cpp
#include "HelloWorldScene.h"
USING_NS_CC;
USING_NS_CC_EXT;
Scene* HelloWorld::createScene()
{
auto scene = Scene::create();
auto layer = HelloWorld::create();
scene->addChild(layer);
return scene;
}
bool HelloWorld::init()
{
if ( !Layer::init() )
{
return false;
}
layer01 = new Layer01();
layer->setPosition(Point(0, 100));
this->addChild(layer01);
banana = Sprite::create("images/banana.png");
banana->setPosition(Point(300,300));
layer01->addChild(banana);
poop = Sprite::create("images/poop.png");
itemSlots = TableView::create(this, Size(535, 70));
itemSlots->setDirection(ScrollView::Direction::HORIZONTAL);
itemSlots->setPosition(Point(115, 15));
itemSlots->setDelegate(this);
this->addChild(itemSlots);
itemSlots->reloadData();
return true;
}
void HelloWorld::tableCellTouched(TableView* table, TableViewCell* cell)
{
}
Size HelloWorld::tableCellSizeForIndex(TableView* table, ssize_t idx)
{
return Size(77, 77);
}
TableViewCell* HelloWorld::tableCellAtIndex(TableView* table, ssize_t idx)
{
auto string = String::createWithFormat("%ld", idx);
TableViewCell* cell = table->dequeueCell();
if (cell == false)
{
cell = new CustomTableViewCell();
cell->autorelease();
auto sprite01 = Sprite::create();
sprite01->setAnchorPoint(Point::ZERO);
sprite01->setPosition(Point::ZERO);
cell->addChild(sprite01);
auto label = LabelTTF::create(string->getCString(), "arial", 20.0);
label->setAnchorPoint(Point::ZERO);
label->setPosition(Point(5, 5));
label->setTag(120);
cell->addChild(label);
}
else {
auto label = (LabelTTF*)cell->getChildByTag(120);
label->setString(string->getCString());
}
return cell;
}
ssize_t HelloWorld::numberOfCellsInTableView(TableView* table)
{
return 20;
}
The easiest but unsafe way is to do following:
//Layer01.cpp
#include "HelloWorld.h"
...
void Layer01::touchDragon()
{
removeChild(banana);
// As your parent is a HelloWorld you can cast it:
HelloWorld* helloWorld = (HelloWorld*)getParent();
auto poopCell = helloWorld->itemSlots->cellAtIndex(2);
poopCell->addChild(helloWorld->poop);
}
But poop will be automatically garbage collected at that time. You need to retain it after creating and release when no longer need.
The better option would be to have a pointer to the HelloWorld layer in the Layer01 and have a separate method for setting a poop:
Layer01.h
// Forward declaration
class HelloWorld;
class Layer01
{
...
HelloWorld* m_hellowWorld;
// Don't forget about create function
static Layer01* create(HelloWorld* helloWorld)
{
Layer01* result = new (std::nothrow) Layer01();
if(result && result->init(helloWorld))
{
result->autorelease();
}
else
{
delete result;
result = nullptr;
}
return result;
}
bool Layer01::init(HelloWorld* helloWorld);
...
};
Layer01.cpp
#include "Layer01.h"
#include "HelloWorld.h"
Layer01::Layer01()
: HelloWorld(nullptr)
{}
bool Layer01::init(HelloWorld* helloWorld)
{
removeChild(banana);
m_hellowWorld = helloWorld;
...
}
void Layer01::touchDragon()
{
m_hellowWorld->setPoop();
}
HelloWorld.h
class HelloWorld
{
...
void setPoop();
...
};
HelloWorld.cpp
...
void HelloWorld::setPoop()
{
auto poopCell = itemSlots->cellAtIndex(2);
poopCell->addChild(Sprite::create("images/poop.png"));
}
I'm trying to load a CCSprite from Facebook server. But when it loads, it appear a black image. And I don't know why. I think that CURL buffer it's 0 I leave my code. I don't know if it's an easy way to do it.
Edit: I already try on the main thread, and also it's black
Note: I'm running it on a pthread.
//called at the end of init
pthread_t tid1;
pthread_create(&tid1, NULL, &loadSync, this);
struct MemoryStruct {
char *memory;
size_t size;
};
static size_t
WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) {
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1);
if (mem->memory == NULL) {
/* out of memory! */
printf("not enough memory (realloc returned NULL)\n");
exit(EXIT_FAILURE);
}
memcpy(&(mem->memory[mem->size]), contents, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
return realsize;
}
//This class it's called helpBlock
static void *loadSync(void *args) {
helpBlock *thiz = (helpBlock*)args;
CURL *curl_handle;
struct MemoryStruct chunk;
/* will be grown as needed by the realloc above /
chunk.size = 0; / no data at this point */
chunk.memory = (char*)malloc(1);
chunk.size = 0;
curl_global_init(CURL_GLOBAL_ALL);
/* init the curl session */
curl_handle = curl_easy_init();
/* specify URL to get */
curl_easy_setopt(curl_handle, CURLOPT_URL, "http://graph.facebook.com/4/picture?width=60&height=60");
/* send all data to this function */
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
/* we pass our 'chunk' struct to the callback function */
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&chunk);
/* some servers don't like requests that are made without a user-agent
field, so we provide one */
curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "libcurl-agent/1.0");
/* get it! */
curl_easy_perform(curl_handle);
/* cleanup curl stuff */
curl_easy_cleanup(curl_handle);
//mySprite->setTexture(CCTextureCache::sharedTextureCache()->addImage("newImage.png"));
CCLog("%s - %d", chunk.memory, chunk.size);
CCImage* img = new CCImage;
img->initWithImageData((void*)chunk.memory, (long)chunk.size, CCImage::kFmtPng);
cocos2d::CCTexture2D* texture = new cocos2d::CCTexture2D();
texture->initWithImage(img);
thiz->firstFriend->frontSprite->setTexture(texture);
if(chunk.memory)
free(chunk.memory);
/* we're done with libcurl, so clean it up */
curl_global_cleanup();
return NULL;
}
i've successfully cross compiled the sdl library for the android platform now i want to display my sdl forms like SDL_Surface and the SDL_Rect in the android screen .
How is that possible?
here is my first try
SDLRenderer::SDLRenderer () :
bmp (NULL),
screen (NULL),
imgConvertCtx (NULL),
isInit (false),
quitKeyPressed (false)
{
}
SDLRenderer::~SDLRenderer ()
{
}
bool SDLRenderer::init (int width, int height)
{ LOGI("sdlrenderer init");
this->screen = SDL_SetVideoMode(width, height, 0, 0);
if(!screen){
LOGI("!screen");
return false;
}
this->bmp = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, this->screen);
LOGI("SDL_CreateYUVOverlay passed");
return true;
}
bool SDLRenderer::processEvents ()
{
SDL_Event sdlEvent;
while(SDL_PollEvent(&sdlEvent))
{
switch(sdlEvent.type)
{
case SDL_KEYDOWN:
if(sdlEvent.key.keysym.sym == SDLK_ESCAPE)
this->quitKeyPressed = true;
break;
case SDL_QUIT: this->quitKeyPressed = true; break;
}
}
return true;
}
bool SDLRenderer::isQuitKeyPressed ()
{
return this->quitKeyPressed;
}
void SDLRenderer::onVideoDataAvailable (const uint8_t **data, videoFrameProperties* props)
{LOGI("sdlrenderer data availabe");
if(!this->isInit){
this->isInit = this->init(props->width, props->height);
LOGI("sdlrenderer data availabe calling render init");
}
LOGI("before SDL_LockYUVOverlay(bmp);");
SDL_LockYUVOverlay(bmp);
LOGI("after SDL_LockYUVOverlay(bmp);");
AVPicture pict;
LOGI("after AVPicture pict;");
pict.data[0] = bmp->pixels[0];
pict.data[1] = bmp->pixels[2];
pict.data[2] = bmp->pixels[1];
pict.linesize[0] = bmp->pitches[0];
pict.linesize[1] = bmp->pitches[2];
pict.linesize[2] = bmp->pitches[1];
LOGI("after creating avpicture");
// Convert the image into YUV format that SDL uses
if(imgConvertCtx == NULL)
{
int w = props->width;
int h = props->height;
imgConvertCtx = sws_getContext(props->width, props->height, (PixelFormat)props- >pxlFmt, w, h, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
if(imgConvertCtx == NULL)
{ LOGI("imgConvertCtx == NULL");
fprintf(stderr, "Cannot initialize the conversion context!\n");
exit(1);
}
}
sws_scale(imgConvertCtx, data, props->linesize, 0, props->height, pict.data, pict.linesize);
LOGI("calling SDL_UnlockYUVOverlay(bmp);");
SDL_UnlockYUVOverlay(bmp);
rect.x = 0;
rect.y = 0;
rect.w = props->width;
rect.h = props->height;
LOGI("sdlrenderer displaying");
SDL_DisplayYUVOverlay(bmp, &rect);
}
there is my main
int main(int argc, char *argv[])
{
SDLRenderer *renderer = new SDLRenderer();
DASHReceiver *receiver = new DASHReceiver(30);
receiver->Init("http://www----custom url here");
LibavDecoder *decoder = new LibavDecoder(receiver);
decoder->attachVideoObserver(renderer);
decoder->setFrameRate(24);
decoder->init();
bool eos = false;
while(!renderer->isQuitKeyPressed() && !eos)
{
eos = !decoder->decode();
renderer->processEvents();
}
decoder->stop();
return 0;
}
Thanks in advance!
You are missing an SDL_Flip or an SDL_UpdateRect to be called on your main SDL_surface, which will update it on the screen.
As far as I can see you are trying to port the bitmovin opensource dash player.
I have already done that and once SDL was ported to android, all other parts of the sofware were working.
I've got exactly the same code as you and this part is working well
be sure to define the surface in the java part
Try google with SDLActivity and use the java code provided from here
Then take a carefull look here http://lists.libsdl.org/pipermail/sdl-libsdl.org/2011-July/081481.html to make some little modification to the java code
// The Unimplemented OpenGL ES API notices *always* indicate you have
// the incorrect context version, which has to be fixed in SDLActivity.java .
int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
int contextAttrs[] = new int[]{
EGL_CONTEXT_CLIENT_VERSION, majorVersion,
EGL10.EGL_NONE
};
EGLContext ctx = egl.eglCreateContext(dpy, config,EGL10.EGL_NO_CONTEXT, contextAttrs);
if (ctx == EGL10.EGL_NO_CONTEXT) {
Log.e("SDL", "Couldn't create context");
return false;
}
/*
EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, null);
if (ctx == EGL10.EGL_NO_CONTEXT) {
Log.e("SDL", "Couldn't create context");
return false;
}
*/
I'm looking for a nice way to address porting Qt applications to Qt/Necessitas (Android).
Some of the QtGUI widgets are absolutely atrocious - unfortunately, including QFileDialog.
Do you know of any replacements with a proper look and feel?
Is making QFileDialog usable anywhere near high priority for Necessitas developers?
#include <QApplication>
#include <QFileDialog>
int main(int argc, char* argv[]) {
QApplication a(argc, argv);
QString fileName = QFileDialog::getOpenFileName(NULL,
QObject::tr("Open Image"), "/home/jana", QObject::tr("Image Files (*.png *.jpg *.bmp)"));
a.exec();
}
Android does not have own, native file dialog. We can use QtAndroidExtras to invoke external application which is able to pick a file:
I wrote wrapper, that could be used for that. Here's full code:
androidfiledialog.h
#ifndef ANDROIDFILEDIALOG_H
#define ANDROIDFILEDIALOG_H
#include <QObject>
#include <QAndroidJniObject>
#include <QtAndroid>
#include <QAndroidActivityResultReceiver>
class AndroidFileDialog : public QObject
{
Q_OBJECT
public:
explicit AndroidFileDialog(QObject *parent = 0);
virtual ~AndroidFileDialog();
bool provideExistingFileName();
private:
class ResultReceiver : public QAndroidActivityResultReceiver {
AndroidFileDialog *_dialog;
public:
ResultReceiver(AndroidFileDialog *dialog);
virtual ~ResultReceiver();
void handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data);
QString uriToPath(QAndroidJniObject uri);
};
static const int EXISTING_FILE_NAME_REQUEST = 1;
ResultReceiver *receiver;
void emitExistingFileNameReady(QString result);
signals:
void existingFileNameReady(QString result);
};
#endif // ANDROIDFILEDIALOG_H
androidfiledialog.cpp
#include "androidfiledialog.h"
AndroidFileDialog::ResultReceiver::ResultReceiver(AndroidFileDialog *dialog) : _dialog(dialog) {}
AndroidFileDialog::ResultReceiver::~ResultReceiver() {}
void AndroidFileDialog::ResultReceiver::handleActivityResult(int receiverRequestCode, int resultCode, const QAndroidJniObject &data)
{
jint RESULT_OK = QAndroidJniObject::getStaticField<jint>("android/app/Activity", "RESULT_OK");
if (receiverRequestCode == EXISTING_FILE_NAME_REQUEST && resultCode == RESULT_OK) {
QAndroidJniObject uri = data.callObjectMethod("getData", "()Landroid/net/Uri;");
QString path = uriToPath(uri);
_dialog->emitExistingFileNameReady(path);
} else {
_dialog->emitExistingFileNameReady(QString());
}
}
QString AndroidFileDialog::ResultReceiver::uriToPath(QAndroidJniObject uri)
{
if (uri.toString().startsWith("file:", Qt::CaseInsensitive)) {
return uri.callObjectMethod("getPath", "()Ljava/lang/String;").toString();
} else {
QAndroidJniObject contentResolver = QtAndroid::androidActivity().callObjectMethod("getContentResolver", "()Landroid/content/ContentResolver;");
QAndroidJniObject cursor = contentResolver.callObjectMethod("query", "(Landroid/net/Uri;[Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)Landroid/database/Cursor;", uri.object<jobject>(), 0, 0, 0, 0);
QAndroidJniObject DATA = QAndroidJniObject::fromString("_data");
jint columnIndex = cursor.callMethod<jint>("getColumnIndexOrThrow", "(Ljava/lang/String;)I", DATA.object<jstring>());
cursor.callMethod<jboolean>("moveToFirst", "()Z");
QAndroidJniObject result = cursor.callObjectMethod("getString", "(I)Ljava/lang/String;", columnIndex);
return result.isValid() ? result.toString() : QString();
}
}
AndroidFileDialog::AndroidFileDialog(QObject *parent) : QObject(parent)
{
receiver = new ResultReceiver(this);
}
AndroidFileDialog::~AndroidFileDialog()
{
delete receiver;
}
bool AndroidFileDialog::provideExistingFileName()
{
QAndroidJniObject ACTION_GET_CONTENT = QAndroidJniObject::fromString("android.intent.action.GET_CONTENT");
QAndroidJniObject intent("android/content/Intent");
if (ACTION_GET_CONTENT.isValid() && intent.isValid()) {
intent.callObjectMethod("setAction", "(Ljava/lang/String;)Landroid/content/Intent;", ACTION_GET_CONTENT.object<jstring>());
intent.callObjectMethod("setType", "(Ljava/lang/String;)Landroid/content/Intent;", QAndroidJniObject::fromString("file/*").object<jstring>());
QtAndroid::startActivity(intent.object<jobject>(), EXISTING_FILE_NAME_REQUEST, receiver);
return true;
} else {
return false;
}
}
void AndroidFileDialog::emitExistingFileNameReady(QString result)
{
emit existingFileNameReady(result);
}
You have to add to your *.pro file:
QT += androidextras
using example:
AndroidFileDialog *fileDialog = new AndroidFileDialog();
connect(fileDialog, SIGNAL(existingFileNameReady(QString)), this, SLOT(openFileNameReady(QString)));
bool success = fileDialog->provideExistingFileName();
if (!success) {
qDebug() << "Problem with JNI or sth like that...";
disconnect(fileDialog, SIGNAL(existingFileNameReady(QString)), this, SLOT(openFileNameReady(QString)));
//or just delete fileDialog instead of disconnect
}
slot implementation:
void MyClass::openFileNameReady(QString fileName)
{
if (!fileName.isNull()) {
qDebug() << "FileName: " << fileName;
} else {
qDebug() << "User did not choose file";
}
}
Please confirm this solution works properly on your device.
You could easily build your own file dialog either with QtWidgets or QML, by using the out-of-the-box QFileSystemModel class or the FolderListModel element.
As for whether it is priority or not, at this point it seems that Necessitas will be absorbed by Digia's efforts to support Android. I doubt there will be significant efforts to style QtWidgets appropriately, since the module is marked as DONE and all the focus for UI is on QML. So, I wouldn't hold by breath if I were you. Plus the stock Qt widgets look completely ugly on non-desktop platforms.
Im writing a programme that opens and openGL windows with an image and connects to my android device where the user uses the device as a sort of trackpad to pan and zoom in and out. All is working fine however the programme gets stuck in the glutMainLoop and will not proceed with accepting data from the device. Apparently glutIdleFunc is the solution to my problem however i cant see how to implement this in my code without getting a memory error? Could someone show me how to put the function into my code so it runs the connection code as well as the opengl stuff?
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <strings.h>
#include <vrpn_Shared.h>
#include <vrpn_Analog.h>
#include <vector>
#include <GL/freeglut.h>
#include <imageviewer.h>
using namespace std;
int done = 0;
int accepted = 0; // Signals that the program should exit
unsigned tracker_stride = 1; // Every nth report will be printed
//-------------------------------------
// This section contains the data structure that holds information on
// the devices that are created. For each named device, a remote of each
// type analog is created.
class device_info {
public:
char *name;
vrpn_Analog_Remote *ana;
};
const unsigned MAX_DEVICES = 2;
//-------------------------------------
// This section contains the data structure that is used to determine how
// often to print a report for each sensor of each tracker. Each element
// contains a counter that is used by the callback routine to keep track
// of how many it has skipped. There is an element for each possible sensor.
// A new array of elements is created for each new tracker object, and a
// pointer to it is passed as the userdata pointer to the callback handlers.
class t_user_callback {
public:
char t_name[vrpn_MAX_TEXT_LEN];
vector<unsigned> t_counts ;
};
//Callback handlers
void VRPN_CALLBACK handle_analog (void *userdata, const vrpn_ANALOGCB a)
{
int i;
const char *name = (const char *)userdata;
printf("Input from %s:\n \n %5.0f", name, a.channel[0]);
for (i = 1; i < a.num_channel; i++) {
printf(" %5.0f \n", a.channel[1]);
}
printf(" \n");
}
int main (int argc, char * argv [])
{
int print_for_tracker = 1; // Print tracker reports?
int print_for_button = 1; // Print button reports?
int print_for_analog = 1; // Print analog reports?
int print_for_dial = 1; // Print dial reports?
int print_for_text = 1; // Print warning/error messages?
device_info device_list[MAX_DEVICES];
unsigned num_devices = 0;
int i;
// Parse arguments, creating objects
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "-notracker")) {
print_for_tracker = 0;
} else if (!strcmp(argv[i], "-nobutton")) {
print_for_button = 0;
} else if (!strcmp(argv[i], "-noanalog")) {
print_for_analog = 0;
} else if (!strcmp(argv[i], "-nodial")) {
print_for_dial = 0;
} else if (!strcmp(argv[i], "-notext")) {
print_for_text = 0;
} else if (!strcmp(argv[i], "-trackerstride")) {
if (tracker_stride <= 0) {
fprintf(stderr, "-trackerstride argument must be 1 or greater\n");
return -1;
}
} else { // Create a device and connect to it.
device_info *dev;
// Name the device and open it as everything
dev = &device_list[num_devices];
dev->name = argv[i];
dev->ana = new vrpn_Analog_Remote(dev->name);
if (print_for_analog) {
printf(" Analog");
dev->ana->register_change_handler(dev->name, handle_analog);
}
printf(".\n");
num_devices++;
}
}
// main interactive loop
printf("Press ^C to exit.\n");
while ( ! done ) {
unsigned i;
// Let all the devices do their things
for (i = 0; i < num_devices; i++) {
device_list[i].ana->mainloop();
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE);
glutInitWindowSize(400,300);
glutInitWindowPosition(200,100);
glutCreateWindow("ImageViewer");
init();
glutDisplayFunc(display);
glutMotionFunc(drag);
glutMouseFunc(mouse);
// glutIdleFunc(IdleFunc);
glutMainLoop();
}
}
return 0;
}
glut is fine if it can manage all of the input devices, and everything is event-driven from the inputs that it manages. Once you have unmanaged input devices or non-event-based processing, you probably want to use something other than glut. Your other alternative is to fork and run your asynchronous stuff in a separate process (or thread).