add hello world example and edit source tree
This commit is contained in:
		
							
								
								
									
										493
									
								
								examples/testbed/framework/main.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										493
									
								
								examples/testbed/framework/main.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,493 @@ | ||||
| /* | ||||
| * Copyright (c) 2016-2016 Irlan Robson http://www.irlan.net | ||||
| * | ||||
| * This software is provided 'as-is', without any express or implied | ||||
| * warranty.  In no event will the authors be held liable for any damages | ||||
| * arising from the use of this software. | ||||
| * Permission is granted to anyone to use this software for any purpose, | ||||
| * including commercial applications, and to alter it and redistribute it | ||||
| * freely, subject to the following restrictions: | ||||
| * 1. The origin of this software must not be misrepresented; you must not | ||||
| * claim that you wrote the original software. If you use this software | ||||
| * in a product, an acknowledgment in the product documentation would be | ||||
| * appreciated but is not required. | ||||
| * 2. Altered source versions must be plainly marked as such, and must not be | ||||
| * misrepresented as being the original software. | ||||
| * 3. This notice may not be removed or altered from any source distribution. | ||||
| */ | ||||
|  | ||||
| #include <glad/glad.h> | ||||
| #include <glfw/glfw3.h> | ||||
| #include <imgui/imgui.h> | ||||
| #include <imgui/imgui_impl_glfw_gl3.h> | ||||
|  | ||||
| #include <testbed/tests/test.h> | ||||
|  | ||||
| GLFWwindow* g_window; | ||||
| Settings g_settings; | ||||
| Test* g_test; | ||||
| u32 g_testCount; | ||||
| Camera g_camera; | ||||
| DebugDraw* g_debugDraw; | ||||
| Profiler* g_profiler; | ||||
| bool g_leftDown; | ||||
| bool g_rightDown; | ||||
| bool g_shiftDown; | ||||
| b3Vec2 g_ps0; | ||||
|  | ||||
| void WindowSize(int w, int h) | ||||
| { | ||||
| 	g_camera.m_width = float32(w); | ||||
| 	g_camera.m_height = float32(h); | ||||
| } | ||||
|  | ||||
| void MouseMove(GLFWwindow* w, double x, double y) | ||||
| { | ||||
| 	b3Vec2 ps; | ||||
| 	ps.Set(float32(x), float32(y)); | ||||
|  | ||||
| 	b3Vec2 dp = ps - g_ps0; | ||||
| 	g_ps0 = ps; | ||||
|  | ||||
| 	Ray3 pw = g_camera.ConvertScreenToWorld(ps); | ||||
|  | ||||
| 	float32 nx = b3Clamp(dp.x, -1.0f, 1.0f); | ||||
| 	float32 ny = b3Clamp(dp.y, -1.0f, 1.0f); | ||||
|  | ||||
| 	if (g_shiftDown) | ||||
| 	{ | ||||
| 		if (g_leftDown) | ||||
| 		{ | ||||
| 			// Negate angles to do positive rotations (CCW) of the world. | ||||
| 			float32 angleX = 0.005f * B3_PI * -nx; | ||||
| 			float32 angleY = 0.005f * B3_PI * -ny; | ||||
|  | ||||
| 			b3Quat qx(b3Vec3(1.0f, 0.0f, 0.0f), angleY); | ||||
| 			b3Quat qy(b3Vec3(0.0f, 1.0f, 0.0f), angleX); | ||||
|  | ||||
| 			g_camera.m_q = qy * g_camera.m_q; | ||||
| 			g_camera.m_q = g_camera.m_q * qx; | ||||
| 			g_camera.m_q.Normalize(); | ||||
| 		} | ||||
|  | ||||
| 		if (g_rightDown) | ||||
| 		{ | ||||
| 			b3Transform xf = g_camera.BuildWorldTransform(); | ||||
| 			g_camera.m_center += 0.2f * nx * xf.rotation.x; | ||||
| 			g_camera.m_center += 0.2f * -ny * xf.rotation.y; | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		g_test->MouseMove(pw); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void MouseWheel(GLFWwindow* w, double dx, double dy) | ||||
| { | ||||
| 	float32 n = b3Clamp(float32(dy), -1.0f, 1.0f); | ||||
| 	if (g_shiftDown) | ||||
| 	{ | ||||
| 		g_camera.m_zoom += 0.5f * -n; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void MouseButton(GLFWwindow* w, int button, int action, int mods) | ||||
| { | ||||
| 	double x, y; | ||||
| 	glfwGetCursorPos(w, &x, &y); | ||||
| 	b3Vec2 p; | ||||
| 	p.Set(float32(x), float32(y)); | ||||
|  | ||||
| 	Ray3 pw = g_camera.ConvertScreenToWorld(p); | ||||
|  | ||||
| 	switch (action) | ||||
| 	{ | ||||
| 	case GLFW_PRESS: | ||||
| 	{ | ||||
| 		if (button == GLFW_MOUSE_BUTTON_LEFT) | ||||
| 		{ | ||||
| 			g_leftDown = true; | ||||
|  | ||||
| 			if (g_shiftDown == false) | ||||
| 			{ | ||||
| 				g_test->MouseLeftDown(pw); | ||||
| 			} | ||||
| 		} | ||||
| 		 | ||||
| 		if (button == GLFW_MOUSE_BUTTON_RIGHT) | ||||
| 		{ | ||||
| 			g_rightDown = true; | ||||
| 		} | ||||
|  | ||||
| 		break; | ||||
| 	} | ||||
| 	case GLFW_RELEASE: | ||||
| 	{ | ||||
| 		if (button == GLFW_MOUSE_BUTTON_LEFT) | ||||
| 		{ | ||||
| 			g_leftDown = false; | ||||
|  | ||||
| 			if (g_shiftDown == false) | ||||
| 			{ | ||||
| 				g_test->MouseLeftUp(pw); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (button == GLFW_MOUSE_BUTTON_RIGHT) | ||||
| 		{ | ||||
| 			g_rightDown = false; | ||||
| 		} | ||||
| 		break; | ||||
| 	} | ||||
| 	default: | ||||
| 	{ | ||||
| 		break; | ||||
| 	} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void KeyButton(GLFWwindow* w, int button, int scancode, int action, int mods) | ||||
| { | ||||
| 	switch (action) | ||||
| 	{ | ||||
| 	case GLFW_PRESS: | ||||
| 	{ | ||||
| 		if (button == GLFW_KEY_LEFT_SHIFT) | ||||
| 		{ | ||||
| 			g_shiftDown = true; | ||||
| 			g_test->KeyDown(button); | ||||
| 		} | ||||
|  | ||||
| 		if (g_shiftDown) | ||||
| 		{ | ||||
| 			if (button == GLFW_KEY_DOWN) | ||||
| 			{ | ||||
| 				g_camera.m_zoom += 0.05f; | ||||
| 			} | ||||
|  | ||||
| 			if (button == GLFW_KEY_UP) | ||||
| 			{ | ||||
| 				g_camera.m_zoom -= 0.05f; | ||||
| 			} | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			g_test->KeyDown(button); | ||||
| 		} | ||||
| 		 | ||||
| 		break; | ||||
| 	} | ||||
| 	case GLFW_RELEASE: | ||||
| 	{ | ||||
| 		if (button == GLFW_KEY_LEFT_SHIFT) | ||||
| 		{ | ||||
| 			g_shiftDown = false; | ||||
| 		} | ||||
|  | ||||
| 		if (g_shiftDown == false) | ||||
| 		{ | ||||
| 			g_test->KeyUp(button); | ||||
| 		} | ||||
|  | ||||
| 		break; | ||||
| 	} | ||||
| 	default: | ||||
| 	{ | ||||
| 		break; | ||||
| 	} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void Char(GLFWwindow* w, unsigned int codepoint) | ||||
| { | ||||
| 	ImGui_ImplGlfwGL3_CharCallback(w, codepoint); | ||||
| } | ||||
|  | ||||
| void CreateInterface() | ||||
| { | ||||
| 	ImGui_ImplGlfwGL3_Init(g_window, false); | ||||
| 	ImGuiIO& io = ImGui::GetIO(); | ||||
| 	io.Fonts[0].AddFontDefault(); | ||||
| } | ||||
|  | ||||
| void DestroyInterface() | ||||
| { | ||||
| 	ImGui_ImplGlfwGL3_Shutdown(); | ||||
| } | ||||
|  | ||||
| bool GetTestName(void*, int idx, const char** name) | ||||
| { | ||||
| 	*name = g_tests[idx].name; | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void Interface() | ||||
| { | ||||
| 	ImGui::SetNextWindowPos(ImVec2(g_camera.m_width, 0.0f)); | ||||
| 	ImGui::SetNextWindowSize(ImVec2(250.0f, g_camera.m_height)); | ||||
| 	ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); | ||||
| 	 | ||||
| 	ImGui::Begin("Controls", NULL, ImVec2(0.0f, 0.0f), 0.25f, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); | ||||
|  | ||||
| 	ImGui::PushItemWidth(-1.0f); | ||||
|  | ||||
| 	ImGui::Text("Test"); | ||||
| 	if (ImGui::Combo("##Test", &g_settings.testID, GetTestName, NULL, g_testCount, g_testCount)) | ||||
| 	{ | ||||
| 		delete g_test; | ||||
| 		g_test = g_tests[g_settings.testID].create(); | ||||
| 		g_settings.lastTestID = -1; | ||||
| 	} | ||||
|  | ||||
| 	ImVec2 buttonSize = ImVec2(-1, 0); | ||||
| 	if (ImGui::Button("Restart", buttonSize)) | ||||
| 	{ | ||||
| 		g_settings.lastTestID = -1; | ||||
| 	} | ||||
| 	if (ImGui::Button("Previous", buttonSize)) | ||||
| 	{ | ||||
| 		g_settings.testID = b3Clamp(g_settings.testID - 1, 0, int(g_testCount) - 1); | ||||
| 		g_settings.lastTestID = -1; | ||||
| 	} | ||||
| 	if (ImGui::Button("Next", buttonSize)) | ||||
| 	{ | ||||
| 		g_settings.testID = b3Clamp(g_settings.testID + 1, 0, int(g_testCount) - 1); | ||||
| 		g_settings.lastTestID = -1; | ||||
| 	} | ||||
| 	if (ImGui::Button("Exit", buttonSize)) | ||||
| 	{ | ||||
| 		glfwSetWindowShouldClose(g_window, true); | ||||
| 	} | ||||
|  | ||||
| 	ImGui::Separator(); | ||||
|  | ||||
| 	ImGui::Text("Step"); | ||||
|  | ||||
| 	ImGui::Text("Hertz"); | ||||
| 	ImGui::SliderFloat("##Hertz", &g_settings.hertz, 0.0f, 240.0f, "%.1f"); | ||||
| 	ImGui::Text("Velocity Iterations"); | ||||
| 	ImGui::SliderInt("##Velocity Iterations", &g_settings.velocityIterations, 0, 50); | ||||
| 	ImGui::Text("Position Iterations"); | ||||
| 	ImGui::SliderInt("#Position Iterations", &g_settings.positionIterations, 0, 50); | ||||
| 	ImGui::Checkbox("Sleep", &g_settings.sleep); | ||||
| 	ImGui::Checkbox("Warm Start", &g_settings.warmStart); | ||||
| 	//ImGui::Checkbox("Convex Cache", &g_settings.convexCache); | ||||
|  | ||||
| 	if (ImGui::Button("Play/Pause", buttonSize)) | ||||
| 	{ | ||||
| 		g_settings.pause = !g_settings.pause; | ||||
| 	} | ||||
| 	if (ImGui::Button("Single Step", buttonSize)) | ||||
| 	{ | ||||
| 		g_settings.pause = true; | ||||
| 		g_settings.singleStep = true; | ||||
| 	} | ||||
|  | ||||
| 	ImGui::Separator(); | ||||
|  | ||||
| 	ImGui::Text("View"); | ||||
| 	ImGui::Checkbox("Grid", &g_settings.drawGrid); | ||||
| 	ImGui::Checkbox("Vertices and Edges", &g_settings.drawVerticesEdges); | ||||
| 	ImGui::Checkbox("Faces", &g_settings.drawFaces); | ||||
| 	ImGui::Checkbox("Center of Masses", &g_settings.drawCenterOfMasses); | ||||
| 	ImGui::Checkbox("Bounding Boxes", &g_settings.drawBounds); | ||||
| 	ImGui::Checkbox("Joints", &g_settings.drawJoints); | ||||
| 	ImGui::Checkbox("Contact Points", &g_settings.drawContactPoints); | ||||
| 	ImGui::Checkbox("Contact Normals", &g_settings.drawContactNormals); | ||||
| 	ImGui::Checkbox("Contact Tangents", &g_settings.drawContactTangents); | ||||
| 	ImGui::Checkbox("Statistics", &g_settings.drawStats); | ||||
| 	ImGui::Checkbox("Profile", &g_settings.drawProfile); | ||||
|  | ||||
| 	ImGui::End(); | ||||
| 	ImGui::PopStyleVar(); | ||||
| } | ||||
|  | ||||
| void Step() | ||||
| { | ||||
| 	if (g_settings.drawGrid) | ||||
| 	{ | ||||
| 		int n = 20; | ||||
|  | ||||
| 		b3Vec3 t; | ||||
| 		t.x = -0.5f * float32(n); | ||||
| 		t.y = 0.0f; | ||||
| 		t.z = -0.5f * float32(n); | ||||
|  | ||||
| 		b3Color color(0.5f, 0.5f, 0.5f, 1.0f); | ||||
| 		for (int i = 0; i < n; i += 1) | ||||
| 		{ | ||||
| 			for (int j = 0; j < n; j += 1) | ||||
| 			{ | ||||
| 				b3Vec3 vs[4]; | ||||
| 				vs[0] = b3Vec3((float)i, 0.0f, (float)j); | ||||
| 				vs[1] = b3Vec3((float)i, 0.0f, (float)j + 1); | ||||
| 				vs[2] = b3Vec3((float)i + 1, 0.0f, (float)j + 1); | ||||
| 				vs[3] = b3Vec3((float)i + 1, 0.0f, (float)j); | ||||
|  | ||||
| 				for (u32 k = 0; k < 4; ++k) | ||||
| 				{ | ||||
| 					vs[k] += t; | ||||
| 				} | ||||
|  | ||||
| 				g_debugDraw->DrawPolygon(vs, 4, color); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (g_settings.testID != g_settings.lastTestID) | ||||
| 	{ | ||||
| 		delete g_test; | ||||
| 		g_settings.lastTestID = g_settings.testID; | ||||
| 		g_test = g_tests[g_settings.testID].create(); | ||||
| 		g_settings.pause = true; | ||||
| 	} | ||||
| 	 | ||||
| 	g_test->Step();	 | ||||
| 	g_debugDraw->Submit(); | ||||
| } | ||||
|  | ||||
| void Run() | ||||
| { | ||||
| 	glFrontFace(GL_CCW); | ||||
| 	glCullFace(GL_BACK); | ||||
| 	glEnable(GL_CULL_FACE); | ||||
| 	glEnable(GL_DEPTH_TEST); | ||||
| 	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | ||||
| 	glEnable(GL_BLEND); | ||||
|  | ||||
| 	glClearColor(0.2f, 0.2f, 0.2f, 1.0f); | ||||
| 	glClearDepth(1.0f); | ||||
|  | ||||
| 	double t1 = glfwGetTime(); | ||||
| 	double frameTime = 0.0; | ||||
|  | ||||
| 	while (glfwWindowShouldClose(g_window) == 0) | ||||
| 	{ | ||||
| 		int width, height; | ||||
| 		glfwGetWindowSize(g_window, &width, &height); | ||||
| 		g_camera.m_width = float32(width) - 250.0f; | ||||
| 		g_camera.m_height = float32(height); | ||||
|  | ||||
| 		glViewport(0, 0, width - 250, height); | ||||
| 		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||||
| 		 | ||||
| 		ImGui_ImplGlfwGL3_NewFrame(); | ||||
| 		 | ||||
| 		ImGui::SetNextWindowPos(ImVec2(0, 0)); | ||||
| 		ImGui::SetNextWindowSize(ImVec2((float)g_camera.m_width, (float)g_camera.m_height)); | ||||
| 		ImGui::Begin("Overlay", NULL, ImVec2(0, 0), 0.0f, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoScrollbar); | ||||
| 		ImGui::SetCursorPos(ImVec2(5, (float)g_camera.m_height - 20)); | ||||
| 		ImGui::Text("%.1f ms", 1000.0 * frameTime); | ||||
| 		ImGui::End(); | ||||
|  | ||||
| 		Interface(); | ||||
| 		Step(); | ||||
|  | ||||
| 		double t = glfwGetTime(); | ||||
| 		frameTime = t - t1; | ||||
| 		t1 = t; | ||||
|  | ||||
| 		ImGui::Render(); | ||||
|  | ||||
| 		glfwSwapBuffers(g_window); | ||||
|  | ||||
| 		glfwPollEvents(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| int main(int argc, char** args) | ||||
| { | ||||
| #if defined(_WIN32) | ||||
| 	// Report memory leaks | ||||
| 	_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)); | ||||
| #endif | ||||
|  | ||||
| 	if (glfwInit() == 0) | ||||
| 	{ | ||||
| 		fprintf(stderr, "Failed to initialize GLFW\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	 | ||||
| 	// Create window | ||||
| 	extern b3Version b3_version; | ||||
| 	char title[256]; | ||||
| 	sprintf(title, "Bounce Testbed Version %d.%d.%d", b3_version.major, b3_version.minor, b3_version.revision); | ||||
|  | ||||
| #if defined(__APPLE__) | ||||
| 	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); | ||||
| 	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0); | ||||
| 	glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); | ||||
| 	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | ||||
| #endif | ||||
| 		 | ||||
| 	g_window = glfwCreateWindow(1024, 768, title, NULL, NULL); | ||||
| 	if (g_window == NULL) | ||||
| 	{		 | ||||
| 		fprintf(stderr, "Failed to open GLFW window\n"); | ||||
| 		glfwTerminate(); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	 | ||||
| 	glfwMakeContextCurrent(g_window); | ||||
| 	glfwSetCursorPosCallback(g_window, MouseMove); | ||||
| 	glfwSetScrollCallback(g_window, MouseWheel); | ||||
| 	glfwSetMouseButtonCallback(g_window, MouseButton); | ||||
| 	glfwSetKeyCallback(g_window, KeyButton); | ||||
| 	glfwSetCharCallback(g_window, Char); | ||||
| 	glfwSwapInterval(1); | ||||
| 	 | ||||
| 	if (gladLoadGL() == 0) | ||||
| 	{ | ||||
| 		fprintf(stderr, "Failed to load OpenGL extensions\n"); | ||||
| 		fprintf(stderr, "Error: %d\n", glad_glGetError()); | ||||
| 		glfwTerminate(); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	printf("OpenGL %s, GLSL %s\n", glGetString(GL_VERSION), glGetString(GL_SHADING_LANGUAGE_VERSION)); | ||||
| 	 | ||||
| 	g_leftDown = false; | ||||
| 	g_rightDown = false; | ||||
| 	g_shiftDown = false; | ||||
| 	g_ps0.SetZero(); | ||||
|  | ||||
| 	// Create UI | ||||
| 	CreateInterface(); | ||||
|  | ||||
| 	// Create profiler | ||||
| 	g_profiler = new Profiler(); | ||||
|  | ||||
| 	// Create renderer | ||||
| 	g_debugDraw = new DebugDraw(); | ||||
|  | ||||
| 	// Run the testbed | ||||
| 	g_testCount = 0; | ||||
| 	while (g_tests[g_testCount].create != NULL) | ||||
| 	{ | ||||
| 		++g_testCount; | ||||
| 	} | ||||
| 	g_test = NULL; | ||||
|  | ||||
| 	Run(); | ||||
|  | ||||
| 	// Destroy the last test | ||||
| 	if (g_test) | ||||
| 	{ | ||||
| 		delete g_test; | ||||
| 		g_test = NULL; | ||||
| 	} | ||||
|  | ||||
| 	// Destroy renderer | ||||
| 	delete g_debugDraw; | ||||
|  | ||||
| 	// Destroy profiler | ||||
| 	delete g_profiler; | ||||
|  | ||||
| 	// Destroy UI | ||||
| 	DestroyInterface(); | ||||
|  | ||||
| 	// Destroy g_window | ||||
| 	glfwTerminate(); | ||||
| 	return 0; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user