1
/****************************************************************************
3
* A versatile mesh processing toolbox o o *
5
* Copyright(C) 2005-2008 \/)\/ *
6
* Visual Computing Lab /\/| *
7
* ISTI - Italian National Research Council | *
9
* All rights reserved. *
11
* This program is free software; you can redistribute it and/or modify *
12
* it under the terms of the GNU General Public License as published by *
13
* the Free Software Foundation; either version 2 of the License, or *
14
* (at your option) any later version. *
16
* This program is distributed in the hope that it will be useful, *
17
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
18
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
22
****************************************************************************/
24
#include "rfx_dialog.h"
26
const float DECTOINT = 10000.0f;
27
const float INTTODEC = 0.0001f;
29
RfxDialog::RfxDialog(RfxShader *s, QAction *a, QGLWidget *parent)
36
setWindowTitle("RenderRfx [" + a->text() + "]");
38
setWidget(ui.RfxDockContents);
39
setFeatures(QDockWidget::AllDockWidgetFeatures);
40
setAllowedAreas(Qt::LeftDockWidgetArea);
44
QListIterator<RfxGLPass*> pit = s->PassesIterator();
45
while (pit.hasNext()) {
46
RfxGLPass *pass = pit.next();
47
ui.comboPasses->addItem("Pass #" +
48
QString().setNum(pass->GetPassIndex()) +
49
" " + pass->GetPassName() + " ");
51
// start from first pass
52
connect(ui.comboPasses, SIGNAL(currentIndexChanged(int)), this,
53
SLOT(PassSelected(int)));
55
ui.comboPasses->setCurrentIndex(0);
58
fixedfont.setFamily("Courier");
59
fixedfont.setFixedPitch(true);
60
fixedfont.setPointSize(10);
61
ui.textVert->setFont(fixedfont);
62
ui.textFrag->setFont(fixedfont);
64
vertHL = new GLSLSynHlighter(ui.textVert->document());
65
fragHL = new GLSLSynHlighter(ui.textFrag->document());
67
// fill log once for dialog, since it reports status for all passes
68
ui.textLog->setPlainText(s->GetCompilationLog().join("\n"));
71
// uniform tab will contain every uniform from every pass
73
pit = s->PassesIterator();
74
while (pit.hasNext()) {
75
RfxGLPass *pass = pit.next();
77
QListIterator<RfxUniform*> it = pass->UniformsIterator();
78
int unifCount = -1; // keep track of uniform index
79
while (it.hasNext()) {
81
RfxUniform *uni = it.next();
85
AddUniformBox(uni, unifCount);
95
void RfxDialog::setupTabs()
98
ui.comboTextures->clear();
99
ui.comboTextures->setEnabled(true);
100
disconnect(ui.comboTextures, 0, 0, 0);
102
QListIterator<RfxUniform*> it = shader->GetPass(selPass)->UniformsIterator();
104
while (it.hasNext()) {
106
RfxUniform *uni = it.next();
107
if (!uni->isTexture())
109
ui.comboTextures->addItem("[" +
110
RfxUniform::GetTypeString(uni->GetType()) +
112
((uni->isRenderable())? " (RT) " : "") +
117
if (ui.comboTextures->count() == 0) {
118
ui.comboTextures->addItem("No textures");
119
ui.comboTextures->setDisabled(true);
121
ui.comboTextures->insertItem(0, "Select...");
122
ui.comboTextures->setCurrentIndex(0);
123
connect(ui.comboTextures, SIGNAL(currentIndexChanged(int)), this,
124
SLOT(TextureSelected(int)));
127
disconnect(ui.btnChangeTexture, 0, 0, 0);
128
ui.BoxTextureProps->setTitle("");
129
ui.EditTexFile->clear();
130
ui.TexStatesTable->clear();
131
ui.TexStatesTable->setRowCount(0);
132
ui.TexStatesTable->setColumnCount(2);
133
ui.TexStatesTable->horizontalHeader()->setStretchLastSection(true);
134
ui.TexStatesTable->horizontalHeader()->hide();
135
ui.TexStatesTable->verticalHeader()->hide();
136
ui.lblPreview->clear();
140
ui.glStatesTable->clear();
141
ui.glStatesTable->setRowCount(0);
142
ui.glStatesTable->setColumnCount(2);
143
ui.glStatesTable->horizontalHeader()->setStretchLastSection(true);
144
ui.glStatesTable->horizontalHeader()->hide();
145
ui.glStatesTable->verticalHeader()->hide();
146
QListIterator<RfxState*> sit = shader->GetPass(selPass)->StatesIterator();
148
while (sit.hasNext()) {
149
RfxState *r = sit.next();
151
// QTableWidget will take ownership of objects, do not delete them.
152
QTableWidgetItem *c0 = new QTableWidgetItem(r->GetRenderState());
153
c0->setFlags(Qt::ItemIsSelectable);
154
QTableWidgetItem *c1 = new QTableWidgetItem(r->GetRenderValue());
155
c1->setFlags(Qt::ItemIsSelectable);
157
ui.glStatesTable->insertRow(rowidx);
158
ui.glStatesTable->setItem(rowidx, 0, c0);
159
ui.glStatesTable->setItem(rowidx, 1, c1);
160
ui.glStatesTable->resizeRowToContents(rowidx);
163
ui.glStatesTable->resizeColumnToContents(0);
164
ui.glStatesTable->resizeColumnToContents(1);
167
/* Vertex/Fragment source view */
168
ui.textVert->setPlainText(shader->GetPass(selPass)->GetVertexSource());
169
ui.textFrag->setPlainText(shader->GetPass(selPass)->GetFragmentSource());
172
RfxDialog::~RfxDialog()
180
void RfxDialog::PassSelected(int idx)
187
void RfxDialog::AddUniformBox(RfxUniform *uni, int uniIndex)
191
QLabel *lblUni = new QLabel();
194
lblText.append(QString("(Pass #%1) ").arg(selPass));
195
lblText.append(uni->GetName());
197
if (!uni->GetSemantic().isNull()) {
198
lblText.append("<span style=\"color:darkgreen;\"><br/> [P: ");
199
lblText.append(uni->GetSemantic());
200
lblText.append("]</span>");
203
lblUni->setText(lblText);
205
QGridLayout *gridUni = new QGridLayout();
207
switch (uni->GetType()) {
208
case RfxUniform::INT:
209
case RfxUniform::FLOAT:
210
case RfxUniform::BOOL:
211
DrawIFace(gridUni, uni, uniIndex, 1, 1);
214
case RfxUniform::VEC2:
215
case RfxUniform::IVEC2:
216
case RfxUniform::BVEC2:
217
DrawIFace(gridUni, uni, uniIndex, 1, 2);
220
case RfxUniform::VEC3:
221
case RfxUniform::IVEC3:
222
case RfxUniform::BVEC3:
223
DrawIFace(gridUni, uni, uniIndex, 1, 3);
226
case RfxUniform::VEC4:
227
case RfxUniform::IVEC4:
228
case RfxUniform::BVEC4:
229
DrawIFace(gridUni, uni, uniIndex, 1, 4);
232
case RfxUniform::MAT2:
233
DrawIFace(gridUni, uni, uniIndex, 2, 2);
236
case RfxUniform::MAT3:
237
DrawIFace(gridUni, uni, uniIndex, 3, 3);
240
case RfxUniform::MAT4:
241
DrawIFace(gridUni, uni, uniIndex, 4, 4);
248
QHBoxLayout *boxContent = new QHBoxLayout();
249
boxContent->addWidget(lblUni);
250
boxContent->addLayout(gridUni);
252
((QVBoxLayout*)ui.scrollUniformsContents->layout())->addLayout(boxContent);
255
void RfxDialog::DrawIFace(QGridLayout *parent, RfxUniform *u, int uidx, int rows, int columns)
257
enum controlType { INT_CTRL, FLOAT_CTRL, BOOL_CTRL };
258
float *val = u->GetValue();
260
QWidget **controls = new QWidget*[rows * columns];
261
QGridLayout *uniLayout = parent;
262
QHBoxLayout *sliderEditLayout = NULL;
263
bool multipleControls = false;
264
QSignalMapper *valMapper = new QSignalMapper(this);
266
switch (u->GetType()) {
267
case RfxUniform::INT:
268
case RfxUniform::IVEC2:
269
case RfxUniform::IVEC3:
270
case RfxUniform::IVEC4:
274
case RfxUniform::FLOAT:
275
case RfxUniform::VEC2:
276
case RfxUniform::VEC3:
277
case RfxUniform::VEC4:
278
case RfxUniform::MAT2:
279
case RfxUniform::MAT3:
280
case RfxUniform::MAT4:
284
case RfxUniform::BOOL:
285
case RfxUniform::BVEC2:
286
case RfxUniform::BVEC3:
287
case RfxUniform::BVEC4:
295
// controls in a grid layout
296
for (int i = 0; i < rows; ++i) {
297
for (int j = 0; j < columns; ++j) {
298
int arrayIdx = j + (i * rows);
301
controls[arrayIdx] = new QSpinBox(this);
302
((QSpinBox*)controls[arrayIdx])->setRange(-99, 99);
303
((QSpinBox*)controls[arrayIdx])->setValue((int)val[arrayIdx]);
304
connect(controls[arrayIdx], SIGNAL(valueChanged(int)),
305
valMapper, SLOT(map()));
306
connect(controls[arrayIdx], SIGNAL(valueChanged(int)), this,
307
SLOT(extendRange(int)));
310
if (u->HasMinMax()) {
311
controls[arrayIdx] = new QSlider(this);
312
((QSlider*)controls[arrayIdx])->setTickPosition(QSlider::NoTicks);
313
((QSlider*)controls[arrayIdx])->setOrientation(Qt::Horizontal);
315
// since qslider only deals with integers, do a little conversion
317
// keep as much as 5 decimal values, others will be lost in conversion
318
int valAsInt = (int)(val[arrayIdx] * DECTOINT);
319
int tickAsInt = (int)(((u->GetMaxRange() - u->GetMinRange()) * 0.01) * DECTOINT);
321
((QSlider*)controls[arrayIdx])->setTickInterval(tickAsInt);
322
((QSlider*)controls[arrayIdx])->setRange((int)(u->GetMinRange() * DECTOINT),
323
(int)(u->GetMaxRange() * DECTOINT));
324
((QSlider*)controls[arrayIdx])->setValue(valAsInt);
325
((QSlider*)controls[arrayIdx])->setToolTip(QString().setNum(val[arrayIdx]));
327
connect(controls[arrayIdx], SIGNAL(valueChanged(int)), valMapper, SLOT(map()));
329
// as per request, if value is a single float, also show a qlineedit to allow
330
// more accurate settings.
331
if (u->GetType() == RfxUniform::FLOAT) {
333
QLineEdit *slideValue = new QLineEdit();
334
slideValue->setAlignment(Qt::AlignRight);
335
slideValue->setText(QString().setNum(val[arrayIdx]));
337
QSignalMapper *yaMapper = new QSignalMapper();
338
connect(controls[arrayIdx], SIGNAL(valueChanged(int)), yaMapper, SLOT(map()));
339
connect(slideValue, SIGNAL(editingFinished()), yaMapper, SLOT(map()));
340
yaMapper->setMapping(controls[arrayIdx], slideValue);
341
yaMapper->setMapping(slideValue, controls[arrayIdx]);
342
connect(yaMapper, SIGNAL(mapped(QWidget*)), this, SLOT(mapSliderLineEdit(QWidget*)));
344
if (!u->GetSemantic().isNull())
345
slideValue->setDisabled(true);
347
multipleControls = true;
348
sliderEditLayout = new QHBoxLayout();
349
sliderEditLayout->addWidget(controls[arrayIdx]);
350
sliderEditLayout->addWidget(slideValue);
354
controls[arrayIdx] = new QDoubleSpinBox(this);
355
((QDoubleSpinBox*)controls[arrayIdx])->setRange(-99.0, 99.0);
356
((QDoubleSpinBox*)controls[arrayIdx])->setValue(val[arrayIdx]);
357
((QDoubleSpinBox*)controls[arrayIdx])->setDecimals(4);
358
((QDoubleSpinBox*)controls[arrayIdx])->setSingleStep(0.01);
359
connect(controls[arrayIdx], SIGNAL(valueChanged(double)),
360
valMapper, SLOT(map()));
361
connect(controls[arrayIdx], SIGNAL(valueChanged(double)), this,
362
SLOT(extendRange(double)));
366
controls[arrayIdx] = new QComboBox(this);
367
((QComboBox*)controls[arrayIdx])->addItem("FALSE");
368
((QComboBox*)controls[arrayIdx])->addItem("TRUE");
370
((QComboBox*)controls[arrayIdx])->setCurrentIndex(0);
371
connect(controls[arrayIdx], SIGNAL(currentIndexChanged(int)),
372
valMapper, SLOT(map()));
376
valMapper->setMapping(controls[arrayIdx],
377
QString().setNum(uidx) + '-' +
378
QString().setNum(arrayIdx) + '-' +
379
QString().setNum(selPass));
381
if (!u->GetSemantic().isNull())
382
controls[arrayIdx]->setDisabled(true);
384
if (multipleControls)
385
uniLayout->addLayout(sliderEditLayout, i, j);
387
uniLayout->addWidget(controls[arrayIdx], i, j);
388
multipleControls = false;
392
connect(valMapper, SIGNAL(mapped(const QString&)), this,
393
SLOT(ChangeValue(const QString&)));
396
void RfxDialog::mapSliderLineEdit(QWidget *w)
398
QObject *theSender = ((QSignalMapper*)QObject::sender())->mapping(w);
400
QSlider *qslide = dynamic_cast<QSlider*>(theSender);
401
if (qslide != NULL) {
402
((QLineEdit*)w)->setText(QString().setNum((float)(qslide->value()) * INTTODEC));
404
// we assume it's a QLineEdit (avoid a costly and useless dynamic_cast)
405
// let's do some more checks since qlineedit input is not limited in range
407
float val = ((QLineEdit*)theSender)->text().toFloat(&res);
408
qslide = ((QSlider*)w);
410
// we only accept float values
414
// if value is beyond min or max, just set min/max
415
if (val > qslide->maximum() * INTTODEC)
416
qslide->setValue(qslide->maximum());
417
else if (val < qslide->minimum() * INTTODEC)
418
qslide->setValue(qslide->minimum());
420
qslide->setValue((int)(val * DECTOINT));
424
void RfxDialog::CleanTab(int tabIdx)
426
// deletes all widgets from specified tab or, if tabIdx == -1
427
// removes all widgets from all tabs
428
// (this applies to *dynamically created* widgets only)
430
if (tabIdx == ALL_TABS) {
431
QMapIterator<int, QWidget*> it(widgetsByTab);
432
while (it.hasNext()) {
433
QWidget *toDelete = it.next().value();
437
widgetsByTab.clear();
440
QList<QWidget*> toDelete = widgetsByTab.values(tabIdx);
441
for (int i = 0; i < toDelete.size(); ++i) {
442
toDelete.at(i)->close();
443
delete toDelete.at(i);
445
widgetsByTab.remove(tabIdx);
449
void RfxDialog::extendRange(double newVal)
451
QDoubleSpinBox *sender = (QDoubleSpinBox*)QObject::sender();
452
if (newVal == sender->minimum() || newVal == sender->maximum()) {
453
if (newVal == sender->minimum())
454
sender->setMinimum(newVal - 50);
456
sender->setMaximum(newVal + 50);
460
void RfxDialog::extendRange(int newVal)
462
QSpinBox *sender = (QSpinBox*)QObject::sender();
463
if (newVal == sender->minimum() || newVal == sender->maximum()) {
464
if (newVal == sender->minimum())
465
sender->setMinimum(newVal - 50);
467
sender->setMaximum(newVal + 50);
471
void RfxDialog::ChangeTexture(int unifIdx)
473
int uniIndex = ui.comboTextures->itemData(unifIdx).toInt();
474
RfxUniform *uni = shader->GetPass(selPass)->getUniform(uniIndex);
477
QString fname = QFileDialog::getOpenFileName(this,
478
tr("Choose Texture"),
479
uni->GetTextureFName());
480
if (!fname.isEmpty()) {
481
uni->SetValue(QDir::fromNativeSeparators(fname));
486
// generate a currentIndexChanged event
487
ui.comboTextures->setCurrentIndex(0);
488
ui.comboTextures->setCurrentIndex(unifIdx);
492
void RfxDialog::ChangeValue(const QString& val)
494
QStringList unif = val.split('-');
495
RfxUniform *uni = shader->GetPass(unif[2].toInt())->getUniform(unif[0].toInt());
496
float *oldVal = uni->GetValue();
499
QObject *sender = ((QSignalMapper*)QObject::sender())->mapping(val);
502
QComboBox *cbox = dynamic_cast<QComboBox*>(sender);
504
newVal = cbox->currentIndex();
506
QSpinBox *sbox = dynamic_cast<QSpinBox*>(sender);
508
newVal = sbox->value();
510
QDoubleSpinBox *dsbox = dynamic_cast<QDoubleSpinBox*>(sender);
512
newVal = dsbox->value();
514
QSlider *qslide = dynamic_cast<QSlider*>(sender);
515
if (qslide != NULL) {
516
newVal = qslide->value() * INTTODEC;
517
qslide->setToolTip(QString().setNum(newVal));
525
oldVal[unif[1].toInt()] = newVal;
530
void RfxDialog::TextureSelected(int idx)
532
disconnect(ui.btnChangeTexture, 0, 0, 0);
537
int uniIndex = ui.comboTextures->itemData(idx).toInt();
538
RfxUniform *uni = shader->GetPass(selPass)->getUniform(uniIndex);
541
// connect Change Texture button
542
QSignalMapper *sigMap = new QSignalMapper(this);
543
connect(ui.btnChangeTexture, SIGNAL(clicked()), sigMap, SLOT(map()));
544
sigMap->setMapping(ui.btnChangeTexture, idx);
545
connect(sigMap, SIGNAL(mapped(int)), this, SLOT(ChangeTexture(int)));
547
ui.BoxTextureProps->setTitle(uni->GetName());
549
// clean and initialize table
550
ui.TexStatesTable->clear();
551
ui.TexStatesTable->setRowCount(0);
552
ui.TexStatesTable->setColumnCount(2);
553
ui.TexStatesTable->horizontalHeader()->setStretchLastSection(true);
554
ui.TexStatesTable->horizontalHeader()->hide();
555
ui.TexStatesTable->verticalHeader()->hide();
557
// delete any existing preview
558
ui.lblPreview->clear();
560
CleanTab(TEXTURE_TAB);
562
if (uni->isRenderable())
563
ui.EditTexFile->clear();
565
ui.EditTexFile->setText(uni->GetTextureFName());
567
QLabel *fname = new QLabel();
568
ui.infoTexLayout->addWidget(fname);
569
widgetsByTab.insert(TEXTURE_TAB, fname);
570
if (!uni->isTextureFound() || !uni->isTextureLoaded()) {
571
if (!uni->isTextureFound())
572
fname->setText("<span style=\"color:darkred;\">Texture file not found</span>");
574
fname->setText("<span style=\"color:darkred;\">Texture binding failed</span>");
576
fname->setText("<span style=\"color:darkgreen;\">Texture loaded</span>");
580
if (uni->isRenderable()) {
581
ii.preview = uni->GetRTTexture();
582
ii.texType = "Render Target";
583
ii.width = (ii.preview.isNull())? 0 : ii.preview.width();
584
ii.height = (ii.preview.isNull())? 0 : ii.preview.height();
588
ii = RfxTextureLoader::LoadAsQImage(uni->GetTextureFName());
590
loaded = !ii.preview.isNull();
593
QLabel *tSize = new QLabel();
594
tSize->setText("Dimensions: " +
595
QString().setNum(ii.width) + " x " +
596
QString().setNum(ii.height) +
597
((ii.depth > 1)? " x " + QString().setNum(ii.depth) : ""));
598
ui.infoTexLayout->addWidget(tSize);
599
widgetsByTab.insert(TEXTURE_TAB, tSize);
601
QLabel *tType = new QLabel();
602
tType->setText("Type: " + ii.texType);
603
ui.infoTexLayout->addWidget(tType);
604
widgetsByTab.insert(TEXTURE_TAB, tType);
606
QLabel *tFormat = new QLabel();
607
tFormat->setText("Format: " + ii.format);
608
ui.infoTexLayout->addWidget(tFormat);
609
widgetsByTab.insert(TEXTURE_TAB, tFormat);
611
// try to get a preview
612
QPixmap prvw = QPixmap::fromImage(ii.preview);
613
if (!prvw.isNull()) {
614
QSize scaledSize(120, 120);
615
if (ii.texType == "Cubemap Texture")
616
scaledSize.setWidth(200);
618
ui.lblPreview->setPixmap(prvw.scaled(scaledSize,
619
Qt::KeepAspectRatio));
623
QLabel *tunit = new QLabel();
624
tunit->setText("Texture Unit: " + QString().setNum(uni->GetTU()));
625
ui.infoTexLayout->addWidget(tunit);
626
widgetsByTab.insert(TEXTURE_TAB, tunit);
629
QListIterator<RfxState*> it = uni->StatesIterator();
631
while (it.hasNext()) {
632
RfxState *r = it.next();
634
// QTableWidget will take ownership of objects, do not delete them.
635
QTableWidgetItem *c0 = new QTableWidgetItem(r->GetTextureState());
636
c0->setFlags(Qt::ItemIsSelectable);
637
QTableWidgetItem *c1 = new QTableWidgetItem(r->GetTextureValue());
638
c1->setFlags(Qt::ItemIsSelectable);
640
ui.TexStatesTable->insertRow(rowidx);
641
ui.TexStatesTable->setItem(rowidx, 0, c0);
642
ui.TexStatesTable->setItem(rowidx, 1, c1);
643
ui.TexStatesTable->resizeRowToContents(rowidx);
646
ui.TexStatesTable->resizeColumnToContents(0);
647
ui.TexStatesTable->resizeColumnToContents(1);
652
/*********************************
653
* GLSL Syntax Highlighter Class *
654
*********************************/
656
GLSLSynHlighter::GLSLSynHlighter(QTextDocument *parent)
657
: QSyntaxHighlighter(parent)
659
HighlightingRule rule;
661
kwordsFormat.setForeground(Qt::blue);
662
QStringList keywords;
663
keywords << "uniform" << "int" << "float" << "bool" << "inout"
664
<< "vec2" << "vec3" << "vec4" << "ivec2" << "out"
665
<< "ivec3" << "ivec4" << "bvec2" << "bvec3" << "in"
666
<< "bvec4" << "mat2" << "mat3" << "mat4" << "attribute"
667
<< "sampler1D" << "sampler2D" << "sampler3D"
668
<< "samplerCube" << "sampler1DShadow" << "void"
669
<< "sampler2DShadow" << "varying" << "const";
671
foreach (QString pattern, keywords) {
672
rule.pattern = QRegExp("\\b" + pattern + "\\b");
673
rule.format = kwordsFormat;
674
highlightingRules.append(rule);
677
builtinsFormat.setForeground(Qt::magenta);
678
QStringList builtins;
679
builtins << "gl_Position" << "gl_ClipSize" << "gl_ClipVertex"
680
<< "gl_Vertex" << "gl_Normal" << "gl_Color" << "gl_FragColor"
681
<< "gl_SecondaryColor" << "gl_FogCoord" << "gl_MultiTexCoord[0-7]"
682
<< "gl_FrontColor" << "gl_BackColor" << "gl_FrontSecondaryColor"
683
<< "gl_BackSecondaryColor" << "gl_TexCoord" << "gl_FogFragCoord"
684
<< "gl_FragData" << "gl_FrontFacing" << "gl_FragCoord"
685
<< "gl_FragDepth" << "gl_ModelViewMatrix" << "gl_ProjectionMatrix"
686
<< "gl_ModelViewProjectionMatrix" << "gl_ModelViewMatrixInverse"
687
<< "gl_ModelViewProjectionMatrixInverse" << "gl_NormalMatrix"
688
<< "gl_NormalScale" << "gl_DepthRange" << "gl_Point"
689
<< "gl_ModelViewMatrixInverseTranspose" << "gl_LightSource"
690
<< "gl_ModelViewMatrixTranspose" << "gl_ProjectionMatrixTranspose"
691
<< "gl_ModelViewProjectionMatrixInverseTranspose" << "gl_Fog"
692
<< "gl_ClipPlane" << "gl_(Eye|Object)Plane[STRQ]"
693
<< "gl_(Front|Back)Material" << "gl_(Front|Back)LightProduct";
695
foreach (QString pattern, builtins) {
696
rule.pattern = QRegExp("\\b" + pattern + "\\b");
697
rule.format = builtinsFormat;
698
highlightingRules.append(rule);
701
functionFormat.setForeground(QColor::fromRgb(255, 0, 141));
702
QStringList functions;
703
functions << "sin" << "cos" << "tan" << "asin" << "acos" << "atan"
704
<< "radians" << "degrees" << "pow" << "exp" << "log"
705
<< "expr2" << "log2" << "sqrt" << "inversesqrt" << "abs"
706
<< "ceil" << "clamp" << "floor" << "fract" << "min" << "mix"
707
<< "max" << "mod" << "sign" << "smoothstep" << "step"
708
<< "ftransform" << "cross" << "distance" << "dot"
709
<< "faceforward" << "length" << "normalize" << "reflect"
710
<< "dFdx" << "dFdy" << "fwidth" << "matrixCompMult" << "all"
711
<< "any" << "equal" << "greaterThan" << "lessThan" << "notEqual"
712
<< "texture1DProj" << "texture2DProj" << "texture3DProj"
713
<< "textureCube" << "noise4" << "texture3D" << "not" << "noise3"
714
<< "texture1D" << "texture2D" << "noise1" << "noise2";
716
foreach (QString pattern, functions) {
717
rule.pattern = QRegExp("\\b" + pattern + "+(?=\\()");
718
rule.format = functionFormat;
719
highlightingRules.append(rule);
722
singleLineCommentFormat.setForeground(Qt::darkGreen);
723
rule.pattern = QRegExp("//[^\n]*");
724
rule.format = singleLineCommentFormat;
725
highlightingRules.append(rule);
727
multiLineCommentFormat = singleLineCommentFormat;
728
commentStartExpression = QRegExp("/\\*");
729
commentEndExpression = QRegExp("\\*/");
732
void GLSLSynHlighter::highlightBlock(const QString &text)
734
foreach (HighlightingRule rule, highlightingRules) {
735
QRegExp expression(rule.pattern);
736
int index = text.indexOf(expression);
738
int length = expression.matchedLength();
739
setFormat(index, length, rule.format);
740
index = text.indexOf(expression, index + length);
744
/* multiline comment management */
745
setCurrentBlockState(0);
748
if (previousBlockState() != 1)
749
startIndex = text.indexOf(commentStartExpression);
751
while (startIndex >= 0) {
752
int endIndex = text.indexOf(commentEndExpression, startIndex);
754
if (endIndex == -1) {
755
setCurrentBlockState(1);
756
commentLength = text.length() - startIndex;
758
commentLength = endIndex - startIndex +
759
commentEndExpression.matchedLength();
761
setFormat(startIndex, commentLength, multiLineCommentFormat);
762
startIndex = text.indexOf(commentStartExpression,
763
startIndex + commentLength);
1
/****************************************************************************
3
* A versatile mesh processing toolbox o o *
5
* Copyright(C) 2005-2008 \/)\/ *
6
* Visual Computing Lab /\/| *
7
* ISTI - Italian National Research Council | *
9
* All rights reserved. *
11
* This program is free software; you can redistribute it and/or modify *
12
* it under the terms of the GNU General Public License as published by *
13
* the Free Software Foundation; either version 2 of the License, or *
14
* (at your option) any later version. *
16
* This program is distributed in the hope that it will be useful, *
17
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
18
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19
* GNU General Public License (http://www.gnu.org/licenses/gpl.txt) *
22
****************************************************************************/
24
#include "rfx_dialog.h"
26
const float RfxDialog::DECTOINT = 10000.0f;
27
const float RfxDialog::INTTODEC = 0.0001f;
29
RfxDialog::RfxDialog(RfxShader *s, QAction *a, QGLWidget *parent)
36
setWindowTitle("RenderRfx [" + a->text() + "]");
38
setWidget(ui.RfxDockContents);
39
setFeatures(QDockWidget::AllDockWidgetFeatures);
40
setAllowedAreas(Qt::LeftDockWidgetArea);
44
QListIterator<RfxGLPass*> pit = s->PassesIterator();
45
while (pit.hasNext()) {
46
RfxGLPass *pass = pit.next();
47
ui.comboPasses->addItem("Pass #" +
48
QString().setNum(pass->GetPassIndex()) +
49
" " + pass->GetPassName() + " ");
51
// start from first pass
52
connect(ui.comboPasses, SIGNAL(currentIndexChanged(int)), this,
53
SLOT(PassSelected(int)));
55
ui.comboPasses->setCurrentIndex(0);
58
fixedfont.setFamily("Courier");
59
fixedfont.setFixedPitch(true);
60
fixedfont.setPointSize(10);
61
ui.textVert->setFont(fixedfont);
62
ui.textFrag->setFont(fixedfont);
64
vertHL = new GLSLSynHlighter(ui.textVert->document());
65
fragHL = new GLSLSynHlighter(ui.textFrag->document());
67
// fill log once for dialog, since it reports status for all passes
68
ui.textLog->setPlainText(s->GetCompilationLog().join("\n"));
71
// uniform tab will contain every uniform from every pass
73
pit = s->PassesIterator();
74
while (pit.hasNext()) {
75
RfxGLPass *pass = pit.next();
77
QListIterator<RfxUniform*> it = pass->UniformsIterator();
78
int unifCount = -1; // keep track of uniform index
79
while (it.hasNext()) {
81
RfxUniform *uni = it.next();
85
/* Verifies if the type of the uniform is special or not */
87
const type_info& ti = typeid(*uni);
89
if(ti != typeid(RfxSpecialUniform))
90
AddUniformBox(uni, unifCount);
92
/* If the uniform is a special one, casts it to special uniform */
93
RfxSpecialUniform* sp = dynamic_cast<RfxSpecialUniform*>(uni);
94
/* and initializes its value */
107
void RfxDialog::setupTabs()
110
ui.comboTextures->clear();
111
ui.comboTextures->setEnabled(true);
112
disconnect(ui.comboTextures, 0, 0, 0);
114
QListIterator<RfxUniform*> it = shader->GetPass(selPass)->UniformsIterator();
116
while (it.hasNext()) {
118
RfxUniform *uni = it.next();
119
if (!uni->isTexture())
121
ui.comboTextures->addItem("[" +
122
RfxUniform::GetTypeString(uni->GetType()) +
124
((uni->isRenderable())? " (RT) " : "") +
129
if (ui.comboTextures->count() == 0) {
130
ui.comboTextures->addItem("No textures");
131
ui.comboTextures->setDisabled(true);
133
ui.comboTextures->insertItem(0, "Select...");
134
ui.comboTextures->setCurrentIndex(0);
135
connect(ui.comboTextures, SIGNAL(currentIndexChanged(int)), this,
136
SLOT(TextureSelected(int)));
139
disconnect(ui.btnChangeTexture, 0, 0, 0);
140
ui.BoxTextureProps->setTitle("");
141
ui.EditTexFile->clear();
142
ui.TexStatesTable->clear();
143
ui.TexStatesTable->setRowCount(0);
144
ui.TexStatesTable->setColumnCount(2);
145
ui.TexStatesTable->horizontalHeader()->setStretchLastSection(true);
146
ui.TexStatesTable->horizontalHeader()->hide();
147
ui.TexStatesTable->verticalHeader()->hide();
148
ui.lblPreview->clear();
152
ui.glStatesTable->clear();
153
ui.glStatesTable->setRowCount(0);
154
ui.glStatesTable->setColumnCount(2);
155
ui.glStatesTable->horizontalHeader()->setStretchLastSection(true);
156
ui.glStatesTable->horizontalHeader()->hide();
157
ui.glStatesTable->verticalHeader()->hide();
158
QListIterator<RfxState*> sit = shader->GetPass(selPass)->StatesIterator();
160
while (sit.hasNext()) {
161
RfxState *r = sit.next();
163
// QTableWidget will take ownership of objects, do not delete them.
164
QTableWidgetItem *c0 = new QTableWidgetItem(r->GetRenderState());
165
c0->setFlags(Qt::ItemIsSelectable);
166
QTableWidgetItem *c1 = new QTableWidgetItem(r->GetRenderValue());
167
c1->setFlags(Qt::ItemIsSelectable);
169
ui.glStatesTable->insertRow(rowidx);
170
ui.glStatesTable->setItem(rowidx, 0, c0);
171
ui.glStatesTable->setItem(rowidx, 1, c1);
172
ui.glStatesTable->resizeRowToContents(rowidx);
175
ui.glStatesTable->resizeColumnToContents(0);
176
ui.glStatesTable->resizeColumnToContents(1);
179
/* Vertex/Fragment source view */
180
ui.textVert->setPlainText(shader->GetPass(selPass)->GetVertexSource());
181
ui.textFrag->setPlainText(shader->GetPass(selPass)->GetFragmentSource());
184
RfxDialog::~RfxDialog()
192
void RfxDialog::PassSelected(int idx)
199
void RfxDialog::AddUniformBox(RfxUniform *uni, int uniIndex)
203
QLabel *lblUni = new QLabel();
206
lblText.append(QString("(Pass #%1) ").arg(selPass));
207
lblText.append(uni->GetName());
209
if (!uni->GetSemantic().isNull()) {
210
lblText.append("<span style=\"color:darkgreen;\"><br/> [P: ");
211
lblText.append(uni->GetSemantic());
212
lblText.append("]</span>");
215
lblUni->setText(lblText);
217
QGridLayout *gridUni = new QGridLayout();
219
switch (uni->GetType()) {
220
case RfxUniform::INT:
221
case RfxUniform::FLOAT:
222
case RfxUniform::BOOL:
223
DrawIFace(gridUni, uni, uniIndex, 1, 1);
226
case RfxUniform::VEC2:
227
case RfxUniform::IVEC2:
228
case RfxUniform::BVEC2:
229
DrawIFace(gridUni, uni, uniIndex, 1, 2);
232
case RfxUniform::VEC3:
233
case RfxUniform::IVEC3:
234
case RfxUniform::BVEC3:
235
DrawIFace(gridUni, uni, uniIndex, 1, 3);
238
case RfxUniform::VEC4:
239
if(uni->isRmColorVariable()){
240
DrawIFace(gridUni, uni, uniIndex, 1, 1);
243
case RfxUniform::IVEC4:
244
case RfxUniform::BVEC4:
245
DrawIFace(gridUni, uni, uniIndex, 1, 4);
248
case RfxUniform::MAT2:
249
DrawIFace(gridUni, uni, uniIndex, 2, 2);
252
case RfxUniform::MAT3:
253
DrawIFace(gridUni, uni, uniIndex, 3, 3);
256
case RfxUniform::MAT4:
257
DrawIFace(gridUni, uni, uniIndex, 4, 4);
264
QHBoxLayout *boxContent = new QHBoxLayout();
265
boxContent->addWidget(lblUni);
266
boxContent->addLayout(gridUni);
268
((QVBoxLayout*)ui.scrollUniformsContents->layout())->addLayout(boxContent);
271
void RfxDialog::DrawIFace(QGridLayout *parent, RfxUniform *u, int uidx, int rows, int columns)
273
enum controlType { INT_CTRL, FLOAT_CTRL, BOOL_CTRL, COLOR_CTRL };
274
enum ColorComponentsType { R, G, B, A };
275
float *val = u->GetValue();
277
ColorComponentsType rgba = R;
278
QWidget **controls = new QWidget*[rows * columns];
279
QGridLayout *uniLayout = parent;
280
QHBoxLayout *sliderEditLayout = NULL;
281
bool multipleControls = false;
282
QSignalMapper *valMapper = new QSignalMapper(this);
284
switch (u->GetType()) {
285
case RfxUniform::INT:
286
case RfxUniform::IVEC2:
287
case RfxUniform::IVEC3:
288
case RfxUniform::IVEC4:
292
case RfxUniform::FLOAT:
293
case RfxUniform::VEC2:
294
case RfxUniform::VEC3:
295
case RfxUniform::VEC4:
296
if(u->isRmColorVariable()){
300
case RfxUniform::MAT2:
301
case RfxUniform::MAT3:
302
case RfxUniform::MAT4:
306
case RfxUniform::BOOL:
307
case RfxUniform::BVEC2:
308
case RfxUniform::BVEC3:
309
case RfxUniform::BVEC4:
316
if(ctrl == COLOR_CTRL)
318
RfxColorBox* mycolorBox = new RfxColorBox(100, 25, QColor(val[0] * 255, val[1] * 255, val[2] * 255, val[3] * 255));
319
uniLayout->addWidget(mycolorBox, 0,0);
320
connect(mycolorBox, SIGNAL(colorChanged()), valMapper, SLOT(map()));
321
valMapper->setMapping(mycolorBox,
322
QString().setNum(uidx) + '-' +
323
QString().setNum(1) + '-' +
324
QString().setNum(selPass));
327
// controls in a grid layout
328
for (int i = 0; i < rows; ++i) {
329
for (int j = 0; j < columns; ++j) {
330
int arrayIdx = j + (i * rows);
333
controls[arrayIdx] = new QSpinBox(this);
334
((QSpinBox*)controls[arrayIdx])->setRange(-99, 99);
335
((QSpinBox*)controls[arrayIdx])->setValue((int)val[arrayIdx]);
336
connect(controls[arrayIdx], SIGNAL(valueChanged(int)),
337
valMapper, SLOT(map()));
338
connect(controls[arrayIdx], SIGNAL(valueChanged(int)), this,
339
SLOT(extendRange(int)));
342
if (u->HasMinMax()) {
343
controls[arrayIdx] = new QSlider(this);
344
((QSlider*)controls[arrayIdx])->setTickPosition(QSlider::NoTicks);
345
((QSlider*)controls[arrayIdx])->setOrientation(Qt::Horizontal);
347
// since qslider only deals with integers, do a little conversion
349
// keep as much as 5 decimal values, others will be lost in conversion
350
int valAsInt = (int)(val[arrayIdx] * DECTOINT);
351
int tickAsInt = (int)(((u->GetMaxRange() - u->GetMinRange()) * 0.01) * DECTOINT);
353
((QSlider*)controls[arrayIdx])->setTickInterval(tickAsInt);
354
((QSlider*)controls[arrayIdx])->setRange((int)(u->GetMinRange() * DECTOINT),
355
(int)(u->GetMaxRange() * DECTOINT));
356
((QSlider*)controls[arrayIdx])->setValue(valAsInt);
357
((QSlider*)controls[arrayIdx])->setToolTip(QString().setNum(val[arrayIdx]));
359
connect(controls[arrayIdx], SIGNAL(valueChanged(int)), valMapper, SLOT(map()));
361
// as per request, if value is a single float, also show a qlineedit to allow
362
// more accurate settings.
363
if (u->GetType() == RfxUniform::FLOAT) {
365
QLineEdit *slideValue = new QLineEdit();
366
slideValue->setAlignment(Qt::AlignRight);
367
slideValue->setText(QString().setNum(val[arrayIdx]));
369
QSignalMapper *yaMapper = new QSignalMapper();
370
connect(controls[arrayIdx], SIGNAL(valueChanged(int)), yaMapper, SLOT(map()));
371
connect(slideValue, SIGNAL(editingFinished()), yaMapper, SLOT(map()));
372
yaMapper->setMapping(controls[arrayIdx], slideValue);
373
yaMapper->setMapping(slideValue, controls[arrayIdx]);
374
connect(yaMapper, SIGNAL(mapped(QWidget*)), this, SLOT(mapSliderLineEdit(QWidget*)));
376
if (!u->GetSemantic().isNull())
377
slideValue->setDisabled(true);
379
multipleControls = true;
380
sliderEditLayout = new QHBoxLayout();
381
sliderEditLayout->addWidget(controls[arrayIdx]);
382
sliderEditLayout->addWidget(slideValue);
386
controls[arrayIdx] = new QDoubleSpinBox(this);
387
((QDoubleSpinBox*)controls[arrayIdx])->setRange(-99.0, 99.0);
388
((QDoubleSpinBox*)controls[arrayIdx])->setValue(val[arrayIdx]);
389
((QDoubleSpinBox*)controls[arrayIdx])->setDecimals(4);
390
((QDoubleSpinBox*)controls[arrayIdx])->setSingleStep(0.01);
391
connect(controls[arrayIdx], SIGNAL(valueChanged(double)),
392
valMapper, SLOT(map()));
393
connect(controls[arrayIdx], SIGNAL(valueChanged(double)), this,
394
SLOT(extendRange(double)));
398
controls[arrayIdx] = new QComboBox(this);
399
((QComboBox*)controls[arrayIdx])->addItem("FALSE");
400
((QComboBox*)controls[arrayIdx])->addItem("TRUE");
402
((QComboBox*)controls[arrayIdx])->setCurrentIndex(0);
403
connect(controls[arrayIdx], SIGNAL(currentIndexChanged(int)),
404
valMapper, SLOT(map()));
410
valMapper->setMapping(controls[arrayIdx],
411
QString().setNum(uidx) + '-' +
412
QString().setNum(arrayIdx) + '-' +
413
QString().setNum(selPass));
415
if (!u->GetSemantic().isNull())
416
controls[arrayIdx]->setDisabled(true);
418
if (multipleControls)
419
uniLayout->addLayout(sliderEditLayout, i, j);
421
uniLayout->addWidget(controls[arrayIdx], i, j);
422
multipleControls = false;
426
connect(valMapper, SIGNAL(mapped(const QString&)), this,
427
SLOT(ChangeValue(const QString&)));
430
void RfxDialog::mapSliderLineEdit(QWidget *w)
432
QObject *theSender = ((QSignalMapper*)QObject::sender())->mapping(w);
434
QSlider *qslide = dynamic_cast<QSlider*>(theSender);
435
if (qslide != NULL) {
436
((QLineEdit*)w)->setText(QString().setNum((float)(qslide->value()) * INTTODEC));
438
// we assume it's a QLineEdit (avoid a costly and useless dynamic_cast)
439
// let's do some more checks since qlineedit input is not limited in range
441
float val = ((QLineEdit*)theSender)->text().toFloat(&res);
442
qslide = ((QSlider*)w);
444
// we only accept float values
448
// if value is beyond min or max, just set min/max
449
if (val > qslide->maximum() * INTTODEC)
450
qslide->setValue(qslide->maximum());
451
else if (val < qslide->minimum() * INTTODEC)
452
qslide->setValue(qslide->minimum());
454
qslide->setValue((int)(val * DECTOINT));
458
void RfxDialog::CleanTab(int tabIdx)
460
// deletes all widgets from specified tab or, if tabIdx == -1
461
// removes all widgets from all tabs
462
// (this applies to *dynamically created* widgets only)
464
if (tabIdx == ALL_TABS) {
465
QMapIterator<int, QWidget*> it(widgetsByTab);
466
while (it.hasNext()) {
467
QWidget *toDelete = it.next().value();
471
widgetsByTab.clear();
474
QList<QWidget*> toDelete = widgetsByTab.values(tabIdx);
475
for (int i = 0; i < toDelete.size(); ++i) {
476
toDelete.at(i)->close();
477
delete toDelete.at(i);
479
widgetsByTab.remove(tabIdx);
483
void RfxDialog::extendRange(double newVal)
485
QDoubleSpinBox *sender = (QDoubleSpinBox*)QObject::sender();
486
if (newVal == sender->minimum() || newVal == sender->maximum()) {
487
if (newVal == sender->minimum())
488
sender->setMinimum(newVal - 50);
490
sender->setMaximum(newVal + 50);
494
void RfxDialog::extendRange(int newVal)
496
QSpinBox *sender = (QSpinBox*)QObject::sender();
497
if (newVal == sender->minimum() || newVal == sender->maximum()) {
498
if (newVal == sender->minimum())
499
sender->setMinimum(newVal - 50);
501
sender->setMaximum(newVal + 50);
505
void RfxDialog::ChangeTexture(int unifIdx)
507
int uniIndex = ui.comboTextures->itemData(unifIdx).toInt();
508
RfxUniform *uni = shader->GetPass(selPass)->getUniform(uniIndex);
511
QString fname = QFileDialog::getOpenFileName(this,
512
tr("Choose Texture"),
513
uni->GetTextureFName());
514
if (!fname.isEmpty()) {
515
uni->SetValue(QDir::fromNativeSeparators(fname));
520
// generate a currentIndexChanged event
521
ui.comboTextures->setCurrentIndex(0);
522
ui.comboTextures->setCurrentIndex(unifIdx);
526
void RfxDialog::ChangeValue(const QString& val)
528
QStringList unif = val.split('-');
529
RfxUniform *uni = shader->GetPass(unif[2].toInt())->getUniform(unif[0].toInt());
530
float *oldVal = uni->GetValue();
533
QObject *sender = ((QSignalMapper*)QObject::sender())->mapping(val);
536
QComboBox *cbox = dynamic_cast<QComboBox*>(sender);
538
newVal = cbox->currentIndex();
540
QSpinBox *sbox = dynamic_cast<QSpinBox*>(sender);
542
newVal = sbox->value();
544
QDoubleSpinBox *dsbox = dynamic_cast<QDoubleSpinBox*>(sender);
546
newVal = dsbox->value();
548
QSlider *qslide = dynamic_cast<QSlider*>(sender);
549
if (qslide != NULL) {
550
newVal = qslide->value() * INTTODEC;
551
qslide->setToolTip(QString().setNum(newVal));
553
RfxColorBox *cBox = dynamic_cast<RfxColorBox*>(sender);
555
float* newVal = cBox->getColorf();
556
oldVal[0] = newVal[0];
557
oldVal[1] = newVal[1];
558
oldVal[2] = newVal[2];
559
oldVal[3] = newVal[3];
571
oldVal[unif[1].toInt()] = newVal;
575
void RfxDialog::TextureSelected(int idx)
577
disconnect(ui.btnChangeTexture, 0, 0, 0);
582
int uniIndex = ui.comboTextures->itemData(idx).toInt();
583
RfxUniform *uni = shader->GetPass(selPass)->getUniform(uniIndex);
586
// connect Change Texture button
587
QSignalMapper *sigMap = new QSignalMapper(this);
588
connect(ui.btnChangeTexture, SIGNAL(clicked()), sigMap, SLOT(map()));
589
sigMap->setMapping(ui.btnChangeTexture, idx);
590
connect(sigMap, SIGNAL(mapped(int)), this, SLOT(ChangeTexture(int)));
592
ui.BoxTextureProps->setTitle(uni->GetName());
594
// clean and initialize table
595
ui.TexStatesTable->clear();
596
ui.TexStatesTable->setRowCount(0);
597
ui.TexStatesTable->setColumnCount(2);
598
ui.TexStatesTable->horizontalHeader()->setStretchLastSection(true);
599
ui.TexStatesTable->horizontalHeader()->hide();
600
ui.TexStatesTable->verticalHeader()->hide();
602
// delete any existing preview
603
ui.lblPreview->clear();
605
CleanTab(TEXTURE_TAB);
607
if (uni->isRenderable())
608
ui.EditTexFile->clear();
610
ui.EditTexFile->setText(uni->GetTextureFName());
612
QLabel *fname = new QLabel();
613
ui.infoTexLayout->addWidget(fname);
614
widgetsByTab.insert(TEXTURE_TAB, fname);
615
if (!uni->isTextureFound() || !uni->isTextureLoaded()) {
616
if (!uni->isTextureFound())
617
fname->setText("<span style=\"color:darkred;\">Texture file not found</span>");
619
fname->setText("<span style=\"color:darkred;\">Texture binding failed</span>");
621
fname->setText("<span style=\"color:darkgreen;\">Texture loaded</span>");
625
if (uni->isRenderable()) {
626
ii.preview = uni->GetRTTexture();
627
ii.texType = "Render Target";
628
ii.width = (ii.preview.isNull())? 0 : ii.preview.width();
629
ii.height = (ii.preview.isNull())? 0 : ii.preview.height();
633
ii = RfxTextureLoader::LoadAsQImage(uni->GetTextureFName());
635
loaded = !ii.preview.isNull();
638
QLabel *tSize = new QLabel();
639
tSize->setText("Dimensions: " +
640
QString().setNum(ii.width) + " x " +
641
QString().setNum(ii.height) +
642
((ii.depth > 1)? " x " + QString().setNum(ii.depth) : ""));
643
ui.infoTexLayout->addWidget(tSize);
644
widgetsByTab.insert(TEXTURE_TAB, tSize);
646
QLabel *tType = new QLabel();
647
tType->setText("Type: " + ii.texType);
648
ui.infoTexLayout->addWidget(tType);
649
widgetsByTab.insert(TEXTURE_TAB, tType);
651
QLabel *tFormat = new QLabel();
652
tFormat->setText("Format: " + ii.format);
653
ui.infoTexLayout->addWidget(tFormat);
654
widgetsByTab.insert(TEXTURE_TAB, tFormat);
656
// try to get a preview
657
QPixmap prvw = QPixmap::fromImage(ii.preview);
658
if (!prvw.isNull()) {
659
QSize scaledSize(120, 120);
660
if (ii.texType == "Cubemap Texture")
661
scaledSize.setWidth(200);
663
ui.lblPreview->setPixmap(prvw.scaled(scaledSize,
664
Qt::KeepAspectRatio));
668
QLabel *tunit = new QLabel();
669
tunit->setText("Texture Unit: " + QString().setNum(uni->GetTU()));
670
ui.infoTexLayout->addWidget(tunit);
671
widgetsByTab.insert(TEXTURE_TAB, tunit);
674
QListIterator<RfxState*> it = uni->StatesIterator();
676
while (it.hasNext()) {
677
RfxState *r = it.next();
679
// QTableWidget will take ownership of objects, do not delete them.
680
QTableWidgetItem *c0 = new QTableWidgetItem(r->GetTextureState());
681
c0->setFlags(Qt::ItemIsSelectable);
682
QTableWidgetItem *c1 = new QTableWidgetItem(r->GetTextureValue());
683
c1->setFlags(Qt::ItemIsSelectable);
685
ui.TexStatesTable->insertRow(rowidx);
686
ui.TexStatesTable->setItem(rowidx, 0, c0);
687
ui.TexStatesTable->setItem(rowidx, 1, c1);
688
ui.TexStatesTable->resizeRowToContents(rowidx);
691
ui.TexStatesTable->resizeColumnToContents(0);
692
ui.TexStatesTable->resizeColumnToContents(1);
697
/*********************************
698
* GLSL Syntax Highlighter Class *
699
*********************************/
701
GLSLSynHlighter::GLSLSynHlighter(QTextDocument *parent)
702
: QSyntaxHighlighter(parent)
704
HighlightingRule rule;
706
kwordsFormat.setForeground(Qt::blue);
707
QStringList keywords;
708
keywords << "uniform" << "int" << "float" << "bool" << "inout"
709
<< "vec2" << "vec3" << "vec4" << "ivec2" << "out"
710
<< "ivec3" << "ivec4" << "bvec2" << "bvec3" << "in"
711
<< "bvec4" << "mat2" << "mat3" << "mat4" << "attribute"
712
<< "sampler1D" << "sampler2D" << "sampler3D"
713
<< "samplerCube" << "sampler1DShadow" << "void"
714
<< "sampler2DShadow" << "varying" << "const";
716
foreach (QString pattern, keywords) {
717
rule.pattern = QRegExp("\\b" + pattern + "\\b");
718
rule.format = kwordsFormat;
719
highlightingRules.append(rule);
722
builtinsFormat.setForeground(Qt::magenta);
723
QStringList builtins;
724
builtins << "gl_Position" << "gl_ClipSize" << "gl_ClipVertex"
725
<< "gl_Vertex" << "gl_Normal" << "gl_Color" << "gl_FragColor"
726
<< "gl_SecondaryColor" << "gl_FogCoord" << "gl_MultiTexCoord[0-7]"
727
<< "gl_FrontColor" << "gl_BackColor" << "gl_FrontSecondaryColor"
728
<< "gl_BackSecondaryColor" << "gl_TexCoord" << "gl_FogFragCoord"
729
<< "gl_FragData" << "gl_FrontFacing" << "gl_FragCoord"
730
<< "gl_FragDepth" << "gl_ModelViewMatrix" << "gl_ProjectionMatrix"
731
<< "gl_ModelViewProjectionMatrix" << "gl_ModelViewMatrixInverse"
732
<< "gl_ModelViewProjectionMatrixInverse" << "gl_NormalMatrix"
733
<< "gl_NormalScale" << "gl_DepthRange" << "gl_Point"
734
<< "gl_ModelViewMatrixInverseTranspose" << "gl_LightSource"
735
<< "gl_ModelViewMatrixTranspose" << "gl_ProjectionMatrixTranspose"
736
<< "gl_ModelViewProjectionMatrixInverseTranspose" << "gl_Fog"
737
<< "gl_ClipPlane" << "gl_(Eye|Object)Plane[STRQ]"
738
<< "gl_(Front|Back)Material" << "gl_(Front|Back)LightProduct";
740
foreach (QString pattern, builtins) {
741
rule.pattern = QRegExp("\\b" + pattern + "\\b");
742
rule.format = builtinsFormat;
743
highlightingRules.append(rule);
746
functionFormat.setForeground(QColor::fromRgb(255, 0, 141));
747
QStringList functions;
748
functions << "sin" << "cos" << "tan" << "asin" << "acos" << "atan"
749
<< "radians" << "degrees" << "pow" << "exp" << "log"
750
<< "expr2" << "log2" << "sqrt" << "inversesqrt" << "abs"
751
<< "ceil" << "clamp" << "floor" << "fract" << "min" << "mix"
752
<< "max" << "mod" << "sign" << "smoothstep" << "step"
753
<< "ftransform" << "cross" << "distance" << "dot"
754
<< "faceforward" << "length" << "normalize" << "reflect"
755
<< "dFdx" << "dFdy" << "fwidth" << "matrixCompMult" << "all"
756
<< "any" << "equal" << "greaterThan" << "lessThan" << "notEqual"
757
<< "texture1DProj" << "texture2DProj" << "texture3DProj"
758
<< "textureCube" << "noise4" << "texture3D" << "not" << "noise3"
759
<< "texture1D" << "texture2D" << "noise1" << "noise2";
761
foreach (QString pattern, functions) {
762
rule.pattern = QRegExp("\\b" + pattern + "+(?=\\()");
763
rule.format = functionFormat;
764
highlightingRules.append(rule);
767
singleLineCommentFormat.setForeground(Qt::darkGreen);
768
rule.pattern = QRegExp("//[^\n]*");
769
rule.format = singleLineCommentFormat;
770
highlightingRules.append(rule);
772
multiLineCommentFormat = singleLineCommentFormat;
773
commentStartExpression = QRegExp("/\\*");
774
commentEndExpression = QRegExp("\\*/");
777
void GLSLSynHlighter::highlightBlock(const QString &text)
779
foreach (HighlightingRule rule, highlightingRules) {
780
QRegExp expression(rule.pattern);
781
int index = text.indexOf(expression);
783
int length = expression.matchedLength();
784
setFormat(index, length, rule.format);
785
index = text.indexOf(expression, index + length);
789
/* multiline comment management */
790
setCurrentBlockState(0);
793
if (previousBlockState() != 1)
794
startIndex = text.indexOf(commentStartExpression);
796
while (startIndex >= 0) {
797
int endIndex = text.indexOf(commentEndExpression, startIndex);
799
if (endIndex == -1) {
800
setCurrentBlockState(1);
801
commentLength = text.length() - startIndex;
803
commentLength = endIndex - startIndex +
804
commentEndExpression.matchedLength();
806
setFormat(startIndex, commentLength, multiLineCommentFormat);
807
startIndex = text.indexOf(commentStartExpression,
808
startIndex + commentLength);
b'\\ No newline at end of file'