Added additive selection blending, with a toggable flash effect. :P

Mon, 15 Apr 2013 01:51:53 +0300

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Mon, 15 Apr 2013 01:51:53 +0300
changeset 106
46e4202a44fc
parent 105
53f95a6e351d
child 107
195aa036da7f

Added additive selection blending, with a toggable flash effect. :P

gldraw.cpp file | annotate | diff | comparison | revisions
gldraw.h file | annotate | diff | comparison | revisions
gui.cpp file | annotate | diff | comparison | revisions
gui.h file | annotate | diff | comparison | revisions
zz_configDialog.cpp file | annotate | diff | comparison | revisions
zz_configDialog.h file | annotate | diff | comparison | revisions
--- a/gldraw.cpp	Sun Apr 14 17:31:09 2013 +0300
+++ b/gldraw.cpp	Mon Apr 15 01:51:53 2013 +0300
@@ -31,25 +31,33 @@
 static double g_StoredBBoxSize;
 static bool g_bPicking = false;
 
+static short g_dPulseTick = 0;
+static const short g_dNumPulseTicks = 8;
+static const short g_dPulseInterval = 65;
+
 cfg (str, gl_bgcolor, "#CCCCD9");
 cfg (str, gl_maincolor, "#707078");
 cfg (float, gl_maincolor_alpha, 1.0);
 cfg (int, gl_linethickness, 2);
 cfg (bool, gl_colorbfc, true);
+cfg (bool, gl_selflash, false);
 
 // ========================================================================= //
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 // ========================================================================= //
-renderer::renderer (QWidget* parent) {
+GLRenderer::GLRenderer (QWidget* parent) {
 	parent = parent; // shhh, GCC
 	fRotX = fRotY = fRotZ = 0.0f;
 	fZoom = 1.0f;
+	
+	qPulseTimer = new QTimer (this);
+	connect (qPulseTimer, SIGNAL (timeout ()), this, SLOT (slot_timerUpdate ()));
 }
 
 // ========================================================================= //
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 // ========================================================================= //
-void renderer::initializeGL () {
+void GLRenderer::initializeGL () {
 	glLoadIdentity();
 	glMatrixMode (GL_MODELVIEW);
 	
@@ -62,23 +70,22 @@
 	glShadeModel (GL_SMOOTH);
 	glEnable (GL_MULTISAMPLE);
 	
-	glEnable (GL_DITHER);
 	glEnable (GL_BLEND);
 	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 	
 	glEnable (GL_LINE_SMOOTH);
 	glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
+	
 	glLineWidth (gl_linethickness);
 	
 	setMouseTracking (true);
-	
 	compileObjects ();
 }
 
 // ========================================================================= //
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 // ========================================================================= //
-QColor renderer::getMainColor () {
+QColor GLRenderer::getMainColor () {
 	QColor col (gl_maincolor.value.chars());
 	
 	if (!col.isValid ())
@@ -89,7 +96,7 @@
 }
 
 // ------------------------------------------------------------------------- //
-void renderer::setBackground () {
+void GLRenderer::setBackground () {
 	QColor col (gl_bgcolor.value.chars());
 	
 	if (!col.isValid ())
@@ -106,7 +113,7 @@
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 // ========================================================================= //
 static vector<short> g_daWarnedColors;
-void renderer::setObjectColor (LDObject* obj) {
+void GLRenderer::setObjectColor (LDObject* obj) {
 	QColor qCol;
 	
 	if (g_bPicking) {
@@ -178,11 +185,23 @@
 		b = qCol.blue (),
 		a = qCol.alpha ();
 	
-	// If it's selected, brighten it up
-	if (g_ForgeWindow->isSelected (obj) && obj->dColor != dEdgeColor) {
-		r = ((r * 3) + (255 * 2)) / 5;
-		g = ((g * 3) + (255 * 2)) / 5;
-		b = ((b * 3) + (255 * 2)) / 5;
+	// If it's selected, brighten it up, also pulse flash it if desired.
+	if (g_ForgeWindow->isSelected (obj)) {
+		short dTick, dNumTicks;
+		
+		if (gl_selflash) {
+			dTick = (g_dPulseTick < (g_dNumPulseTicks / 2)) ? g_dPulseTick : (g_dNumPulseTicks - g_dPulseTick);
+			dNumTicks = g_dNumPulseTicks;
+		} else {
+			dTick = 2;
+			dNumTicks = 5;
+		}
+		
+		const long lAdd = ((dTick * 128) / dNumTicks);
+		r = min (r + lAdd, 255l);
+		g = min (g + lAdd, 255l);
+		b = min (b + lAdd, 255l);
+		
 		a = 255;
 	}
 	
@@ -196,7 +215,7 @@
 // ========================================================================= //
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 // ========================================================================= //
-void renderer::hardRefresh () {
+void GLRenderer::hardRefresh () {
 	compileObjects ();
 	paintGL ();
 	swapBuffers ();
@@ -207,7 +226,7 @@
 // ========================================================================= //
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 // ========================================================================= //
-void renderer::resizeGL (int w, int h) {
+void GLRenderer::resizeGL (int w, int h) {
 	glViewport (0, 0, w, h);
 	glLoadIdentity ();
 	glMatrixMode (GL_PROJECTION);
@@ -217,10 +236,13 @@
 // ========================================================================= //
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 // ========================================================================= //
-void renderer::paintGL () {
+void GLRenderer::paintGL () {
 	glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 	glMatrixMode (GL_MODELVIEW);
 	
+	if (g_CurrentFile == null)
+		return;
+	
 	glPushMatrix ();
 		glLoadIdentity ();
 		
@@ -231,39 +253,45 @@
 		glRotatef (fRotY, 0.0f, 1.0f, 0.0f);
 		glRotatef (fRotZ, 0.0f, 0.0f, 1.0f);
 		
-		for (GLuint uList : uaObjLists)
-			glCallList (uList);
+		for (LDObject* obj : g_CurrentFile->objects)
+			glCallList (obj->uGLList);
 	glPopMatrix ();
 }
 
 // ========================================================================= //
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 // ========================================================================= //
-void renderer::compileObjects () {
+void GLRenderer::compileObjects () {
 	uaObjLists.clear ();
 	
 	g_faObjectOffset[0] = -(g_BBox.v0.x + g_BBox.v1.x) / 2;
 	g_faObjectOffset[1] = -(g_BBox.v0.y + g_BBox.v1.y) / 2;
 	g_faObjectOffset[2] = -(g_BBox.v0.z + g_BBox.v1.z) / 2;
 	g_StoredBBoxSize = g_BBox.calcSize ();
-	printf ("bbox size is %f\n", g_StoredBBoxSize);
 	
 	if (!g_CurrentFile) {
 		printf ("renderer: no files loaded, cannot compile anything\n");
 		return;
 	}
 	
-	for (LDObject* obj : g_CurrentFile->objects) 
+	for (LDObject* obj : g_CurrentFile->objects) {
+		GLuint uList = glGenLists (1);
+		glNewList (uList, GL_COMPILE);
+		
 		compileOneObject (obj);
+		
+		glEndList ();
+		uaObjLists.push_back (uList);
+		obj->uGLList = uList;
+	}
 }
 
 // ========================================================================= //
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 // ========================================================================= //
-template<class T> void renderer::compileSubObject (LDObject* obj,
+template<class T> void GLRenderer::compileSubObject (LDObject* obj,
 	const GLenum eGLType, const short dVerts)
 {
-	setObjectColor (obj);
 	T* newobj = static_cast<T*> (obj);
 	glBegin (eGLType);
 	
@@ -276,9 +304,8 @@
 // ========================================================================= //
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 // ========================================================================= //
-void renderer::compileOneObject (LDObject* obj) {
-	GLuint uList = glGenLists (1);
-	glNewList (uList, GL_COMPILE);
+void GLRenderer::compileOneObject (LDObject* obj) {
+	setObjectColor (obj);
 	
 	switch (obj->getType ()) {
 	case OBJ_Line:
@@ -352,16 +379,12 @@
 	default:
 		break;
 	}
-	
-	glEndList ();
-	uaObjLists.push_back (uList);
-	obj->uGLList = uList;
 }
 
 // ========================================================================= //
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 // ========================================================================= //
-void renderer::compileVertex (vertex& vrt) {
+void GLRenderer::compileVertex (vertex& vrt) {
 	glVertex3d (
 		(vrt.x + g_faObjectOffset[0]) / g_StoredBBoxSize,
 		-(vrt.y + g_faObjectOffset[1]) / g_StoredBBoxSize,
@@ -371,7 +394,7 @@
 // ========================================================================= //
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 // ========================================================================= //
-void renderer::clampAngle (double& fAngle) {
+void GLRenderer::clampAngle (double& fAngle) {
 	while (fAngle < 0)
 		fAngle += 360.0;
 	while (fAngle > 360.0)
@@ -381,7 +404,7 @@
 // ========================================================================= //
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 // ========================================================================= //
-void renderer::mouseReleaseEvent (QMouseEvent* event) {
+void GLRenderer::mouseReleaseEvent (QMouseEvent* event) {
 	if ((qMouseButtons & Qt::LeftButton) && !(event->buttons() & Qt::LeftButton)) {
 		if (ulTotalMouseMove < 10)
 			pick (event->x(), event->y());
@@ -390,7 +413,7 @@
 	}
 }
 
-void renderer::mousePressEvent (QMouseEvent* event) {
+void GLRenderer::mousePressEvent (QMouseEvent* event) {
 	qMouseButtons = event->buttons();
 	if (event->buttons() & Qt::LeftButton)
 		ulTotalMouseMove = 0;
@@ -399,7 +422,7 @@
 // ========================================================================= //
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 // ========================================================================= //
-void renderer::mouseMoveEvent (QMouseEvent *event) {
+void GLRenderer::mouseMoveEvent (QMouseEvent *event) {
 	int dx = event->x () - lastPos.x ();
 	int dy = event->y () - lastPos.y ();
 	ulTotalMouseMove += abs (dx) + abs (dy);
@@ -428,7 +451,9 @@
 }
 
 // ========================================================================= //
-void renderer::pick (uint mx, uint my) {
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+// ========================================================================= //
+void GLRenderer::pick (uint mx, uint my) {
 	g_ForgeWindow->paSelection.clear ();
 	
 	glDisable (GL_DITHER);
@@ -442,15 +467,26 @@
 	GLubyte pixel[3];
 	GLint viewport[4];
 	glGetIntegerv (GL_VIEWPORT, viewport);
-	glReadPixels (mx, viewport[3] - my, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, reinterpret_cast<GLvoid*> (pixel));
+	glReadPixels (mx, viewport[3] - my, 1, 1, GL_RGB, GL_UNSIGNED_BYTE,
+		reinterpret_cast<GLvoid*> (pixel));
 	
-	if (pixel[0] != 255 || pixel[1] != 255 || pixel[2] != 255) {
+	const bool bHasSelection = (pixel[0] != 255 || pixel[1] != 255 || pixel[2] != 255);
+	
+	if (bHasSelection) {
 		ulong idx = pixel[0] + (pixel[1] * 256) + (pixel[2] * 256 * 256);
 		
 		LDObject* obj = g_CurrentFile->object (idx);
 		g_ForgeWindow->paSelection.push_back (obj);
 	}
 	
+	if (gl_selflash) {
+		if (bHasSelection) {
+			qPulseTimer->start (g_dPulseInterval);
+			g_dPulseTick = 0;
+		} else
+			qPulseTimer->stop ();
+	}
+	
 	g_bPicking = false;
 	glEnable (GL_DITHER);
 	
@@ -458,4 +494,35 @@
 	
 	setBackground ();
 	hardRefresh ();
+}
+
+// ========================================================================= //
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+// ========================================================================= //
+void GLRenderer::updateObjectColors() {
+	for (LDObject* obj : g_ForgeWindow->getSelectedObjects ()) {
+		// Replace the old list with the new one.
+		for (ulong i = 0; i < uaObjLists.size(); ++i)
+			if (uaObjLists[i] == obj->uGLList)
+				uaObjLists.erase (uaObjLists.begin() + i);
+		
+		GLuint uList = glGenLists (1);
+		glNewList (uList, GL_COMPILE);
+		
+		compileOneObject (obj);
+		
+		glEndList ();
+		uaObjLists.push_back (uList);
+		obj->uGLList = uList;
+	}
+}
+
+// ========================================================================= //
+void GLRenderer::slot_timerUpdate () {
+	++g_dPulseTick %= g_dNumPulseTicks;
+	printf ("%d\n", g_dPulseTick);
+	
+	updateObjectColors ();
+	paintGL ();
+	swapBuffers ();
 }
\ No newline at end of file
--- a/gldraw.h	Sun Apr 14 17:31:09 2013 +0300
+++ b/gldraw.h	Mon Apr 15 01:51:53 2013 +0300
@@ -20,14 +20,22 @@
 #define __GLDRAW_H__
 
 #include <QGLWidget>
+#include <qtimer.h>
 #include "common.h"
 #include "ldtypes.h"
 
-class renderer : public QGLWidget {
+// =============================================================================
+// GLRenderer
+// 
+// The main renderer object, draws the brick on the screen, manages the camera
+// and selection picking. The instance of GLRenderer is accessible as
+// g_ForgeWindow->R
+// =============================================================================
+class GLRenderer : public QGLWidget {
 	Q_OBJECT
 	
 public:
-	renderer (QWidget* parent = null);
+	GLRenderer (QWidget* parent = null);
 	void hardRefresh ();
 	void compileObjects ();
 	void setBackground ();
@@ -55,10 +63,16 @@
 	void compileVertex (vertex& vrt);
 	void clampAngle (double& fAngle);
 	void setObjectColor (LDObject* obj);
+	void updateObjectColors ();
+	
+	QTimer* qPulseTimer;
 	
 	Qt::MouseButtons qMouseButtons;
 	Qt::KeyboardModifiers qKeyMods;
 	ulong ulTotalMouseMove;
+	
+private slots:
+	void slot_timerUpdate ();
 };
 
 #endif // __GLDRAW_H__
\ No newline at end of file
--- a/gui.cpp	Sun Apr 14 17:31:09 2013 +0300
+++ b/gui.cpp	Mon Apr 15 01:51:53 2013 +0300
@@ -83,7 +83,7 @@
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 // ========================================================================= //
 ForgeWindow::ForgeWindow () {
-	R = new renderer;
+	R = new GLRenderer;
 	
 	qObjList = new QTreeWidget;
 	qObjList->setHeaderHidden (true);
--- a/gui.h	Sun Apr 14 17:31:09 2013 +0300
+++ b/gui.h	Mon Apr 15 01:51:53 2013 +0300
@@ -102,7 +102,7 @@
 	Q_OBJECT
 	
 public:
-	renderer* R;
+	GLRenderer* R;
 	
 	// Object list view
 	QTreeWidget* qObjList;
--- a/zz_configDialog.cpp	Sun Apr 14 17:31:09 2013 +0300
+++ b/zz_configDialog.cpp	Mon Apr 15 01:51:53 2013 +0300
@@ -38,6 +38,7 @@
 extern_cfg (int, gl_linethickness);
 extern_cfg (int, gui_toolbar_iconsize);
 extern_cfg (str, gui_colortoolbar);
+extern_cfg (bool, gl_selflash);
 
 ConfigDialog* g_ConfigDialog = null;
 
@@ -122,6 +123,9 @@
 	qGLColorBFC = new QCheckBox ("Red/green BFC view");
 	INIT_CHECKBOX (qGLColorBFC, gl_colorbfc)
 	
+	qGLSelFlash = new QCheckBox ("Selection flash");
+	INIT_CHECKBOX (qGLSelFlash, gl_selflash)
+	
 	QGridLayout* layout = new QGridLayout;
 	layout->addWidget (qLDrawPathLabel, 0, 0);
 	layout->addWidget (qLDrawPath, 0, 1, 1, 2);
@@ -140,8 +144,9 @@
 	layout->addWidget (qToolBarIconSizeLabel, 3, 0);
 	layout->addWidget (qToolBarIconSize, 3, 1);
 	
-	layout->addWidget (qLVColorize, 4, 0, 1, 2);
-	layout->addWidget (qGLColorBFC, 4, 2, 1, 2);
+	layout->addWidget (qLVColorize, 4, 0);
+	layout->addWidget (qGLColorBFC, 5, 0);
+	layout->addWidget (qGLSelFlash, 6, 0);
 	qMainTab->setLayout (layout);
 	
 	// Add the tab to the manager
@@ -545,6 +550,7 @@
 		
 		APPLY_CHECKBOX (dlg.qLVColorize, lv_colorize)
 		APPLY_CHECKBOX (dlg.qGLColorBFC, gl_colorbfc)
+		APPLY_CHECKBOX (dlg.qGLSelFlash, gl_selflash)
 		
 		gl_maincolor_alpha = ((double)dlg.qGLForegroundAlpha->value ()) / 10.0f;
 		gl_linethickness = dlg.qGLLineThickness->value ();
--- a/zz_configDialog.h	Sun Apr 14 17:31:09 2013 +0300
+++ b/zz_configDialog.h	Mon Apr 15 01:51:53 2013 +0300
@@ -40,7 +40,7 @@
 	QLineEdit* qLDrawPath;
 	QPushButton* qLDrawPathFindButton;
 	QPushButton* qGLBackgroundButton, *qGLForegroundButton;
-	QCheckBox* qLVColorize, *qGLColorBFC;
+	QCheckBox* qLVColorize, *qGLColorBFC, *qGLSelFlash;
 	QSlider* qGLForegroundAlpha, *qGLLineThickness, *qToolBarIconSize;
 	
 	// =========================================================================

mercurial