Esempio n. 1
0
int _main_(int /*_argc*/, char** /*_argv*/)
{
	// Create vertex stream declaration.
	PosColorVertex::init();
	PosColorTexCoord0Vertex::init();

	uint32_t width = 1280;
	uint32_t height = 720;
	uint32_t debug = BGFX_DEBUG_TEXT;
	uint32_t reset = BGFX_RESET_VSYNC;

	bgfx::init();
	bgfx::reset(width, height, reset);

	// Enable debug text.
	bgfx::setDebug(debug);

	// Get renderer capabilities info.
	const bgfx::Caps* caps = bgfx::getCaps();

	// Setup root path for binary shaders. Shader binaries are different 
	// for each renderer.
	switch (caps->rendererType)
	{
	default:
		break;

	case bgfx::RendererType::OpenGL:
	case bgfx::RendererType::OpenGLES:
		s_flipV = true;
		break;
	}

	// Imgui.
	void* data = load("font/droidsans.ttf");
	imguiCreate(data);
	free(data);

	const bgfx::Memory* mem;

	// Create static vertex buffer.
	mem = bgfx::makeRef(s_cubeVertices, sizeof(s_cubeVertices) );
	bgfx::VertexBufferHandle vbh = bgfx::createVertexBuffer(mem, PosColorVertex::ms_decl);

	// Create static index buffer.
	mem = bgfx::makeRef(s_cubeIndices, sizeof(s_cubeIndices) );
	bgfx::IndexBufferHandle ibh = bgfx::createIndexBuffer(mem);

	// Create texture sampler uniforms.
	bgfx::UniformHandle u_texColor0 = bgfx::createUniform("u_texColor0", bgfx::UniformType::Uniform1iv);
	bgfx::UniformHandle u_texColor1 = bgfx::createUniform("u_texColor1", bgfx::UniformType::Uniform1iv);
	bgfx::UniformHandle u_color     = bgfx::createUniform("u_color",     bgfx::UniformType::Uniform4fv);

	bgfx::ProgramHandle blend          = loadProgram("vs_oit",      "fs_oit"                  );
	bgfx::ProgramHandle wbSeparatePass = loadProgram("vs_oit",      "fs_oit_wb_separate"      );
	bgfx::ProgramHandle wbSeparateBlit = loadProgram("vs_oit_blit", "fs_oit_wb_separate_blit" );
	bgfx::ProgramHandle wbPass         = loadProgram("vs_oit",      "fs_oit_wb"               );
	bgfx::ProgramHandle wbBlit         = loadProgram("vs_oit_blit", "fs_oit_wb_blit"          );

	bgfx::TextureHandle fbtextures[2] = { BGFX_INVALID_HANDLE, BGFX_INVALID_HANDLE };
	bgfx::FrameBufferHandle fbh = BGFX_INVALID_HANDLE; 

	int64_t timeOffset = bx::getHPCounter();

	uint32_t mode = 1;
	int32_t scrollArea = 0;
	bool frontToBack = true;
	bool fadeInOut = false;

	uint32_t oldWidth = 0;
	uint32_t oldHeight = 0;
	uint32_t oldReset = reset;

	entry::MouseState mouseState;
	while (!entry::processEvents(width, height, debug, reset, &mouseState) )
	{
		if (oldWidth  != width
		||  oldHeight != height
		||  oldReset  != reset
		||  !bgfx::isValid(fbh) )
		{
			// Recreate variable size render targets when resolution changes.
			oldWidth  = width;
			oldHeight = height;
			oldReset  = reset;

			if (bgfx::isValid(fbh) )
			{
				bgfx::destroyFrameBuffer(fbh);
			}

			fbtextures[0] = bgfx::createTexture2D(width, height, 1, bgfx::TextureFormat::RGBA16F, BGFX_TEXTURE_RT);
			fbtextures[1] = bgfx::createTexture2D(width, height, 1, bgfx::TextureFormat::R16F,    BGFX_TEXTURE_RT);
			fbh = bgfx::createFrameBuffer(BX_COUNTOF(fbtextures), fbtextures, true);
		}

		imguiBeginFrame(mouseState.m_mx
			, mouseState.m_my
			, (mouseState.m_buttons[entry::MouseButton::Left  ] ? IMGUI_MBUT_LEFT  : 0)
			| (mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT : 0)
			, 0
			, width
			, height
			);

		imguiBeginScrollArea("Settings", width - width / 4 - 10, 10, width / 4, height / 3, &scrollArea);
		imguiSeparatorLine();

		imguiLabel("Blend mode:");

		mode = imguiChoose(mode
			, "None"
			, "Separate"
			, "MRT Independent"
			);

		imguiSeparatorLine();

		if (imguiCheck("Front to back", frontToBack) )
		{
			frontToBack ^= true;
		}

		if (imguiCheck("Fade in/out", fadeInOut) )
		{
			fadeInOut ^= true;
		}

		imguiEndScrollArea();
		imguiEndFrame();

		// Set view 0 default viewport.
		bgfx::setViewRectMask(0x3, 0, 0, width, height);

		int64_t now = bx::getHPCounter();
		static int64_t last = now;
		const int64_t frameTime = now - last;
		last = now;
		const double freq = double(bx::getHPFrequency() );
		const double toMs = 1000.0/freq;

		float time = (float)( (now-timeOffset)/freq);

		// Use debug font to print information about this example.
		bgfx::dbgTextClear();
		// Reference:
		// Weighted, Blended Order-Independent Transparency
		// http://jcgt.org/published/0002/02/09/
		// http://casual-effects.blogspot.com/2014/03/weighted-blended-order-independent.html
		bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/19-oit");
		bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Weighted, Blended Order Independent Transparency.");
		bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs);

		float at[3] = { 0.0f, 0.0f, 0.0f };
		float eye[3] = { 0.0f, 0.0f, -7.0f };
	
		float view[16];
		float proj[16];

		// Set view and projection matrix for view 0.
		bx::mtxLookAt(view, eye, at);
		bx::mtxProj(proj, 60.0f, float(width)/float(height), 0.1f, 100.0f);

		bgfx::setViewTransform(0, view, proj);

		bgfx::setViewClearMask(0x3
			, BGFX_CLEAR_COLOR_BIT|BGFX_CLEAR_DEPTH_BIT
			, 0x00000000
			, 1.0f
			, 0
			);

		bgfx::FrameBufferHandle invalid = BGFX_INVALID_HANDLE;
		bgfx::setViewFrameBuffer(0, 0 == mode ? invalid : fbh);

		// Set view and projection matrix for view 1.
		bx::mtxIdentity(view);
		bx::mtxOrtho(proj, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f);
		bgfx::setViewTransform(1, view, proj);

		for (uint32_t depth = 0; depth < 3; ++depth)
		{
			uint32_t zz = frontToBack ? 2-depth : depth;

			for (uint32_t yy = 0; yy < 3; ++yy)
			{
				for (uint32_t xx = 0; xx < 3; ++xx)
				{
					float color[4] = { xx*1.0f/3.0f, zz*1.0f/3.0f, yy*1.0f/3.0f, 0.5f };

					if (fadeInOut
					&&  zz == 1)
					{
						color[3] = sinf(time*3.0f)*0.49f+0.5f;
					}

					bgfx::setUniform(u_color, color);

					BX_UNUSED(time);
					float mtx[16];
					bx::mtxRotateXY(mtx, time*0.023f + xx*0.21f, time*0.03f + yy*0.37f);
					//mtxIdentity(mtx);
					mtx[12] = -2.5f + float(xx)*2.5f;
					mtx[13] = -2.5f + float(yy)*2.5f;
					mtx[14] = -2.5f + float(zz)*2.5f; //0.0f; // sinf(time + ( (xx+1)*(yy+1)/9.0f)*float(M_PI) )*50.0f+50.0f; //90.0f - (xx+1)*(yy+1)*10.0f;

					// Set transform for draw call.
					bgfx::setTransform(mtx);

					// Set vertex and index buffer.
					bgfx::setVertexBuffer(vbh);
					bgfx::setIndexBuffer(ibh);

					const uint64_t state = 0
						| BGFX_STATE_CULL_CW
						| BGFX_STATE_RGB_WRITE
						| BGFX_STATE_ALPHA_WRITE
						| BGFX_STATE_DEPTH_TEST_LESS
						| BGFX_STATE_MSAA
						;

					switch (mode)
					{
						case 0:
							// Set vertex and fragment shaders.
							bgfx::setProgram(blend);

							// Set render states.
							bgfx::setState(state
								| BGFX_STATE_BLEND_ALPHA
								);
							break;

						case 1:
							// Set vertex and fragment shaders.
							bgfx::setProgram(wbSeparatePass);

							// Set render states.
							bgfx::setState(state
								| BGFX_STATE_BLEND_FUNC_SEPARATE(BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_ZERO, BGFX_STATE_BLEND_INV_SRC_ALPHA)
								);
							break;

						default:
							// Set vertex and fragment shaders.
							bgfx::setProgram(wbPass);

							// Set render states.
							bgfx::setState(state
								| BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_ONE, BGFX_STATE_BLEND_ONE)
								| BGFX_STATE_BLEND_INDEPENDENT
								, 0
								| BGFX_STATE_BLEND_FUNC_RT_1(BGFX_STATE_BLEND_ZERO, BGFX_STATE_BLEND_SRC_COLOR)
								);
							break;
					}

					// Submit primitive for rendering to view 0.
					bgfx::submit(0);
				}
			}
		}

		if (0 != mode)
		{
			bgfx::setTexture(0, u_texColor0, fbtextures[0]);
			bgfx::setTexture(1, u_texColor1, fbtextures[1]);
			bgfx::setProgram(1 == mode ? wbSeparateBlit : wbBlit);
			bgfx::setState(0
				| BGFX_STATE_RGB_WRITE
				| BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_INV_SRC_ALPHA, BGFX_STATE_BLEND_SRC_ALPHA)
				);
			screenSpaceQuad( (float)width, (float)height, s_flipV);
			bgfx::submit(1);
		}

		// Advance to next frame. Rendering thread will be kicked to 
		// process submitted rendering primitives.
		bgfx::frame();
	}

	// Cleanup.
	imguiDestroy();

	bgfx::destroyFrameBuffer(fbh);
	bgfx::destroyIndexBuffer(ibh);
	bgfx::destroyVertexBuffer(vbh);
	bgfx::destroyProgram(blend);
	bgfx::destroyProgram(wbSeparatePass);
	bgfx::destroyProgram(wbSeparateBlit);
	bgfx::destroyProgram(wbPass);
	bgfx::destroyProgram(wbBlit);
	bgfx::destroyUniform(u_texColor0);
	bgfx::destroyUniform(u_texColor1);
	bgfx::destroyUniform(u_color);

	// Shutdown bgfx.
	bgfx::shutdown();

	return 0;
}
Esempio n. 2
0
BX_NO_INLINE bool mainloop()
{
	if (!entry::processEvents(width, height, debug, reset, &mouseState) )
	{
		int64_t now = bx::getHPCounter();
		static int64_t last = now;
		const int64_t hpFreq = bx::getHPFrequency();
		const int64_t frameTime = now - last;
		last = now;
		const double freq = double(hpFreq);
		const double toMs = 1000.0/freq;

		deltaTimeNs += frameTime*1000000/hpFreq;

		if (deltaTimeNs > 1000000)
		{
			deltaTimeAvgNs = deltaTimeNs / bx::int64_max(1, numFrames);

			if (autoAdjust)
			{
				if (deltaTimeAvgNs < highwm)
				{
					dim = bx::uint32_min(dim + 2, 40);
				}
				else if (deltaTimeAvgNs > lowwm)
				{
					dim = bx::uint32_max(dim - 1, 2);
				}
			}

			deltaTimeNs = 0;
			numFrames = 0;
		}
		else
		{
			++numFrames;
		}

		float time = (float)( (now-timeOffset)/freq);

		imguiBeginFrame(mouseState.m_mx
				, mouseState.m_my
				, (mouseState.m_buttons[entry::MouseButton::Left  ] ? IMGUI_MBUT_LEFT  : 0)
				| (mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT : 0)
				, 0
				, width
				, height
				);

		imguiBeginScrollArea("Settings", width - width / 4 - 10, 10, width / 4, height / 3, &scrollArea);
		imguiSeparatorLine();

		transform = imguiChoose(transform
				, "Rotate"
				, "No fragments"
				);
		imguiSeparatorLine();

		if (imguiCheck("Auto adjust", autoAdjust) )
		{
			autoAdjust ^= true;
		}

		imguiSlider("Dim", dim, 5, 40);
		imguiLabel("Draw calls: %d", dim*dim*dim);
		imguiLabel("Avg Delta Time (1 second) [ms]: %0.4f", deltaTimeAvgNs/1000.0f);

		imguiEndScrollArea();
		imguiEndFrame();

		float at[3] = { 0.0f, 0.0f, 0.0f };
		float eye[3] = { 0.0f, 0.0f, -35.0f };

		float view[16];
		float proj[16];
		bx::mtxLookAt(view, eye, at);
		bx::mtxProj(proj, 60.0f, float(width)/float(height), 0.1f, 100.0f);

		// Set view and projection matrix for view 0.
		bgfx::setViewTransform(0, view, proj);

		// Set view 0 default viewport.
		bgfx::setViewRect(0, 0, 0, width, height);

		// This dummy draw call is here to make sure that view 0 is cleared
		// if no other draw calls are submitted to view 0.
		bgfx::submit(0);

		// Use debug font to print information about this example.
		bgfx::dbgTextClear();
		bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/17-drawstress");
		bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Draw stress, maximizing number of draw calls.");
		bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: %7.3f[ms]", double(frameTime)*toMs);

		float mtxS[16];
		const float scale = 0 == transform ? 0.25f : 0.0f;
		bx::mtxScale(mtxS, scale, scale, scale);

		const float step = 0.6f;
		float pos[3];
		pos[0] = -step*dim / 2.0f;
		pos[1] = -step*dim / 2.0f;
		pos[2] = -15.0;

		for (uint32_t zz = 0; zz < uint32_t(dim); ++zz)
		{
			for (uint32_t yy = 0; yy < uint32_t(dim); ++yy)
			{
				for (uint32_t xx = 0; xx < uint32_t(dim); ++xx)
				{
					float mtxR[16];
					bx::mtxRotateXYZ(mtxR, time + xx*0.21f, time + yy*0.37f, time + yy*0.13f);

					float mtx[16];
					bx::mtxMul(mtx, mtxS, mtxR);

					mtx[12] = pos[0] + float(xx)*step;
					mtx[13] = pos[1] + float(yy)*step;
					mtx[14] = pos[2] + float(zz)*step;

					// Set model matrix for rendering.
					bgfx::setTransform(mtx);

					// Set vertex and fragment shaders.
					bgfx::setProgram(program);

					// Set vertex and index buffer.
					bgfx::setVertexBuffer(vbh);
					bgfx::setIndexBuffer(ibh);

					// Set render states.
					bgfx::setState(BGFX_STATE_DEFAULT);

					// Submit primitive for rendering to view 0.
					bgfx::submit(0);
				}
			}
		}

		// Advance to next frame. Rendering thread will be kicked to
		// process submitted rendering primitives.
		bgfx::frame();

		return false;
	}

	return true;
}
Esempio n. 3
0
int _main_(int _argc, char** _argv)
{
	Args args(_argc, _argv);

	uint32_t width = 1280;
	uint32_t height = 720;
	uint32_t debug = BGFX_DEBUG_TEXT;
	uint32_t reset  = 0
		| BGFX_RESET_VSYNC
		| BGFX_RESET_MSAA_X16
		;

	bgfx::init(args.m_type, args.m_pciId);
	bgfx::reset(width, height, reset);

	// Enable debug text.
	bgfx::setDebug(debug);

	// Set views  clear state.
	bgfx::setViewClear(0
		, BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH
		, 0x303030ff
		, 1.0f
		, 0
		);

	// Imgui.
	imguiCreate();

	// Uniforms.
	Uniforms uniforms;
	uniforms.init();

	// Vertex declarations.
	PosColorTexCoord0Vertex::init();

	LightProbe lightProbes[LightProbe::Count];
	lightProbes[LightProbe::Bolonga].load("bolonga");
	lightProbes[LightProbe::Kyoto  ].load("kyoto");
	LightProbe::Enum currentLightProbe = LightProbe::Bolonga;

	bgfx::UniformHandle u_mtx        = bgfx::createUniform("u_mtx",        bgfx::UniformType::Mat4);
	bgfx::UniformHandle u_params     = bgfx::createUniform("u_params",     bgfx::UniformType::Vec4);
	bgfx::UniformHandle u_flags      = bgfx::createUniform("u_flags",      bgfx::UniformType::Vec4);
	bgfx::UniformHandle u_camPos     = bgfx::createUniform("u_camPos",     bgfx::UniformType::Vec4);
	bgfx::UniformHandle s_texCube    = bgfx::createUniform("s_texCube",    bgfx::UniformType::Int1);
	bgfx::UniformHandle s_texCubeIrr = bgfx::createUniform("s_texCubeIrr", bgfx::UniformType::Int1);

	bgfx::ProgramHandle programMesh  = loadProgram("vs_ibl_mesh",   "fs_ibl_mesh");
	bgfx::ProgramHandle programSky   = loadProgram("vs_ibl_skybox", "fs_ibl_skybox");

	Mesh* meshBunny;
	meshBunny = meshLoad("meshes/bunny.bin");

	Mesh* meshOrb;
	meshOrb = meshLoad("meshes/orb.bin");

	Camera camera;
	Mouse mouse;

	struct Settings
	{
		Settings()
		{
			m_envRotCurr = 0.0f;
			m_envRotDest = 0.0f;
			m_lightDir[0] = -0.8f;
			m_lightDir[1] = 0.2f;
			m_lightDir[2] = -0.5f;
			m_lightCol[0] = 1.0f;
			m_lightCol[1] = 1.0f;
			m_lightCol[2] = 1.0f;
			m_glossiness = 0.7f;
			m_exposure = 0.0f;
			m_bgType = 3.0f;
			m_radianceSlider = 2.0f;
			m_reflectivity = 0.85f;
			m_rgbDiff[0] = 1.0f;
			m_rgbDiff[1] = 1.0f;
			m_rgbDiff[2] = 1.0f;
			m_rgbSpec[0] = 1.0f;
			m_rgbSpec[1] = 1.0f;
			m_rgbSpec[2] = 1.0f;
			m_lod = 0.0f;
			m_doDiffuse = false;
			m_doSpecular = false;
			m_doDiffuseIbl = true;
			m_doSpecularIbl = true;
			m_showLightColorWheel = true;
			m_showDiffColorWheel = true;
			m_showSpecColorWheel = true;
			m_metalOrSpec = 0;
			m_meshSelection = 0;
			m_crossCubemapPreview = ImguiCubemap::Latlong;
		}

		float m_envRotCurr;
		float m_envRotDest;
		float m_lightDir[3];
		float m_lightCol[3];
		float m_glossiness;
		float m_exposure;
		float m_radianceSlider;
		float m_bgType;
		float m_reflectivity;
		float m_rgbDiff[3];
		float m_rgbSpec[3];
		float m_lod;
		bool m_doDiffuse;
		bool m_doSpecular;
		bool m_doDiffuseIbl;
		bool m_doSpecularIbl;
		bool m_showLightColorWheel;
		bool m_showDiffColorWheel;
		bool m_showSpecColorWheel;
		uint8_t m_metalOrSpec;
		uint8_t m_meshSelection;
		ImguiCubemap::Enum m_crossCubemapPreview;
	};

	Settings settings;

	int32_t leftScrollArea = 0;

	entry::MouseState mouseState;
	while (!entry::processEvents(width, height, debug, reset, &mouseState) )
	{
		imguiBeginFrame(mouseState.m_mx
			, mouseState.m_my
			, (mouseState.m_buttons[entry::MouseButton::Left  ] ? IMGUI_MBUT_LEFT   : 0)
			| (mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT  : 0)
			| (mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0)
			, mouseState.m_mz
			, uint16_t(width)
			, uint16_t(height)
			);

		static int32_t rightScrollArea = 0;
		imguiBeginScrollArea("", width - 256 - 10, 10, 256, 700, &rightScrollArea);

		imguiLabel("Environment light:");
		imguiIndent();
		imguiBool("IBL Diffuse",  settings.m_doDiffuseIbl);
		imguiBool("IBL Specular", settings.m_doSpecularIbl);
		currentLightProbe = LightProbe::Enum(imguiTabs(
								  uint8_t(currentLightProbe)
								, true
								, ImguiAlign::LeftIndented
								, 16
								, 2
								, 2
								, "Bolonga"
								, "Kyoto"
								) );
		if (imguiCube(lightProbes[currentLightProbe].m_tex, settings.m_lod, settings.m_crossCubemapPreview, true) )
		{
			settings.m_crossCubemapPreview = ImguiCubemap::Enum( (settings.m_crossCubemapPreview+1) % ImguiCubemap::Count);
		}
		imguiSlider("Texture LOD", settings.m_lod, 0.0f, 10.1f, 0.1f);
		imguiUnindent();

		imguiSeparator(8);
		imguiLabel("Directional light:");
		imguiIndent();
		imguiBool("Diffuse",  settings.m_doDiffuse);
		imguiBool("Specular", settings.m_doSpecular);
		const bool doDirectLighting = settings.m_doDiffuse || settings.m_doSpecular;
		imguiSlider("Light direction X", settings.m_lightDir[0], -1.0f, 1.0f, 0.1f, doDirectLighting);
		imguiSlider("Light direction Y", settings.m_lightDir[1], -1.0f, 1.0f, 0.1f, doDirectLighting);
		imguiSlider("Light direction Z", settings.m_lightDir[2], -1.0f, 1.0f, 0.1f, doDirectLighting);
		imguiColorWheel("Color:", settings.m_lightCol, settings.m_showLightColorWheel, 0.6f, doDirectLighting);
		imguiUnindent();

		imguiSeparator(8);
		imguiLabel("Background:");
		imguiIndent();
		{
			int32_t selection;
			if      (0.0f == settings.m_bgType) { selection = UINT8_C(0); }
			else if (7.0f == settings.m_bgType) { selection = UINT8_C(2); }
			else                                { selection = UINT8_C(1); }

			selection = imguiTabs(
							  uint8_t(selection)
							, true
							, ImguiAlign::LeftIndented
							, 16
							, 2
							, 3
							, "Skybox"
							, "Radiance"
							, "Irradiance"
							);
			if      (0 == selection) { settings.m_bgType = 0.0f; }
			else if (2 == selection) { settings.m_bgType = 7.0f; }
			else                     { settings.m_bgType = settings.m_radianceSlider; }
			const bool isRadiance = (selection == 1);
			imguiSlider("Mip level", settings.m_radianceSlider, 1.0f, 6.0f, 0.1f, isRadiance);
		}
		imguiUnindent();

		imguiSeparator(8);
		imguiLabel("Post processing:");
		imguiIndent();
		imguiSlider("Exposure", settings.m_exposure, -4.0f, 4.0f, 0.1f);
		imguiUnindent();

		imguiSeparator();

		imguiEndScrollArea();

		imguiBeginScrollArea("", 10, 70, 256, 636, &leftScrollArea);

		imguiLabel("Mesh:");
		imguiIndent();
		settings.m_meshSelection = uint8_t(imguiChoose(settings.m_meshSelection, "Bunny", "Orbs") );
		imguiUnindent();

		const bool isBunny = (0 == settings.m_meshSelection);
		if (!isBunny)
		{
			settings.m_metalOrSpec = 0;
		}

		imguiSeparator(4);
		imguiLabel("Workflow:");
		imguiIndent();
		if (imguiCheck("Metalness", 0 == settings.m_metalOrSpec, isBunny) ) { settings.m_metalOrSpec = 0; }
		if (imguiCheck("Specular",  1 == settings.m_metalOrSpec, isBunny) ) { settings.m_metalOrSpec = 1; }
		imguiUnindent();

		imguiSeparator(4);
		imguiLabel("Material:");
		imguiIndent();
		imguiSlider("Glossiness", settings.m_glossiness, 0.0f, 1.0f, 0.01f, isBunny);
		imguiSlider(0 == settings.m_metalOrSpec ? "Metalness" : "Diffuse - Specular", settings.m_reflectivity, 0.0f, 1.0f, 0.01f, isBunny);
		imguiUnindent();

		imguiColorWheel("Diffuse:", &settings.m_rgbDiff[0], settings.m_showDiffColorWheel, 0.7f);
		imguiSeparator();
		imguiColorWheel("Specular:", &settings.m_rgbSpec[0], settings.m_showSpecColorWheel, 0.7f, (1 == settings.m_metalOrSpec) && isBunny);

		imguiEndScrollArea();

		imguiEndFrame();

		uniforms.m_glossiness   = settings.m_glossiness;
		uniforms.m_reflectivity = settings.m_reflectivity;
		uniforms.m_exposure     = settings.m_exposure;
		uniforms.m_bgType       = settings.m_bgType;
		uniforms.m_metalOrSpec   = float(settings.m_metalOrSpec);
		uniforms.m_doDiffuse     = float(settings.m_doDiffuse);
		uniforms.m_doSpecular    = float(settings.m_doSpecular);
		uniforms.m_doDiffuseIbl  = float(settings.m_doDiffuseIbl);
		uniforms.m_doSpecularIbl = float(settings.m_doSpecularIbl);
		bx::memCopy(uniforms.m_rgbDiff,  settings.m_rgbDiff,  3*sizeof(float) );
		bx::memCopy(uniforms.m_rgbSpec,  settings.m_rgbSpec,  3*sizeof(float) );
		bx::memCopy(uniforms.m_lightDir, settings.m_lightDir, 3*sizeof(float) );
		bx::memCopy(uniforms.m_lightCol, settings.m_lightCol, 3*sizeof(float) );

		int64_t now = bx::getHPCounter();
		static int64_t last = now;
		const int64_t frameTime = now - last;
		last = now;
		const double freq = double(bx::getHPFrequency() );
		const double toMs = 1000.0/freq;
		const float deltaTimeSec = float(double(frameTime)/freq);

		// Use debug font to print information about this example.
		bgfx::dbgTextClear();
		bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/18-ibl");
		bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Image-based lighting.");
		bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs);

		// Camera.
		const bool mouseOverGui = imguiMouseOverArea();
		mouse.update(float(mouseState.m_mx), float(mouseState.m_my), mouseState.m_mz, width, height);
		if (!mouseOverGui)
		{
			if (mouseState.m_buttons[entry::MouseButton::Left])
			{
				camera.orbit(mouse.m_dx, mouse.m_dy);
			}
			else if (mouseState.m_buttons[entry::MouseButton::Right])
			{
				camera.dolly(mouse.m_dx + mouse.m_dy);
			}
			else if (mouseState.m_buttons[entry::MouseButton::Middle])
			{
				settings.m_envRotDest += mouse.m_dx*2.0f;
			}
			else if (0 != mouse.m_scroll)
			{
				camera.dolly(float(mouse.m_scroll)*0.05f);
			}
		}
		camera.update(deltaTimeSec);
		bx::memCopy(uniforms.m_cameraPos, camera.m_pos.curr, 3*sizeof(float) );

		// View Transform 0.
		float view[16];
		float proj[16];
		bx::mtxIdentity(view);
		bx::mtxOrtho(proj, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f);
		bgfx::setViewTransform(0, view, proj);

		// View Transform 1.
		camera.mtxLookAt(view);
		bx::mtxProj(proj, 45.0f, float(width)/float(height), 0.1f, 100.0f, bgfx::getCaps()->homogeneousDepth);
		bgfx::setViewTransform(1, view, proj);

		// View rect.
		bgfx::setViewRect(0, 0, 0, uint16_t(width), uint16_t(height) );
		bgfx::setViewRect(1, 0, 0, uint16_t(width), uint16_t(height) );

		// Env rotation.
		const float amount = bx::fmin(deltaTimeSec/0.12f, 1.0f);
		settings.m_envRotCurr = bx::flerp(settings.m_envRotCurr, settings.m_envRotDest, amount);

		// Env mtx.
		float mtxEnvView[16];
		camera.envViewMtx(mtxEnvView);
		float mtxEnvRot[16];
		bx::mtxRotateY(mtxEnvRot, settings.m_envRotCurr);
		bx::mtxMul(uniforms.m_mtx, mtxEnvView, mtxEnvRot); // Used for Skybox.

		// Submit view 0.
		bgfx::setTexture(0, s_texCube, lightProbes[currentLightProbe].m_tex);
		bgfx::setTexture(1, s_texCubeIrr, lightProbes[currentLightProbe].m_texIrr);
		bgfx::setState(BGFX_STATE_RGB_WRITE|BGFX_STATE_ALPHA_WRITE);
		screenSpaceQuad( (float)width, (float)height, true);
		uniforms.submit();
		bgfx::submit(0, programSky);

		// Submit view 1.
		bx::memCopy(uniforms.m_mtx, mtxEnvRot, 16*sizeof(float)); // Used for IBL.
		if (0 == settings.m_meshSelection)
		{
			// Submit bunny.
			float mtx[16];
			bx::mtxSRT(mtx, 1.0f, 1.0f, 1.0f, 0.0f, bx::pi, 0.0f, 0.0f, -0.80f, 0.0f);
			bgfx::setTexture(0, s_texCube,    lightProbes[currentLightProbe].m_tex);
			bgfx::setTexture(1, s_texCubeIrr, lightProbes[currentLightProbe].m_texIrr);
			uniforms.submit();
			meshSubmit(meshBunny, 1, programMesh, mtx);
		}
		else
		{
			// Submit orbs.
			for (float yy = 0, yend = 5.0f; yy < yend; yy+=1.0f)
			{
				for (float xx = 0, xend = 5.0f; xx < xend; xx+=1.0f)
				{
					const float scale   =  1.2f;
					const float spacing =  2.2f;
					const float yAdj    = -0.8f;

					float mtx[16];
					bx::mtxSRT(mtx
							, scale/xend
							, scale/xend
							, scale/xend
							, 0.0f
							, 0.0f
							, 0.0f
							, 0.0f      + (xx/xend)*spacing - (1.0f + (scale-1.0f)*0.5f - 1.0f/xend)
							, yAdj/yend + (yy/yend)*spacing - (1.0f + (scale-1.0f)*0.5f - 1.0f/yend)
							, 0.0f
							);

					uniforms.m_glossiness   =        xx*(1.0f/xend);
					uniforms.m_reflectivity = (yend-yy)*(1.0f/yend);
					uniforms.m_metalOrSpec = 0.0f;
					uniforms.submit();

					bgfx::setTexture(0, s_texCube,    lightProbes[currentLightProbe].m_tex);
					bgfx::setTexture(1, s_texCubeIrr, lightProbes[currentLightProbe].m_texIrr);
					meshSubmit(meshOrb, 1, programMesh, mtx);
				}
			}
		}

		// Advance to next frame. Rendering thread will be kicked to
		// process submitted rendering primitives.
		bgfx::frame();
	}

	meshUnload(meshBunny);
	meshUnload(meshOrb);

	// Cleanup.
	bgfx::destroyProgram(programMesh);
	bgfx::destroyProgram(programSky);

	bgfx::destroyUniform(u_camPos);
	bgfx::destroyUniform(u_flags);
	bgfx::destroyUniform(u_params);
	bgfx::destroyUniform(u_mtx);

	bgfx::destroyUniform(s_texCube);
	bgfx::destroyUniform(s_texCubeIrr);

	for (uint8_t ii = 0; ii < LightProbe::Count; ++ii)
	{
		lightProbes[ii].destroy();
	}

	uniforms.destroy();

	imguiDestroy();

	// Shutdown bgfx.
	bgfx::shutdown();

	return 0;
}
Esempio n. 4
0
int _main_(int _argc, char** _argv)
{
	Args args(_argc, _argv);

	uint32_t width = 1280;
	uint32_t height = 720;
	uint32_t debug = BGFX_DEBUG_TEXT;
	uint32_t reset = BGFX_RESET_VSYNC;

	bgfx::init(args.m_type, args.m_pciId);
	bgfx::reset(width, height, reset);

	// Enable debug text.
	bgfx::setDebug(debug);

	// Set views  clear state.
	bgfx::setViewClear(0
		, BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH
		, 0x303030ff
		, 1.0f
		, 0
		);

	// Imgui.
	imguiCreate();

	// Uniforms.
	s_uniforms.init();

	// Vertex declarations.
	PosColorTexCoord0Vertex::init();

	LightProbe lightProbes[LightProbe::Count];
	lightProbes[LightProbe::Wells ].load("wells");
	lightProbes[LightProbe::Uffizi].load("uffizi");
	lightProbes[LightProbe::Pisa  ].load("pisa");
	lightProbes[LightProbe::Ennis ].load("ennis");
	lightProbes[LightProbe::Grace ].load("grace");
	LightProbe::Enum currentLightProbe = LightProbe::Wells;

	bgfx::UniformHandle u_mtx        = bgfx::createUniform("u_mtx",        bgfx::UniformType::Mat4);
	bgfx::UniformHandle u_params     = bgfx::createUniform("u_params",     bgfx::UniformType::Vec4);
	bgfx::UniformHandle u_flags      = bgfx::createUniform("u_flags",      bgfx::UniformType::Vec4);
	bgfx::UniformHandle u_camPos     = bgfx::createUniform("u_camPos",     bgfx::UniformType::Vec4);
	bgfx::UniformHandle s_texCube    = bgfx::createUniform("s_texCube",    bgfx::UniformType::Int1);
	bgfx::UniformHandle s_texCubeIrr = bgfx::createUniform("s_texCubeIrr", bgfx::UniformType::Int1);

	bgfx::ProgramHandle programMesh  = loadProgram("vs_ibl_mesh",   "fs_ibl_mesh");
	bgfx::ProgramHandle programSky   = loadProgram("vs_ibl_skybox", "fs_ibl_skybox");

	Mesh* meshBunny;
	meshBunny = meshLoad("meshes/bunny.bin");

	struct Settings
	{
		float m_speed;
		float m_glossiness;
		float m_exposure;
		float m_diffspec;
		float m_rgbDiff[3];
		float m_rgbSpec[3];
		bool m_diffuse;
		bool m_specular;
		bool m_diffuseIbl;
		bool m_specularIbl;
		bool m_showDiffColorWheel;
		bool m_showSpecColorWheel;
		ImguiCubemap::Enum m_crossCubemapPreview;
	};

	Settings settings;
	settings.m_speed = 0.37f;
	settings.m_glossiness = 1.0f;
	settings.m_exposure = 0.0f;
	settings.m_diffspec = 0.65f;
	settings.m_rgbDiff[0] = 0.2f;
	settings.m_rgbDiff[1] = 0.2f;
	settings.m_rgbDiff[2] = 0.2f;
	settings.m_rgbSpec[0] = 1.0f;
	settings.m_rgbSpec[1] = 1.0f;
	settings.m_rgbSpec[2] = 1.0f;
	settings.m_diffuse = true;
	settings.m_specular = true;
	settings.m_diffuseIbl = true;
	settings.m_specularIbl = true;
	settings.m_showDiffColorWheel = true;
	settings.m_showSpecColorWheel = false;
	settings.m_crossCubemapPreview = ImguiCubemap::Cross;

	float time = 0.0f;

	int32_t leftScrollArea = 0;

	entry::MouseState mouseState;
	while (!entry::processEvents(width, height, debug, reset, &mouseState) )
	{
		imguiBeginFrame(mouseState.m_mx
			, mouseState.m_my
			, (mouseState.m_buttons[entry::MouseButton::Left  ] ? IMGUI_MBUT_LEFT   : 0)
			| (mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT  : 0)
			| (mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0)
			, mouseState.m_mz
			, width
			, height
			);

		static int32_t rightScrollArea = 0;
		imguiBeginScrollArea("Settings", width - 256 - 10, 10, 256, 540, &rightScrollArea);

		imguiLabel("Shade:");
		imguiSeparator();
		imguiBool("Diffuse",      settings.m_diffuse);
		imguiBool("Specular",     settings.m_specular);
		imguiBool("IBL Diffuse",  settings.m_diffuseIbl);
		imguiBool("IBL Specular", settings.m_specularIbl);

		imguiSeparatorLine();
		imguiSlider("Speed", settings.m_speed, 0.0f, 1.0f, 0.01f);
		imguiSeparatorLine();

		imguiSeparator();
		imguiSlider("Exposure", settings.m_exposure, -8.0f, 8.0f, 0.01f);
		imguiSeparator();

		imguiLabel("Environment:");
		currentLightProbe = LightProbe::Enum(imguiChoose(currentLightProbe
													   , "Wells"
													   , "Uffizi"
													   , "Pisa"
													   , "Ennis"
													   , "Grace"
													   ) );
		static float lod = 0.0f;
		if (imguiCube(lightProbes[currentLightProbe].m_tex, lod, settings.m_crossCubemapPreview, true) )
		{
			settings.m_crossCubemapPreview = ImguiCubemap::Enum( (settings.m_crossCubemapPreview+1) % ImguiCubemap::Count);
		}
		imguiSlider("Texture LOD", lod, 0.0f, 10.1f, 0.1f);

		imguiEndScrollArea();

		imguiBeginScrollArea("Settings", 10, 70, 256, 576, &leftScrollArea);

		imguiLabel("Material properties:");
		imguiSeparator();
		imguiSlider("Diffuse - Specular", settings.m_diffspec,   0.0f, 1.0f, 0.01f);
		imguiSlider("Glossiness"        , settings.m_glossiness, 0.0f, 1.0f, 0.01f);
		imguiSeparator();

		imguiColorWheel("Diffuse color:", &settings.m_rgbDiff[0], settings.m_showDiffColorWheel);
		imguiSeparator();
		imguiColorWheel("Specular color:", &settings.m_rgbSpec[0], settings.m_showSpecColorWheel);

		imguiSeparator();
		imguiLabel("Predefined materials:");
		imguiSeparator();

		if (imguiButton("Gold") )
		{
			settings.m_glossiness = 0.8f;
			settings.m_diffspec   = 1.0f;

			settings.m_rgbDiff[0] = 0.0f;
			settings.m_rgbDiff[1] = 0.0f;
			settings.m_rgbDiff[2] = 0.0f;

			settings.m_rgbSpec[0] = 1.0f;
			settings.m_rgbSpec[1] = 0.86f;
			settings.m_rgbSpec[2] = 0.58f;
		}

		if (imguiButton("Copper") )
		{
			settings.m_glossiness = 0.67f;
			settings.m_diffspec   = 1.0f;

			settings.m_rgbDiff[0] = 0.0f;
			settings.m_rgbDiff[1] = 0.0f;
			settings.m_rgbDiff[2] = 0.0f;

			settings.m_rgbSpec[0] = 0.98f;
			settings.m_rgbSpec[1] = 0.82f;
			settings.m_rgbSpec[2] = 0.76f;
		}

		if (imguiButton("Titanium") )
		{
			settings.m_glossiness = 0.57f;
			settings.m_diffspec   = 1.0f;

			settings.m_rgbDiff[0] = 0.0f;
			settings.m_rgbDiff[1] = 0.0f;
			settings.m_rgbDiff[2] = 0.0f;

			settings.m_rgbSpec[0] = 0.76f;
			settings.m_rgbSpec[1] = 0.73f;
			settings.m_rgbSpec[2] = 0.71f;
		}

		if (imguiButton("Steel") )
		{
			settings.m_glossiness = 0.82f;
			settings.m_diffspec   = 1.0f;

			settings.m_rgbDiff[0] = 0.0f;
			settings.m_rgbDiff[1] = 0.0f;
			settings.m_rgbDiff[2] = 0.0f;

			settings.m_rgbSpec[0] = 0.77f;
			settings.m_rgbSpec[1] = 0.78f;
			settings.m_rgbSpec[2] = 0.77f;
		}

		imguiEndScrollArea();

		imguiEndFrame();

		s_uniforms.m_glossiness = settings.m_glossiness;
		s_uniforms.m_exposure = settings.m_exposure;
		s_uniforms.m_diffspec = settings.m_diffspec;
		s_uniforms.m_flags[0] = float(settings.m_diffuse);
		s_uniforms.m_flags[1] = float(settings.m_specular);
		s_uniforms.m_flags[2] = float(settings.m_diffuseIbl);
		s_uniforms.m_flags[3] = float(settings.m_specularIbl);
		memcpy(s_uniforms.m_rgbDiff, settings.m_rgbDiff, 3*sizeof(float) );
		memcpy(s_uniforms.m_rgbSpec, settings.m_rgbSpec, 3*sizeof(float) );

		s_uniforms.submitPerFrameUniforms();

		int64_t now = bx::getHPCounter();
		static int64_t last = now;
		const int64_t frameTime = now - last;
		last = now;
		const double freq = double(bx::getHPFrequency() );
		const double toMs = 1000.0/freq;

		time += (float)(frameTime*settings.m_speed/freq);
		s_uniforms.m_camPosTime[3] = time;

		// Use debug font to print information about this example.
		bgfx::dbgTextClear();
		bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/18-ibl");
		bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: Image based lightning.");
		bgfx::dbgTextPrintf(0, 3, 0x0f, "Frame: % 7.3f[ms]", double(frameTime)*toMs);

		float at[3] = { 0.0f, 0.0f, 0.0f };
		float eye[3] = { 0.0f, 0.0f, -3.0f };

		bx::mtxRotateXY(s_uniforms.m_mtx
			, 0.0f
			, time
			);

		float view[16];
		float proj[16];

		bx::mtxIdentity(view);
		bx::mtxOrtho(proj, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f);
		bgfx::setViewTransform(0, view, proj);

		bx::mtxLookAt(view, eye, at);
		memcpy(s_uniforms.m_camPosTime, eye, 3*sizeof(float) );
		bx::mtxProj(proj, 60.0f, float(width)/float(height), 0.1f, 100.0f);
		bgfx::setViewTransform(1, view, proj);

		bgfx::setViewRect(0, 0, 0, width, height);
		bgfx::setViewRect(1, 0, 0, width, height);

		// View 0.
		bgfx::setTexture(0, s_texCube, lightProbes[currentLightProbe].m_tex);
		bgfx::setState(BGFX_STATE_RGB_WRITE|BGFX_STATE_ALPHA_WRITE);
		screenSpaceQuad( (float)width, (float)height, true);
		s_uniforms.submitPerDrawUniforms();
		bgfx::submit(0, programSky);

		// View 1.
		float mtx[16];
		bx::mtxSRT(mtx
				, 1.0f
				, 1.0f
				, 1.0f
				, 0.0f
				, bx::pi+time
				, 0.0f
				, 0.0f
				, -1.0f
				, 0.0f
				);

		bgfx::setTexture(0, s_texCube,    lightProbes[currentLightProbe].m_tex);
		bgfx::setTexture(1, s_texCubeIrr, lightProbes[currentLightProbe].m_texIrr);
		meshSubmit(meshBunny, 1, programMesh, mtx);

		// Advance to next frame. Rendering thread will be kicked to
		// process submitted rendering primitives.
		bgfx::frame();
	}

	meshUnload(meshBunny);

	// Cleanup.
	bgfx::destroyProgram(programMesh);
	bgfx::destroyProgram(programSky);

	bgfx::destroyUniform(u_camPos);
	bgfx::destroyUniform(u_flags);
	bgfx::destroyUniform(u_params);
	bgfx::destroyUniform(u_mtx);

	bgfx::destroyUniform(s_texCube);
	bgfx::destroyUniform(s_texCubeIrr);

	for (uint8_t ii = 0; ii < LightProbe::Count; ++ii)
	{
		lightProbes[ii].destroy();
	}

	s_uniforms.destroy();

	imguiDestroy();

	// Shutdown bgfx.
	bgfx::shutdown();

	return 0;
}
Esempio n. 5
0
int _main_(int /*_argc*/, char** /*_argv*/)
{
	uint32_t width  = 1280;
	uint32_t height = 720;
	uint32_t debug  = BGFX_DEBUG_TEXT;
	uint32_t reset  = BGFX_RESET_VSYNC;

	bgfx::init();
	bgfx::reset(width, height, reset);

	// Enable debug text.
	bgfx::setDebug(debug);

	// Set view 0 clear state.
	bgfx::setViewClear(0
		, BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH
		, 0x303030ff
		, 1.0f
		, 0
		);

	const bgfx::Caps* caps = bgfx::getCaps();
	const bool computeSupported  = !!(caps->supported & BGFX_CAPS_COMPUTE);
	const bool indirectSupported = !!(caps->supported & BGFX_CAPS_DRAW_INDIRECT);

	if (computeSupported)
	{
		// Imgui.
		imguiCreate();

		bgfx::VertexDecl quadVertexDecl;
		quadVertexDecl.begin()
			.add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float)
			.end();

		// Create static vertex buffer.
		bgfx::VertexBufferHandle vbh = bgfx::createVertexBuffer(
				// Static data can be passed with bgfx::makeRef
				bgfx::makeRef(s_quadVertices, sizeof(s_quadVertices) )
				, quadVertexDecl
				);

		// Create static index buffer.
		bgfx::IndexBufferHandle ibh = bgfx::createIndexBuffer(
				// Static data can be passed with bgfx::makeRef
				bgfx::makeRef(s_quadIndices, sizeof(s_quadIndices) )
				);

		// Create particle program from shaders.
		bgfx::ProgramHandle particleProgram = loadProgram("vs_particle", "fs_particle");

		// Setup compute buffers
		bgfx::VertexDecl computeVertexDecl;
		computeVertexDecl.begin()
			.add(bgfx::Attrib::TexCoord0, 4, bgfx::AttribType::Float)
			.end();

		const uint32_t threadGroupUpdateSize = 512;
		const uint32_t maxParticleCount = 32 * 1024;

		bgfx::DynamicVertexBufferHandle currPositionBuffer0 = bgfx::createDynamicVertexBuffer(1 << 15, computeVertexDecl, BGFX_BUFFER_COMPUTE_READ_WRITE);
		bgfx::DynamicVertexBufferHandle currPositionBuffer1 = bgfx::createDynamicVertexBuffer(1 << 15, computeVertexDecl, BGFX_BUFFER_COMPUTE_READ_WRITE);
		bgfx::DynamicVertexBufferHandle prevPositionBuffer0 = bgfx::createDynamicVertexBuffer(1 << 15, computeVertexDecl, BGFX_BUFFER_COMPUTE_READ_WRITE);
		bgfx::DynamicVertexBufferHandle prevPositionBuffer1 = bgfx::createDynamicVertexBuffer(1 << 15, computeVertexDecl, BGFX_BUFFER_COMPUTE_READ_WRITE);

		bgfx::UniformHandle u_params = bgfx::createUniform("u_params", bgfx::UniformType::Vec4, 3);

		bgfx::ProgramHandle initInstancesProgram   = bgfx::createProgram(loadShader("cs_init_instances"), true);
		bgfx::ProgramHandle updateInstancesProgram = bgfx::createProgram(loadShader("cs_update_instances"), true);

		bgfx::ProgramHandle indirectProgram       = BGFX_INVALID_HANDLE;
		bgfx::IndirectBufferHandle indirectBuffer = BGFX_INVALID_HANDLE;

		if (indirectSupported)
		{
			indirectProgram = bgfx::createProgram(loadShader("cs_indirect"), true);
			indirectBuffer  = bgfx::createIndirectBuffer(2);
		}

		u_paramsDataStruct u_paramsData;
		InitializeParams(0, &u_paramsData);

		bgfx::setUniform(u_params, &u_paramsData, 3);
		bgfx::setBuffer(0, prevPositionBuffer0, bgfx::Access::Write);
		bgfx::setBuffer(1, currPositionBuffer0, bgfx::Access::Write);
		bgfx::dispatch(0, initInstancesProgram, maxParticleCount / threadGroupUpdateSize, 1, 1);

		float view[16];
		float initialPos[3] = { 0.0f, 0.0f, -45.0f };
		cameraCreate();
		cameraSetPosition(initialPos);
		cameraSetVerticalAngle(0.0f);
		cameraGetViewMtx(view);

		int32_t scrollArea = 0;

		bool useIndirect = false;

		entry::MouseState mouseState;
		while (!entry::processEvents(width, height, debug, reset, &mouseState) )
		{
			int64_t now = bx::getHPCounter();
			static int64_t last = now;
			const int64_t frameTime = now - last;
			last = now;
			const double freq = double(bx::getHPFrequency() );
			const float deltaTime = float(frameTime/freq);

			if (deltaTime > 1000.0)
			{
				abort();
			}

			// Set view 0 default viewport.
			bgfx::setViewRect(0, 0, 0, width, height);

			// Use debug font to print information about this example.
			bgfx::dbgTextClear();
			bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/24-nbody");
			bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: N-body simulation with compute shaders using buffers.");

			imguiBeginFrame(mouseState.m_mx
					, mouseState.m_my
					, (mouseState.m_buttons[entry::MouseButton::Left  ] ? IMGUI_MBUT_LEFT  : 0)
					| (mouseState.m_buttons[entry::MouseButton::Right ] ? IMGUI_MBUT_RIGHT : 0)
					, mouseState.m_mz
					, width
					, height
					);
			imguiBeginScrollArea("Settings", width - width / 4 - 10, 10, width / 4, 500, &scrollArea);
			imguiSlider("Random seed", u_paramsData.baseSeed, 0, 100);
			int32_t shape = imguiChoose(u_paramsData.initialShape, "Point", "Sphere", "Box", "Donut");
			imguiSlider("Initial speed", u_paramsData.initialSpeed, 0.0f, 300.0f, 0.1f);
			bool defaults = imguiButton("Reset");
			imguiSeparatorLine();
			imguiSlider("Particle count (x512)", u_paramsData.dispatchSize, 1, 64);
			imguiSlider("Gravity", u_paramsData.gravity, 0.0f, 0.3f, 0.001f);
			imguiSlider("Damping", u_paramsData.damping, 0.0f, 1.0f, 0.01f);
			imguiSlider("Max acceleration", u_paramsData.maxAccel, 0.0f, 100.0f, 0.01f);
			imguiSlider("Time step", u_paramsData.timeStep, 0.0f, 0.02f, 0.0001f);
			imguiSeparatorLine();
			imguiSlider("Particle intensity", u_paramsData.particleIntensity, 0.0f, 1.0f, 0.001f);
			imguiSlider("Particle size", u_paramsData.particleSize, 0.0f, 1.0f, 0.001f);
			imguiSlider("Particle power", u_paramsData.particlePower, 0.001f, 16.0f, 0.01f);
			imguiSeparatorLine();
			if (imguiCheck("Use draw/dispatch indirect", useIndirect, indirectSupported) )
			{
				useIndirect = !useIndirect;
			}
			imguiEndScrollArea();
			imguiEndFrame();

			// Modify parameters and reset if shape is changed
			if (shape != u_paramsData.initialShape)
			{
				defaults = true;
				InitializeParams(shape, &u_paramsData);
			}

			if (defaults)
			{
				bgfx::setBuffer(0, prevPositionBuffer0, bgfx::Access::Write);
				bgfx::setBuffer(1, currPositionBuffer0, bgfx::Access::Write);
				bgfx::setUniform(u_params, &u_paramsData, 3);
				bgfx::dispatch(0, initInstancesProgram, maxParticleCount / threadGroupUpdateSize, 1, 1);
			}

			if (useIndirect)
			{
				bgfx::setUniform(u_params, &u_paramsData, 3);
				bgfx::setBuffer(0, indirectBuffer, bgfx::Access::Write);
				bgfx::dispatch(0, indirectProgram);
			}

			bgfx::setBuffer(0, prevPositionBuffer0, bgfx::Access::Read);
			bgfx::setBuffer(1, currPositionBuffer0, bgfx::Access::Read);
			bgfx::setBuffer(2, prevPositionBuffer1, bgfx::Access::Write);
			bgfx::setBuffer(3, currPositionBuffer1, bgfx::Access::Write);
			bgfx::setUniform(u_params, &u_paramsData, 3);

			if (useIndirect)
			{
				bgfx::dispatch(0, updateInstancesProgram, indirectBuffer, 1);
			}
			else
			{
				bgfx::dispatch(0, updateInstancesProgram, u_paramsData.dispatchSize, 1, 1);
			}

			bx::xchg(currPositionBuffer0, currPositionBuffer1);
			bx::xchg(prevPositionBuffer0, prevPositionBuffer1);

			// Update camera.
			cameraUpdate(deltaTime, mouseState);
			cameraGetViewMtx(view);

			// Set view and projection matrix for view 0.
			const bgfx::HMD* hmd = bgfx::getHMD();
			if (NULL != hmd && 0 != (hmd->flags & BGFX_HMD_RENDERING) )
			{
				float viewHead[16];
				float eye[3] = {};
				bx::mtxQuatTranslationHMD(viewHead, hmd->eye[0].rotation, eye);

				float tmp[16];
				bx::mtxMul(tmp, view, viewHead);

				float proj[16];
				bx::mtxProj(proj, hmd->eye[0].fov, 0.1f, 10000.0f);

				bgfx::setViewTransform(0, tmp, proj);

				// Set view 0 default viewport.
				//
				// Use HMD's width/height since HMD's internal frame buffer size
				// might be much larger than window size.
				bgfx::setViewRect(0, 0, 0, hmd->width, hmd->height);
			}
			else
			{
				float proj[16];
				bx::mtxProj(proj, 90.0f, float(width)/float(height), 0.1f, 10000.0f);
				bgfx::setViewTransform(0, view, proj);

				// Set view 0 default viewport.
				bgfx::setViewRect(0, 0, 0, width, height);
			}

			// Set vertex and index buffer.
			bgfx::setVertexBuffer(vbh);
			bgfx::setIndexBuffer(ibh);
			bgfx::setInstanceDataBuffer(currPositionBuffer0, 0, u_paramsData.dispatchSize * threadGroupUpdateSize);

			// Set render states.
			bgfx::setState(0
					| BGFX_STATE_RGB_WRITE
					| BGFX_STATE_BLEND_ADD
					| BGFX_STATE_DEPTH_TEST_ALWAYS
					);

			// Submit primitive for rendering to view 0.
			if (useIndirect)
			{
				bgfx::submit(0, particleProgram, indirectBuffer, 0);
			}
			else
			{
				bgfx::submit(0, particleProgram);
			}

			// Advance to next frame. Rendering thread will be kicked to
			// process submitted rendering primitives.
			bgfx::frame();
		}

		// Cleanup.
		cameraDestroy();
		imguiDestroy();

		if (indirectSupported)
		{
			bgfx::destroyProgram(indirectProgram);
			bgfx::destroyIndirectBuffer(indirectBuffer);
		}


		bgfx::destroyUniform(u_params);
		bgfx::destroyDynamicVertexBuffer(currPositionBuffer0);
		bgfx::destroyDynamicVertexBuffer(currPositionBuffer1);
		bgfx::destroyDynamicVertexBuffer(prevPositionBuffer0);
		bgfx::destroyDynamicVertexBuffer(prevPositionBuffer1);
		bgfx::destroyProgram(updateInstancesProgram);
		bgfx::destroyProgram(initInstancesProgram);
		bgfx::destroyIndexBuffer(ibh);
		bgfx::destroyVertexBuffer(vbh);
		bgfx::destroyProgram(particleProgram);
	}
	else
	{
		int64_t timeOffset = bx::getHPCounter();

		entry::MouseState mouseState;
		while (!entry::processEvents(width, height, debug, reset, &mouseState) )
		{
			int64_t now = bx::getHPCounter();
			float time = (float)( (now - timeOffset)/double(bx::getHPFrequency() ) );

			bgfx::setViewRect(0, 0, 0, width, height);

			bgfx::dbgTextClear();
			bgfx::dbgTextPrintf(0, 1, 0x4f, "bgfx/examples/24-nbody");
			bgfx::dbgTextPrintf(0, 2, 0x6f, "Description: N-body simulation with compute shaders using buffers.");

			bool blink = uint32_t(time*3.0f)&1;
			bgfx::dbgTextPrintf(0, 5, blink ? 0x1f : 0x01, " Compute is not supported by GPU. ");

			bgfx::touch(0);
			bgfx::frame();
		}
	}

	// Shutdown bgfx.
	bgfx::shutdown();

	return 0;
}