Esempio n. 1
3
/**
 \brief Draw a target circle and threshold along with the current pad position.
 \param idX the ID of the horizontal axis
 \param idY the ID of the vertical axis
 \param axesValues the axes raw values
 \param threshRadius the radius of the filtering threshold
 \ingroup ControllerTest
 */
void drawPadTarget(const int idX, const int idY, const std::vector<float> & axesValues, const float threshRadius){
	const ImU32 whiteColor = IM_COL32(255,255,255, 255);
	const int aidRX = idX;
	const int aidRY = idY;
	const float magRX = aidRX >= 0 ? axesValues[aidRX] : 0.0f;
	const float magRY = aidRY >= 0 ? axesValues[aidRY] : 0.0f;
	// Detect overflow on each axis.
	const bool overflow = (std::abs(magRX) > 1.0) || (std::abs(magRY) > 1.0);
	// Get current rendering position on screen.
	const ImVec2 posR = ImGui::GetCursorScreenPos();
	ImDrawList * drawListR = ImGui::GetWindowDrawList();
	// Draw "safe" region.
	drawListR->AddRectFilled(posR, ImVec2(posR.x + 200, posR.y + 200), overflow ? IM_COL32(30,0,0,255) : IM_COL32(0,30,0, 255));
	drawListR->AddCircleFilled(ImVec2(posR.x + 100, posR.y + 100), threshRadius, IM_COL32(0, 0, 0, 255), 32);
	// Draw frame and cross lines.
	drawListR->AddRect(posR, ImVec2(posR.x + 200, posR.y + 200), overflow ? IM_COL32(255,0,0, 255) : whiteColor);
	drawListR->AddLine(ImVec2(posR.x + 100, posR.y), ImVec2(posR.x + 100, posR.y+200), whiteColor);
	drawListR->AddLine(ImVec2(posR.x, posR.y + 100), ImVec2(posR.x + 200, posR.y+100), whiteColor);
	// Draw threshold and unit radius circles.
	drawListR->AddCircle(ImVec2(posR.x + 100, posR.y + 100), threshRadius, IM_COL32(0, 255, 0, 255), 32);
	drawListR->AddCircle(ImVec2(posR.x + 100, posR.y + 100), 100, whiteColor, 32);
	// Current axis position.
	drawListR->AddCircleFilled(ImVec2(posR.x + magRX * 100 + 100, posR.y + magRY * 100 + 100), 10, whiteColor);
}
void TransferFunctionUi::drawControlPointsUi()
{
    const ImVec2 p = ui::GetCursorScreenPos();
    ImDrawList* drawList = ui::GetWindowDrawList();
    int width = ui::GetContentRegionAvailWidth() - 4.0f;
    ImU32 white = ImColor(1.0f, 1.0f, 1.0f, 1.0f);
    ImU32 black = ImColor(0.0f, 0.0f, 0.0f, 1.0f);
    float sz = 20.0f;
    float x = p.x + 4.0f;
    float y = p.y + 4.0f;
    float step = static_cast<float>(width) / 256;
    auto& colorPoints = getColorPoints();
    auto& alphaPoints = getAlphaPoints();

    for (int i = 0; i < 256; i++)
    {
        const auto& color = getColor(i);
        ImU32 col32 = ImColor(color);
        // draw color transfer function
        drawList->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col32, 2.0f * step);
        x += step;
    }

    for (auto& colorP : colorPoints)
    {
        const auto& color = colorP.getColor();
        ImU32 col32 = ImColor(color.r, color.g, color.b, 1.0f);
        ImU32 invCol32 = ImColor(1.0f - color.r, 1.0f - color.g, 1.0f - color.b, 1.0f);
        drawList->AddCircleFilled(ImVec2(p.x + step * colorP.getIsoValue() + 4.0f, y + sz), 5, col32, 24);
        drawList->AddCircle(ImVec2(p.x + step * colorP.getIsoValue() + 4.0f, y + sz), 5, invCol32, 24);
    }

    for (int i = 0; i < 255; i++)
    {
        auto aBegin = clamp(1.0f - getColor(i).a, 0.0f, 1.0f);
        auto aEnd = clamp(1.0f - getColor(i + 1).a, 0.0f, 1.0f);
        drawList->AddLine(ImVec2(p.x + step * i + 4.0f, y - 124.0f + aBegin * 120),
            ImVec2(p.x + step * (i + 1) + 4.0f, y - 124.0f + aEnd * 120), white, 2);
    }

    for (auto& alphaP : alphaPoints)
    {
        const auto& alpha = 1.0f - alphaP.getAlpha();
        ImU32 opacity = ImColor(1.0f - vec4(alpha));
        drawList->AddCircleFilled(ImVec2(p.x + step * alphaP.getIsoValue() + 4.0f, y - 124.0f + alpha * 120), 5, opacity, 24);
        drawList->AddCircle(ImVec2(p.x + step * alphaP.getIsoValue() + 4.0f, y - 124.0f + alpha * 120), 5, black, 24);
    }

    ui::Dummy(ImVec2(width, sz + 15.0f));
}
Esempio n. 3
0
/**
 The main function of the controller tester.
 \param argc the number of input arguments.
 \param argv a pointer to the raw input arguments.
 \return a general error code.
 \ingroup ControllerTest
 */
int main(int argc, char** argv) {
	
	// First, init/parse/load configuration.
	RenderingConfig config(std::vector<std::string>(argv, argv+argc));
	// Override window dimensions.
	
	config.initialWidth = 800;
	config.initialHeight = 800;
	GLFWwindow* window = Interface::initWindow("Controller test", config);
	if(!window){
		return -1;
	}
	
	// Enable raw mode for the input, that way all controllers will be raw controllers.
	Input::manager().preferRawControllers(true);
	
	// Will contain reference button/axes to raw input mappings.
	std::vector<int> buttonsMapping(Controller::ControllerInputCount, -1);
	std::vector<int> axesMapping(Controller::ControllerInputCount, -1);
	// Controller texture.
	const GLuint controllerTexId = Resources::manager().getTexture("ControllerLayout", {GL_RGBA8})->id;
	
	bool firstFrame = true;
	const ImU32 highlightColor = IM_COL32(172, 172, 172, 255);
	
	float threshold = 0.02f;
	
	// Start the display/interaction loop.
	while (!glfwWindowShouldClose(window)) {
		// Update events (inputs,...).
		Input::manager().update();
		// Handle quitting.
		if(Input::manager().pressed(Input::KeyEscape)){
			glfwSetWindowShouldClose(window, GL_TRUE);
		}
		
		// Reload resources.
		if(Input::manager().triggered(Input::KeyP)){
			Resources::manager().reload();
		}
		
		// Detect either a new connected controller or a first frame with an already connected controller.
		if(Input::manager().controllerConnected() || (firstFrame && Input::manager().controllerAvailable())){
			firstFrame = false;
			const RawController * controller = static_cast<RawController*>(Input::manager().controller());
			const int axesCount = int(controller->allAxes.size());
			const int buttonsCount = int(controller->allButtons.size());
			
			// Check if some elements were already modified.
			bool wereEmpty = true;
			for(int i = 0; i < int(buttonsMapping.size()); ++i){
				if(wereEmpty && buttonsMapping[i] >= 0){
					wereEmpty = false;
				}
				// Update mapping for extraneous button IDs.
				if(buttonsMapping[i] >= buttonsCount){
					buttonsMapping[i] = -1;
				}
			}
			for(int i = 0; i < int(axesMapping.size()); ++i){
				if(wereEmpty && axesMapping[i] >= 0){
					wereEmpty = false;
				}
				if(axesMapping[i] >= axesCount){
					axesMapping[i] = -1;
				}
			}
		
			// If everything was -1 (first launch), attribute the buttons and axes sequentially, just to help with the visualisation and assignment.
			if(wereEmpty){
				for(int i = 0; i < std::min(int(buttonsMapping.size()), buttonsCount); ++i){
					buttonsMapping[i] = i;
				}
				// Start from the end for the axes.
				for(int i = 0; i < std::min(int(axesMapping.size()), axesCount); ++i){
					const int actionId = int(axesMapping.size()) - 1 - i;
					// Avoid double mappings.
					if(buttonsMapping[actionId] >= 0){
						continue;
					}
					axesMapping[actionId] = i;
				}
			}
		}
		
		// Start a new frame for the interface.
		Interface::beginFrame();
		
		// Render nothing.
		const glm::vec2 screenSize = Input::manager().size();
		glViewport(0, 0, (GLsizei)screenSize[0], (GLsizei)screenSize[1]);
		glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);
		
		// Set a fullscreen fixed window.
		ImGui::SetNextWindowPos(ImVec2(0,0));
		ImGui::SetNextWindowBgAlpha(1.0f);
		ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize);
		const ImGuiWindowFlags windowOptions = ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoTitleBar;
		
		if(ImGui::Begin("Controller", nullptr, windowOptions)){
			if(!Input::manager().controllerAvailable()){
				ImGui::Text("No controller connected.");
			} else {
				// Load/save configuration files.
				if(ImGui::Button("Load...")){
					std::string inputPath;
					const bool res = Interface::showPicker(Interface::Picker::Load, "", inputPath);
					if(res && !inputPath.empty()){
						const std::string settingsContent = Resources::manager().loadStringFromExternalFile(inputPath);
						Controller::parseConfiguration(settingsContent, axesMapping, buttonsMapping);
					}
				}
				ImGui::SameLine();
				if(ImGui::Button("Save...")){
					std::string outputPath;
					const bool res = Interface::showPicker(Interface::Picker::Save, "", outputPath);
					if(res && !outputPath.empty()){
						const Controller * controller = Input::manager().controller();
						Controller::saveConfiguration(outputPath, controller->guid(), controller->name(), axesMapping, buttonsMapping);
					}
				}
				ImGui::Separator();
				
				// Infos on the controller.
				RawController * controller = static_cast<RawController*>(Input::manager().controller());
				const int axesCount = int(controller->allAxes.size());
				const int buttonsCount = int(controller->allButtons.size());
				ImGui::Text("%s, id: %d, axes: %d, buttons: %d", controller->name().c_str(), controller->id(), axesCount, buttonsCount);
				
				// Display raw axes and buttons and update their display when the user interacts with them.
				if(ImGui::CollapsingHeader("Raw inputs##HEADER", ImGuiTreeNodeFlags_DefaultOpen)){
					ImGui::Columns(2);
					
					for(int aid = 0; aid < axesCount; ++aid){
						const std::string axisName = "A" + std::to_string(aid);
						ImGui::SliderFloat(axisName.c_str(), &controller->allAxes[aid], -1.0f, 1.0f);
						ImGui::NextColumn();
					}
					ImGui::Columns(1);
					ImGui::Separator();
					ImGui::Columns(10);
					for(int bid = 0; bid < buttonsCount; ++bid){
						const std::string buttonName = "B" + std::to_string(bid);
						ImGui::RadioButton(buttonName.c_str(), controller->allButtons[bid].pressed);
						ImGui::NextColumn();
					}
					ImGui::Columns(1);
				}
				
			
				if(ImGui::CollapsingHeader("Assignment##HEADER", ImGuiTreeNodeFlags_DefaultOpen)){
					// Display the controller layout, highlight pressed buttons.
					ImGui::BeginChild("##ControllerLayout", ImVec2(450, 300));
					// Get current rnedering position on screen.
					const ImVec2 pos = ImGui::GetCursorScreenPos();
					ImDrawList * drawList = ImGui::GetWindowDrawList();
					
					// Render the left pad first.
					const int aidLX = axesMapping[Controller::PadLeftX];
					const int aidLY = axesMapping[Controller::PadLeftY];
					const float magLX = aidLX >= 0 ? controller->allAxes[aidLX] : 0.0f;
					const float magLY = aidLY >= 0 ? controller->allAxes[aidLY] : 0.0f;
					if((aidLX >= 0 || aidLY >= 0) && (magLX*magLX + magLY*magLY > threshold)){
						drawList->AddCircleFilled(ImVec2(pos.x+154, pos.y+179), 34, highlightColor);
						drawList->AddCircleFilled(ImVec2(pos.x+154, pos.y+179), 26, IM_COL32(0, 0, 0, 255));
					}
					
					// Then the right pad.
					const int aidRX = axesMapping[Controller::PadRightX];
					const int aidRY = axesMapping[Controller::PadRightY];
					const float magRX = aidRX >= 0 ? controller->allAxes[aidRX] : 0.0f;
					const float magRY = aidRY >= 0 ? controller->allAxes[aidRY] : 0.0f;
					if((aidRX >= 0 || aidRY >= 0) && (magRX*magRX + magRY*magRY > threshold)){
						drawList->AddCircleFilled(ImVec2(pos.x+296, pos.y+179), 34, highlightColor);
						drawList->AddCircleFilled(ImVec2(pos.x+296, pos.y+179), 26, IM_COL32(0, 0, 0, 255));
					}
					
					// Render the left trigger (assuming its default value is -1.0).
					const int aidLT = axesMapping[Controller::TriggerL2];
					const float magLT = aidLT >= 0 ? controller->allAxes[aidLT]*0.5+0.5f : 0.0f;
					if(aidLT >= 0 && (magLT*magLT > threshold)){
						drawButton(drawList, Controller::TriggerL2, pos, highlightColor);
					}
					// And the right trigger (assuming its default value is -1.0).
					const int aidRT = axesMapping[Controller::TriggerR2];
					const float magRT = aidRT >= 0 ? controller->allAxes[aidRT]*0.5+0.5f : 0.0f;
					if(aidRT >= 0 && (magRT*magRT > threshold)){
						drawButton(drawList, Controller::TriggerR2, pos, highlightColor);
					}
					
					// Render each button if active.
					for(int bid = 0; bid < int(buttonsMapping.size()); ++bid){
						const int bmid = buttonsMapping[bid];
						if(bmid >= 0 && controller->allButtons[bmid].pressed){
							drawButton(drawList, Controller::ControllerInput(bid), pos, highlightColor);
						}
					}
					
					// Overlay the controller transparent texture.
					ImGui::Image(reinterpret_cast<void*>(controllerTexId), ImVec2(450, 300), ImVec2(0, 1), ImVec2(1,0));
					
					ImGui::EndChild();
					ImGui::SameLine();
					
					// Display combo selectors to assign raw input to each button.
					ImGui::BeginChild("##Layout selection", ImVec2(0, 300));
					ImGui::PushItemWidth(80);
					const int spacing = 160;
					
					showCombo("A", buttonsCount, "B", buttonsMapping[Controller::ButtonA]); ImGui::SameLine(spacing);
					showCombo("B", buttonsCount, "B", buttonsMapping[Controller::ButtonB]);
					showCombo("X", buttonsCount, "B", buttonsMapping[Controller::ButtonX]); ImGui::SameLine(spacing);
					showCombo("Y", buttonsCount, "B", buttonsMapping[Controller::ButtonY]);
					
					showCombo("Up", buttonsCount, "B", buttonsMapping[Controller::ButtonUp]); ImGui::SameLine(spacing);
					showCombo("Left", buttonsCount, "B", buttonsMapping[Controller::ButtonLeft]);
					showCombo("Down", buttonsCount, "B", buttonsMapping[Controller::ButtonDown]); ImGui::SameLine(spacing);
					showCombo("Right", buttonsCount, "B", buttonsMapping[Controller::ButtonRight]);
					
					showCombo("L1", buttonsCount, "B", buttonsMapping[Controller::BumperL1]); ImGui::SameLine(spacing);
					showCombo("R1", buttonsCount, "B", buttonsMapping[Controller::BumperR1]);
					showCombo("L2", buttonsCount, "B", buttonsMapping[Controller::TriggerL2]); ImGui::SameLine(spacing);
					showCombo("R2", buttonsCount, "B", buttonsMapping[Controller::TriggerR2]);
					showCombo("L3", buttonsCount, "B", buttonsMapping[Controller::ButtonL3]); ImGui::SameLine(spacing);
					showCombo("R3", buttonsCount, "B", buttonsMapping[Controller::ButtonR3]);
					
					showCombo("Menu", buttonsCount, "B", buttonsMapping[Controller::ButtonMenu]); ImGui::SameLine(spacing);
					showCombo("View", buttonsCount, "B", buttonsMapping[Controller::ButtonView]);
					showCombo("Logo", buttonsCount, "B", buttonsMapping[Controller::ButtonLogo]);
					
					ImGui::Separator();
					showCombo("Left X", axesCount, "A", axesMapping[Controller::PadLeftX]);  ImGui::SameLine(spacing);
					showCombo("Left Y", axesCount, "A", axesMapping[Controller::PadLeftY]);
					showCombo("Right X", axesCount, "A", axesMapping[Controller::PadRightX]);  ImGui::SameLine(spacing);
					showCombo("Right Y", axesCount, "A", axesMapping[Controller::PadRightY]);
					showCombo("L. trigger", axesCount, "A", axesMapping[Controller::TriggerL2]); ImGui::SameLine(spacing);
					showCombo("R. trigger", axesCount, "A", axesMapping[Controller::TriggerR2]);
					
					ImGui::PopItemWidth();
					// Add threshold setup slider.
					ImGui::PushItemWidth(240);
					ImGui::SliderFloat("Threshold", &threshold, 0.0f, 0.3f);
					ImGui::PopItemWidth();
					ImGui::EndChild();
				}
				
				// Display targets with the current axis positions.
				if(ImGui::CollapsingHeader("Calibration##HEADER", ImGuiTreeNodeFlags_DefaultOpen)){
					
					const float threshRadius = sqrt(threshold) * 100;
					// Titles.
					ImGui::Text("Left pad & trigger"); ImGui::SameLine(300); ImGui::Text("Right pad & trigger");
					
					// Left pad.
					ImGui::BeginChild("PadLeftTarget", ImVec2(200, 200));
					drawPadTarget(axesMapping[Controller::PadLeftX], axesMapping[Controller::PadLeftY], controller->allAxes, threshRadius);
					ImGui::EndChild();
					ImGui::SameLine(220);
					// Left trigger
					ImGui::BeginChild("TriggerL2", ImVec2(40, 200));
					drawTriggerTarget(axesMapping[Controller::TriggerL2], controller->allAxes, threshRadius);
					ImGui::EndChild();
					
					ImGui::SameLine(300);
					// Right pad.
					ImGui::BeginChild("PadRightTarget", ImVec2(200, 200));
					drawPadTarget(axesMapping[Controller::PadRightX], axesMapping[Controller::PadRightY], controller->allAxes, threshRadius);
					ImGui::EndChild();
					
					// Right trigger
					ImGui::SameLine(520);
					ImGui::BeginChild("TriggerR2", ImVec2(40, 200));
					drawTriggerTarget(axesMapping[Controller::TriggerR2], controller->allAxes, threshRadius);
					ImGui::EndChild();
					
					
					
				}
			}
		}
		ImGui::End();
		
		
		// Then render the interface.
		Interface::endFrame();
		//Display the result for the current rendering loop.
		glfwSwapBuffers(window);

	}
	
	// Clean the interface.
	Interface::clean();
	
	Resources::manager().clean();
	// Close GL context and any other GLFW resources.
	glfwDestroyWindow(window);
	glfwTerminate();
	
	return 0;
}