2012-12-30 19 views
6

Đây là câu hỏi ít hơn về OpenGL và nhiều câu hỏi về tổ chức C++.Bộ tiểu bang OpenGL

Tôi sẽ có biểu đồ cảnh đơn giản (một cây) với các nút (vì lợi ích của câu hỏi này) tất cả sẽ hiển thị một số hình. Để cụ thể hơn, mỗi người có một số lệnh rút OpenGL bên trong phương thức draw().

Vì lý do tối ưu, tôi muốn nhóm các đối tượng giống nhau lại với nhau và vẽ tất cả cùng một lúc. Vì lý do này tôi muốn một cách thể hiện những gì tôi đang gọi là "bộ nhà nước" cho OpenGL. Một bộ trạng thái chỉ là một bó của các liên kết OpenGL, hoặc các lệnh được đặt trước khi vẽ được gọi trên các đối tượng X, và không được đặt sau đó.

Do đó, tập hợp nhà nước có ít nhất set()unset() và sẽ được hệ thống hiển thị gọi trước và sau khi vẽ lệnh của các nút sử dụng tập hợp trạng thái này.

Câu hỏi của tôi là cách diễn đạt các bộ trạng thái đã nói? Chắc chắn một loạt các chức năng có thể làm, nhưng tôi muốn có thể đặt tên một bộ và gọi lại nó. Giống như nút A có một tập hợp trạng thái là LIGHTING_AND_SHADOW và nút B có CEL_SHADING.

Vì lý do này, hãy tạo một lớp trừu tượng có tên là stateSet về cơ bản là giao diện cho các phương pháp set()unset() và có mỗi bộ trạng thái kế thừa từ nó. Nhưng, nó đòi hỏi việc tạo ra một loạt các đối tượng chỉ để có được một tên cơ bản. nó có vẻ như có thể có một cách tốt hơn.

Cũng lý tưởng tôi muốn có danh sách tất cả stateSets có thể dễ dàng bị thu hồi. Ví dụ: trước khi kết xuất bắt đầu, sẽ tốt hơn nếu có thể sắp xếp tất cả các nút trong biểu đồ cảnh theo stateSet của chúng.

Bất kỳ ý tưởng nào?

+0

Có vẻ như bạn đang yêu cầu chúng tôi cung cấp tên cho bộ tiểu bang của bạn. Bạn có thể xây dựng một chút về loại trợ giúp nào bạn đang tìm kiếm hay không. – Mads

+0

Nếu chương trình GLSL đang hoạt động là một phần của "bộ trạng thái" thì bạn có thể làm cho "bộ trạng thái" này trong lớp chương trình GLSL của bạn: mỗi người biết trạng thái cần thiết và chương trình cần thiết để hoạt động. Sau đó, bạn nhóm các nút cho mỗi chương trình trước khi kết xuất. – Gigi

Trả lời

2

Bạn có thể triển khai trạng thái của mình bằng cách sử dụng mẫu đơn. Sau đó, một lớp theo dõi trạng thái singleton khác quản lý các thể hiện của các lớp trạng thái này, và chỉ thiết lập một trạng thái khi nó chưa được thiết lập. Xem dưới đây để thực hiện thô. Điều này sẽ cung cấp cho bạn ý tưởng về cách thực hiện:

class SingletonStateClass1 { 
public: 
    static SingletonStateClass1* getInstance() { 
     if(! instanceFlag) { 
      single = new SingletonStateClass1(); 
      instanceFlag = true; 
      return single; 
     } 
     else { 
      return single; 
     } 
    } 
    void set() { 
     // Do setting stuff 
    } 
    void unset() { 
     // Do unsetting stuff 
    } 
    ~SingletonStateClass1() { 
     instanceFlag = false; 
    } 

private: 
    static bool instanceFlag; 
    static SingletonStateClass1 *single; 
    SingletonStateClass1() {} //private constructor 
}; 
bool SingletonStateClass1::instanceFlag = false; //needs to be set so that the first call to getInstance() works ok. 


//ASSUME THERE IS ANOTHER CLASS WITH SIMILAR DESIGN, NAMED: SingletonStateClass2 

class SingletonStateTracker { 
public: 
    static SingletonStateTracker* getInstance() { 
     if(! instanceFlag) { 
      single = new SingletonStateTracker(); 
      state1 = SingletonStateClass1::getInstance(); 
      state2 = SingletonStateClass2::getInstance(); 
      instanceFlag = true; 
      isSetState1 = false; 
      isSetState2 = false; 
      return single; 
     } 
     else { 
      return single; 
     } 
    } 

    // Only setting a state unsets the other states 
    void set1() { 
     if (!isSetState1) { 
      if (isSetState2) { 
       state2->unset(); 
       isSetState2 = false; 
      } 
      state1->set(); 
      isSetState1 = true; 
     } 
    } 
    void set2() { 
     if (!isSetState2) { 
      if (isSetState1) { 
       state1->unset(); 
       isSetState1 = false; 
      } 
      state2->set(); 
      isSetState2 = true; 
     } 
    } 

private: 
    static bool instanceFlag; 
    static bool isSetState1; 
    static bool isSetState2; 
    static SingletonStateTracker *single; 
    static SingletonStateClass1 *state1; 
    static SingletonStateClass2 *state2; 
    SingletonStateTracker() {} //private constructor 
}; 
bool SingletonStateTracker::instanceFlag = false; //needs to be set so that the first call to getInstance() works ok. 




class DrawableObject1 { 
public: 
    DrawableObject1() { 
     tracker = SingletonStateTracker::getInstance(); 
    } 
    void draw() const 
    { 
     tracker->set1(); 
     //DO YOUR OBJECT SPECIFIC OPENGL DRAW STUFF HERE 
    } 
private: 
    SingletonStateTracker* tracker; 
}; 

class DrawableObject2 { 
public: 
    DrawableObject2() { 
     tracker = SingletonStateTracker::getInstance(); 
    } 
    void draw() const 
    { 
     tracker->set2(); 
     //DO YOUR OBJECT SPECIFIC OPENGL DRAW STUFF HERE 
    } 
private: 
    SingletonStateTracker* tracker; 
}; 


/* Below two classes show a crude usage of the above design */ 
class Scene { 
    // ... other stuff ... 

public: 
    DrawableObject1 obj1a; 
    DrawableObject1 obj1b; 
    DrawableObject2 obj2; 
    // ... other stuff ... 
}; 

class Viewer { 
    // ... other stuff ... 
public: 
    void draw() { 
     scene->obj1a.draw(); //This call unsets state2, sets state1 
     scene->obj1b.draw(); //This call does not set any state since state1 is already set 
     scene->obj2.draw(); //This call unsets state1, sets state2 
    } 
private: 
    Scene* scene; 
    // ... other stuff ... 
}; 

Lưu ý rằng thiết kế ở trên rất đơn giản. Bạn có thể có nhiều Class State để kế thừa một giao diện chung như bạn đã lưu ý trong câu hỏi của mình. Điều quan trọng là phải có một lớp Tracker (a.k.a Manager) thông qua đó các đối tượng thiết lập các trạng thái. Công việc của lớp Tracker là loại bỏ các thiết lập không cần thiết của một trạng thái nếu nó đã được thiết lập, và bỏ đặt các trạng thái khác nếu chúng được thiết lập hiện tại.

+0

Điều này là tuyệt vời, tôi chắc chắn có thể chạy với điều này. Như bạn đã đề xuất, tôi sẽ tiếp tục và tạo một giao diện StateSet với set() unset() và getInstance(), và người quản lý có thể có tất cả các loại goodies. Tôi đặc biệt thích khả năng người quản lý gọi unset() bất cứ khi nào một StateSet khác được thiết lập, do đó loại bỏ sự cần thiết phải bỏ đặt để được gọi bởi người dùng. Cảm ơn một lần nữa! -Cody –

+0

Suy nghĩ thêm: từ quan điểm thiết kế an toàn, bạn có thể muốn đóng gói định nghĩa của các lớp trạng thái riêng tư trong lớp người quản lý. Bằng cách này, các lớp này thậm chí không cần phải là singleton, vì người quản lý đảm bảo chỉ có một cá thể tĩnh của mỗi lớp trong số các lớp trạng thái này và không có quyền truy cập công khai vào các hàm tạo của chúng. Người quản lý vẫn là Singleton. Nó là kinda một lớp logger, nơi Singleton được đề xuất và sử dụng rộng rãi. – meyumer

1

Vì lý do này làm cho một lớp trừu tượng gọi là stateSet đó là về cơ bản là một giao diện cho set()unset() phương pháp và có mỗi tiểu bang thiết kế thừa từ nó có vẻ như là một ý tưởng tốt. Tuy nhiên, nó đòi hỏi phải tạo ra một loạt các đối tượng chỉ để có được một tên về cơ bản.

Triển khai lớp trừu tượng giả định của bạn hoạt động thông qua bảng chức năng ảo, thường được triển khai như một mảng con trỏ hàm. Các đối tượng rõ ràng vô nghĩa mà bạn sẽ khởi tạo trong trường hợp này giữ trạng thái có ý nghĩa - các con trỏ hàm đó.Để thay thế việc tạo nhiều mảng của hai con trỏ hàm, có lẽ bạn nên tạo hai mảng con trỏ hàm, chỉ mục tên vào mảng, giữ lại chỉ mục được sử dụng cuối cùng và kiểm tra stateSet(uint state_name) để xem state_name có khác không trước khi gián tiếp thông qua các mảng. Tôi khuyên bạn nên ẩn tất cả trạng thái toàn cầu đó khỏi các đơn vị biên dịch khác mặc dù từ khóa static.

Cách tiếp cận này cung cấp ít an toàn hơn - không có nghĩa ngữ nghĩa ngăn bạn chuyển bất kỳ số nguyên nào vào số stateSet(uint) và không kiểm tra phạm vi trên một mảng thô trừ khi bạn tự đặt nó ở đó.

Hai tùy chọn khác về cơ bản là khá giống nhau; vì vậy hãy xem xét ý tưởng của riêng bạn.

Các vấn đề liên quan