void RenderContextPolicy<
				ShaderCollection::VertexSolidVertexColor,
				ShaderCollection::FragmentSolidVertexColor,
				ShaderCollection::No>::BindParameters(const CoreState& params)
		{
			const Math::mat4 proj_view_world = params.m_projection * params.m_view * params.m_world;
			SetUniformMatrix4f(uProjViewWorld, &proj_view_world[0]);

			SetUpOpenGL(params);
		}
Esempio n. 2
0
int main(void)
{
	printf("\n"
	       "Controls:  - Left/Right Click to zoom in/out, centring on cursor position.\n"
	       "           - Left Click and Drag to pan.\n"
	       "           - r to reset view.\n"
	       "           - q,w to decrease, increase max iteration count\n"
	       "           - a,s to decrease, increase colour period\n"
	       "           - g to toggle Gaussian Blur after computation\n"
	       "           - b to run some benchmarks.\n"
	       "           - p to show a double-precision limited zoom.\n"
	       "           - h to save a high resolution image of the current view to current directory.\n"
	       "           - Esc to quit.\n\n");

	// Set render function, dependent on compile time flag. All have the same signature,
	// with all necessary variables defined inside the structs.
#ifdef WITHOPENCL
	RenderMandelbrotPtr RenderMandelbrot = &RenderMandelbrotOpenCL;
#elif defined(WITHAVX)
	RenderMandelbrotPtr RenderMandelbrot = &RenderMandelbrotAVXCPU;
	// AVX double prec vector width (4) must divide horizontal (x) resolution
	assert(XRESOLUTION % 4 == 0);
#elif defined(WITHGMP)
	RenderMandelbrotPtr RenderMandelbrot = &RenderMandelbrotGMPCPU;
#else
	RenderMandelbrotPtr RenderMandelbrot = &RenderMandelbrotCPU;
#endif


	// Define and initialize structs
	imageStruct image;
	renderStruct render;
	// Set image resolution
	image.xRes = XRESOLUTION;
	image.yRes = YRESOLUTION;
	// Initial values for boundaries, iteration count
	SetInitialValues(&image);
	// Update OpenGL texture on render. This is disabled when rendering high resolution images
	render.updateTex = 1;
	// Allocate host memory, used to set up OpenGL texture, even if we are using interop OpenCL
	image.pixels = malloc(image.xRes * image.yRes * sizeof *(image.pixels) *3);


	// OpenGL variables and setup
	render.window = NULL;
	GLuint vertexShader, fragmentShader, shaderProgram;
	GLuint vao, vbo, ebo, tex;
	SetUpOpenGL(&(render.window), image.xRes, image.yRes, &vertexShader, &fragmentShader, &shaderProgram, &vao, &vbo, &ebo, &tex);


#ifdef WITHOPENCL
	// OpenCL variables and setup
	cl_platform_id    *platform;
	cl_device_id      **device_id;
	cl_program        program;
	cl_int            err;
	render.globalSize = image.xRes * image.yRes;
	render.localSize = OPENCLLOCALSIZE;
	assert(render.globalSize % render.localSize == 0);

	// Initially set variable that controls interop of OpenGL and OpenCL to 0, set to 1 if
	// interop device found successfully
	render.glclInterop = 0;

	if (InitialiseCLEnvironment(&platform, &device_id, &program, &render) == EXIT_FAILURE) {
		printf("Error initialising OpenCL environment\n");
		return EXIT_FAILURE;
	}
	size_t sizeBytes = image.xRes * image.yRes * 3 * sizeof(float);
	render.pixelsDevice = clCreateBuffer(render.contextCL, CL_MEM_READ_WRITE, sizeBytes, NULL, &err);
	// if we aren't using interop, allocate another buffer on the device for output, on the pointer
	// for the texture
	if (render.glclInterop == 0) {
		render.pixelsTex = clCreateBuffer(render.contextCL, CL_MEM_READ_WRITE, sizeBytes, NULL, &err);
	}

	// finish texture initialization so that we can use with OpenCL if glclInterop
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.xRes, image.yRes, 0, GL_RGB, GL_FLOAT, image.pixels);
	// Configure image from OpenGL texture "tex"
	if (render.glclInterop) {
		render.pixelsTex = clCreateFromGLTexture(render.contextCL, CL_MEM_WRITE_ONLY, GL_TEXTURE_2D, 0, tex, &err);
		CheckOpenCLError(err, __LINE__);
	}


	// Create kernels
	render.renderMandelbrotKernel = clCreateKernel(program, "renderMandelbrotKernel", &err);
	CheckOpenCLError(err, __LINE__);
	render.gaussianBlurKernel = clCreateKernel(program, "gaussianBlurKernel", &err);
	CheckOpenCLError(err, __LINE__);
	render.gaussianBlurKernel2 = clCreateKernel(program, "gaussianBlurKernel2", &err);
	CheckOpenCLError(err, __LINE__);
#endif


	// Start main loop: Update until we encounter user input. Look for Esc key (quit), left and right mount
	// buttons (zoom in on cursor position, zoom out on cursor position), "r" -- reset back to initial coords,
	// "b" -- run some benchmarks, "p" -- display a double precision limited zoom.
	// Re-render the Mandelbrot set as and when we need, in the user input conditionals.

	// Initial render:
	RenderMandelbrot(&render, &image);

	while (!glfwWindowShouldClose(render.window)) {

		// draw
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
		// Swap buffers
		glfwSwapBuffers(render.window);


		// USER INPUT TESTS.
		// Continuous render, poll for input:
		//glfwPollEvents();
		// Render only on update, wait for input:
		glfwWaitEvents();


		// if user presses Esc, close window to leave loop
		if (glfwGetKey(render.window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
		    glfwSetWindowShouldClose(render.window, GL_TRUE);
		}


		// if user left-clicks in window, zoom in, centring on cursor position
		// if click and drag, simply re-position centre without zooming
		else if (glfwGetMouseButton(render.window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS) {

			// Get Press cursor location
			double xPressPos, yPressPos, xReleasePos, yReleasePos;
			int shift = 0;
			glfwGetCursorPos(render.window, &xPressPos, &yPressPos);

			// Wait for mousebutton release, re-rendering as mouse moves
			while (glfwGetMouseButton(render.window, GLFW_MOUSE_BUTTON_LEFT) != GLFW_RELEASE) {

				glfwGetCursorPos(render.window, &xReleasePos, &yReleasePos);

				if (fabs(xReleasePos-xPressPos) > DRAGPIXELS || fabs(yReleasePos-yPressPos) > DRAGPIXELS) {
					// Set shift variable. Don't zoom after button release if this is 1
					shift = 1;
					// Determine shift in mandelbrot coords
					double xShift = (xReleasePos-xPressPos)/(double)image.xRes*(image.xMax-image.xMin);
					double yShift = (yReleasePos-yPressPos)/(double)image.yRes*(image.yMax-image.yMin);

					// Add shift to boundaries
					image.xMin = image.xMin - xShift;
					image.xMax = image.xMax - xShift;
					image.yMin = image.yMin - yShift;
					image.yMax = image.yMax - yShift;

					// Update "current" (press) position
					xPressPos = xReleasePos;
					yPressPos = yReleasePos;

					// Re-render and draw
					RenderMandelbrot(&render, &image);
					glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
					glfwSwapBuffers(render.window);
				}
				glfwPollEvents();
			}

			// else, zoom in smoothly over ZOOMSTEPS frames
			if (!shift) {
				SmoothZoom(&render, &image, RenderMandelbrot, xReleasePos, yReleasePos, ZOOMFACTOR, ITERSFACTOR);
			}
		}


		// if user right-clicks in window, zoom out, centring on cursor position
		else if (glfwGetMouseButton(render.window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS) {
			while (glfwGetMouseButton(render.window, GLFW_MOUSE_BUTTON_RIGHT) != GLFW_RELEASE) {
				glfwPollEvents();
			}

			// Get cursor position, in *screen coordinates*
			double xReleasePos, yReleasePos;
			glfwGetCursorPos(render.window, &xReleasePos, &yReleasePos);

			// Zooming out, so use 1/FACTORs.
			SmoothZoom(&render, &image, RenderMandelbrot, xReleasePos, yReleasePos, 1.0/ZOOMFACTOR, 1.0/ITERSFACTOR);
		}


		// if user presses "r", reset view
		else if (glfwGetKey(render.window, GLFW_KEY_R) == GLFW_PRESS) {
			while (glfwGetKey(render.window, GLFW_KEY_R) != GLFW_RELEASE) {
				glfwPollEvents();
			}
			printf("Resetting...\n");
			SetInitialValues(&image);
			RenderMandelbrot(&render, &image);
		}


		// if user presses "g", toggle gaussian blur
		else if (glfwGetKey(render.window, GLFW_KEY_G) == GLFW_PRESS) {
			while (glfwGetKey(render.window, GLFW_KEY_G) != GLFW_RELEASE) {
				glfwPollEvents();
			}
			if (image.gaussianBlur == 1) {
				printf("Toggling Gaussian Blur Off...\n");
				image.gaussianBlur = 0;
			}
			else {
				printf("Toggling Gaussian Blur On...\n");
				image.gaussianBlur = 1;
			}
			RenderMandelbrot(&render, &image);
		}


		// if user presses "q", decrease max iteration count
		else if (glfwGetKey(render.window, GLFW_KEY_Q) == GLFW_PRESS) {
			while (glfwGetKey(render.window, GLFW_KEY_Q) != GLFW_RELEASE) {
				glfwPollEvents();
			}
			printf("Decreasing max iteration count from %d to %d\n", image.maxIters, (int)(image.maxIters/ITERSFACTOR));
			image.maxIters /= ITERSFACTOR;
			RenderMandelbrot(&render, &image);
		}
		// if user presses "w", increase max iteration count
		else if (glfwGetKey(render.window, GLFW_KEY_W) == GLFW_PRESS) {
			while (glfwGetKey(render.window, GLFW_KEY_W) != GLFW_RELEASE) {
				glfwPollEvents();
			}
			printf("Increasing max iteration count from %d to %d\n", image.maxIters, (int)(image.maxIters*ITERSFACTOR));
			image.maxIters *= ITERSFACTOR;
			RenderMandelbrot(&render, &image);
		}


		// if user presses "a", decrease colour period
		else if (glfwGetKey(render.window, GLFW_KEY_A) == GLFW_PRESS) {
			while (glfwGetKey(render.window, GLFW_KEY_A) != GLFW_RELEASE) {
				glfwPollEvents();
			}
			printf("Decreasing colour period from %.0lf to %.0lf\n", image.colourPeriod, fmax(32, image.colourPeriod-32));
			image.colourPeriod = fmax(32, image.colourPeriod-32);
			RenderMandelbrot(&render, &image);
		}
		// if user presses "s", increase colour period
		else if (glfwGetKey(render.window, GLFW_KEY_S) == GLFW_PRESS) {
			while (glfwGetKey(render.window, GLFW_KEY_S) != GLFW_RELEASE) {
				glfwPollEvents();
			}
			printf("Increasing colour period from %.0lf to %.0lf\n", image.colourPeriod, image.colourPeriod+32);
			image.colourPeriod += 32;
			RenderMandelbrot(&render, &image);
		}


		// if user presses "b", run some benchmarks.
		else if (glfwGetKey(render.window, GLFW_KEY_B) == GLFW_PRESS) {
			while (glfwGetKey(render.window, GLFW_KEY_B) != GLFW_RELEASE) {
				glfwPollEvents();
			}

			printf("Running Benchmarks...\n");

			printf("Whole fractal:\n");
			SetInitialValues(&image);
			RunBenchmark(&render, &image, RenderMandelbrot);

			printf("Early Bail-out:\n");
			image.xMin = -0.8153143016681144;
			image.xMax = -0.6839170011300622;
			image.yMin = -0.0365167077914237;
			image.yMax =  0.0373942737612310;
			image.maxIters = 112;
			RunBenchmark(&render, &image, RenderMandelbrot);

			printf("Spiral:\n");
			image.xMin = -0.8673755781976442;
			image.xMax = -0.8673711898931797;
			image.yMin = -0.2156059883952151;
			image.yMax = -0.2156035199739536;
			image.maxIters = 1757;
			RunBenchmark(&render, &image, RenderMandelbrot);

			printf("Highly zoomed:\n");
			image.xMin = -0.8712903154956539;
			image.xMax = -0.8712903108993595;
			image.yMin = -0.2293516610223087;
			image.yMax = -0.2293516584368930;
			image.maxIters = 10750;
			RunBenchmark(&render, &image, RenderMandelbrot);

			printf("Complete.\n");
		// Re-render with original coords
			SetInitialValues(&image);
			RenderMandelbrot(&render, &image);
		}


		// if user presses "p", zoom in, such that the double precision algorithm looks pixellated
		else if (glfwGetKey(render.window, GLFW_KEY_P) == GLFW_PRESS) {
			while (glfwGetKey(render.window, GLFW_KEY_P) != GLFW_RELEASE) {
				glfwPollEvents();
			}
			printf("Precision test...\n");
			image.xMin = -1.25334325335487362;
			image.xMax = -1.25334325335481678;
			image.yMin = -0.34446232396119353;
			image.yMax = -0.34446232396116155;
			image.maxIters = 1389952;
			RenderMandelbrot(&render, &image);
		}


		// if user presses "h", render a high resolution version of the current view, and
		// save it to disk as an image
		else if (glfwGetKey(render.window, GLFW_KEY_H) == GLFW_PRESS) {
			while (glfwGetKey(render.window, GLFW_KEY_H) != GLFW_RELEASE) {
				glfwPollEvents();
			}
			double startTime = GetWallTime();
			printf("Saving high resolution (%d x %d) image...\n",
			       image.xRes*HIGHRESOLUTIONMULTIPLIER, image.yRes*HIGHRESOLUTIONMULTIPLIER);
			HighResolutionRender(&render, &image, RenderMandelbrot);
			printf("   --- done. Total time: %lfs\n", GetWallTime()-startTime);
		}
	}



	// clean up
#ifdef WITHOPENCL
	CleanUpCLEnvironment(&platform, &device_id, &(render.contextCL), &(render.queue), &program);
#endif

	glDeleteProgram(shaderProgram);
	glDeleteShader(fragmentShader);
	glDeleteShader(vertexShader);
	glDeleteBuffers(1, &ebo);
	glDeleteBuffers(1, &vbo);
	glDeleteVertexArrays(1, &vao);

	// Close OpenGL window and terminate GLFW
	glfwDestroyWindow(render.window);
	glfwTerminate();

	// Free dynamically allocated memory
	free(image.pixels);
	return 0;
}