سؤال

أريد أن أقوم بتطبيق مؤشراتي الخاصة في نافذة OpenGL / Full. الطريقة المعتادة للقيام بذلك هي لتجميد المؤشر (لذلك لا يمكن أن تصل إلى حواف الشاشة) وتتبع موقفها بنفسك. يمكنني جعل المؤشر على الشاشة غير مرئية باستخدام

glutSetCursor(GLUT_CURSOR_NONE);

ثم داخل اتصال GlatpassiveIveMotionFunc نقل المؤشر إلى منتصف النافذة باستخدام

int centerX = (float)kWindowWidth / 2.0;
int centerY = (float)kWindowHeight / 2.0;

int deltaX = (x - centerX);
int deltaY = (y - centerY);

mouseX += deltaX / (float)kWindowWidth;
mouseY -= deltaY / (float)kWindowHeight;

glutWarpPointer( centerX, centerY );

يعمل هذا في أنه يحتفظ المؤشر عالقا في منتصف النافذة. المشكلة هي أنه عندما أقوم بسحب الماوس "OpenGL" (داخل اتصال GlutdisplayFunc () هو متشنج للغاية.

لقد بحثت عبر الإنترنت ووجدت أنه يمكن أن تكون هناك مشكلة حيث يتسبب glutwarpointer () إلى استدعاء اتصال glatPassivePemotionFunC مرة أخرى، مما يؤدي إلى حلقة، ولكن هذا لا يبدو أن هذا يحدث هنا.

أنا على Mac OS X ووجدت منشورا قائلا أن CgdisplayMoveCursortopoint كان مناسبا أفضل لهذا. استدعاء cgdisplaymoveCursortopoint يعمل ولكن الحركة لا تزال متشنج جدا (ويبدو أن أحصل على الكثير من الأحداث حيث x و y كلاهما 0). في أي حال، أود أن يعمل هذا للعمل على Linux وكذلك حل Mac فقط غير مثالي (لكنني على ما يرام القيام بأشياء مختلفة على الأنظمة المختلفة).

لقد خفضت هذا إلى اختبار.

#include <stdio.h>
#include <OpenGL/OpenGL.h>
#include <GLUT/GLUT.h>

int curX = 0;
int curY = 0;

void display() {
    glClearColor( 0.0, 0.0, 0.0, 1.0 );
    glClear( GL_COLOR_BUFFER_BIT );

    float vx = (float)curX / 300.0 + 0.5;
    float vy = (float)curY / 300.0 + 0.5;

    glColor3f( 1.0, 0.0, 0.0 );
    glBegin( GL_POINTS );
        glVertex3f( vx, vy, 0.0 );
    glEnd();

    glutSwapBuffers();

}

void passivemotion( int x, int y ) {
    int centerX = 150;
    int centerY = 150;

    int deltaX = x - centerX;
    int deltaY = y - centerY;
    curX += deltaX;
    curY -= deltaY;

    glutWarpPointer( centerX, centerY );
}

void timer( int val ) {
    glutTimerFunc( 16, &timer,  0);
    glutPostRedisplay();
}

int main (int argc, char * argv[]) {
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGB);
    glutInitWindowSize(300,300);
    glutCreateWindow("FPS Mouse Sample");
    glutDisplayFunc(&display);
    glutPassiveMotionFunc(&passivemotion);
    glutSetCursor( GLUT_CURSOR_NONE );
    glutTimerFunc( 16, &timer, 0 );
    glutMainLoop();
    return 0;
}
هل كانت مفيدة؟

المحلول

شكرا AIB للنصائح. حصلت لي أن أبحث في تفكيك glutwarpointer وأصبحت واضحة ما كان يحدث. استدعاء glutwarppointer cgpostmouseevent مما يؤدي إلى مجموعة من الأحداث الهراء (وليس هناك أي وسيلة لتخطيها لأنك تحصل فقط على أحداث الماوس مرة واحدة لكل إطار، ستتأخر الأحداث الجديدة "الحقيقية" الجديدة). الحل الذي وجدته هو الاعوجاج فقط عندما يكون المؤشر على حافة الشاشة (النقطة، بعد كل شيء، هو التظاهر بأنه لا يمكن أن تصل النقطة إلى حافة الشاشة). في أي حال، هنا هو الرمز.

int lastX = 150;
int lastY = 150;
void passivemotion( int x, int y ) {    
    int deltaX = x - lastX;
    int deltaY = y - lastY;

    lastX = x;
    lastY = y;

    if( deltaX == 0 && deltaY == 0 ) return;

    int windowX     = glutGet( GLUT_WINDOW_X );
    int windowY     = glutGet( GLUT_WINDOW_Y );
    int screenWidth     = glutGet( GLUT_SCREEN_WIDTH );
    int screenHeight    = glutGet( GLUT_SCREEN_HEIGHT );

    int screenLeft = -windowX;
    int screenTop = -windowY;
    int screenRight = screenWidth - windowX;
    int screenBottom = screenHeight - windowY;

    if( x <= screenLeft+10 || (y) <= screenTop+10 || x >= screenRight-10 || y >= screenBottom - 10) {
        lastX = 150;
        lastY = 150;
        glutWarpPointer( lastX, lastY );
        //  If on Mac OS X, the following will also work (and CGwarpMouseCursorPosition seems faster than glutWarpPointer).
        //  CGPoint centerPos = CGPointMake( windowX + lastX, windowY + lastY );
        //  CGWarpMouseCursorPosition( centerPos );
        // Have to re-hide if the user touched any UI element with the invisible pointer, like the Dock.
        //  CGDisplayHideCursor(kCGDirectMainDisplay);
    }

    curX += deltaX;
    curY -= deltaY;
}

نصائح أخرى

لقد وجدت نهج أفضل. ما يجري هو أن نظام التشغيل الذي يقمع الأحداث لمدة 0.25 ثانية تقريبا بعد أن تشوه الماوس. لذلك، بدلا من ذلك فقط اتصل:

#ifdef __APPLE__
CGSetLocalEventsSuppressionInterval(0.0);
#endif

ثم كل شيء سوف يسير إلى عصير دون أي التأتأة.

قد تحتاج إلى تضمين:

#include <ApplicationServices/ApplicationServices.h>

وأضف هذا الإطار إلى مشروعك أو إلى خيارات المحول البرمجي الخاص بك.

لاحظ أنه قد تحصل على حدث لنقل الماوس إلى مركز الشاشة، لذلك أتجاهل الحدث إذا كان من منتصف الشاشة.

ليس لدي الكثير من الخبرة مع وفرة، وحفظ لأمثلة الكتاب الأحمر، ولكن هل هو متشنج بسبب ما ترسم المؤشر، أو عدد المرات التي ترسمها؟ إذا قمت فقط بسحب نقطة حيث من المفترض أن يستخدم المؤشر مكالمات OpenGL، فهل لا يزال متشنجا؟ هل يمكن أن يكون رمز التوقيت مشكلة؟

ما الرمز الذي تتصل به لتحديث المؤشر كل علامة؟ أفترض أنه ليس الرمز المدرج كما سيتم حساب نقطة المركز في كل مرة، بدلا من حدث تغيير الحجم.

اعتذاري عن الإجابة عن عمياء هنا (أي مع خبرة قدرة محدودة).

أنا أظن هنا، لكنني أظن أن الحركة متشاكة لأن المؤشر يتم رسمه في وظيفة رسم التطبيق الخاصة بك (عرض ())، بدلا من التعامل مع نظام التشغيل.

يتم التعامل مع مؤشر الماوس العادي على مستوى السائق من خلال Xoring صورة المؤشر مع محتويات المخزن المؤقت للإطار - وبالتالي البرق بسرعة، ومعالجتها مع أولوية عالية للغاية من خلال نظام التشغيل في روتين خدمة المقاطعة (للحفاظ على وهم الاستجابة).

عندما ترسمها بنفسك، فأنت تخضع لآلية الجدولة العادية لنظام التشغيل الخاص بك وتذهب من خلال واضحة واضحة و Redraw النافذة بأكملها. في هذه الحالة، يكون سريعا ولكن ليس بأسرع ما نستخدمه مع مؤشر الماوس بسبب أعلاه.

باختصار، لست متأكدا من أنك سوف تحصل عليه من أي وقت مضى أن تكون بأسرع ما تتوقع أن تكون (خاصة لأن وظيفة العرض والمنطق التطبيق يحصل أكثر تعقيدا).

حظ سعيد!

هل تتوفر حركة الماوس فوق عدد قليل من الإطارات؟ لا يمكنني العثور على التعليمات البرمجية لمشروعي السابق لأنني في العمل. لكنني أعتقد أنني أسفرت إلى نقل حركات الماوس فوق بعض الإطارات، قبل أن أفعل أن الحركة كانت متشنج للغاية.

هل يمكن أن يكون لأنك تقوم بإبراز المخازن المؤقتة على نافذة مخزنة مزدوجة؟

مثالك لا يعمل على نظام Win32 الخاص بي، إلا إذا قمت بإضافة Gruls_Double إلى glutinitdisplayMode ().

يحرر:

انت على حق. يبدو أن استدعاء Glutwarppointer () من داخل وظيفة الحركة تتسبب في حلقة في نظام My [Win32]. لا يحصل المؤقت حتى على فرصة للإطلاق إلا إذا قمت بالنقر فوق زر أو شيء ما. أراهن أن قائمة انتظار الرسائل يجري غمرتها أحداث الحركة.

لا يبدو أن شاشة العرض () اليمنى من وظيفة الحركة تعمل، إما - هذه المرة فشل في تسجيل أي نوع من الحركة.

الطريقة الوحيدة التي يمكنني الحصول عليها من مثالك للعمل عن طريق تغيير مبني للمجهول رد الاتصال الحركة إلى نشيط رد الاتصال بالحرار وعرض الاتصال () مباشرة من هذه الوظيفة. أعلم أن هذا بعيد عن ما كنت تقصد به أصلا، ولكن على الأقل حصلت على بعض الحركة السلسة بهذه الطريقة.

هل حاولت استخدام futidlefunc () لتشغيل تحديثات العرض الخاصة بك لك؟ قد لا تزال لا تعمل مع قائمة انتظار الرسائل التي غمرتها الفيضانات ولكن قد يكون الأمر يستحق المحاولة. يمكنك أيضا النظر في التقاط الماوس باستخدام مكالمة API بدلا من التفاف المؤشر يدويا إلى مركز النافذة في كل حركة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top