আমি কীভাবে একটি মোড়ক ক্লাসের উদাহরণের সাথে কী_ক্যালব্যাক সংযুক্ত করতে পারি?


11

আমি আমার জিএলএফডাব্লু 3 কলকে একটি একক শ্রেণিতে গুটিয়ে দেওয়ার চেষ্টা করছি:

class WindowManager {
private:
    GLFWwindow* window_;
    GLFWmonitor* monitor_;
    Keyboard* keyboard_;
...
}

এবং আমি একটি সিঙ্গলটন কীবোর্ড ক্লাস সেটআপ করার চেষ্টা করছি যা কার্যকর করার সময় কী প্রেসগুলি সংগ্রহ করে। GLFW এ আমি একটি key_callbackফাংশন সেট করতে পারি যা শ্রেণীর সংজ্ঞার বাইরে (একটি ফাংশন):

WindowManager::WindowManager() {
    ...
    glfwSetKeyCallback(window_, key_callback);
    ...
}

// not a class function
void key_callback(GLFWwindow* window, int key, int scan code, int action, int mods) {
    ...
}

আমি কীভাবে আমার কলব্যাক এবং আমার WindowManagerউদাহরণটি সংযুক্ত করতে পারি যাতে আমি keyboard_বস্তুর মান সেট করতে পারি ? আমি key_callbackসদস্যের ফাংশনটি তৈরি করতে পারি না WindowManagerকারণ এটি কাজ করবে না কারণ এই ফাংশনটি উইন্ডো ম্যানেজার শ্রেণির সদস্য এবং C ++ শ্রেণীর সদস্য ফাংশনে তাদের নামগুলি ঝুলিয়ে দেবে।

উত্তর:


11

আমি এই একই সমস্যা ছিল। এটি বিরক্তিকর যে glfwSetWindowUserPointer এবং glfGetWindowUserPointer ব্যবহারের বিষয়ে খুব কম ডকুমেন্টেশন রয়েছে। আপনার সমস্যার সমাধানটি এখানে দেওয়া হল:

WindowManager::WindowManager() {
    // ...
    glfwSetUserPointer(window_, this);
    glfwSetKeyCallback(window_, key_callback_);
    // ...
}

void WindowManager::key_callback(GLFWwindow *window, int, int ,int, int) {
    WindowManager *windowManager =
      static_cast<WindowManager*>(glfwGetUserPointer(window));
    Keyboard *keyboard = windowManager->keyboard_;

    switch(key) {
        case GLFW_KEY_ESCAPE:
             keyboard->reconfigure();
             break;
     }
}

যাইহোক, যেহেতু এটি সি ++ ক্লাস সহ জিএলএফডাব্লু ব্যবহারের শীর্ষ ফলাফলগুলির মধ্যে একটি, আমিও একটি সি ++ শ্রেণিতে একটি গল্ফডাব্লু উইন্ডোকে আবদ্ধ করার আমার পদ্ধতিটি সরবরাহ করব। আমি মনে করি এটি এটি করার জন্য এটি সবচেয়ে মার্জিত উপায়, কারণ এটি গ্লোবাল, সিঙ্গেলনস বা ইউনিক_পটার ব্যবহার করা এড়ানো যায় না, প্রোগ্রামারটিকে উইন্ডোটিকে আরও অনেক OO / C ++ - y স্টাইলে ম্যানিপুলেট করতে দেয় এবং সাবক্লাসিংয়ের অনুমতি দেয় (মূল্যের ব্যয়ে) কিছুটা বেশি বিশৃঙ্খলাযুক্ত শিরোনাম ফাইল)।

// Window.hpp
#include <GLFW/glfw3.h>
class Window {
public:
    Window();
    auto ViewportDidResize(int w, int h)             -> void;
    // Make virtual you want to subclass so that windows have 
    // different contents. Another strategy is to split the
    // rendering calls into a renderer class.
    (virtual) auto RenderScene(void)                 -> void;
    (virtual) auto UpdateScene(double ms)            -> void;
    // etc for input, quitting
private:
    GLFWwindow *m_glfwWindow;

    // Here are our callbacks. I like making them inline so they don't take up
    // any of the cpp file
    inline static auto WindowResizeCallback(
        GLFWwindow *win,
        int w,
        int h) -> void {
            Window *window = static_cast<Window*>(glfwGetUserPointer(win));
            window->ViewportDidResize(w, h);
    }
    inline static auto WindowRefreshCallback(
        void) -> void {
            Window *window = static_cast<Window*>(glfwGetUserPointer(win));
            window->RenderScene(void);
    }
    // same for input, quitting
}

এবং জন্য:

// Window.cpp
#include <GLFW/glfw3.h>
#include "Window.hpp"
Window::Window() {
    // initialise glfw and m_glfwWindow,
    // create openGL context, initialise any other c++ resources
    glfwInit();
    m_glfwWindow = glfwCreateWindow(800, 600, "GL", NULL, NULL);        

    // needed for glfwGetUserPointer to work
    glfwSetWindowUserPointer(m_glfwWindow, this);

    // set our static functions as callbacks
    glfwSetFramebufferSizeCallback(m_glfwWindow, WindowResizeCallback);
    glfwSetWindowRefreshCallback(m_glfwWindow, WindowRefreshCallback);
}

// Standard window methods are called for each window
auto
Window::ViewportDidResize(int w, int h) -> void
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
}

এটি সম্ভবত উইন্ডো ম্যানেজার / ইনপুট ম্যানেজার শ্রেণীর সাথে বেশ সহজেই সংহত করা যেতে পারে তবে আমি মনে করি প্রতিটি উইন্ডো নিজেই পরিচালনা করা আরও সহজ।


আমি বেশ কয়েক বছর পরে ফিরে এসে আপডেট উত্তরটি দেখেছি। সত্যিই ভাল আপনাকে ধন্যবাদ
আর্মেনবি

স্থির ফাংশনগুলিতে, আপনি একটি শ্রেণীর (যেমন Window *window ) একটি নতুন উদাহরণ তৈরি করছেন । এটি কীভাবে সমস্যার সমাধান করবে?
ক্রোকো

আমি লক্ষ্য করেছি উত্তরটি নতুন কয়েকটি সি ++ বৈশিষ্ট্য সমর্থন করার জন্য পরিবর্তিত হয়েছে। অটোতে ফাংশন রিটার্ন টাইপ সেট করার কোনও সুবিধা আছে এবং তারপরে -> অকার্যকর ব্যবহার করে ইঙ্গিতটি টাইপ করুন?
আর্মেনবি

5

কলব্যাকগুলি অবশ্যই ফ্রি ফাংশন বা স্থির ফাংশন হতে পারে, যেমনটি আপনি খুঁজে পেয়েছেন। কলব্যাকগুলি GLFWwindow*একটি স্বয়ংক্রিয় thisপয়েন্টারের জায়গায় তাদের প্রথম যুক্তি হিসাবে গ্রহণ করে ।

জিএলএফডাব্লু দিয়ে আপনি ব্যবহার করতে পারেন glwSetWindowUserPointerএবং প্রতি উইন্ডো উদাহরণ হিসাবে glfwGetWindowUserPointerএকটি রেফারেন্স সঞ্চয় এবং পুনরুদ্ধার করতে পারেন ।WindowManagerWindow

মনে রাখবেন যে এটি খাঁটি সি এপিআই হওয়ায় GLFW ভার্চুয়াল ফাংশনগুলিকে কোনও ধরণের সরাসরি পলিমারফিজম ব্যবহার করে না। এই জাতীয় এপিআইগুলি সর্বদা ফ্রি ফাংশন ধরে নেয় (সি এর কোনও শ্রেণি বা সদস্য ফাংশন নেই, ভার্চুয়াল বা অন্যথায়) এবং স্পষ্টত "অবজেক্ট দৃষ্টান্তগুলি" পরামিতি হিসাবে পাস করে (সাধারণত প্রথম প্যারামিটার হিসাবে থাকে; সি এর কোনও নেই this)। গুড সি এপিআইগুলিতে ব্যবহারকারীর পয়েন্টার কার্যকারিতাও অন্তর্ভুক্ত থাকে (কখনও কখনও "অন্যান্য বিষয়গুলির মধ্যে" ব্যবহারকারী ডেটা "নামে পরিচিত) যাতে আপনাকে গ্লোবাল ব্যবহার করতে না হয়।

পুরানো উত্তর:

আপনার যদি WindowManager(বা অন্যান্য সিস্টেমে) অন্যান্য ডেটা অ্যাক্সেস করতে হয় তবে আপনি যদি কলব্যাকগুলি থেকে অ্যাক্সেস করতে চান তবে সেগুলি বিশ্বব্যাপী অ্যাক্সেসযোগ্য হতে পারে। উদাহরণস্বরূপ, এমন একটি গ্লোবাল করুন std::unique_ptr<Engine>যা আপনি আপনার উইন্ডো ম্যানেজারটি অ্যাক্সেস করতে ব্যবহার করতে পারেন, বা কেবল একটি গ্লোবাল তৈরি করুন std::unique_ptr<WindowManager>( std::unique_ptrযদি আপনি চান তবে "সিঙ্গলেটের জন্য আরও ভাল কিছু" দিয়ে প্রতিস্থাপন করুন )।

আপনি যদি একাধিক উইন্ডো সমর্থন চান, তবে আপনার উইন্ডো WindowManagerমানচিত্রের জন্য কিছু ডেটা কাঠামো থাকতে হবে std :: unordered_map GLFWwindow * `তাদের প্রয়োজনীয় ডেটা সন্ধান করতে তারা পেয়েছে।GLFWwindow*' values to your ownclasses in some way, e.g. using aor the like. Your callback could then access the global and query the datastructure using the


আপনার সাহায্যের জন্য ধন্যবাদ। এর মতো দৃশ্যে, কী কীভাবে এটি সাধারণত পরিচালনা করা হয় (কীবোর্ডের ইনপুটগুলিতে নজর রাখার জন্য একটি গ্লোবাল ইউনিক_পিটার ব্যবহার করে)? আমি এর মতো কোনও গ্লোবাল ভেরিয়েবলগুলি এড়াতে চেয়েছিলাম এবং কীবোর্ডের কনস্ট পয়েন্টারগুলির যাকে প্রয়োজন এটির কাছাকাছি যেতে পছন্দ করেছি তবে মনে হচ্ছে এটি সম্ভব নয়, আমি ঠিক আছি?
আর্মেনবি

1
সাধারণত কোনও ইউনিক_পিটার নয়, তবে সিঙ্গলটন ব্যবহার করা অস্বাভাবিক নয়। জিএলএফডাব্লুতে উইন্ডোগুলির জন্য একটি সেট ব্যবহারকারী ডেটা ফাংশন রয়েছে যা গ্লোবালটির প্রয়োজনীয়তা এড়াতে পারে। বেশিরভাগ "ভাল" সি এপিআই তে কিছু মিল রয়েছে। আমি যখন সত্যিকারের কম্পিউটারে ফিরে আসব তখন সেই প্রস্তাবের উত্তর দিতে পারে।
শান মিডলডিচ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.