fractorium/Source/Fractorium/GLWidget.cpp

1458 lines
44 KiB
C++
Raw Normal View History

#include "FractoriumPch.h"
#include "GLWidget.h"
#include "Fractorium.h"
//#define OLDDRAG 1
/// <summary>
/// Constructor which passes parent widget to the base and initializes OpenGL profile.
/// This will need to change in the future to implement all drawing as shader programs.
/// </summary>
2014-12-11 00:50:15 -05:00
/// <param name="p">The parent widget</param>
GLWidget::GLWidget(QWidget* p)
: QOpenGLWidget(p)
{
QSurfaceFormat qsf;
m_Init = false;
m_Drawing = false;
m_TexWidth = 0;
m_TexHeight = 0;
m_OutputTexID = 0;
m_Fractorium = nullptr;
qsf.setSwapInterval(1);//Vsync.
qsf.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
qsf.setVersion(2, 0);
setFormat(qsf);
}
/// <summary>
/// Empty destructor.
/// </summary>
GLWidget::~GLWidget()
{
}
/// <summary>
/// A manual initialization that must be called immediately after the main window is shown
/// and the virtual initializeGL() is called.
/// </summary>
void GLWidget::InitGL()
{
if (!m_Init)
{
int w = m_Fractorium->ui.GLParentScrollArea->width();
int h = m_Fractorium->ui.GLParentScrollArea->height();
SetDimensions(w, h);
m_Fractorium->m_WidthSpin->setValue(w);
m_Fractorium->m_HeightSpin->setValue(h);
//Start with a flock of 10 random embers. Can't do this until now because the window wasn't maximized yet, so the sizes would have been off.
m_Fractorium->OnActionNewFlock(false);
m_Fractorium->m_Controller->DelayedStartRenderTimer();
m_Init = true;
}
}
/// <summary>
/// Draw the final rendered image as a texture on a quad that is the same size as the window.
/// Different action is taken based on whether a CPU or OpenCL renderer is used.
/// For CPU, the output image buffer must be copied to OpenGL every time it's drawn.
/// For OpenCL, the output image and the texture are the same thing, so no copying is necessary
/// and all image memory remains on the card.
/// </summary>
void GLWidget::DrawQuad()
{
GLint texWidth = 0, texHeight = 0;
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
RendererBase* renderer = m_Fractorium->m_Controller->Renderer();
vector<byte>* finalImage = m_Fractorium->m_Controller->FinalImage();
//Ensure all allocation has taken place first.
if (m_OutputTexID != 0 && finalImage && !finalImage->empty())
{
glBindTexture(GL_TEXTURE_2D, m_OutputTexID);//The texture to draw to.
//Only draw if the dimensions match exactly.
2014-12-11 00:50:15 -05:00
if (m_TexWidth == width() && m_TexHeight == height() && ((m_TexWidth * m_TexHeight * 4) == GLint(finalImage->size())))
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, 1, 1, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
//Copy data from CPU to OpenGL if using a CPU renderer. This is not needed when using OpenCL.
if (renderer->RendererType() == CPU_RENDERER)
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, m_TexWidth, m_TexHeight, GL_RGBA, GL_UNSIGNED_BYTE, finalImage->data());
glBegin(GL_QUADS);//This will need to be converted to a shader at some point in the future.
glTexCoord2f(0.0, 0.0); glVertex2f(0.0, 0.0);
glTexCoord2f(0.0, 1.0); glVertex2f(0.0, 1.0);
glTexCoord2f(1.0, 1.0); glVertex2f(1.0, 1.0);
glTexCoord2f(1.0, 0.0); glVertex2f(1.0, 0.0);
glEnd();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
glBindTexture(GL_TEXTURE_2D, 0);//Stop using this texture.
}
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
}
/// <summary>
/// Set drag and drag modifier states to nothing.
/// </summary>
void GLEmberControllerBase::ClearDrag()
{
m_DragModifier = 0;
m_DragState = DragNone;
}
/// <summary>
/// Wrapper around Allocate() call on the GL widget.
/// </summary>
bool GLEmberControllerBase::Allocate(bool force) { return m_GL->Allocate(force); }
/// <summary>
/// Clear the OpenGL output window to be the background color of the current ember.
/// Both buffers must be cleared, else artifacts will show up.
/// </summary>
template <typename T>
void GLEmberController<T>::ClearWindow()
{
Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
m_GL->makeCurrent();
m_GL->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_GL->glClearColor(ember->m_Background.r, ember->m_Background.g, ember->m_Background.b, 1.0);
}
/// <summary>
/// Set the currently selected xform.
/// The currently selected xform is drawn with a circle around it, with all others only showing their axes.
/// </summary>
/// <param name="xform">The xform.</param>
template <typename T>
void GLEmberController<T>::SetSelectedXform(Xform<T>* xform)
{
//By doing this check, it prevents triggering unnecessary events when selecting an xform on this window with the mouse,
//which will set the combo box on the main window, which will trigger this call. However, if the xform has been selected
//here with the mouse, the window has already repainted, so there's no need to do it again.
if (m_SelectedXform != xform || m_HoverXform != xform)
{
m_HoverXform = xform;
m_SelectedXform = xform;
if (m_GL->m_Init)
//m_GL->update();
m_GL->repaint();//Force immediate redraw with repaint() instead of update().
}
}
/// <summary>
/// Setters for main window pointers.
/// </summary>
void GLWidget::SetMainWindow(Fractorium* f) { m_Fractorium = f; }
/// <summary>
/// Getters for OpenGL state.
/// </summary>
bool GLWidget::Init() { return m_Init; }
bool GLWidget::Drawing() { return m_Drawing; }
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
GLint GLWidget::MaxTexSize() { return m_MaxTexSize; }
GLuint GLWidget::OutputTexID() { return m_OutputTexID; }
/// <summary>
/// Initialize OpenGL, called once at startup after the main window constructor finishes.
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
/// Although it seems an awkward place to put some of this setup code, the dimensions of the
/// main window and its widgets are not fully initialized before this is called.
/// Once this is done, the render timer is started after a short delay.
/// Rendering is then clear to begin.
/// </summary>
void GLWidget::initializeGL()
{
if (!m_Init && initializeOpenGLFunctions() && m_Fractorium)
{
glClearColor(0.0, 0.0, 0.0, 1.0);
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
glEnable(GL_TEXTURE_2D);
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_MaxTexSize);
glDisable(GL_TEXTURE_2D);
m_Fractorium->m_WidthSpin->setMaximum(m_MaxTexSize);
m_Fractorium->m_HeightSpin->setMaximum(m_MaxTexSize);
}
}
/// <summary>
/// The main drawing/update function.
/// First the quad will be drawn, then the remaining affine circles.
/// </summary>
void GLWidget::paintGL()
{
FractoriumEmberControllerBase* controller = m_Fractorium->m_Controller.get();
//Ensure there is a renderer and that it's supposed to be drawing, signified by the running timer.
if (controller && controller->Renderer() && controller->RenderTimerRunning())
{
RendererBase* renderer = controller->Renderer();
m_Drawing = true;
controller->GLController()->DrawImage();
//Affine drawing.
bool pre = m_Fractorium->ui.PreAffineGroupBox->isChecked();
bool post = m_Fractorium->ui.PostAffineGroupBox->isChecked();
float unitX = fabs(renderer->UpperRightX(false) - renderer->LowerLeftX(false)) / 2.0f;
float unitY = fabs(renderer->UpperRightY(false) - renderer->LowerLeftY(false)) / 2.0f;
glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
glEnable(GL_POINT_SMOOTH);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(-unitX, unitX, -unitY, unitY, -1, 1);//Projection matrix: OpenGL camera is always centered, just move the ember internally inside the renderer.
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glDisable(GL_DEPTH_TEST);
controller->GLController()->DrawAffines(pre, post);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
glDisable(GL_POINT_SMOOTH);
m_Drawing = false;
}
}
/// <summary>
/// Draw the image on the quad.
/// </summary>
template <typename T>
void GLEmberController<T>::DrawImage()
{
RendererBase* renderer = m_FractoriumEmberController->Renderer();
Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
m_GL->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
m_GL->glClearColor(ember->m_Background.r, ember->m_Background.g, ember->m_Background.b, 1.0);
m_GL->glDisable(GL_DEPTH_TEST);
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
renderer->EnterFinalAccum();//Lock, may not be necessary, but just in case.
renderer->EnterResize();
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
if (SizesMatch())//Ensure all sizes are correct. If not, do nothing.
{
vector<byte>* finalImage = m_FractoriumEmberController->FinalImage();
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
if (renderer->RendererType() == OPENCL_RENDERER || finalImage)//Final image only matters for CPU renderer.
if (renderer->RendererType() == OPENCL_RENDERER || finalImage->size() == renderer->FinalBufferSize())
m_GL->DrawQuad();//Output image is drawn here.
}
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
renderer->LeaveResize();//Unlock, may not be necessary.
renderer->LeaveFinalAccum();
}
/// <summary>
/// Draw the affine circles.
/// </summary>
/// <param name="pre">True to draw pre affines, else don't.</param>
/// <param name="post">True to draw post affines, else don't.</param>
template <typename T>
void GLEmberController<T>::DrawAffines(bool pre, bool post)
{
QueryVMP();//Resolves to float or double specialization function depending on T.
Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
bool dragging = m_DragState == DragDragging;
//Draw grid if control key is pressed.
0.4.1.5 Beta 11/28/2014 --User Changes Remove limit on the number of xforms allowable on the GPU. This was previously 21. Show actual strips count to be used in parens outside of user specified strips count on final render dialog. Allow for adjustment of iteration depth and fuse count per ember and save/read these values with the xml. Iteration optimizations on both CPU and GPU. Automatically adjust default quality spinner value when using CPU/GPU to 10/30, respectively. --Bug Fixes Fix severe randomization bug with OpenCL. Fix undo list off by one error when doing a new edit anywhere but the end of the undo list. Make integer variation parameters use 4 decimal places in the variations list like all the others. New build of the latest Qt to fix scroll bar drawing bug. Prevent grid from showing as much when pressing control to increase a spinner's increment speed. Still shows sometimes, but better than before. --Code Changes Pass count and fuse to iterator as a structure now to allow for passing more params in the future. Slightly different grid/block logic when running DE filtering on the GPU. Attempt a different way of doing DE, but #define out because it ended up not being faster. Restructure some things to allow for a variable length xforms buffer to be passed to the GPU. Add sub batch size and fuse count as ember members, and remove them from the renderer classes. Remove m_LastPass from Renderer. It should have been removed with passes. Pass seeds as a buffer to the OpenCL iteration kernel, rather than a single seed that gets modified. Slight optimization on CPU accum. Use case statement instead of if/else for xform chosing in OpenCL for a 2% speedup on params with large numbers of xforms. Add SizeOf() wrapper around sizeof(vec[0]) * vec.size(). Remove LogScaleSum() functions from the CPU and GPU because they're no longer used since passes were removed. Make some OpenCLWrapper getters const. Better ogranize RendererCL methods that return grid dimensions.
2014-11-28 04:37:51 -05:00
if (m_GL->hasFocus() && ((m_DragModifier & DragModControl) == DragModControl))
{
m_GL->glLineWidth(1.0f);
m_GL->DrawGrid();
}
//When dragging, only draw the selected xform's affine and hide all others.
if (!m_Fractorium->m_Settings->ShowAllXforms() && dragging)
{
if (m_SelectedXform)
DrawAffine(m_SelectedXform, m_AffineType == AffinePre, true);
}
else//Show all while dragging, or not dragging just hovering/mouse move.
{
if (pre && m_Fractorium->DrawAllPre())//Draw all pre affine if specified.
{
for (uint i = 0; i < ember->TotalXformCount(); i++)
{
Xform<T>* xform = ember->GetTotalXform(i);
bool selected = dragging ? (m_SelectedXform == xform) : (m_HoverXform == xform);
DrawAffine(xform, true, selected);
}
}
else if (pre && m_HoverXform)//Only draw current pre affine.
{
DrawAffine(m_HoverXform, true, true);
}
if (post && m_Fractorium->DrawAllPost())//Draw all post affine if specified.
{
for (uint i = 0; i < ember->TotalXformCount(); i++)
{
Xform<T>* xform = ember->GetTotalXform(i);
bool selected = dragging ? (m_SelectedXform == xform) : (m_HoverXform == xform);
DrawAffine(xform, false, selected);
}
}
else if (post && m_HoverXform)//Only draw current post affine.
{
DrawAffine(m_HoverXform, false, true);
}
}
if (dragging)//Draw large yellow dot on select or drag.
{
m_GL->glPointSize(6.0f);
m_GL->glBegin(GL_POINTS);
m_GL->glColor4f(1.0f, 1.0f, 0.5f, 1.0f);
m_GL->glVertex2f(m_DragHandlePos.x, m_DragHandlePos.y);
m_GL->glEnd();
m_GL->glPointSize(1.0f);//Restore point size.
}
else if (m_HoverType != HoverNone && m_HoverXform == m_SelectedXform)//Draw large turquoise dot on hover if they are hovering over the selected xform.
{
m_GL->glPointSize(6.0f);
m_GL->glBegin(GL_POINTS);
m_GL->glColor4f(0.5f, 1.0f, 1.0f, 1.0f);
m_GL->glVertex2f(m_HoverHandlePos.x, m_HoverHandlePos.y);
m_GL->glEnd();
m_GL->glPointSize(1.0f);
}
}
/// <summary>
/// Set drag modifiers based on key press.
/// </summary>
/// <param name="e">The event</param>
2014-12-11 00:50:15 -05:00
bool GLEmberControllerBase::KeyPress_(QKeyEvent* e)
{
#ifdef OLDDRAG
if (e->key() == Qt::Key_Shift)
m_DragModifier |= DragModShift;
else if (e->key() == Qt::Key_Control || e->key() == Qt::Key_C)
m_DragModifier |= DragModControl;
else if (e->key() == Qt::Key_Alt || e->key() == Qt::Key_A)
m_DragModifier |= DragModAlt;
else
return false;
return true;
#else
if (e->key() == Qt::Key_Control)
{
m_DragModifier |= DragModControl;
return true;
}
#endif
return false;
}
/// <summary>
2014-12-11 00:50:15 -05:00
/// Call controller KeyPress_().
/// </summary>
/// <param name="e">The event</param>
void GLWidget::keyPressEvent(QKeyEvent* e)
{
2014-12-11 00:50:15 -05:00
if (!GLController() || !GLController()->KeyPress_(e))
QOpenGLWidget::keyPressEvent(e);
update();
}
/// <summary>
/// Set drag modifiers based on key release.
/// </summary>
/// <param name="e">The event</param>
2014-12-11 00:50:15 -05:00
bool GLEmberControllerBase::KeyRelease_(QKeyEvent* e)
{
#ifdef OLDDRAG
if (e->key() == Qt::Key_Shift)
m_DragModifier &= ~DragModShift;
else if (e->key() == Qt::Key_Control || e->key() == Qt::Key_C)
m_DragModifier &= ~DragModControl;
else if (e->key() == Qt::Key_Alt || e->key() == Qt::Key_A)
m_DragModifier &= ~DragModAlt;
else
return false;
return true;
#else
if (e->key() == Qt::Key_Control)
{
m_DragModifier &= ~DragModControl;
return true;
}
#endif
return false;
}
/// <summary>
2014-12-11 00:50:15 -05:00
/// Call controller KeyRelease_().
/// </summary>
/// <param name="e">The event</param>
void GLWidget::keyReleaseEvent(QKeyEvent* e)
{
2014-12-11 00:50:15 -05:00
if (!GLController() || !GLController()->KeyRelease_(e))
QOpenGLWidget::keyReleaseEvent(e);
update();
}
/// <summary>
/// Determine if the mouse click was over an affine circle
/// and set the appropriate selection information to be used
/// on subsequent mouse move events.
/// If nothing was selected, then reset the selection and drag states.
/// </summary>
/// <param name="e">The event</param>
template <typename T>
void GLEmberController<T>::MousePress(QMouseEvent* e)
{
v3T mouseFlipped(e->x(), m_Viewport[3] - e->y(), 0);//Must flip y because in OpenGL, 0,0 is bottom left, but in windows, it's top left.
Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
RendererBase* renderer = m_FractoriumEmberController->Renderer();
//Ensure everything has been initialized.
if (!renderer)
return;
m_MouseDownPos = glm::ivec2(e->x(), e->y());//Capture the raster coordinates of where the mouse was clicked.
m_MouseWorldPos = WindowToWorld(mouseFlipped, false);//Capture the world cartesian coordinates of where the mouse is.
m_BoundsDown.w = renderer->LowerLeftX(false);//Need to capture these because they'll be changing if scaling.
m_BoundsDown.x = renderer->LowerLeftY(false);
m_BoundsDown.y = renderer->UpperRightX(false);
m_BoundsDown.z = renderer->UpperRightY(false);
#ifndef OLDDRAG
Qt::KeyboardModifiers mod = e->modifiers();
if (mod.testFlag(Qt::ShiftModifier))
m_DragModifier |= DragModShift;
//if (mod.testFlag(Qt::ControlModifier))// || mod.testFlag(Qt::Key_C))
// m_DragModifier |= DragModControl;
if (mod.testFlag(Qt::AltModifier))// || mod.testFlag(Qt::Key_A))
m_DragModifier |= DragModAlt;
#endif
if (m_DragState == DragNone)//Only take action if the user wasn't already dragging.
{
m_MouseDownWorldPos = m_MouseWorldPos;//Set the mouse down position to the current position.
if (e->button() & Qt::LeftButton)
{
int xformIndex = UpdateHover(mouseFlipped);//Determine if an affine circle was clicked.
if (m_HoverXform && xformIndex != -1)
{
m_SelectedXform = m_HoverXform;
m_DragSrcTransform = Affine2D<T>(m_AffineType == AffinePre ? m_SelectedXform->m_Affine : m_SelectedXform->m_Post);//Copy the affine of the xform that was selected.
m_DragHandlePos = m_HoverHandlePos;
m_DragHandleOffset = m_DragHandlePos - m_MouseWorldPos;
m_DragState = DragDragging;
//The user has selected an xform by clicking on it, so update the main GUI by selecting this xform in the combo box.
m_Fractorium->CurrentXform(xformIndex);
//Draw large yellow dot on select or drag.
m_GL->glPointSize(6.0f);
m_GL->glBegin(GL_POINTS);
m_GL->glColor4f(1.0f, 1.0f, 0.5f, 1.0f);
m_GL->glVertex2f(m_DragHandlePos.x, m_DragHandlePos.y);
m_GL->glEnd();
m_GL->glPointSize(1.0f);//Restore point size.
m_GL->repaint();
}
else//Nothing was selected.
{
//m_SelectedXform = nullptr;
m_DragState = DragNone;
}
}
else if (e->button() == Qt::MiddleButton)//Middle button does whole image translation.
{
m_CenterDownX = ember->m_CenterX;//Capture where the center of the image is because this value will change when panning.
m_CenterDownY = ember->m_CenterY;
m_DragState = DragPanning;
}
else if (e->button() == Qt::RightButton)//Right button does whole image rotation and scaling.
{
UpdateHover(mouseFlipped);
m_SelectedXform = m_HoverXform;
m_CenterDownX = ember->m_CenterX;//Capture these because they will change when rotating and scaling.
m_CenterDownY = ember->m_CenterY;
m_RotationDown = ember->m_Rotate;
m_ScaleDown = ember->m_PixelsPerUnit;
m_DragState = DragRotateScale;
}
}
}
/// <summary>
/// Call controller MousePress().
/// </summary>
/// <param name="e">The event</param>
void GLWidget::mousePressEvent(QMouseEvent* e)
{
setFocus();//Must do this so that this window gets keyboard events.
if (GLEmberControllerBase* controller = GLController())
controller->MousePress(e);
QOpenGLWidget::mousePressEvent(e);
}
/// <summary>
/// Reset the selection and dragging state, but re-calculate the
/// hovering state because the mouse might still be over an affine circle.
/// </summary>
/// <param name="e">The event</param>
template <typename T>
void GLEmberController<T>::MouseRelease(QMouseEvent* e)
{
v3T mouseFlipped(e->x(), m_Viewport[3] - e->y(), 0);//Must flip y because in OpenGL, 0,0 is bottom left, but in windows, it's top left.
m_MouseWorldPos = WindowToWorld(mouseFlipped, false);
if (m_DragState == DragDragging && (e->button() & Qt::LeftButton))
UpdateHover(mouseFlipped);
m_DragState = DragNone;
#ifndef OLDDRAG
m_DragModifier = 0;
#endif
m_GL->repaint();//Force immediate redraw.
}
/// <summary>
/// Call controller MouseRelease().
/// </summary>
/// <param name="e">The event</param>
void GLWidget::mouseReleaseEvent(QMouseEvent* e)
{
setFocus();//Must do this so that this window gets keyboard events.
if (GLEmberControllerBase* controller = GLController())
controller->MouseRelease(e);
QOpenGLWidget::mouseReleaseEvent(e);
}
/// <summary>
/// If dragging, update relevant values and reset entire rendering process.
/// If hovering, update display.
/// </summary>
/// <param name="e">The event</param>
template <typename T>
void GLEmberController<T>::MouseMove(QMouseEvent* e)
{
bool draw = true;
glm::ivec2 mouse(e->x(), e->y());
v3T mouseFlipped(e->x(), m_Viewport[3] - e->y(), 0);//Must flip y because in OpenGL, 0,0 is bottom left, but in windows, it's top left.
Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
//First check to see if the mouse actually moved.
if (mouse == m_MousePos)
return;
m_MousePos = mouse;
m_MouseWorldPos = WindowToWorld(mouseFlipped, false);
2014-12-11 00:50:15 -05:00
//v3T mouseDelta = m_MouseWorldPos - m_MouseDownWorldPos;//Determine how far the mouse has moved in world cartesian coordinates.
//Update status bar on main window, regardless of whether anything is being dragged.
if (m_Fractorium->m_Controller->RenderTimerRunning())
m_Fractorium->SetCoordinateStatus(e->x(), e->y(), m_MouseWorldPos.x, m_MouseWorldPos.y);
if (m_SelectedXform && m_DragState == DragDragging)//Dragging and affine.
{
bool pre = m_AffineType == AffinePre;
Affine2D<T>* affine = pre ? &m_SelectedXform->m_Affine : &m_SelectedXform->m_Post;//Determine pre or post affine.
if (m_HoverType == HoverTranslation)
*affine = CalcDragTranslation();
else if (m_HoverType == HoverXAxis)
*affine = CalcDragXAxis();
else if (m_HoverType == HoverYAxis)
*affine = CalcDragYAxis();
m_FractoriumEmberController->FillAffineWithXform(m_SelectedXform, pre);//Update the spinners in the affine tab of the main window.
m_FractoriumEmberController->UpdateRender();//Restart the rendering process.
}
else if (m_DragState == DragPanning)//Translating the whole image.
{
T x = -(m_MouseWorldPos.x - m_MouseDownWorldPos.x);
T y = (m_MouseWorldPos.y - m_MouseDownWorldPos.y);
Affine2D<T> rotMat;
rotMat.C(m_CenterDownX);
rotMat.F(m_CenterDownY);
rotMat.Rotate(ember->m_Rotate);
v2T v1(x, y);
v2T v2 = rotMat.TransformVector(v1);
ember->m_CenterX = v2.x;
ember->m_CenterY = ember->m_RotCenterY = v2.y;
m_FractoriumEmberController->SetCenter(ember->m_CenterX, ember->m_CenterY);//Will restart the rendering process.
}
else if (m_DragState == DragRotateScale)//Rotating and scaling the whole image.
{
T rot = CalcRotation();
T scale = CalcScale();
ember->m_Rotate = NormalizeDeg180<T>(m_RotationDown + rot);
m_Fractorium->SetRotation(ember->m_Rotate, true);
ember->m_PixelsPerUnit = m_ScaleDown + scale;
m_Fractorium->SetScale(ember->m_PixelsPerUnit);//Will restart the rendering process.
}
else
{
//If the user doesn't already have a key down, and they aren't dragging, clear the keys to be safe.
//This is done because if they do an alt+tab between windows, it thinks the alt key is down.
if (e->modifiers() == Qt::NoModifier)
ClearDrag();
//Check if they weren't dragging and weren't hovering over any affine.
//In that case, nothing needs to be done.
if (UpdateHover(mouseFlipped) == -1)
draw = false;
//Xform<T>* previousHover = m_HoverXform;
//
//if (UpdateHover(mouseFlipped) == -1)
// m_HoverXform = m_SelectedXform;
//
//if (m_HoverXform == previousHover)
// draw = false;
}
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
//Only update if the user was dragging or hovered over a point.
//Use repaint() to update immediately for a more responsive feel.
if ((m_DragState != DragNone) || draw)
m_GL->update();
//m_GL->repaint();
}
/// <summary>
/// Call controller MouseMove().
/// </summary>
/// <param name="e">The event</param>
void GLWidget::mouseMoveEvent(QMouseEvent* e)
{
setFocus();//Must do this so that this window gets keyboard events.
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
if (GLEmberControllerBase* controller = GLController())
controller->MouseMove(e);
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
QOpenGLWidget::mouseMoveEvent(e);
}
/// <summary>
/// Mouse wheel changes the scale (pixels per unit) which
/// will zoom in the image in our out, while sacrificing quality.
/// If the user needs to preserve quality, they can use the zoom spinner
/// on the main window.
/// </summary>
/// <param name="e">The event</param>
template <typename T>
void GLEmberController<T>::Wheel(QWheelEvent* e)
{
Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
if (m_Fractorium && !(e->buttons() & Qt::MiddleButton))//Middle button does whole image translation, so ignore the mouse wheel while panning to avoid inadvertent zooming.
m_Fractorium->SetScale(ember->m_PixelsPerUnit + (e->angleDelta().y() >= 0 ? 50 : -50));
}
/// <summary>
/// Call controller Wheel().
/// </summary>
/// <param name="e">The event</param>
void GLWidget::wheelEvent(QWheelEvent* e)
{
if (GLEmberControllerBase* controller = GLController())
controller->Wheel(e);
//Do not call QOpenGLWidget::wheelEvent(e) because this should only affect the scale and not the position of the scroll bars.
}
/// <summary>
2014-12-12 03:54:03 -05:00
/// Respond to a resize event which will set the double click default value
/// in the width and height spinners.
/// Note, this does not change the size of the ember being rendered or
/// the OpenGL texture it's being drawn on.
/// </summary>
/// <param name="e">The event</param>
//void GLWidget::resizeEvent(QResizeEvent* e)
//{
// if (m_Fractorium)
// {
// }
//
// QOpenGLWidget::resizeEvent(e);
//}
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
/// <summary>
/// Set the dimensions of the drawing area.
/// This will be called from the main window's SyncSizes() function.
/// </summary>
/// <param name="w">Width in pixels</param>
/// <param name="h">Height in pixels</param>
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
void GLWidget::SetDimensions(int w, int h)
{
setFixedSize(w, h);
//resize(w, h);
2014-12-14 20:12:01 -05:00
//m_Fractorium->ui.GLParentScrollAreaContents->setFixedSize(w, h);
}
/// <summary>
/// Set up texture memory to match the size of the window.
/// If first allocation, generate, bind and set parameters.
/// If subsequent call, only take action if dimensions don't match the window. In such case,
/// first deallocate, then reallocate.
/// </summary>
/// <returns>True if success, else false.</returns>
bool GLWidget::Allocate(bool force)
{
bool alloc = false;
2014-12-11 00:50:15 -05:00
bool doResize = force || m_TexWidth != width() || m_TexHeight != height();
bool doIt = doResize || m_OutputTexID == 0;
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
if (doIt)
{
m_TexWidth = width();
m_TexHeight = height();
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
2014-12-11 00:50:15 -05:00
if (doResize)
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
Deallocate();
glGenTextures(1, &m_OutputTexID);
glBindTexture(GL_TEXTURE_2D, m_OutputTexID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);//Fractron had this as GL_LINEAR_MIPMAP_LINEAR for OpenCL and Cuda.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_TexWidth, m_TexHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
alloc = true;
}
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
if (alloc)
{
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
}
return m_OutputTexID != 0;
}
/// <summary>
/// Deallocate texture memory.
/// </summary>
/// <returns>True if anything deleted, else false.</returns>
bool GLWidget::Deallocate()
{
bool deleted = false;
if (m_OutputTexID != 0)
{
glBindTexture(GL_TEXTURE_2D, m_OutputTexID);
glDeleteTextures(1, &m_OutputTexID);
m_OutputTexID = 0;
deleted = true;
}
return deleted;
}
/// <summary>
/// Set the viewport to match the window dimensions.
/// If the dimensions already match, no action is taken.
/// </summary>
void GLWidget::SetViewport()
{
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
if (m_Init && (m_ViewWidth != m_TexWidth || m_ViewHeight != m_TexHeight))
{
2014-12-11 00:50:15 -05:00
glViewport(0, 0, GLint(m_TexWidth), GLint(m_TexHeight));
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
m_ViewWidth = m_TexWidth;
m_ViewHeight = m_TexHeight;
}
}
/// <summary>
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
/// Determine whether the dimensions of the renderer's current ember match
/// the dimensions of the widget, texture and viewport.
/// Since this uses the renderer's dimensions, this
/// must be called after the renderer has set the current ember.
/// </summary>
/// <returns>True if all sizes match, else false.</returns>
template <typename T>
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
bool GLEmberController<T>::SizesMatch()
{
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
0.4.1.3 Beta 10/14/2014 --User Changes Size is no longer fixed to the window size. Size scaling is done differently in the final render dialog. This fixes several bugs. Remove Xml saving size from settings and options dialog, it no longer applies. Final render can be broken into strips. Set default save path to the desktop if none is found in the settings file. Set default output size to 1920x1080 if none is found in the settings file. --Bug Fixes Better memory size reporting in final render dialog. --Code Changes Migrate to C++11, Qt 5.3.1, and Visual Studio 2013. Change most instances of unsigned int to size_t, and int to intmax_t. Add m_OrigPixPerUnit and m_ScaleType to Ember for scaling purposes. Replace some sprintf_s() calls in XmlToEmber with ostringstream. Move more non-templated members into RendererBase. Add CopyVec() overload that takes a per element function pointer. Add vector Memset(). Replace '&' with '+' instead of "&amp;" in XmlToEmber for much faster parsing. Break strips rendering out into EmberCommon and call from EmberRender and Fractorium. Make AddAndWriteBuffer() just call WriteBuffer(). Make AddAndWriteImage() delete the existing image first before replacing it. Add SetOutputTexture() to RendererCL to support making new textures in response to resize events. Remove multiple return statements in RendererCL, and replace with a bool that tracks results. Add ToDouble(), MakeEnd(), ToString() and Exists() wrappers in Fractorium. Add Size() wrapper in EmberFile. Make QString function arguments const QString&, and string with const string&. Make ShowCritical() wrapper for invoking a message box from another thread. Add combo box to TwoButtonWidget and rename.
2014-10-14 11:53:15 -04:00
return (ember &&
ember->m_FinalRasW == m_GL->width() &&
ember->m_FinalRasH == m_GL->height() &&
m_GL->width() == m_GL->m_TexWidth &&
m_GL->height() == m_GL->m_TexHeight &&
m_GL->m_TexWidth == m_GL->m_ViewWidth &&
m_GL->m_TexHeight == m_GL->m_ViewHeight);
}
/// <summary>
/// Draw the grid in response to the control key being pressed.
/// The frequency of the grid lines will change depending on the zoom.
/// Calculated with the frame always centered, the renderer just moves the camera.
/// </summary>
void GLWidget::DrawGrid()
{
RendererBase* renderer = m_Fractorium->m_Controller->Renderer();
float unitX = fabs(renderer->UpperRightX(false) - renderer->LowerLeftX(false)) / 2.0f;
float unitY = fabs(renderer->UpperRightY(false) - renderer->LowerLeftY(false)) / 2.0f;
float rad = max(unitX, unitY);
float xLow = floor(-unitX);
float xHigh = ceil(unitX);
float yLow = floor(-unitY);
float yHigh = ceil(unitY);
glBegin(GL_LINES);
if (rad <= 8.0f)
{
glColor4f(0.5f, 0.5f, 0.5f, 0.5f);
2014-12-11 00:50:15 -05:00
for (float fx = xLow; fx <= xHigh; fx += GridStep)
{
2014-12-11 00:50:15 -05:00
glVertex2f(fx, yLow);
glVertex2f(fx, yHigh);
}
2014-12-11 00:50:15 -05:00
for (float fy = yLow; fy < yHigh; fy += GridStep)
{
2014-12-11 00:50:15 -05:00
glVertex2f(xLow, fy);
glVertex2f(xHigh, fy);
}
}
if (unitX <= 64.0f)
{
glColor4f(0.5f, 0.5f, 0.5f, 1.0f);
2014-12-11 00:50:15 -05:00
for (float fx = xLow; fx <= xHigh; fx += 1.0f)
{
2014-12-11 00:50:15 -05:00
glVertex2f(fx, yLow);
glVertex2f(fx, yHigh);
}
2014-12-11 00:50:15 -05:00
for (float fy = yLow; fy < yHigh; fy += 1.0f)
{
2014-12-11 00:50:15 -05:00
glVertex2f(xLow, fy);
glVertex2f(xHigh, fy);
}
}
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
glVertex2f(0.0f, 0.0f);
glVertex2f(xHigh, 0.0f);
glColor4f(0.5f, 0.0f, 0.0f, 1.0f);
glVertex2f(0.0f, 0.0f);
glVertex2f(xLow, 0.0f);
glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
glVertex2f(0.0f, 0.0f);
glVertex2f(0.0f, yHigh);
glColor4f(0.0f, 0.5f, 0.0f, 1.0f);
glVertex2f(0.0f, 0.0f);
glVertex2f(0.0f, yLow);
glEnd();
}
/// <summary>
/// Draw the unit square.
/// </summary>
void GLWidget::DrawUnitSquare()
{
glLineWidth(1.0f);
glBegin(GL_LINES);
glColor4f(1.0f, 1.0f, 1.0f, 0.25f);
glVertex2f(-1,-1);
glVertex2f( 1,-1);
glVertex2f(-1, 1);
glVertex2f( 1, 1);
glVertex2f(-1,-1);
glVertex2f(-1, 1);
glVertex2f( 1,-1);
glVertex2f( 1, 1);
glColor4f(1.0f, 0.0f, 0.0f, 0.5f);
glVertex2f(-1, 0);
glVertex2f( 1, 0);
glColor4f(0.0f, 1.0f, 0.0f, 0.5f);
glVertex2f( 0,-1);
glVertex2f( 0, 1);
glEnd();
}
/// <summary>
/// Draw the pre or post affine circle for the passed in xform.
/// For drawing affine transforms, multiply the identity model view matrix by the
/// affine for each xform, so that all points are considered to be "1".
/// </summary>
/// <param name="xform">A pointer to the xform whose affine will be drawn</param>
/// <param name="pre">True for pre affine, else false for post.</param>
/// <param name="selected">True if selected (draw enclosing circle), else false (only draw axes).</param>
template <typename T>
void GLEmberController<T>::DrawAffine(Xform<T>* xform, bool pre, bool selected)
{
Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
bool final = ember->IsFinalXform(xform);
int index = ember->GetXformIndex(xform);
size_t size = ember->m_Palette.m_Entries.size();
v4T color = ember->m_Palette.m_Entries[Clamp<T>(xform->m_ColorX * size, 0, size - 1)];
Affine2D<T>* affine = pre ? &xform->m_Affine : &xform->m_Post;
//For some incredibly strange reason, even though glm and OpenGL use matrices with a column-major
//data layout, nothing will work here unless they are flipped to row major order. This is how it was
//done in Fractron.
m4T mat = affine->ToMat4RowMajor();
m_GL->glPushMatrix();
m_GL->glLoadIdentity();
MultMatrix(mat);
m_GL->glLineWidth(3.0f);//One 3px wide, colored black, except green on x axis for post affine.
m_GL->DrawAffineHelper(index, selected, pre, final, true);
m_GL->glLineWidth(1.0f);//Again 1px wide, colored white, to give a white middle with black outline effect.
m_GL->DrawAffineHelper(index, selected, pre, final, false);
m_GL->glPointSize(5.0f);//Three black points, one in the center and two on the circle. Drawn big 5px first to give a black outline.
m_GL->glBegin(GL_POINTS);
m_GL->glColor4f(0.0f, 0.0f, 0.0f, selected ? 1.0f : 0.5f);
m_GL->glVertex2f(0.0f, 0.0f);
m_GL->glVertex2f(1.0f, 0.0f);
m_GL->glVertex2f(0.0f, 1.0f);
m_GL->glEnd();
m_GL->glLineWidth(2.0f);//Draw lines again for y axis only, without drawing the circle, using the color of the selected xform.
m_GL->glBegin(GL_LINES);
m_GL->glColor4f(color.r, color.g, color.b, 1.0f);
m_GL->glVertex2f(0.0f, 0.0f);
m_GL->glVertex2f(0.0f, 1.0f);
m_GL->glEnd();
m_GL->glPointSize(3.0f);//Draw smaller white points, to give a black outline effect.
m_GL->glBegin(GL_POINTS);
m_GL->glColor4f(1.0f, 1.0f, 1.0f, selected ? 1.0f : 0.5f);
m_GL->glVertex2f(0.0f, 0.0f);
m_GL->glVertex2f(1.0f, 0.0f);
m_GL->glVertex2f(0.0f, 1.0f);
m_GL->glEnd();
m_GL->glPopMatrix();
}
/// <summary>
/// Draw the axes, and optionally the surrounding circle
/// of an affine transform.
/// </summary>
/// <param name="index"></param>
/// <param name="selected">True if selected (draw enclosing circle), else false (only draw axes).</param>
/// <param name="pre"></param>
/// <param name="final"></param>
/// <param name="background"></param>
void GLWidget::DrawAffineHelper(int index, bool selected, bool pre, bool final, bool background)
{
float px = 1.0f;
float py = 0.0f;
QColor col = final ? m_Fractorium->m_FinalXformComboColor : m_Fractorium->m_XformComboColors[index % XFORM_COLOR_COUNT];
glBegin(GL_LINES);
//Circle part.
if (!background)
{
glColor4f(col.redF(), col.greenF(), col.blueF(), 1.0f);//Draw pre affine transform with white.
}
else
{
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);//Draw pre affine transform outline with white.
}
if (selected)
{
for (int i = 1; i <= 64; i++)//The circle.
{
2014-12-11 00:50:15 -05:00
float theta = float(M_PI) * 2.0f * float(i % 64) / 64.0f;
float fx = float(cos(theta));
float fy = float(sin(theta));
glVertex2f(px, py);
2014-12-11 00:50:15 -05:00
glVertex2f(fx, fy);
px = fx;
py = fy;
}
}
//Lines from center to circle.
if (!background)
{
glColor4f(col.redF(), col.greenF(), col.blueF(), 1.0f);
}
else
{
if (pre)
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);//Draw pre affine transform outline with white.
else
glColor4f(0.0f, 0.75f, 0.0f, 1.0f);//Draw post affine transform outline with green.
}
//The lines from the center to the circle.
glVertex2f(0.0f, 0.0f);//X axis.
glVertex2f(1.0f, 0.0f);
if (background)
glColor4f(0.0f, 0.0f, 0.0f, 1.0f);
glVertex2f(0.0f, 0.0f);//Y axis.
glVertex2f(0.0f, 1.0f);
glEnd();
}
/// <summary>
/// Determine the index of the xform being hovered over if any.
/// Give precedence to the currently selected xform, if any.
/// </summary>
/// <param name="glCoords">The mouse raster coordinates to check</param>
/// <returns>The index of the xform being hovered over, else -1 if no hover.</returns>
template <typename T>
int GLEmberController<T>::UpdateHover(v3T& glCoords)
{
bool pre = m_Fractorium->ui.PreAffineGroupBox->isChecked();
bool post = m_Fractorium->ui.PostAffineGroupBox->isChecked();
bool preAll = pre && m_Fractorium->DrawAllPre();
bool postAll = post && m_Fractorium->DrawAllPost();
uint bestIndex = -1;
T bestDist = 10;
Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
m_HoverType = HoverNone;
//If there's a selected/current xform, check it first so it gets precedence over the others.
if (m_SelectedXform != nullptr)
{
//These checks prevent highlighting the pre/post selected xform circle, when one is set to show all, and the other
//is set to show current, and the user hovers over another xform, but doesn't select it, then moves the mouse
//back over the hidden circle for the pre/post that was set to only show current.
bool checkSelPre = preAll || (pre && m_HoverXform == m_SelectedXform);
bool checkSelPost = postAll || (post && m_HoverXform == m_SelectedXform);
if (CheckXformHover(m_SelectedXform, glCoords, bestDist, checkSelPre, checkSelPost))
{
m_HoverXform = m_SelectedXform;
bestIndex = ember->GetTotalXformIndex(m_SelectedXform);
}
}
//Check all xforms.
for (uint i = 0; i < ember->TotalXformCount(); i++)
{
Xform<T>* xform = ember->GetTotalXform(i);
if (preAll || (pre && m_HoverXform == xform))//Only check pre affine if they are shown.
{
if (CheckXformHover(xform, glCoords, bestDist, true, false))
{
m_HoverXform = xform;
bestIndex = i;
}
}
if (postAll || (post && m_HoverXform == xform))//Only check post affine if they are shown.
{
if (CheckXformHover(xform, glCoords, bestDist, false, true))
{
m_HoverXform = xform;
bestIndex = i;
}
}
}
return bestIndex;
}
/// <summary>
/// Determine the passed in xform's pre/post affine transforms are being hovered over.
/// Meant to be called in succession when checking all xforms for hover, and the best
/// hover distance is recorded in the bestDist reference parameter.
/// Mouse coordinates will be converted internally to world cartesian coordinates for checking.
/// </summary>
/// <param name="xform">A pointer to the xform to check for hover</param>
/// <param name="glCoords">The mouse raster coordinates to check</param>
/// <param name="bestDist">Reference to hold the best distance found so far</param>
/// <param name="pre">True to check pre affine, else don't.</param>
/// <param name="post">True to check post affine, else don't.</param>
/// <returns>True if hovering and the distance is smaller than the bestDist parameter</returns>
template <typename T>
bool GLEmberController<T>::CheckXformHover(Xform<T>* xform, v3T& glCoords, T& bestDist, bool pre, bool post)
{
bool preFound = false, postFound = false;
float dist = 0.0f;
v3T pos;
Ember<T>* ember = m_FractoriumEmberController->CurrentEmber();
if (pre)
{
v3T translation(xform->m_Affine.C()/* - ember->m_CenterX*/, /*ember->m_CenterY + */xform->m_Affine.F(), 0);
v3T transScreen = glm::project(translation, m_Modelview, m_Projection, m_Viewport);
v3T xAxis(xform->m_Affine.A(), xform->m_Affine.D(), 0);
v3T xAxisScreen = glm::project(translation + xAxis, m_Modelview, m_Projection, m_Viewport);
v3T yAxis(xform->m_Affine.B(), xform->m_Affine.E(), 0);
v3T yAxisScreen = glm::project(translation + yAxis, m_Modelview, m_Projection, m_Viewport);
pos = translation;
dist = glm::distance(glCoords, transScreen);
if (dist < bestDist)
{
bestDist = dist;
m_HoverType = HoverTranslation;
m_HoverHandlePos = pos;
preFound = true;
}
pos = translation + xAxis;
dist = glm::distance(glCoords, xAxisScreen);
if (dist < bestDist)
{
bestDist = dist;
m_HoverType = HoverXAxis;
m_HoverHandlePos = pos;
preFound = true;
}
pos = translation + yAxis;
dist = glm::distance(glCoords, yAxisScreen);
if (dist < bestDist)
{
bestDist = dist;
m_HoverType = HoverYAxis;
m_HoverHandlePos = pos;
preFound = true;
}
if (preFound)
m_AffineType = AffinePre;
}
if (post)
{
v3T translation(xform->m_Post.C()/* - ember->m_CenterX*/, /*ember->m_CenterY + */xform->m_Post.F(), 0);
v3T transScreen = glm::project(translation, m_Modelview, m_Projection, m_Viewport);
v3T xAxis(xform->m_Post.A(), xform->m_Post.D(), 0);
v3T xAxisScreen = glm::project(translation + xAxis, m_Modelview, m_Projection, m_Viewport);
v3T yAxis(xform->m_Post.B(), xform->m_Post.E(), 0);
v3T yAxisScreen = glm::project(translation + yAxis, m_Modelview, m_Projection, m_Viewport);
pos = translation;
dist = glm::distance(glCoords, transScreen);
if (dist < bestDist)
{
bestDist = dist;
m_HoverType = HoverTranslation;
m_HoverHandlePos = pos;
postFound = true;
}
pos = translation + xAxis;
dist = glm::distance(glCoords, xAxisScreen);
if (dist < bestDist)
{
bestDist = dist;
m_HoverType = HoverXAxis;
m_HoverHandlePos = pos;
postFound = true;
}
pos = translation + yAxis;
dist = glm::distance(glCoords, yAxisScreen);
if (dist < bestDist)
{
bestDist = dist;
m_HoverType = HoverYAxis;
m_HoverHandlePos = pos;
postFound = true;
}
if (postFound)
m_AffineType = AffinePost;
}
return preFound || postFound;
}
/// <summary>
/// Calculate the new affine transform when dragging with the x axis with the left mouse button.
/// The value returned will depend on whether any modifier keys were held down.
/// None: Rotate and scale only.
/// Local Pivot:
/// Shift: Rotate only about affine center.
/// Alt: Free transform.
/// Shift + Alt: Rotate single axis about affine center.
/// Control: Rotate and scale, snapping to grid.
/// Control + Shift: Rotate only, snapping to grid.
/// Control + Alt: Free transform, snapping to grid.
/// Control + Shift + Alt: Rotate single axis about affine center, snapping to grid.
/// World Pivot:
/// Shift + Alt: Rotate single axis about world center.
/// Control + Shift + Alt: Rotate single axis about world center, snapping to grid.
/// All others are the same as local pivot.
/// </summary>
/// <returns>The new affine transform to be assigned to the selected xform</returns>
template <typename T>
Affine2D<T> GLEmberController<T>::CalcDragXAxis()
{
v3T t3, newAxis, newPos;
Affine2D<T> result = m_DragSrcTransform;
bool worldPivotShiftAlt = !m_Fractorium->LocalPivot() &&
((m_DragModifier & DragModShift) == DragModShift) &&
((m_DragModifier & DragModAlt) == DragModAlt);
if (worldPivotShiftAlt)
t3 = v3T(0, 0, 0);
else
t3 = v3T(m_DragSrcTransform.O(), 0);
if ((m_DragModifier & DragModShift) == DragModShift)
{
v3T targetAxis = m_MouseWorldPos - t3;
v3T norm = glm::normalize(targetAxis);
if ((m_DragModifier & DragModControl) == DragModControl)
norm = SnapToNormalizedAngle(norm, 24);
if (worldPivotShiftAlt)
newAxis = norm * glm::length(m_DragSrcTransform.O() + m_DragSrcTransform.X());
else
newAxis = norm * glm::length(m_DragSrcTransform.X());
}
else
{
if ((m_DragModifier & DragModControl) == DragModControl)
newPos = SnapToGrid(m_MouseWorldPos);
else
newPos = m_MouseWorldPos + m_DragHandleOffset;
newAxis = newPos - t3;
}
if ((m_DragModifier & DragModAlt) == DragModAlt)
{
if (worldPivotShiftAlt)
result.X(v2T(newAxis) - m_DragSrcTransform.O());
else
result.X(v2T(newAxis));
}
else
{
result.RotateScaleXTo(v2T(newAxis));
}
m_DragHandlePos = v3T(result.O() + result.X(), 0);
return result;
}
/// <summary>
/// Calculate the new affine transform when dragging with the y axis with the left mouse button.
/// The value returned will depend on whether any modifier keys were held down.
/// None: Rotate and scale only.
/// Local Pivot:
/// Shift: Rotate only about affine center.
/// Alt: Free transform.
/// Shift + Alt: Rotate single axis about affine center.
/// Control: Rotate and scale, snapping to grid.
/// Control + Shift: Rotate only, snapping to grid.
/// Control + Alt: Free transform, snapping to grid.
/// Control + Shift + Alt: Rotate single axis about affine center, snapping to grid.
/// World Pivot:
/// Shift + Alt: Rotate single axis about world center.
/// Control + Shift + Alt: Rotate single axis about world center, snapping to grid.
/// All others are the same as local pivot.
/// </summary>
/// <returns>The new affine transform to be assigned to the selected xform</returns>
template <typename T>
Affine2D<T> GLEmberController<T>::CalcDragYAxis()
{
v3T t3, newAxis, newPos;
Affine2D<T> result = m_DragSrcTransform;
bool worldPivotShiftAlt = !m_Fractorium->LocalPivot() &&
((m_DragModifier & DragModShift) == DragModShift) &&
((m_DragModifier & DragModAlt) == DragModAlt);
if (worldPivotShiftAlt)
t3 = v3T(0, 0, 0);
else
t3 = v3T(m_DragSrcTransform.O(), 0);
if ((m_DragModifier & DragModShift) == DragModShift)
{
v3T targetAxis = m_MouseWorldPos - t3;
v3T norm = glm::normalize(targetAxis);
if ((m_DragModifier & DragModControl) == DragModControl)
norm = SnapToNormalizedAngle(norm, 24);
if (worldPivotShiftAlt)
newAxis = norm * glm::length(m_DragSrcTransform.O() + m_DragSrcTransform.Y());
else
newAxis = norm * glm::length(m_DragSrcTransform.Y());
}
else
{
if ((m_DragModifier & DragModControl) == DragModControl)
newPos = SnapToGrid(m_MouseWorldPos);
else
newPos = m_MouseWorldPos + m_DragHandleOffset;
newAxis = newPos - t3;
}
if ((m_DragModifier & DragModAlt) == DragModAlt)
{
if (worldPivotShiftAlt)
result.Y(v2T(newAxis) - m_DragSrcTransform.O());
else
result.Y(v2T(newAxis));
}
else
{
result.RotateScaleYTo(v2T(newAxis));
}
m_DragHandlePos = v3T(result.O() + result.Y(), 0);
return result;
}
/// <summary>
/// Calculate the new affine transform when dragging the center with the left mouse button.
/// The value returned will depend on whether any modifier keys were held down.
/// None: Free transform.
/// Local Pivot:
/// Shift: Rotate about world center, keeping orientation the same.
/// Control: Free transform, snapping to grid.
/// Control + Shift: Rotate about world center, keeping orientation the same, snapping to grid.
/// World Pivot:
/// Shift: Rotate about world center, rotating orientation.
/// Control + Shift: Rotate about world center, rotating orientation, snapping to grid.
/// All others are the same as local pivot.
/// </summary>
/// <returns>The new affine transform to be assigned to the selected xform</returns>
template <typename T>
Affine2D<T> GLEmberController<T>::CalcDragTranslation()
{
v3T newPos, newX, newY;
Affine2D<T> result = m_DragSrcTransform;
bool worldPivotShift = !m_Fractorium->LocalPivot() && ((m_DragModifier & DragModShift) == DragModShift);
if ((m_DragModifier & DragModShift) == DragModShift)
{
v3T norm = glm::normalize(m_MouseWorldPos);
if ((m_DragModifier & DragModControl) == DragModControl)
norm = SnapToNormalizedAngle(norm, 12);
newPos = glm::length(m_DragSrcTransform.O()) * norm;
if (worldPivotShift)
{
T startAngle = atan2(m_DragSrcTransform.O().y, m_DragSrcTransform.O().x);
T endAngle = atan2(newPos.y, newPos.x);
T angle = startAngle - endAngle;
result.Rotate(angle * RAD_2_DEG);
}
}
else
{
if ((m_DragModifier & DragModControl) == DragModControl)
newPos = SnapToGrid(m_MouseWorldPos);
else
newPos = m_MouseWorldPos + m_DragHandleOffset;
}
result.O(v2T(newPos));
m_DragHandlePos = newPos;
return result;
}
/// <summary>
/// Thin wrapper to check if all controllers are ok and return a pointer to the GLController.
/// </summary>
/// <returns>A pointer to the GLController if everything is ok, else false.</returns>
GLEmberControllerBase* GLWidget::GLController()
{
if (m_Fractorium && m_Fractorium->ControllersOk())
return m_Fractorium->m_Controller->GLController();
return nullptr;
}
2014-12-11 00:50:15 -05:00
template class GLEmberController<float>;
#ifdef DO_DOUBLE
template class GLEmberController<double>;
#endif