मेरे पास एक ओपनगल गेम बनाने के साथ-साथ qglwidget के समान समस्याएं थीं, और जिस समाधान के साथ मैं आया था वह स्क्रैच-निर्मित नियंत्रण प्रदान करने के लिए ऑर्थोग्राफिक प्रक्षेपण का उपयोग कर रहा है। मुख्य ड्रॉ फ़ंक्शन के अंत में, मैं एक अलग फ़ंक्शन को कॉल करता हूं जो दृश्य सेट करता है और फिर 2 डी बिट्स खींचता है। माउस घटनाओं के लिए, मैं मुख्य विजेट पर भेजे गए कार्यक्रमों को कैप्चर करता हूं, फिर हिट टेस्ट, रिकर्सिव समन्वय ऑफसेट्स और छद्म-कॉलबैक के संयोजन का उपयोग करता हूं जो मेरे नियंत्रण को घोंसला करने की अनुमति देता है। मेरे कार्यान्वयन में, मैं एक समय में शीर्ष स्तर नियंत्रण (मुख्य रूप से स्क्रॉल बॉक्स) पर आदेश अग्रेषित करता हूं, लेकिन यदि आप गतिशील रूप से नियंत्रण जोड़ना चाहते हैं तो आप आसानी से एक लिंक-सूची संरचना जोड़ सकते हैं। मैं वर्तमान में रंगीन पैनलों के रूप में भागों को प्रस्तुत करने के लिए क्वाड का उपयोग कर रहा हूं, लेकिन यह बनावट जोड़ने या उन्हें 3 डी घटकों को भी बनाना चाहिए जो गतिशील प्रकाश का जवाब देते हैं। वहाँ कोड का एक बहुत कुछ है, तो मैं कर रहा हूँ बस वाला टुकड़ों में प्रासंगिक बिट फेंक:
void GLWidget::drawOverlay() {
glClear(GL_DEPTH_BUFFER_BIT);
glPushMatrix(); //reset
glLoadIdentity(); //modelview
glMatrixMode(GL_PROJECTION);//set ortho camera
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0,width()-2*padX,height()-2*padY,0); // <--critical; padx/y is just the letterboxing I use
glMatrixMode(GL_MODELVIEW);
glDisable(GL_DEPTH_TEST); // <-- necessary if you want to draw things in the order you call them
glDisable(GL_LIGHTING); // <-- lighting can cause weird artifacts
drawHUD(); //<-- Actually does the drawing
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION); glPopMatrix();
glMatrixMode(GL_MODELVIEW); glPopMatrix();
}
यह:
void GLWidget::paintGL() {
if (isPaused) return;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix();
glLightfv(GL_LIGHT0, GL_POSITION, FV0001);
gluLookAt(...);
// Typical 3d stuff
glCallList(Body::glGrid);
glPopMatrix();
//non3d bits
drawOverlay(); // <---call the 2d rendering
fpsCount++;
}
यहाँ कोड है कि 2 डी प्रतिपादन के लिए modelview/प्रक्षेपण मैट्रिक्स सेट करता है मुख्य ड्राइंग फ़ंक्शन है जो हड सामान को संभालता है; अधिकांश ड्रॉ फ़ंक्शंस बड़े 'बैकराउंड पैनल' खंड के समान होते हैं। आप मूल रूप से modelview मैट्रिक्स धक्का, जैसे आप 3 डी में होगा अनुवाद कर/बारी बारी से/पैमाने का उपयोग करें, नियंत्रण रंग, तो popmatrix: नियंत्रण के लिए खुद को
void GLWidget::drawHUD() {
float gridcol[] = { 0.5, 0.1, 0.5, 0.9 };
float gridcolB[] = { 0.3, 0.0, 0.3, 0.9 };
//string caption
QString tmpStr = QString::number(FPS);
drawText(tmpStr.toAscii(),120+padX,20+padY);
//Markers
tGroup* tmpGroup = curGroup->firstChild;
while (tmpGroup != 0) {
drawMarker(tmpGroup->scrXYZ);
tmpGroup = tmpGroup->nextItem;
}
//Background panel
glEnable(GL_BLEND);
glTranslatef(0,height()*0.8,0);
glBegin(GL_QUADS);
glColor4fv(gridcol);
glVertex2f(0.0f, 0.0);
glVertex2f(width(), 0);
glColor4fv(gridcolB);
glVertex2f(width(), height()*0.2);
glVertex2f(0.0f, height()*0.2);
glEnd();
glDisable(GL_BLEND);
glLoadIdentity(); //nec b/c of translate ^^
glTranslatef(-padX,-padY,0);
//Controls
cargoBox->Draw();
sideBox->Draw();
econBox->Draw();
}
अब। मेरे सभी नियंत्रण जैसे बटन, स्लाइडर्स, लेबल इत्यादि सभी खाली वर्चुअल फ़ंक्शंस वाले सामान्य बेस क्लास से वंचित होते हैं जो उन्हें एक-दूसरे के साथ-साथ अज्ञात रूप से बातचीत करने की अनुमति देते हैं। बेस में सामान्य सामान जैसे ऊंचाई, निर्देशांक, आदि के साथ-साथ कॉलबैक और टेक्स्ट प्रतिपादन को संभालने के लिए कुछ पॉइंटर्स भी होते हैं। जेनेरिक हिटेस्ट (एक्स, वाई) फ़ंक्शन भी शामिल है जो बताता है कि इसे क्लिक किया गया है या नहीं। यदि आप अंडाकार नियंत्रण चाहते हैं तो आप यह आभासी बना सकते हैं। यहाँ आधार वर्ग, hitTest, और एक सरल बटन .:
class glBase {
public:
glBase(float tx, float ty, float tw, float th);
virtual void Draw() {return;}
virtual glBase* mouseDown(float xIn, float yIn) {return this;}
virtual void mouseUp(float xIn, float yIn) {return;}
virtual void mouseMove(float xIn, float yIn) {return;}
virtual void childCallBack(float vIn, void* caller) {return;}
bool HitTest(float xIn, float yIn);
float xOff, yOff;
float width, height;
glBase* parent;
static GLWidget* renderer;
protected:
glBase* callFwd;
};
bool glBase::HitTest(float xIn, float yIn) { //input should be relative to parents space
xIn -= xOff; yIn -= yOff;
if (yIn >= 0 && xIn >= 0) {
if (xIn <= width && yIn <= height) return true;
}
return false;
}
class glButton : public glBase {
public:
glButton(float tx, float ty, float tw, float th, char rChar);
void Draw();
glBase* mouseDown(float xIn, float yIn);
void mouseUp(float xIn, float yIn);
private:
bool isPressed;
char renderChar;
};
glButton::glButton(float tx, float ty, float tw, float th, char rChar) :
glBase(tx, ty, tw, th), isPressed(false), renderChar(rChar) {}
void glButton::Draw() {
float gridcolA[] = { 0.5, 0.6, 0.5, 1.0 };//up
float gridcolB[] = { 0.2, 0.3, 0.2, 1.0 };
float gridcolC[] = { 1.0, 0.2, 0.1, 1.0 };//dn
float gridcolD[] = { 1.0, 0.5, 0.3, 1.0 };
float* upState;
float* upStateB;
if (isPressed) {
upState = gridcolC;
upStateB = gridcolD;
} else {
upState = gridcolA;
upStateB = gridcolB;
}
glPushMatrix();
glTranslatef(xOff,yOff,0);
glBegin(GL_QUADS);
glColor4fv(upState);
glVertex2f(0, 0);
glVertex2f(width, 0);
glColor4fv(upStateB);
glVertex2f(width, height);
glVertex2f(0, height);
glEnd();
if (renderChar != 0) //center
renderer->drawChar(renderChar, (width - 12)/2, (height - 16)/2);
glPopMatrix();
}
glBase* glButton::mouseDown(float xIn, float yIn) {
isPressed = true;
return this;
}
void glButton::mouseUp(float xIn, float yIn) {
isPressed = false;
if (parent != 0) {
if (HitTest(xIn, yIn)) parent->childCallBack(0, this);
}
}
के बाद से स्लाइडर्स की तरह यौगिक नियंत्रण एकाधिक बटन है, और scrollboxes टाइल्स और स्लाइडर है, यह सब ड्राइंग के लिए पुनरावर्ती होने की जरूरत है के लिए कोड है/माउस घटनाओं। प्रत्येक नियंत्रण में एक सामान्य कॉलबैक फ़ंक्शन भी होता है जो मान और उसके स्वयं के पते को पास करता है; यह अभिभावक को यह देखने के लिए अपने प्रत्येक बच्चे का परीक्षण करने की अनुमति देता है कि कौन कॉल कर रहा है, और उचित प्रतिक्रिया दें (उदाहरण के लिए ऊपर/नीचे बटन)। ध्यान दें कि सी/डाटर में नए/हटाए जाने के माध्यम से बाल नियंत्रण जोड़े जाते हैं। इसके अलावा, बच्चों के नियंत्रण के लिए ड्रा() कार्यों को माता-पिता के अपने ड्रॉ() कॉल के दौरान बुलाया जाता है, जो सबकुछ स्वयं निहित होने की अनुमति देता है। यहाँ एक मध्य स्तर स्लाइडबार कि 3 उप बटन होते हैं से प्रासंगिक कोड है:
glBase* glSlider::mouseDown(float xIn, float yIn) {
xIn -= xOff; yIn -= yOff;//move from parent to local coords
if (slider->HitTest(xIn,yIn-width)) { //clicked slider
yIn -= width; //localize to field area
callFwd = slider->mouseDown(xIn, yIn);
dragMode = true;
dragY = yIn - slider->yOff;
} else if (upButton->HitTest(xIn,yIn)) {
callFwd = upButton->mouseDown(xIn, yIn);
} else if (downButton->HitTest(xIn,yIn)) {
callFwd = downButton->mouseDown(xIn, yIn);
} else {
//clicked in field, but not on slider
}
return this;
}//TO BE CHECKED (esp slider hit)
void glSlider::mouseUp(float xIn, float yIn) {
xIn -= xOff; yIn -= yOff;
if (callFwd != 0) {
callFwd->mouseUp(xIn, yIn); //ok to not translate b/c slider doesn't callback
callFwd = 0;
dragMode = false;
} else {
//clicked in field, not any of the 3 buttons
}
}
void glSlider::childCallBack(float vIn, void* caller) { //can use value blending for smooth
float tDelta = (maxVal - minVal)/(10);
if (caller == upButton) {//only gets callbacks from ud buttons
setVal(Value - tDelta);
} else {
setVal(Value + tDelta);
}
}
अब जब हम आत्म निहित नियंत्रण है कि एक ओपन संदर्भ में प्रस्तुत करना है, यह सब आवश्यक है शीर्ष स्तर के नियंत्रण से इंटरफेस है , उदाहरण के लिए glwidget से माउस घटनाओं।
void GLWidget::mousePressEvent(QMouseEvent* event) {
if (cargoBox->HitTest(event->x()-padX, event->y()-padY)) { //if clicked first scrollbox
callFwd = cargoBox->mouseDown(event->x()-padX, event->y()-padY); //forward the click, noting which last got
return;
} else if (sideBox->HitTest(event->x()-padX, event->y()-padY)) {
callFwd = sideBox->mouseDown(event->x()-padX, event->y()-padY);
return;
} else if (econBox->HitTest(event->x()-padX, event->y()-padY)) {
callFwd = econBox->mouseDown(event->x()-padX, event->y()-padY);
return;
}
lastPos = event->pos(); //for dragging
}
void GLWidget::mouseReleaseEvent(QMouseEvent *event) {
if (callFwd != 0) { //Did user mousedown on something?
callFwd->mouseUp(event->x()-padX, event->y()-padY);
callFwd = 0; //^^^ Allows you to drag off a button before releasing w/o triggering its callback
return;
} else { //local
tBase* tmpPick = pickObject(event->x(), event->y());
//normal clicking, game stuff...
}
}
कुल मिलाकर इस प्रणाली एक छोटे से hacky है, और मैं नहीं जोड़ा है कुंजीपटल प्रतिक्रिया या आकार बदलने जैसी कुछ सुविधाओं, लेकिन इन, जोड़ने के लिए हो सकता है कॉलबैक में एक 'घटना प्रकार' की आवश्यकता होती है आसान होना चाहिए (यानी माउस या कीबोर्ड)। आप ग्लोबबेस को सबसे ऊपर-विजेट में भी उपclass कर सकते हैं, और यह माता-पिता को प्राप्त करने की अनुमति भी देगा-> बालकॉलबैक। यद्यपि यह बहुत काम है, इस प्रणाली को केवल वेनिला सी ++/ओपनजीएल की आवश्यकता होती है और यह देशी क्यूटी सामान की तुलना में बहुत कम सीपीयू/मेमोरी संसाधनों का उपयोग करता है, शायद परिमाण या दो के क्रम से। अगर आपको और जानकारी चाहिए, तो बस पूछें।
मुझे अभी एहसास हुआ कि मैं केवल परिप्रेक्ष्य के बजाय रेंडर मोड को ऑर्थोनॉर्मल पर सेट कर सकता हूं। यह जीयूआई शेडर अनावश्यक बनाता है। लेकिन फिर भी, मुझे लगता है कि Qt3D में ओवरपेनटिंग करने के लिए एक अंतर्निहित तरीका होना चाहिए (क्योंकि पुराने पुराने QGLWidget में एक विधि है (जिसे मैं Qt5 विजेट मॉड्यूल में उपयोग करने के बाद से उपयोग नहीं करना चाहता हूं और नहीं कर सकता QGLPainter का उपयोग करके प्रस्तुत करें))। – leemes
यह एक संभावना प्रतीत होता है (यह बहुत अच्छा लगता है): http://comments.gmane.org/gmane.comp.lib.qt.3d/264 – leemes