<commit_before>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

// [[CITE]] Tarjan's strongly connected components algorithm
// Tarjan, R. E. (1972), "Depth-first search and linear graph algorithms", SIAM Journal on Computing 1 (2): 146-160, doi:10.1137/0201010
// http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm

#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include <stdlib.h>
#include <stdio.h>
#include <set>

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct SccWorker
{
	RTLIL::Design *design;
	RTLIL::Module *module;
	SigMap sigmap;
	CellTypes ct;

	std::set<RTLIL::Cell*> workQueue;
	std::map<RTLIL::Cell*, std::set<RTLIL::Cell*>> cellToNextCell;
	std::map<RTLIL::Cell*, RTLIL::SigSpec> cellToPrevSig, cellToNextSig;

	std::map<RTLIL::Cell*, std::pair<int, int>> cellLabels;
	std::map<RTLIL::Cell*, int> cellDepth;
	std::set<RTLIL::Cell*> cellsOnStack;
	std::vector<RTLIL::Cell*> cellStack;
	int labelCounter;

	std::map<RTLIL::Cell*, int> cell2scc;
	std::vector<std::set<RTLIL::Cell*>> sccList;

	void run(RTLIL::Cell *cell, int depth, int maxDepth)
	{
		log_assert(workQueue.count(cell) > 0);

		workQueue.erase(cell);
		cellLabels[cell] = std::pair<int, int>(labelCounter, labelCounter);
		labelCounter++;

		cellsOnStack.insert(cell);
		cellStack.push_back(cell);

		if (maxDepth >= 0)
			cellDepth[cell] = depth;

		for (auto nextCell : cellToNextCell[cell])
			if (cellLabels.count(nextCell) == 0) {
				run(nextCell, depth+1, maxDepth);
				cellLabels[cell].second = min(cellLabels[cell].second, cellLabels[nextCell].second);
			} else
			if (cellsOnStack.count(nextCell) > 0 && (maxDepth < 0 || cellDepth[nextCell] + maxDepth > depth)) {
					cellLabels[cell].second = min(cellLabels[cell].second, cellLabels[nextCell].second);
			}

		if (cellLabels[cell].first == cellLabels[cell].second)
		{
			if (cellStack.back() == cell)
			{
				cellStack.pop_back();
				cellsOnStack.erase(cell);
			}
			else
			{
				log("Found an SCC:");
				std::set<RTLIL::Cell*> scc;
				while (cellsOnStack.count(cell) > 0) {
					RTLIL::Cell *c = cellStack.back();
					cellStack.pop_back();
					cellsOnStack.erase(c);
					log(" %s", RTLIL::id2cstr(c->name));
					cell2scc[c] = sccList.size();
					scc.insert(c);
				}
				sccList.push_back(scc);
				log("\n");
			}
		}
	}

	SccWorker(RTLIL::Design *design, RTLIL::Module *module, bool nofeedbackMode, bool allCellTypes, int maxDepth) :
			design(design), module(module), sigmap(module)
	{
		if (module->processes.size() > 0) {
			log("Skipping module %s as it contains processes (run 'proc' pass first).\n", module->name.c_str());
			return;
		}

		if (allCellTypes) {
			ct.setup(design);
		} else {
			ct.setup_internals();
			ct.setup_stdcells();
		}

		SigPool selectedSignals;
		SigSet<RTLIL::Cell*> sigToNextCells;

		for (auto &it : module->wires_)
			if (design->selected(module, it.second))
				selectedSignals.add(sigmap(RTLIL::SigSpec(it.second)));

		for (auto &it : module->cells_)
		{
			RTLIL::Cell *cell = it.second;

			if (!design->selected(module, cell))
				continue;

			if (!allCellTypes && !ct.cell_known(cell->type))
				continue;

			workQueue.insert(cell);

			RTLIL::SigSpec inputSignals, outputSignals;

			for (auto &conn : cell->connections())
			{
				bool isInput = true, isOutput = true;

				if (ct.cell_known(cell->type)) {
					isInput = ct.cell_input(cell->type, conn.first);
					isOutput = ct.cell_output(cell->type, conn.first);
				}

				RTLIL::SigSpec sig = selectedSignals.extract(sigmap(conn.second));
				sig.sort_and_unify();

				if (isInput)
					inputSignals.append(sig);
				if (isOutput)
					outputSignals.append(sig);
			}

			inputSignals.sort_and_unify();
			outputSignals.sort_and_unify();

			cellToPrevSig[cell] = inputSignals;
			cellToNextSig[cell] = outputSignals;
			sigToNextCells.insert(inputSignals, cell);
		}

		for (auto cell : workQueue)
		{
			cellToNextCell[cell] = sigToNextCells.find(cellToNextSig[cell]);

			if (!nofeedbackMode && cellToNextCell[cell].count(cell)) {
				log("Found an SCC:");
				std::set<RTLIL::Cell*> scc;
				log(" %s", RTLIL::id2cstr(cell->name));
				cell2scc[cell] = sccList.size();
				scc.insert(cell);
				sccList.push_back(scc);
				log("\n");
			}
		}

		labelCounter = 0;
		cellLabels.clear();

		while (!workQueue.empty())
		{
			RTLIL::Cell *cell = *workQueue.begin();
			log_assert(cellStack.size() == 0);
			cellDepth.clear();

			run(cell, 0, maxDepth);
		}

		log("Found %d SCCs in module %s.\n", int(sccList.size()), RTLIL::id2cstr(module->name));
	}

	void select(RTLIL::Selection &sel)
	{
		for (int i = 0; i < int(sccList.size()); i++)
		{
			std::set<RTLIL::Cell*> &cells = sccList[i];
			RTLIL::SigSpec prevsig, nextsig, sig;

			for (auto cell : cells) {
				sel.selected_members[module->name].insert(cell->name);
				prevsig.append(cellToPrevSig[cell]);
				nextsig.append(cellToNextSig[cell]);
			}

			prevsig.sort_and_unify();
			nextsig.sort_and_unify();
			sig = prevsig.extract(nextsig);

			for (auto &chunk : sig.chunks())
				if (chunk.wire != NULL)
					sel.selected_members[module->name].insert(chunk.wire->name);
		}
	}
};

struct SccPass : public Pass {
	SccPass() : Pass("scc", "detect strongly connected components (logic loops)") { }
	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    scc [options] [selection]\n");
		log("\n");
		log("This command identifies strongly connected components (aka logic loops) in the\n");
		log("design.\n");
		log("\n");
		log("    -expect <num>\n");
		log("        expect to find exactly <num> SSCs. A different number of SSCs will\n");
		log("        produce an error.\n");
		log("\n");
		log("    -max_depth <num>\n");
		log("        limit to loops not longer than the specified number of cells. This\n");
		log("        can e.g. be useful in identifying small local loops in a module that\n");
		log("        implements one large SCC.\n");
		log("\n");
		log("    -nofeedback\n");
		log("        do not count cells that have their output fed back into one of their\n");
		log("        inputs as single-cell scc.\n");
		log("\n");
		log("    -all_cell_types\n");
		log("        Usually this command only considers internal non-memory cells. With\n");
		log("        this option set, all cells are considered. For unknown cells all ports\n");
		log("        are assumed to be bidirectional 'inout' ports.\n");
		log("\n");
		log("    -set_attr <name> <value>\n");
		log("        set the specified attribute on all cells that are part of a logic\n");
		log("        loop. the special token {} in the value is replaced with a unique\n");
		log("        identifier for the logic loop.\n");
		log("\n");
		log("    -select\n");
		log("        replace the current selection with a selection of all cells and wires\n");
		log("        that are part of a found logic loop\n");
		log("\n");
	}
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		std::map<std::string, std::string> setAttr;
		bool allCellTypes = false;
		bool selectMode = false;
		bool nofeedbackMode = false;
		int maxDepth = -1;
		int expect = -1;

		log_header(design, "Executing SCC pass (detecting logic loops).\n");

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++) {
			if (args[argidx] == "-max_depth" && argidx+1 < args.size()) {
				maxDepth = atoi(args[++argidx].c_str());
				continue;
			}
			if (args[argidx] == "-expect" && argidx+1 < args.size()) {
				expect = atoi(args[++argidx].c_str());
				continue;
			}
			if (args[argidx] == "-nofeedback") {
				nofeedbackMode = true;
				continue;
			}
			if (args[argidx] == "-all_cell_types") {
				allCellTypes = true;
				continue;
			}
			if (args[argidx] == "-set_attr" && argidx+2 < args.size()) {
				setAttr[args[argidx+1]] = args[argidx+2];
				argidx += 2;
				continue;
			}
			if (args[argidx] == "-select") {
				selectMode = true;
				continue;
			}
			break;
		}
		int origSelectPos = design->selection_stack.size() - 1;
		extra_args(args, argidx, design);

		RTLIL::Selection newSelection(false);
		int scc_counter = 0;

		for (auto &mod_it : design->modules_)
			if (design->selected(mod_it.second))
			{
				SccWorker worker(design, mod_it.second, nofeedbackMode, allCellTypes, maxDepth);

				if (!setAttr.empty())
				{
					for (const auto &cells : worker.sccList)
					{
						for (auto attr : setAttr)
						{
							IdString attr_name(RTLIL::escape_id(attr.first));
							string attr_valstr = attr.second;
							string index = stringf("%d", scc_counter);

							for (size_t pos = 0; (pos = attr_valstr.find("{}", pos)) != string::npos; pos += index.size())
								attr_valstr.replace(pos, 2, index);

							Const attr_value(attr_valstr);

							for (auto cell : cells)
								cell->attributes[attr_name] = attr_value;
						}

						scc_counter++;
					}
				}
				else
				{
					scc_counter += GetSize(worker.sccList);
				}

				if (selectMode)
					worker.select(newSelection);
			}

		if (expect >= 0) {
			if (scc_counter == expect)
				log("Found and expected %d SCCs.\n", scc_counter);
			else
				log_error("Found %d SCCs but expected %d.\n", scc_counter, expect);
		} else
			log("Found %d SCCs.\n", scc_counter);

		if (selectMode) {
			log_assert(origSelectPos >= 0);
			design->selection_stack[origSelectPos] = newSelection;
			design->selection_stack[origSelectPos].optimize(design);
		}
	}
} SccPass;

PRIVATE_NAMESPACE_END
<commit_msg>scc to use design->selected_modules() which avoids black/white-boxes<commit_after>/*
 *  yosys -- Yosys Open SYnthesis Suite
 *
 *  Copyright (C) 2012  Clifford Wolf <clifford@clifford.at>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

// [[CITE]] Tarjan's strongly connected components algorithm
// Tarjan, R. E. (1972), "Depth-first search and linear graph algorithms", SIAM Journal on Computing 1 (2): 146-160, doi:10.1137/0201010
// http://en.wikipedia.org/wiki/Tarjan's_strongly_connected_components_algorithm

#include "kernel/register.h"
#include "kernel/celltypes.h"
#include "kernel/sigtools.h"
#include "kernel/log.h"
#include <stdlib.h>
#include <stdio.h>
#include <set>

USING_YOSYS_NAMESPACE
PRIVATE_NAMESPACE_BEGIN

struct SccWorker
{
	RTLIL::Design *design;
	RTLIL::Module *module;
	SigMap sigmap;
	CellTypes ct;

	std::set<RTLIL::Cell*> workQueue;
	std::map<RTLIL::Cell*, std::set<RTLIL::Cell*>> cellToNextCell;
	std::map<RTLIL::Cell*, RTLIL::SigSpec> cellToPrevSig, cellToNextSig;

	std::map<RTLIL::Cell*, std::pair<int, int>> cellLabels;
	std::map<RTLIL::Cell*, int> cellDepth;
	std::set<RTLIL::Cell*> cellsOnStack;
	std::vector<RTLIL::Cell*> cellStack;
	int labelCounter;

	std::map<RTLIL::Cell*, int> cell2scc;
	std::vector<std::set<RTLIL::Cell*>> sccList;

	void run(RTLIL::Cell *cell, int depth, int maxDepth)
	{
		log_assert(workQueue.count(cell) > 0);

		workQueue.erase(cell);
		cellLabels[cell] = std::pair<int, int>(labelCounter, labelCounter);
		labelCounter++;

		cellsOnStack.insert(cell);
		cellStack.push_back(cell);

		if (maxDepth >= 0)
			cellDepth[cell] = depth;

		for (auto nextCell : cellToNextCell[cell])
			if (cellLabels.count(nextCell) == 0) {
				run(nextCell, depth+1, maxDepth);
				cellLabels[cell].second = min(cellLabels[cell].second, cellLabels[nextCell].second);
			} else
			if (cellsOnStack.count(nextCell) > 0 && (maxDepth < 0 || cellDepth[nextCell] + maxDepth > depth)) {
					cellLabels[cell].second = min(cellLabels[cell].second, cellLabels[nextCell].second);
			}

		if (cellLabels[cell].first == cellLabels[cell].second)
		{
			if (cellStack.back() == cell)
			{
				cellStack.pop_back();
				cellsOnStack.erase(cell);
			}
			else
			{
				log("Found an SCC:");
				std::set<RTLIL::Cell*> scc;
				while (cellsOnStack.count(cell) > 0) {
					RTLIL::Cell *c = cellStack.back();
					cellStack.pop_back();
					cellsOnStack.erase(c);
					log(" %s", RTLIL::id2cstr(c->name));
					cell2scc[c] = sccList.size();
					scc.insert(c);
				}
				sccList.push_back(scc);
				log("\n");
			}
		}
	}

	SccWorker(RTLIL::Design *design, RTLIL::Module *module, bool nofeedbackMode, bool allCellTypes, int maxDepth) :
			design(design), module(module), sigmap(module)
	{
		if (module->processes.size() > 0) {
			log("Skipping module %s as it contains processes (run 'proc' pass first).\n", module->name.c_str());
			return;
		}

		if (allCellTypes) {
			ct.setup(design);
		} else {
			ct.setup_internals();
			ct.setup_stdcells();
		}

		SigPool selectedSignals;
		SigSet<RTLIL::Cell*> sigToNextCells;

		for (auto &it : module->wires_)
			if (design->selected(module, it.second))
				selectedSignals.add(sigmap(RTLIL::SigSpec(it.second)));

		for (auto &it : module->cells_)
		{
			RTLIL::Cell *cell = it.second;

			if (!design->selected(module, cell))
				continue;

			if (!allCellTypes && !ct.cell_known(cell->type))
				continue;

			workQueue.insert(cell);

			RTLIL::SigSpec inputSignals, outputSignals;

			for (auto &conn : cell->connections())
			{
				bool isInput = true, isOutput = true;

				if (ct.cell_known(cell->type)) {
					isInput = ct.cell_input(cell->type, conn.first);
					isOutput = ct.cell_output(cell->type, conn.first);
				}

				RTLIL::SigSpec sig = selectedSignals.extract(sigmap(conn.second));
				sig.sort_and_unify();

				if (isInput)
					inputSignals.append(sig);
				if (isOutput)
					outputSignals.append(sig);
			}

			inputSignals.sort_and_unify();
			outputSignals.sort_and_unify();

			cellToPrevSig[cell] = inputSignals;
			cellToNextSig[cell] = outputSignals;
			sigToNextCells.insert(inputSignals, cell);
		}

		for (auto cell : workQueue)
		{
			cellToNextCell[cell] = sigToNextCells.find(cellToNextSig[cell]);

			if (!nofeedbackMode && cellToNextCell[cell].count(cell)) {
				log("Found an SCC:");
				std::set<RTLIL::Cell*> scc;
				log(" %s", RTLIL::id2cstr(cell->name));
				cell2scc[cell] = sccList.size();
				scc.insert(cell);
				sccList.push_back(scc);
				log("\n");
			}
		}

		labelCounter = 0;
		cellLabels.clear();

		while (!workQueue.empty())
		{
			RTLIL::Cell *cell = *workQueue.begin();
			log_assert(cellStack.size() == 0);
			cellDepth.clear();

			run(cell, 0, maxDepth);
		}

		log("Found %d SCCs in module %s.\n", int(sccList.size()), RTLIL::id2cstr(module->name));
	}

	void select(RTLIL::Selection &sel)
	{
		for (int i = 0; i < int(sccList.size()); i++)
		{
			std::set<RTLIL::Cell*> &cells = sccList[i];
			RTLIL::SigSpec prevsig, nextsig, sig;

			for (auto cell : cells) {
				sel.selected_members[module->name].insert(cell->name);
				prevsig.append(cellToPrevSig[cell]);
				nextsig.append(cellToNextSig[cell]);
			}

			prevsig.sort_and_unify();
			nextsig.sort_and_unify();
			sig = prevsig.extract(nextsig);

			for (auto &chunk : sig.chunks())
				if (chunk.wire != NULL)
					sel.selected_members[module->name].insert(chunk.wire->name);
		}
	}
};

struct SccPass : public Pass {
	SccPass() : Pass("scc", "detect strongly connected components (logic loops)") { }
	void help() YS_OVERRIDE
	{
		//   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
		log("\n");
		log("    scc [options] [selection]\n");
		log("\n");
		log("This command identifies strongly connected components (aka logic loops) in the\n");
		log("design.\n");
		log("\n");
		log("    -expect <num>\n");
		log("        expect to find exactly <num> SSCs. A different number of SSCs will\n");
		log("        produce an error.\n");
		log("\n");
		log("    -max_depth <num>\n");
		log("        limit to loops not longer than the specified number of cells. This\n");
		log("        can e.g. be useful in identifying small local loops in a module that\n");
		log("        implements one large SCC.\n");
		log("\n");
		log("    -nofeedback\n");
		log("        do not count cells that have their output fed back into one of their\n");
		log("        inputs as single-cell scc.\n");
		log("\n");
		log("    -all_cell_types\n");
		log("        Usually this command only considers internal non-memory cells. With\n");
		log("        this option set, all cells are considered. For unknown cells all ports\n");
		log("        are assumed to be bidirectional 'inout' ports.\n");
		log("\n");
		log("    -set_attr <name> <value>\n");
		log("        set the specified attribute on all cells that are part of a logic\n");
		log("        loop. the special token {} in the value is replaced with a unique\n");
		log("        identifier for the logic loop.\n");
		log("\n");
		log("    -select\n");
		log("        replace the current selection with a selection of all cells and wires\n");
		log("        that are part of a found logic loop\n");
		log("\n");
	}
	void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE
	{
		std::map<std::string, std::string> setAttr;
		bool allCellTypes = false;
		bool selectMode = false;
		bool nofeedbackMode = false;
		int maxDepth = -1;
		int expect = -1;

		log_header(design, "Executing SCC pass (detecting logic loops).\n");

		size_t argidx;
		for (argidx = 1; argidx < args.size(); argidx++) {
			if (args[argidx] == "-max_depth" && argidx+1 < args.size()) {
				maxDepth = atoi(args[++argidx].c_str());
				continue;
			}
			if (args[argidx] == "-expect" && argidx+1 < args.size()) {
				expect = atoi(args[++argidx].c_str());
				continue;
			}
			if (args[argidx] == "-nofeedback") {
				nofeedbackMode = true;
				continue;
			}
			if (args[argidx] == "-all_cell_types") {
				allCellTypes = true;
				continue;
			}
			if (args[argidx] == "-set_attr" && argidx+2 < args.size()) {
				setAttr[args[argidx+1]] = args[argidx+2];
				argidx += 2;
				continue;
			}
			if (args[argidx] == "-select") {
				selectMode = true;
				continue;
			}
			break;
		}
		int origSelectPos = design->selection_stack.size() - 1;
		extra_args(args, argidx, design);

		RTLIL::Selection newSelection(false);
		int scc_counter = 0;

		for (auto mod : design->selected_modules())
		{
			SccWorker worker(design, mod, nofeedbackMode, allCellTypes, maxDepth);

			if (!setAttr.empty())
			{
				for (const auto &cells : worker.sccList)
				{
					for (auto attr : setAttr)
					{
						IdString attr_name(RTLIL::escape_id(attr.first));
						string attr_valstr = attr.second;
						string index = stringf("%d", scc_counter);

						for (size_t pos = 0; (pos = attr_valstr.find("{}", pos)) != string::npos; pos += index.size())
							attr_valstr.replace(pos, 2, index);

						Const attr_value(attr_valstr);

						for (auto cell : cells)
							cell->attributes[attr_name] = attr_value;
					}

					scc_counter++;
				}
			}
			else
			{
				scc_counter += GetSize(worker.sccList);
			}

			if (selectMode)
				worker.select(newSelection);
		}

		if (expect >= 0) {
			if (scc_counter == expect)
				log("Found and expected %d SCCs.\n", scc_counter);
			else
				log_error("Found %d SCCs but expected %d.\n", scc_counter, expect);
		} else
			log("Found %d SCCs.\n", scc_counter);

		if (selectMode) {
			log_assert(origSelectPos >= 0);
			design->selection_stack[origSelectPos] = newSelection;
			design->selection_stack[origSelectPos].optimize(design);
		}
	}
} SccPass;

PRIVATE_NAMESPACE_END
<|endoftext|>


<commit_before><commit_msg>Can use qualifications in yield statements.<commit_after><|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*! @file
    @brief  input クラス @n
			数値、文字列などの入力クラス
			Copyright 2017 Kunihito Hiramatsu
    @author 平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstdint>

extern "C" {

	char sci_getch(void);

};

namespace utils {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  標準入力ファンクタ
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class def_chainp {
		const char* str_;
		char		last_;
		bool		unget_;
	public:
		def_chainp(const char* str = nullptr) : str_(str), last_(0), unget_(false) { }

		void unget() {
			unget_ = true;
		}

		char operator() () {
			if(unget_) {
				unget_ = false;
			} else {
				if(str_ == nullptr) {
					last_ = sci_getch();
				} else {
					last_ = *str_;
					if(last_ != 0) { ++str_; }
				}
			}
			return last_;
		}
	};

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  汎用入力クラス
		@param[in]	INP	入力クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class INP>
	class basic_input {

		const char*	form_;

		INP			inp_;

		uint32_t bin_() {
			uint32_t a = 0;
			char ch;
			while((ch = inp_()) != 0 && ch >= '0' && ch <= '1') {
				a <<= 1;
				a += ch - '0';
			}
			return a;
		}

		uint32_t oct_() {
			uint32_t a = 0;
			char ch;
			while((ch = inp_()) != 0 && ch >= '0' && ch <= '7') {
				a <<= 3;
				a += ch - '0';
			}
			return a;
		}

		uint32_t dec_() {
			uint32_t a = 0;
			char ch;
			while((ch = inp_()) != 0 && ch >= '0' && ch <= '9') {
				a *= 10;
				a += ch - '0';
			}
			return a;
		}

		uint32_t hex_() {
			uint32_t a = 0;
			char ch;
			while((ch = inp_()) != 0) {
				if(ch >= '0' && ch <= '9') {
					a <<= 4;
					a += ch - '0';
				} else if(ch >= 'A' && ch <= 'F') {
					a <<= 4;
					a += ch - 'A' + 10;
				} else if(ch >= 'a' && ch <= 'f') {
					a <<= 4;
					a += ch - 'a' + 10;
				} else {
					break;
				}
			}
			return a;
		}

		enum class mode : uint8_t {
			NONE,
			BIN,
			OCT,
			DEC,
			HEX,
		};
		mode	mode_;
		bool	err_;

		static uint16_t	cnvcnt_;

		enum class fmm : uint8_t {
			none,
			type,

		};

		void next_()
		{
			fmm cm = fmm::none;
			char ch;
			while((ch = *form_++) != 0) {
				switch(cm) {
				case fmm::none:
					if(ch == '[') {
						auto a = inp_();
						const char* p = form_;
						bool ok = false;
						while((ch = *p++) != 0 && ch != ']') {
							if(ch == a) ok = true;
						}
						form_ = p;
						if(!ok) {
							err_ = true;
							return;
						}
					} else if(ch == '%' && *form_ != '%') {
						cm = fmm::type;
					} else if(ch != inp_()) {
						err_ = true;
						return;
					}
					break;
				case fmm::type:
					if(ch == 'b' || ch == 'B') {
						mode_ = mode::BIN;
					} else if(ch == 'o' || ch == 'O') {
						mode_ = mode::OCT;
					} else if(ch == 'd' || ch == 'D') {
						mode_ = mode::DEC;
					} else if(ch == 'x' || ch == 'X') {
						mode_ = mode::HEX;
					} else {
						err_ = true;
					}
					return;
				}
			}
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
			@param[in]	form	入力形式
			@param[in]	inp		変換文字列（nullptrの場合、sci_getch で取得）
		*/
		//-----------------------------------------------------------------//
		basic_input(const char* form, const char* inp = nullptr) : form_(form), inp_(inp),
			mode_(mode::NONE), err_(false)
		{
			cnvcnt_ = 0;
			next_();
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  正常変換数を取得
			@return 正常変換数
		*/
		//-----------------------------------------------------------------//
		static uint16_t get_conversion() { return cnvcnt_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  オペレーター「%」（int32_t）
			@param[in]	val	整数値
			@return	自分の参照
		*/
		//-----------------------------------------------------------------//
		basic_input& operator % (int32_t& val)
		{
			if(err_) return *this;

			bool neg = false;
			{
				auto s = inp_();
				if(s == '-') { neg = true; }
				else if(s == '+') { neg = false; }
				else inp_.unget();
			}
			uint32_t v = 0;
			switch(mode_) {
			case mode::BIN:
				v = bin_();
				break;
			case mode::OCT:
				v = oct_();
				break;
			case mode::DEC:
				v = dec_();
				break;
			case mode::HEX:
				v = hex_();
				break;
			default:
				err_ = true;
				break;
			}
			if(neg) val = -static_cast<int32_t>(v);
			else val = static_cast<int32_t>(v);
			if(!err_) {
				++cnvcnt_;
				inp_.unget();
				next_();
			}
			return *this;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  オペレーター「%」（uint32_t）
			@param[in]	val	整数値
			@return	自分の参照
		*/
		//-----------------------------------------------------------------//
		basic_input& operator % (uint32_t& val)
		{
			if(err_) return *this;

			uint32_t v = 0;
			switch(mode_) {
			case mode::BIN:
				v = bin_();
				break;
			case mode::OCT:
				v = oct_();
				break;
			case mode::DEC:
				v = dec_();
				break;
			case mode::HEX:
				v = hex_();
				break;
			default:
				err_ = true;
				break;
			}
			if(!err_) {
				++cnvcnt_;
				inp_.unget();
				next_();
				val = v;
			}
			return *this;
		}
	};

	template<class INP> uint16_t basic_input<INP>::cnvcnt_;

	typedef basic_input<def_chainp> input;

}
<commit_msg>update operator<commit_after>#pragma once
//=====================================================================//
/*! @file
    @brief  input クラス @n
			数値、文字列などの入力クラス
			Copyright 2017 Kunihito Hiramatsu
    @author 平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <type_traits>

extern "C" {

	char sci_getch(void);

};

namespace utils {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  標準入力ファンクタ
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	class def_chainp {
		const char* str_;
		char		last_;
		bool		unget_;
	public:
		def_chainp(const char* str = nullptr) : str_(str), last_(0), unget_(false) { }

		void unget() {
			unget_ = true;
		}

		char operator() () {
			if(unget_) {
				unget_ = false;
			} else {
				if(str_ == nullptr) {
					last_ = sci_getch();
				} else {
					last_ = *str_;
					if(last_ != 0) { ++str_; }
				}
			}
			return last_;
		}
	};

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief  汎用入力クラス
		@param[in]	INP	入力クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class INP>
	class basic_input {

		const char*	form_;

		INP			inp_;

		uint32_t bin_() {
			uint32_t a = 0;
			char ch;
			while((ch = inp_()) != 0 && ch >= '0' && ch <= '1') {
				a <<= 1;
				a += ch - '0';
			}
			return a;
		}

		uint32_t oct_() {
			uint32_t a = 0;
			char ch;
			while((ch = inp_()) != 0 && ch >= '0' && ch <= '7') {
				a <<= 3;
				a += ch - '0';
			}
			return a;
		}

		uint32_t dec_() {
			uint32_t a = 0;
			char ch;
			while((ch = inp_()) != 0 && ch >= '0' && ch <= '9') {
				a *= 10;
				a += ch - '0';
			}
			return a;
		}

		uint32_t hex_() {
			uint32_t a = 0;
			char ch;
			while((ch = inp_()) != 0) {
				if(ch >= '0' && ch <= '9') {
					a <<= 4;
					a += ch - '0';
				} else if(ch >= 'A' && ch <= 'F') {
					a <<= 4;
					a += ch - 'A' + 10;
				} else if(ch >= 'a' && ch <= 'f') {
					a <<= 4;
					a += ch - 'a' + 10;
				} else {
					break;
				}
			}
			return a;
		}

		enum class mode : uint8_t {
			NONE,
			BIN,
			OCT,
			DEC,
			HEX,
		};
		mode	mode_;
		bool	err_;

		int		num_;

		enum class fmm : uint8_t {
			none,
			type,

		};

		void next_()
		{
			fmm cm = fmm::none;
			char ch;
			while((ch = *form_++) != 0) {
				switch(cm) {
				case fmm::none:
					if(ch == '[') {
						auto a = inp_();
						const char* p = form_;
						bool ok = false;
						while((ch = *p++) != 0 && ch != ']') {
							if(ch == a) ok = true;
						}
						form_ = p;
						if(!ok) {
							err_ = true;
							return;
						}
					} else if(ch == '%' && *form_ != '%') {
						cm = fmm::type;
					} else if(ch != inp_()) {
						err_ = true;
						return;
					}
					break;
				case fmm::type:
					if(ch == 'b' || ch == 'B') {
						mode_ = mode::BIN;
					} else if(ch == 'o' || ch == 'O') {
						mode_ = mode::OCT;
					} else if(ch == 'd' || ch == 'D') {
						mode_ = mode::DEC;
					} else if(ch == 'x' || ch == 'X') {
						mode_ = mode::HEX;
					} else {
						err_ = true;
					}
					return;
				}
			}
			if(ch == 0 && inp_() == 0) ;
			else {
				err_ = true;
			}
		}

		int32_t nb_(bool sign = true)
		{
			bool neg = false;
			if(sign) {
				auto s = inp_();
				if(s == '-') { neg = true; }
				else if(s == '+') { neg = false; }
				else inp_.unget();
			}
			uint32_t v = 0;
			switch(mode_) {
			case mode::BIN:
				v = bin_();
				break;
			case mode::OCT:
				v = oct_();
				break;
			case mode::DEC:
				v = dec_();
				break;
			case mode::HEX:
				v = hex_();
				break;
			default:
				err_ = true;
				break;
			}
			if(!err_) {
				inp_.unget();
				next_();
				if(!err_) ++num_;
			}
			if(neg) return -static_cast<int32_t>(v);
			else return static_cast<int32_t>(v);
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief  コンストラクター
			@param[in]	form	入力形式
			@param[in]	inp		変換文字列（nullptrの場合、sci_getch で取得）
		*/
		//-----------------------------------------------------------------//
		basic_input(const char* form, const char* inp = nullptr) : form_(form), inp_(inp),
			mode_(mode::NONE), err_(false), num_(0)
		{
			next_();
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  正常変換数を取得
			@return 正常変換数
		*/
		//-----------------------------------------------------------------//
		int num() const { return num_; }

		//-----------------------------------------------------------------//
		/*!
			@brief  テンプレート・オペレーター「%」
			@param[in]	val	整数型
			@return	自分の参照
		*/
		//-----------------------------------------------------------------//
		template <typename T>
		basic_input& operator % (T& val)
		{
			if(err_) return *this;
			val = nb_(!std::is_signed<T>::value);
			return *this;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief  オペレーター「=」
		*/
		//-----------------------------------------------------------------//
		basic_input& operator = (const basic_input& in) { return *this; }
	};

	typedef basic_input<def_chainp> input;

}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "google/cloud/storage/internal/lifecycle_rule_parser.h"
#include "google/cloud/storage/internal/common_metadata_parser.h"

namespace google {
namespace cloud {
namespace storage {
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
namespace internal {
namespace {

absl::optional<std::vector<std::string>> ParseStringListCondition(
    nlohmann::json const& condition, char const* name) {
  if (!condition.contains(name)) return absl::nullopt;
  std::vector<std::string> matches;
  for (auto const& kv : condition[name].items()) {
    matches.emplace_back(kv.value().get<std::string>());
  }
  return matches;
}

Status ParseIntCondition(absl::optional<std::int32_t>& field,
                         nlohmann::json const& condition, char const* name) {
  if (!condition.contains(name)) return Status{};
  auto value = internal::ParseIntField(condition, name);
  if (!value) return std::move(value).status();
  field.emplace(*value);
  return Status{};
}

Status ParseBoolCondition(absl::optional<bool>& field,
                          nlohmann::json const& condition, char const* name) {
  if (!condition.contains(name)) return Status{};
  auto value = internal::ParseBoolField(condition, name);
  if (!value) return std::move(value).status();
  field.emplace(*value);
  return Status{};
}

Status ParseDateCondition(absl::optional<absl::CivilDay>& field,
                          nlohmann::json const& condition, char const* name) {
  if (!condition.contains(name)) return Status{};
  auto const date = condition.value(name, "");
  absl::CivilDay day;
  if (!absl::ParseCivilTime(date, &day)) {
    return Status(StatusCode::kInvalidArgument,
                  "Cannot parse " + std::string(name) + " with value=<" + date +
                      "> as a date");
  }
  field.emplace(std::move(day));
  return Status{};
}

}  // namespace

StatusOr<LifecycleRule> LifecycleRuleParser::FromJson(
    nlohmann::json const& json) {
  if (!json.is_object()) {
    return Status(StatusCode::kInvalidArgument, __func__);
  }
  LifecycleRule result;
  if (json.count("action") != 0) {
    result.action_.type = json["action"].value("type", "");
    result.action_.storage_class = json["action"].value("storageClass", "");
  }
  if (json.count("condition") == 0) return result;

  auto condition = json["condition"];

  auto status = ParseIntCondition(result.condition_.age, condition, "age");
  if (!status.ok()) return status;
  status = ParseDateCondition(result.condition_.created_before, condition,
                              "createdBefore");
  if (!status.ok()) return status;
  status = ParseBoolCondition(result.condition_.is_live, condition, "isLive");
  if (!status.ok()) return status;
  result.condition_.matches_storage_class =
      ParseStringListCondition(condition, "matchesStorageClass");
  status = ParseIntCondition(result.condition_.num_newer_versions, condition,
                             "numNewerVersions");
  if (!status.ok()) return status;
  status = ParseIntCondition(result.condition_.days_since_noncurrent_time,
                             condition, "daysSinceNoncurrentTime");
  if (!status.ok()) return status;
  status = ParseDateCondition(result.condition_.noncurrent_time_before,
                              condition, "noncurrentTimeBefore");
  if (!status.ok()) return status;
  status = ParseIntCondition(result.condition_.days_since_custom_time,
                             condition, "daysSinceCustomTime");
  if (!status.ok()) return status;
  status = ParseDateCondition(result.condition_.custom_time_before, condition,
                              "customTimeBefore");
  if (!status.ok()) return status;
  result.condition_.matches_prefix =
      ParseStringListCondition(condition, "matchesPrefix");
  result.condition_.matches_suffix =
      ParseStringListCondition(condition, "matchesSuffix");
  return result;
}

StatusOr<LifecycleRule> LifecycleRuleParser::FromString(
    std::string const& text) {
  auto json = nlohmann::json::parse(text, nullptr, false);
  return FromJson(json);
}

}  // namespace internal
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
}  // namespace storage
}  // namespace cloud
}  // namespace google
<commit_msg>cleanup(storage): fix `clang-tidy` build (#9429)<commit_after>// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "google/cloud/storage/internal/lifecycle_rule_parser.h"
#include "google/cloud/storage/internal/common_metadata_parser.h"

namespace google {
namespace cloud {
namespace storage {
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
namespace internal {
namespace {

absl::optional<std::vector<std::string>> ParseStringListCondition(
    nlohmann::json const& condition, char const* name) {
  if (!condition.contains(name)) return absl::nullopt;
  std::vector<std::string> matches;
  for (auto const& kv : condition[name].items()) {
    matches.emplace_back(kv.value().get<std::string>());
  }
  return matches;
}

Status ParseIntCondition(absl::optional<std::int32_t>& field,
                         nlohmann::json const& condition, char const* name) {
  if (!condition.contains(name)) return Status{};
  auto value = internal::ParseIntField(condition, name);
  if (!value) return std::move(value).status();
  field.emplace(*value);
  return Status{};
}

Status ParseBoolCondition(absl::optional<bool>& field,
                          nlohmann::json const& condition, char const* name) {
  if (!condition.contains(name)) return Status{};
  auto value = internal::ParseBoolField(condition, name);
  if (!value) return std::move(value).status();
  field.emplace(*value);
  return Status{};
}

Status ParseDateCondition(absl::optional<absl::CivilDay>& field,
                          nlohmann::json const& condition, char const* name) {
  if (!condition.contains(name)) return Status{};
  auto const date = condition.value(name, "");
  absl::CivilDay day;
  if (!absl::ParseCivilTime(date, &day)) {
    return Status(StatusCode::kInvalidArgument,
                  "Cannot parse " + std::string(name) + " with value=<" + date +
                      "> as a date");
  }
  field.emplace(std::move(day));
  return Status{};
}

}  // namespace

StatusOr<LifecycleRule> LifecycleRuleParser::FromJson(
    nlohmann::json const& json) {
  if (!json.is_object()) {
    return Status(StatusCode::kInvalidArgument, __func__);
  }
  LifecycleRule result;
  if (json.count("action") != 0) {
    result.action_.type = json["action"].value("type", "");
    result.action_.storage_class = json["action"].value("storageClass", "");
  }
  if (json.count("condition") == 0) return result;

  auto const& condition = json["condition"];

  auto status = ParseIntCondition(result.condition_.age, condition, "age");
  if (!status.ok()) return status;
  status = ParseDateCondition(result.condition_.created_before, condition,
                              "createdBefore");
  if (!status.ok()) return status;
  status = ParseBoolCondition(result.condition_.is_live, condition, "isLive");
  if (!status.ok()) return status;
  result.condition_.matches_storage_class =
      ParseStringListCondition(condition, "matchesStorageClass");
  status = ParseIntCondition(result.condition_.num_newer_versions, condition,
                             "numNewerVersions");
  if (!status.ok()) return status;
  status = ParseIntCondition(result.condition_.days_since_noncurrent_time,
                             condition, "daysSinceNoncurrentTime");
  if (!status.ok()) return status;
  status = ParseDateCondition(result.condition_.noncurrent_time_before,
                              condition, "noncurrentTimeBefore");
  if (!status.ok()) return status;
  status = ParseIntCondition(result.condition_.days_since_custom_time,
                             condition, "daysSinceCustomTime");
  if (!status.ok()) return status;
  status = ParseDateCondition(result.condition_.custom_time_before, condition,
                              "customTimeBefore");
  if (!status.ok()) return status;
  result.condition_.matches_prefix =
      ParseStringListCondition(condition, "matchesPrefix");
  result.condition_.matches_suffix =
      ParseStringListCondition(condition, "matchesSuffix");
  return result;
}

StatusOr<LifecycleRule> LifecycleRuleParser::FromString(
    std::string const& text) {
  auto json = nlohmann::json::parse(text, nullptr, false);
  return FromJson(json);
}

}  // namespace internal
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
}  // namespace storage
}  // namespace cloud
}  // namespace google
<|endoftext|>


<commit_before>/*
***************************************
*   Asylum3D @ 2014-12-24
***************************************
*/

#include "../../asylum.hpp"

/*****************************************************************************/
/*                                  Effect                                   */
/*****************************************************************************/

/* Asylum Namespace */
namespace asy {

/****************************/
/* Wavefront Effect (Fixed) */
/****************************/
class crh3d9_ffct_wf_fixed : public IEffect
{
private:
    bool                m_uselt;
    BOOL*               m_onoff;
    DWORD               m_count;
    int64u              m_flags;
    D3DCOLOR*           m_color;
    D3DLIGHT9*          m_light;
    LPDIRECT3DDEVICE9   m_devcs;

public:
    /* ===================================================================================================================== */
    crh3d9_ffct_wf_fixed (D3DCOLOR* ambient, D3DLIGHT9* light, BOOL* onoff, DWORD count, int64u flags, const crh3d9_main* main)
    {
        m_onoff = onoff;
        m_count = count;
        m_flags = flags;
        m_light = light;
        m_color = ambient;
        m_devcs = main->get_main()->dev;
        m_uselt = (m_light != NULL && m_onoff != NULL) ? true : false;
    }

    /* ========================== */
    virtual ~crh3d9_ffct_wf_fixed ()
    {
    }

public:
    /* =============== */
    virtual void enter ()
    {
        uint_t  fvf = D3DFVF_XYZ;

        m_devcs->SetRenderState(D3DRS_COLORVERTEX, FALSE);
        m_devcs->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
        m_devcs->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL);
        if (m_flags & ATTR_TYPE_TRANS) {
            m_devcs->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
            m_devcs->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
            m_devcs->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
            m_devcs->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
        }
        if (m_flags & ATTR_TYPE_NORMAL) {
            fvf |= D3DFVF_NORMAL;
            if (m_uselt) {
                m_devcs->SetRenderState(D3DRS_LIGHTING, TRUE);
                if (m_flags & ATTR_TYPE_SPECULAR)
                    m_devcs->SetRenderState(D3DRS_SPECULARENABLE, TRUE);
            }
        }
        if (m_flags & ATTR_TYPE_TEXTURE)
            fvf |= D3DFVF_TEX1;
        m_devcs->SetFVF(fvf);
    }

    /* =============== */
    virtual void leave ()
    {
        m_devcs->SetRenderState(D3DRS_COLORVERTEX, TRUE);
        m_devcs->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
        m_devcs->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_COLOR2);
        if (m_flags & ATTR_TYPE_TRANS)
            m_devcs->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
        if (m_flags & ATTR_TYPE_NORMAL) {
            if (m_uselt) {
                m_devcs->SetRenderState(D3DRS_LIGHTING, FALSE);
                if (m_flags & ATTR_TYPE_SPECULAR)
                    m_devcs->SetRenderState(D3DRS_SPECULARENABLE, FALSE);
            }
        }
    }

    /* ================ */
    virtual void update ()
    {
        if (m_color != NULL)
            m_devcs->SetRenderState(D3DRS_AMBIENT, m_color[0]);
        if (m_uselt) {
            for (DWORD idx = 0; idx < m_count; idx++) {
                m_devcs->SetLight(idx, &m_light[idx]);
                m_devcs->LightEnable(idx, m_onoff[idx]);
            }
        }
    }
};

}   /* namespace */

/* ================================================================================ */
CR_API asy::IEffect* create_crh3d9_ffct_wf_fixed (D3DCOLOR* ambient, D3DLIGHT9* light,
                BOOL* onoff, DWORD count, int64u flags, const asy::crh3d9_main* main)
{
    asy::crh3d9_ffct_wf_fixed*  ffct;

    ffct = new asy::crh3d9_ffct_wf_fixed (ambient, light, onoff, count, flags, main);
    return ((asy::IEffect*)ffct);
}

/*****************************************************************************/
/*                                Attribute                                  */
/*****************************************************************************/

/* Asylum Namespace */
namespace asy {

/*******************************/
/* Wavefront Attribute (Fixed) */
/*******************************/
class crh3d9_attr_wf_fixed : public IAttrib
{
protected:
    D3DMATERIAL9        m_mtl;
    crh3d9_texr*        m_map_kd;
    LPDIRECT3DDEVICE9   m_device;

public:
    /* ======================================== */
    crh3d9_attr_wf_fixed (const crh3d9_main* main)
    {
        m_device = main->get_main()->dev;
    }

    /* ========================== */
    virtual ~crh3d9_attr_wf_fixed ()
    {
    }

public:
    /* ===================================================================== */
    bool init_ff (const sWAVEFRONT_M* mtl, const map_acs<crh3d9_texr>* texpool)
    {
        if (mtl->map_kd != NULL) {
            m_map_kd = texpool->get(mtl->map_kd);
            if (m_map_kd == NULL)
                return (false);
        }
        else {
            m_map_kd = NULL;
        }
        m_mtl.Diffuse.r = mtl->kd.x;
        m_mtl.Diffuse.g = mtl->kd.y;
        m_mtl.Diffuse.b = mtl->kd.z;
        m_mtl.Diffuse.a = mtl->d;
        if (m_mtl.Diffuse.a < 0.0f)
            m_mtl.Diffuse.a = 0.0f;
        else
        if (m_mtl.Diffuse.a > 1.0f)
            m_mtl.Diffuse.a = 1.0f;
        m_mtl.Ambient.r = mtl->ka.x;
        m_mtl.Ambient.g = mtl->ka.y;
        m_mtl.Ambient.b = mtl->ka.z;
        m_mtl.Ambient.a = 0.0f;
        m_mtl.Specular.r = mtl->ks.x;
        m_mtl.Specular.g = mtl->ks.y;
        m_mtl.Specular.b = mtl->ks.z;
        m_mtl.Specular.a = 0.0f;
        m_mtl.Emissive.r = 0.0f;
        m_mtl.Emissive.g = 0.0f;
        m_mtl.Emissive.b = 0.0f;
        m_mtl.Emissive.a = 0.0f;
        m_mtl.Power = mtl->ns;
        m_type = ATTR_TYPE_NORMAL;
        if (m_mtl.Diffuse.a < 1.0f)
            m_type |= ATTR_TYPE_TRANS;
        if (m_map_kd != NULL)
            m_type |= ATTR_TYPE_TEXTURE;
        if (m_mtl.Specular.r <= 0.0f && m_mtl.Specular.g <= 0.0f &&
            m_mtl.Specular.b <= 0.0f && m_mtl.Specular.a <= 0.0f)
            m_type |= ATTR_TYPE_SPECULAR;
        return (true);
    }

    /* ================ */
    virtual void commit ()
    {
        if (m_map_kd != NULL)
            m_map_kd->apply(0);
        else
            m_device->SetTexture(0, NULL);
        m_device->SetMaterial(&m_mtl);
    }
};

}   /* namespace */

/* ==================================================================== */
CR_API asy::IAttrib* create_crh3d9_attr_wf_fixed (const sWAVEFRONT_M* mtl,
    const asy::map_acs<asy::crh3d9_texr>* texpool, const asy::crh3d9_main* main)
{
    asy::crh3d9_attr_wf_fixed*  attr;

    attr = new asy::crh3d9_attr_wf_fixed (main);
    if (attr != NULL) {
        if (!attr->init_ff(mtl, texpool)) {
            delete attr;
            attr = NULL;
        }
    }
    return ((asy::IAttrib*)attr);
}

/*****************************************************************************/
/*                                   Mesh                                    */
/*****************************************************************************/

/* Asylum Namespace */
namespace asy {

/**********************************/
/* Wavefront Mesh (Single Stream) */
/**********************************/
class crh3d9_mesh_wf_ss : public IMesh
{
private:
    sD3D9_MESH*         m_mesh;
    const sD3D9_CALL*   m_call;
    LPDIRECT3DDEVICE9   m_devs;

public:
    /* ===================================== */
    crh3d9_mesh_wf_ss (const crh3d9_main* main)
    {
        m_mesh = NULL;
        m_call = main->get_call();
        m_devs = main->get_main()->dev;
    }

    /* ======================= */
    virtual ~crh3d9_mesh_wf_ss ()
    {
        if (m_mesh != NULL)
            m_call->release_mesh(m_mesh);
    }

public:
    /* ==================================================================== */
    bool init2_ss (const sWAVEFRONT* obj, leng_t idx, const crh3d9_main* main)
    {
        leng_t  nv, ni, bpv;

        nv = wfront_gen_mesh2(NULL, NULL, NULL, 0, 0, 0, NULL, &ni, obj, idx);
        if (nv == 0)
            return (false);
        bpv = sizeof(vec3d_t);
        if (obj->p_f[0].idx[2] != 0)
            bpv += sizeof(vec3d_t);
        if (obj->p_f[0].idx[1] != 0)
            bpv += sizeof(vec2d_t);

        void_t* vb;
        void_t* ib;

        vb = mem_calloc(nv, bpv);
        if (vb == NULL)
            return (false);
        if (nv > 65536)
            ib = mem_calloc(ni, sizeof(int32u));
        else
            ib = mem_calloc(ni, sizeof(int16u));
        if (ib == NULL) {
            mem_free(vb);
            return (false);
        }

        uint_t      fvf;
        vec3d_t*    xyz;
        vec3d_t*    nrm;
        vec2d_t*    uvw;

        fvf = D3DFVF_XYZ;
        xyz = (vec3d_t*)vb;
        if (obj->p_f[0].idx[2] != 0) {
            fvf |= D3DFVF_NORMAL;
            nrm = xyz + 1;
            uvw = (vec2d_t*)(nrm + 1);
        }
        else {
            nrm = NULL;
            uvw = (vec2d_t*)(xyz + 1);
        }
        if (obj->p_f[0].idx[1] != 0)
            fvf |= D3DFVF_TEX1;
        else
            uvw = NULL;
        wfront_gen_mesh2(xyz, nrm, uvw, bpv, 0, 0, ib, NULL, obj, idx);
        m_mesh = m_call->create_mesh_vib(main->get_main(), nv, bpv, ni,
                            D3DPOOL_MANAGED, D3DUSAGE_WRITEONLY, D3DPOOL_MANAGED,
                                    D3DUSAGE_WRITEONLY, fvf, vb, ib);
        mem_free(vb);
        mem_free(ib);
        if (m_mesh == NULL)
            return (false);
        return (true);
    }

    /* ================ */
    virtual void commit ()
    {
        m_devs->SetStreamSource(0, m_mesh->vbuf, 0, m_mesh->nbpv);
        m_devs->SetIndices(m_mesh->ibuf);
        m_devs->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, m_mesh->vnum, 0, m_mesh->ntri);
    }
};

}   /* namespace */

/* ========================================================================= */
CR_API asy::IMesh* create_crh3d9_mesh_wf_ss (const sWAVEFRONT* obj, leng_t idx,
                                             const asy::crh3d9_main* main)
{
    asy::crh3d9_mesh_wf_ss* mesh;

    mesh = new asy::crh3d9_mesh_wf_ss (main);
    if (mesh != NULL) {
        if (!mesh->init2_ss(obj, idx, main)) {
            delete mesh;
            mesh = NULL;
        }
    }
    return ((asy::IMesh*)mesh);
}

/*****************************************************************************/
/*                               Object Base                                 */
/*****************************************************************************/

/* =========================================================================== */
CR_API bool create_crh3d9_base_wf (asy::object_base* base, const sWAVEFRONT* obj,
                            create_crh3d9_attr_wf_t fattr, create_crh3d9_mesh_wf_t fmesh,
                                    const asy::map_acs<asy::crh3d9_texr>* texpool,
                                            const asy::crh3d9_main* main)
{
    asy::commit_batch   cb;

    base->list.init();
    for (leng_t idx = 0; idx < obj->n_m; idx++) {
        leng_t  ii, cnt = 0, cmp = idx + 1;
        for (ii = 0; ii < obj->n_g; ii++) {
            if (obj->p_g[ii].attr < cmp)
                break;
            if (obj->p_g[ii].attr == cmp)
                cnt += 1;
        }
        if (cnt == 0)
            continue;
        cb.attr = fattr(&obj->p_m[idx], texpool, main);
        if (cb.attr == NULL)
            goto _failure1;
        cb.mesh = mem_talloc(cnt + 1, asy::IMesh*);
        if (cb.mesh == NULL) {
            delete cb.attr;
            goto _failure1;
        }
        for (cnt = 0, ii = 0; ii < obj->n_g; ii++) {
            if (obj->p_g[ii].attr < cmp)
                break;
            if (obj->p_g[ii].attr == cmp) {
                cb.mesh[cnt] = fmesh(obj, ii, main);
                if (cb.mesh[cnt] == NULL)
                    goto _failure2;
                cnt += 1;
            }
        }
        cb.mesh[cnt] = NULL;
        if (base->list.append(&cb) == NULL)
            goto _failure2;
    }
    if (base->list.size() == 0)
        goto _failure1;
    bound_get_aabb(&base->aabb, obj->p_v, obj->n_v, sizeof(vec3d_t));
    bound_get_ball(&base->ball, obj->p_v, obj->n_v, sizeof(vec3d_t));
    return (true);

_failure2:
    cb.free();
_failure1:
    base->free();
    return (false);
}
<commit_msg>Asylum: 代码微调<commit_after>/*
***************************************
*   Asylum3D @ 2014-12-24
***************************************
*/

#include "../../asylum.hpp"

/*****************************************************************************/
/*                                  Effect                                   */
/*****************************************************************************/

/* Asylum Namespace */
namespace asy {

/****************************/
/* Wavefront Effect (Fixed) */
/****************************/
class crh3d9_ffct_wf_fixed : public IEffect
{
private:
    bool                m_uselt;
    BOOL*               m_onoff;
    DWORD               m_count;
    int64u              m_flags;
    D3DCOLOR*           m_color;
    D3DLIGHT9*          m_light;
    LPDIRECT3DDEVICE9   m_devcs;

public:
    /* ===================================================================================================================== */
    crh3d9_ffct_wf_fixed (D3DCOLOR* ambient, D3DLIGHT9* light, BOOL* onoff, DWORD count, int64u flags, const crh3d9_main* main)
    {
        m_onoff = onoff;
        m_count = count;
        m_flags = flags;
        m_light = light;
        m_color = ambient;
        m_devcs = main->get_main()->dev;
        m_uselt = (m_light != NULL && m_onoff != NULL && m_count != 0) ? true : false;
    }

    /* ========================== */
    virtual ~crh3d9_ffct_wf_fixed ()
    {
    }

public:
    /* =============== */
    virtual void enter ()
    {
        uint_t  fvf = D3DFVF_XYZ;

        m_devcs->SetRenderState(D3DRS_COLORVERTEX, FALSE);
        m_devcs->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_MATERIAL);
        m_devcs->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL);
        if (m_flags & ATTR_TYPE_TRANS) {
            m_devcs->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);
            m_devcs->SetRenderState(D3DRS_BLENDOP, D3DBLENDOP_ADD);
            m_devcs->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
            m_devcs->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
        }
        if (m_flags & ATTR_TYPE_NORMAL) {
            fvf |= D3DFVF_NORMAL;
            if (m_uselt) {
                m_devcs->SetRenderState(D3DRS_LIGHTING, TRUE);
                if (m_flags & ATTR_TYPE_SPECULAR)
                    m_devcs->SetRenderState(D3DRS_SPECULARENABLE, TRUE);
            }
        }
        if (m_flags & ATTR_TYPE_TEXTURE)
            fvf |= D3DFVF_TEX1;
        m_devcs->SetFVF(fvf);
    }

    /* =============== */
    virtual void leave ()
    {
        m_devcs->SetRenderState(D3DRS_COLORVERTEX, TRUE);
        m_devcs->SetRenderState(D3DRS_DIFFUSEMATERIALSOURCE, D3DMCS_COLOR1);
        m_devcs->SetRenderState(D3DRS_SPECULARMATERIALSOURCE, D3DMCS_COLOR2);
        if (m_flags & ATTR_TYPE_TRANS)
            m_devcs->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
        if (m_flags & ATTR_TYPE_NORMAL) {
            if (m_uselt) {
                m_devcs->SetRenderState(D3DRS_LIGHTING, FALSE);
                if (m_flags & ATTR_TYPE_SPECULAR)
                    m_devcs->SetRenderState(D3DRS_SPECULARENABLE, FALSE);
            }
        }
    }

    /* ================ */
    virtual void update ()
    {
        if (m_color != NULL)
            m_devcs->SetRenderState(D3DRS_AMBIENT, m_color[0]);
        if (m_uselt) {
            for (DWORD idx = 0; idx < m_count; idx++) {
                m_devcs->SetLight(idx, &m_light[idx]);
                m_devcs->LightEnable(idx, m_onoff[idx]);
            }
        }
    }
};

}   /* namespace */

/* ================================================================================ */
CR_API asy::IEffect* create_crh3d9_ffct_wf_fixed (D3DCOLOR* ambient, D3DLIGHT9* light,
                BOOL* onoff, DWORD count, int64u flags, const asy::crh3d9_main* main)
{
    asy::crh3d9_ffct_wf_fixed*  ffct;

    ffct = new asy::crh3d9_ffct_wf_fixed (ambient, light, onoff, count, flags, main);
    return ((asy::IEffect*)ffct);
}

/*****************************************************************************/
/*                                Attribute                                  */
/*****************************************************************************/

/* Asylum Namespace */
namespace asy {

/*******************************/
/* Wavefront Attribute (Fixed) */
/*******************************/
class crh3d9_attr_wf_fixed : public IAttrib
{
protected:
    D3DMATERIAL9        m_mtl;
    crh3d9_texr*        m_map_kd;
    LPDIRECT3DDEVICE9   m_device;

public:
    /* ======================================== */
    crh3d9_attr_wf_fixed (const crh3d9_main* main)
    {
        m_device = main->get_main()->dev;
    }

    /* ========================== */
    virtual ~crh3d9_attr_wf_fixed ()
    {
    }

public:
    /* ===================================================================== */
    bool init_ff (const sWAVEFRONT_M* mtl, const map_acs<crh3d9_texr>* texpool)
    {
        if (mtl->map_kd != NULL) {
            m_map_kd = texpool->get(mtl->map_kd);
            if (m_map_kd == NULL)
                return (false);
        }
        else {
            m_map_kd = NULL;
        }
        m_mtl.Diffuse.r = mtl->kd.x;
        m_mtl.Diffuse.g = mtl->kd.y;
        m_mtl.Diffuse.b = mtl->kd.z;
        m_mtl.Diffuse.a = mtl->d;
        if (m_mtl.Diffuse.a < 0.0f)
            m_mtl.Diffuse.a = 0.0f;
        else
        if (m_mtl.Diffuse.a > 1.0f)
            m_mtl.Diffuse.a = 1.0f;
        m_mtl.Ambient.r = mtl->ka.x;
        m_mtl.Ambient.g = mtl->ka.y;
        m_mtl.Ambient.b = mtl->ka.z;
        m_mtl.Ambient.a = 0.0f;
        m_mtl.Specular.r = mtl->ks.x;
        m_mtl.Specular.g = mtl->ks.y;
        m_mtl.Specular.b = mtl->ks.z;
        m_mtl.Specular.a = 0.0f;
        m_mtl.Emissive.r = 0.0f;
        m_mtl.Emissive.g = 0.0f;
        m_mtl.Emissive.b = 0.0f;
        m_mtl.Emissive.a = 0.0f;
        m_mtl.Power = mtl->ns;
        m_type = ATTR_TYPE_NORMAL;
        if (m_mtl.Diffuse.a < 1.0f)
            m_type |= ATTR_TYPE_TRANS;
        if (m_map_kd != NULL)
            m_type |= ATTR_TYPE_TEXTURE;
        if (m_mtl.Specular.r <= 0.0f && m_mtl.Specular.g <= 0.0f &&
            m_mtl.Specular.b <= 0.0f && m_mtl.Specular.a <= 0.0f)
            m_type |= ATTR_TYPE_SPECULAR;
        return (true);
    }

    /* ================ */
    virtual void commit ()
    {
        if (m_map_kd != NULL)
            m_map_kd->apply(0);
        else
            m_device->SetTexture(0, NULL);
        m_device->SetMaterial(&m_mtl);
    }
};

}   /* namespace */

/* ==================================================================== */
CR_API asy::IAttrib* create_crh3d9_attr_wf_fixed (const sWAVEFRONT_M* mtl,
    const asy::map_acs<asy::crh3d9_texr>* texpool, const asy::crh3d9_main* main)
{
    asy::crh3d9_attr_wf_fixed*  attr;

    attr = new asy::crh3d9_attr_wf_fixed (main);
    if (attr != NULL) {
        if (!attr->init_ff(mtl, texpool)) {
            delete attr;
            attr = NULL;
        }
    }
    return ((asy::IAttrib*)attr);
}

/*****************************************************************************/
/*                                   Mesh                                    */
/*****************************************************************************/

/* Asylum Namespace */
namespace asy {

/**********************************/
/* Wavefront Mesh (Single Stream) */
/**********************************/
class crh3d9_mesh_wf_ss : public IMesh
{
private:
    sD3D9_MESH*         m_mesh;
    const sD3D9_CALL*   m_call;
    LPDIRECT3DDEVICE9   m_devs;

public:
    /* ===================================== */
    crh3d9_mesh_wf_ss (const crh3d9_main* main)
    {
        m_mesh = NULL;
        m_call = main->get_call();
        m_devs = main->get_main()->dev;
    }

    /* ======================= */
    virtual ~crh3d9_mesh_wf_ss ()
    {
        if (m_mesh != NULL)
            m_call->release_mesh(m_mesh);
    }

public:
    /* ==================================================================== */
    bool init2_ss (const sWAVEFRONT* obj, leng_t idx, const crh3d9_main* main)
    {
        leng_t  nv, ni, bpv;

        nv = wfront_gen_mesh2(NULL, NULL, NULL, 0, 0, 0, NULL, &ni, obj, idx);
        if (nv == 0)
            return (false);
        bpv = sizeof(vec3d_t);
        if (obj->p_f[0].idx[2] != 0)
            bpv += sizeof(vec3d_t);
        if (obj->p_f[0].idx[1] != 0)
            bpv += sizeof(vec2d_t);

        void_t* vb;
        void_t* ib;

        vb = mem_calloc(nv, bpv);
        if (vb == NULL)
            return (false);
        if (nv > 65536)
            ib = mem_calloc(ni, sizeof(int32u));
        else
            ib = mem_calloc(ni, sizeof(int16u));
        if (ib == NULL) {
            mem_free(vb);
            return (false);
        }

        uint_t      fvf;
        vec3d_t*    xyz;
        vec3d_t*    nrm;
        vec2d_t*    uvw;

        fvf = D3DFVF_XYZ;
        xyz = (vec3d_t*)vb;
        if (obj->p_f[0].idx[2] != 0) {
            fvf |= D3DFVF_NORMAL;
            nrm = xyz + 1;
            uvw = (vec2d_t*)(nrm + 1);
        }
        else {
            nrm = NULL;
            uvw = (vec2d_t*)(xyz + 1);
        }
        if (obj->p_f[0].idx[1] != 0)
            fvf |= D3DFVF_TEX1;
        else
            uvw = NULL;
        wfront_gen_mesh2(xyz, nrm, uvw, bpv, 0, 0, ib, NULL, obj, idx);
        m_mesh = m_call->create_mesh_vib(main->get_main(), nv, bpv, ni,
                            D3DPOOL_MANAGED, D3DUSAGE_WRITEONLY, D3DPOOL_MANAGED,
                                    D3DUSAGE_WRITEONLY, fvf, vb, ib);
        mem_free(vb);
        mem_free(ib);
        if (m_mesh == NULL)
            return (false);
        return (true);
    }

    /* ================ */
    virtual void commit ()
    {
        m_devs->SetStreamSource(0, m_mesh->vbuf, 0, m_mesh->nbpv);
        m_devs->SetIndices(m_mesh->ibuf);
        m_devs->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, m_mesh->vnum, 0, m_mesh->ntri);
    }
};

}   /* namespace */

/* ========================================================================= */
CR_API asy::IMesh* create_crh3d9_mesh_wf_ss (const sWAVEFRONT* obj, leng_t idx,
                                             const asy::crh3d9_main* main)
{
    asy::crh3d9_mesh_wf_ss* mesh;

    mesh = new asy::crh3d9_mesh_wf_ss (main);
    if (mesh != NULL) {
        if (!mesh->init2_ss(obj, idx, main)) {
            delete mesh;
            mesh = NULL;
        }
    }
    return ((asy::IMesh*)mesh);
}

/*****************************************************************************/
/*                               Object Base                                 */
/*****************************************************************************/

/* =========================================================================== */
CR_API bool create_crh3d9_base_wf (asy::object_base* base, const sWAVEFRONT* obj,
                            create_crh3d9_attr_wf_t fattr, create_crh3d9_mesh_wf_t fmesh,
                                    const asy::map_acs<asy::crh3d9_texr>* texpool,
                                            const asy::crh3d9_main* main)
{
    asy::commit_batch   cb;

    base->list.init();
    for (leng_t idx = 0; idx < obj->n_m; idx++) {
        leng_t  ii, cnt = 0, cmp = idx + 1;
        for (ii = 0; ii < obj->n_g; ii++) {
            if (obj->p_g[ii].attr < cmp)
                break;
            if (obj->p_g[ii].attr == cmp)
                cnt += 1;
        }
        if (cnt == 0)
            continue;
        cb.attr = fattr(&obj->p_m[idx], texpool, main);
        if (cb.attr == NULL)
            goto _failure1;
        cb.mesh = mem_talloc(cnt + 1, asy::IMesh*);
        if (cb.mesh == NULL) {
            delete cb.attr;
            goto _failure1;
        }
        for (cnt = 0, ii = 0; ii < obj->n_g; ii++) {
            if (obj->p_g[ii].attr < cmp)
                break;
            if (obj->p_g[ii].attr == cmp) {
                cb.mesh[cnt] = fmesh(obj, ii, main);
                if (cb.mesh[cnt] == NULL)
                    goto _failure2;
                cnt += 1;
            }
        }
        cb.mesh[cnt] = NULL;
        if (base->list.append(&cb) == NULL)
            goto _failure2;
    }
    if (base->list.size() == 0)
        goto _failure1;
    if (!base->list.no_grow())
        goto _failure1;
    bound_get_aabb(&base->aabb, obj->p_v, obj->n_v, sizeof(vec3d_t));
    bound_get_ball(&base->ball, obj->p_v, obj->n_v, sizeof(vec3d_t));
    return (true);

_failure2:
    cb.free();
_failure1:
    base->free();
    return (false);
}
<|endoftext|>


<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2004-2007 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "factory_p.h"

#include "backendinterface.h"
#include "medianode_p.h"
#include "audiooutput.h"
#include "audiooutput_p.h"
#include "globalstatic_p.h"
#include "objectdescription.h"
#include "platformplugin.h"
#include "phononnamespace_p.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QLibrary>
#include <QtCore/QList>
#include <QtCore/QPluginLoader>
#include <QtCore/QPointer>
#include <QtGui/QIcon>
#ifndef QT_NO_DBUS
#include <QtDBus/QtDBus>
#endif

QT_BEGIN_NAMESPACE

namespace Phonon
{

class PlatformPlugin;
class FactoryPrivate : public Phonon::Factory::Sender
{
    friend QObject *Factory::backend(bool);
    Q_OBJECT
    public:
        FactoryPrivate();
        ~FactoryPrivate();
        bool createBackend();
        PlatformPlugin *platformPlugin();

        QPointer<QObject> m_backendObject;
        PlatformPlugin *m_platformPlugin;
        bool m_noPlatformPlugin;

        QList<QObject *> objects;
        QList<MediaNodePrivate *> mediaNodePrivateList;

    private Q_SLOTS:
        /**
         * This is called via DBUS when the user changes the Phonon Backend.
         */
        void phononBackendChanged();

        /**
         * unregisters the backend object
         */
        void objectDestroyed(QObject *);

        void objectDescriptionChanged(ObjectDescriptionType);
};

PHONON_GLOBAL_STATIC(Phonon::FactoryPrivate, globalFactory)

void Factory::setBackend(QObject *b)
{
    Q_ASSERT(globalFactory->m_backendObject == 0);
    globalFactory->m_backendObject = b;
}

/*void Factory::createBackend(const QString &library, const QString &version)
{
    Q_ASSERT(globalFactory->m_backendObject == 0);
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        globalFactory->m_backendObject = f->createBackend(library, version);
    }
}*/

bool FactoryPrivate::createBackend()
{
    Q_ASSERT(m_backendObject == 0);
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        m_backendObject = f->createBackend();
    }
    if (!m_backendObject) {
        // could not load a backend through the platform plugin. Falling back to the default
        // (finding the first loadable backend).
        const QLatin1String suffix("/phonon_backend/");
        foreach (QString libPath, QCoreApplication::libraryPaths()) {
            libPath += suffix;
            const QDir dir(libPath);
            if (!dir.exists()) {
                pDebug() << Q_FUNC_INFO << dir.absolutePath() << "does not exist";
                continue;
            }
            foreach (const QString &pluginName, dir.entryList(QDir::Files)) {
                QPluginLoader pluginLoader(libPath + pluginName);
                if (!pluginLoader.load()) {
                    pDebug() << Q_FUNC_INFO << "  load failed:"
                             << pluginLoader.errorString();
                    continue;
                }
                pDebug() << pluginLoader.instance();
                m_backendObject = pluginLoader.instance();
                if (m_backendObject) {
                    break;
                }

                // no backend found, don't leave an unused plugin in memory
                pluginLoader.unload();
            }

            if (m_backendObject) {
                break;
            }
        }
        if (!m_backendObject) {
            pWarning() << Q_FUNC_INFO << "phonon backend plugin could not be loaded";
            return false;
        }
    }

    connect(m_backendObject, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)),
            SLOT(objectDescriptionChanged(ObjectDescriptionType)));

    return true;
}

FactoryPrivate::FactoryPrivate()
    : m_backendObject(0),
    m_platformPlugin(0),
    m_noPlatformPlugin(false)
{
    // Add the post routine to make sure that all other global statics (especially the ones from Qt)
    // are still available. If the FactoryPrivate dtor is called too late many bad things can happen
    // as the whole backend might still be alive.
    qAddPostRoutine(globalFactory.destroy);
#ifndef QT_NO_DBUS
    QDBusConnection::sessionBus().connect(QString(), QString(), "org.kde.Phonon.Factory",
            "phononBackendChanged", this, SLOT(phononBackendChanged()));
#endif
}

FactoryPrivate::~FactoryPrivate()
{
    foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
        bp->deleteBackendObject();
    }
    if (objects.size() > 0) {
        pError() << "The backend objects are not deleted as was requested.";
        qDeleteAll(objects);
    }
    delete m_backendObject;
    delete m_platformPlugin;
}

void FactoryPrivate::objectDescriptionChanged(ObjectDescriptionType type)
{
#ifdef PHONON_METHODTEST
    Q_UNUSED(type);
#else
    pDebug() << Q_FUNC_INFO << type;
    switch (type) {
    case AudioOutputDeviceType:
        emit availableAudioOutputDevicesChanged();
        break;
    default:
        break;
    }
    //emit capabilitiesChanged();
#endif // PHONON_METHODTEST
}

Factory::Sender *Factory::sender()
{
    return globalFactory;
}

bool Factory::isMimeTypeAvailable(const QString &mimeType)
{
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        return f->isMimeTypeAvailable(mimeType);
    }
    return true; // the MIME type might be supported, let BackendCapabilities find out
}

void Factory::registerFrontendObject(MediaNodePrivate *bp)
{
    globalFactory->mediaNodePrivateList.prepend(bp); // inserted last => deleted first
}

void Factory::deregisterFrontendObject(MediaNodePrivate *bp)
{
    // The Factory can already be cleaned up while there are other frontend objects still alive.
    // When those are deleted they'll call deregisterFrontendObject through ~BasePrivate
    if (!globalFactory.isDestroyed()) {
        globalFactory->mediaNodePrivateList.removeAll(bp);
    }
}

void FactoryPrivate::phononBackendChanged()
{
    if (m_backendObject) {
        foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
            bp->deleteBackendObject();
        }
        if (objects.size() > 0) {
            pDebug() << "WARNING: we were asked to change the backend but the application did\n"
                "not free all references to objects created by the factory. Therefore we can not\n"
                "change the backend without crashing. Now we have to wait for a restart to make\n"
                "backendswitching possible.";
            // in case there were objects deleted give 'em a chance to recreate
            // them now
            foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
                bp->createBackendObject();
            }
            return;
        }
        delete m_backendObject;
        m_backendObject = 0;
    }
    createBackend();
    foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
        bp->createBackendObject();
    }
    emit backendChanged();
}

//X void Factory::freeSoundcardDevices()
//X {
//X     if (globalFactory->backend) {
//X         globalFactory->backend->freeSoundcardDevices();
//X     }
//X }

void FactoryPrivate::objectDestroyed(QObject * obj)
{
    //pDebug() << Q_FUNC_INFO << obj;
    objects.removeAll(obj);
}

#define FACTORY_IMPL(classname) \
QObject *Factory::create ## classname(QObject *parent) \
{ \
    if (backend()) { \
        return registerQObject(qobject_cast<BackendInterface *>(backend())->createObject(BackendInterface::classname##Class, parent)); \
    } \
    return 0; \
}
#define FACTORY_IMPL_1ARG(classname) \
QObject *Factory::create ## classname(int arg1, QObject *parent) \
{ \
    if (backend()) { \
        return registerQObject(qobject_cast<BackendInterface *>(backend())->createObject(BackendInterface::classname##Class, parent, QList<QVariant>() << arg1)); \
    } \
    return 0; \
}

FACTORY_IMPL(MediaObject)
FACTORY_IMPL_1ARG(Effect)
FACTORY_IMPL(VolumeFaderEffect)
FACTORY_IMPL(AudioOutput)
FACTORY_IMPL(AudioDataOutput)
FACTORY_IMPL(Visualization)
FACTORY_IMPL(VideoDataOutput)
FACTORY_IMPL(VideoWidget)

#undef FACTORY_IMPL

PlatformPlugin *FactoryPrivate::platformPlugin()
{
    if (m_platformPlugin) {
        return m_platformPlugin;
    }
    if (m_noPlatformPlugin) {
        return 0;
    }
#ifndef QT_NO_DBUS
    if (!QCoreApplication::instance() || QCoreApplication::applicationName().isEmpty()) {
        pWarning() << "Phonon needs QCoreApplication::applicationName to be set to export audio output names through the DBUS interface";
    }
#endif
    const QString suffix(QLatin1String("/phonon_platform/"));
    Q_ASSERT(QCoreApplication::instance());
    foreach (QString libPath, QCoreApplication::libraryPaths()) {
        libPath += suffix;
        const QDir dir(libPath);
        if (!dir.exists()) {
            pDebug() << Q_FUNC_INFO << dir.absolutePath() << "does not exist";
            continue;
        }
        foreach (const QString &pluginName, dir.entryList(QDir::Files)) {
            QPluginLoader pluginLoader(libPath + pluginName);
            if (!pluginLoader.load()) {
                pDebug() << Q_FUNC_INFO << "  platform plugin load failed:"
                    << pluginLoader.errorString();
                continue;
            }
            pDebug() << pluginLoader.instance();
            QObject *qobj = pluginLoader.instance();
            m_platformPlugin = qobject_cast<PlatformPlugin *>(qobj);
            pDebug() << m_platformPlugin;
            if (m_platformPlugin) {
                connect(qobj, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)),
                        SLOT(objectDescriptionChanged(ObjectDescriptionType)));
                return m_platformPlugin;
            } else {
                pDebug() << Q_FUNC_INFO << dir.absolutePath() << "exists but the platform plugin was not loadable:" << pluginLoader.errorString();
                pluginLoader.unload();
            }
        }
    }
    pDebug() << Q_FUNC_INFO << "phonon_platform/kde plugin could not be loaded";
    m_noPlatformPlugin = true;
    return 0;
}

PlatformPlugin *Factory::platformPlugin()
{
    return globalFactory->platformPlugin();
}

QObject *Factory::backend(bool createWhenNull)
{
    if (globalFactory.isDestroyed()) {
        return 0;
    }
    if (createWhenNull && globalFactory->m_backendObject == 0) {
        globalFactory->createBackend();
        // XXX: might create "reentrancy" problems:
        // a method calls this method and is called again because the
        // backendChanged signal is emitted
        emit globalFactory->backendChanged();
    }
    return globalFactory->m_backendObject;
}

#define GET_STRING_PROPERTY(name) \
QString Factory::name() \
{ \
    if (globalFactory->m_backendObject) { \
        return globalFactory->m_backendObject->property(#name).toString(); \
    } \
    return QString(); \
} \

GET_STRING_PROPERTY(identifier)
GET_STRING_PROPERTY(backendName)
GET_STRING_PROPERTY(backendComment)
GET_STRING_PROPERTY(backendVersion)
GET_STRING_PROPERTY(backendIcon)
GET_STRING_PROPERTY(backendWebsite)

QObject *Factory::registerQObject(QObject *o)
{
    if (o) {
        QObject::connect(o, SIGNAL(destroyed(QObject *)), globalFactory, SLOT(objectDestroyed(QObject *)), Qt::DirectConnection);
        globalFactory->objects.append(o);
    }
    return o;
}

} //namespace Phonon

QT_END_NAMESPACE

#include "factory.moc"
#include "moc_factory_p.cpp"

// vim: sw=4 ts=4
<commit_msg>make it stop playback a bit faster on shutdown. Especially with streams and the xine backend there was a quite noticable delay<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2004-2007 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "factory_p.h"

#include "backendinterface.h"
#include "medianode_p.h"
#include "mediaobject.h"
#include "audiooutput.h"
#include "audiooutput_p.h"
#include "globalstatic_p.h"
#include "objectdescription.h"
#include "platformplugin.h"
#include "phononnamespace_p.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QLibrary>
#include <QtCore/QList>
#include <QtCore/QPluginLoader>
#include <QtCore/QPointer>
#include <QtGui/QIcon>
#ifndef QT_NO_DBUS
#include <QtDBus/QtDBus>
#endif

QT_BEGIN_NAMESPACE

namespace Phonon
{

class PlatformPlugin;
class FactoryPrivate : public Phonon::Factory::Sender
{
    friend QObject *Factory::backend(bool);
    Q_OBJECT
    public:
        FactoryPrivate();
        ~FactoryPrivate();
        bool createBackend();
        PlatformPlugin *platformPlugin();

        QPointer<QObject> m_backendObject;
        PlatformPlugin *m_platformPlugin;
        bool m_noPlatformPlugin;

        QList<QObject *> objects;
        QList<MediaNodePrivate *> mediaNodePrivateList;

    private Q_SLOTS:
        /**
         * This is called via DBUS when the user changes the Phonon Backend.
         */
        void phononBackendChanged();

        /**
         * unregisters the backend object
         */
        void objectDestroyed(QObject *);

        void objectDescriptionChanged(ObjectDescriptionType);
};

PHONON_GLOBAL_STATIC(Phonon::FactoryPrivate, globalFactory)

void Factory::setBackend(QObject *b)
{
    Q_ASSERT(globalFactory->m_backendObject == 0);
    globalFactory->m_backendObject = b;
}

/*void Factory::createBackend(const QString &library, const QString &version)
{
    Q_ASSERT(globalFactory->m_backendObject == 0);
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        globalFactory->m_backendObject = f->createBackend(library, version);
    }
}*/

bool FactoryPrivate::createBackend()
{
    Q_ASSERT(m_backendObject == 0);
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        m_backendObject = f->createBackend();
    }
    if (!m_backendObject) {
        // could not load a backend through the platform plugin. Falling back to the default
        // (finding the first loadable backend).
        const QLatin1String suffix("/phonon_backend/");
        foreach (QString libPath, QCoreApplication::libraryPaths()) {
            libPath += suffix;
            const QDir dir(libPath);
            if (!dir.exists()) {
                pDebug() << Q_FUNC_INFO << dir.absolutePath() << "does not exist";
                continue;
            }
            foreach (const QString &pluginName, dir.entryList(QDir::Files)) {
                QPluginLoader pluginLoader(libPath + pluginName);
                if (!pluginLoader.load()) {
                    pDebug() << Q_FUNC_INFO << "  load failed:"
                             << pluginLoader.errorString();
                    continue;
                }
                pDebug() << pluginLoader.instance();
                m_backendObject = pluginLoader.instance();
                if (m_backendObject) {
                    break;
                }

                // no backend found, don't leave an unused plugin in memory
                pluginLoader.unload();
            }

            if (m_backendObject) {
                break;
            }
        }
        if (!m_backendObject) {
            pWarning() << Q_FUNC_INFO << "phonon backend plugin could not be loaded";
            return false;
        }
    }

    connect(m_backendObject, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)),
            SLOT(objectDescriptionChanged(ObjectDescriptionType)));

    return true;
}

FactoryPrivate::FactoryPrivate()
    : m_backendObject(0),
    m_platformPlugin(0),
    m_noPlatformPlugin(false)
{
    // Add the post routine to make sure that all other global statics (especially the ones from Qt)
    // are still available. If the FactoryPrivate dtor is called too late many bad things can happen
    // as the whole backend might still be alive.
    qAddPostRoutine(globalFactory.destroy);
#ifndef QT_NO_DBUS
    QDBusConnection::sessionBus().connect(QString(), QString(), "org.kde.Phonon.Factory",
            "phononBackendChanged", this, SLOT(phononBackendChanged()));
#endif
}

FactoryPrivate::~FactoryPrivate()
{
    foreach (QObject *o, objects) {
        MediaObject *m = qobject_cast<MediaObject *>(o);
        if (m) {
            m->stop();
        }
    }
    foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
        bp->deleteBackendObject();
    }
    if (objects.size() > 0) {
        pError() << "The backend objects are not deleted as was requested.";
        qDeleteAll(objects);
    }
    delete m_backendObject;
    delete m_platformPlugin;
}

void FactoryPrivate::objectDescriptionChanged(ObjectDescriptionType type)
{
#ifdef PHONON_METHODTEST
    Q_UNUSED(type);
#else
    pDebug() << Q_FUNC_INFO << type;
    switch (type) {
    case AudioOutputDeviceType:
        emit availableAudioOutputDevicesChanged();
        break;
    default:
        break;
    }
    //emit capabilitiesChanged();
#endif // PHONON_METHODTEST
}

Factory::Sender *Factory::sender()
{
    return globalFactory;
}

bool Factory::isMimeTypeAvailable(const QString &mimeType)
{
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        return f->isMimeTypeAvailable(mimeType);
    }
    return true; // the MIME type might be supported, let BackendCapabilities find out
}

void Factory::registerFrontendObject(MediaNodePrivate *bp)
{
    globalFactory->mediaNodePrivateList.prepend(bp); // inserted last => deleted first
}

void Factory::deregisterFrontendObject(MediaNodePrivate *bp)
{
    // The Factory can already be cleaned up while there are other frontend objects still alive.
    // When those are deleted they'll call deregisterFrontendObject through ~BasePrivate
    if (!globalFactory.isDestroyed()) {
        globalFactory->mediaNodePrivateList.removeAll(bp);
    }
}

void FactoryPrivate::phononBackendChanged()
{
    if (m_backendObject) {
        foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
            bp->deleteBackendObject();
        }
        if (objects.size() > 0) {
            pDebug() << "WARNING: we were asked to change the backend but the application did\n"
                "not free all references to objects created by the factory. Therefore we can not\n"
                "change the backend without crashing. Now we have to wait for a restart to make\n"
                "backendswitching possible.";
            // in case there were objects deleted give 'em a chance to recreate
            // them now
            foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
                bp->createBackendObject();
            }
            return;
        }
        delete m_backendObject;
        m_backendObject = 0;
    }
    createBackend();
    foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
        bp->createBackendObject();
    }
    emit backendChanged();
}

//X void Factory::freeSoundcardDevices()
//X {
//X     if (globalFactory->backend) {
//X         globalFactory->backend->freeSoundcardDevices();
//X     }
//X }

void FactoryPrivate::objectDestroyed(QObject * obj)
{
    //pDebug() << Q_FUNC_INFO << obj;
    objects.removeAll(obj);
}

#define FACTORY_IMPL(classname) \
QObject *Factory::create ## classname(QObject *parent) \
{ \
    if (backend()) { \
        return registerQObject(qobject_cast<BackendInterface *>(backend())->createObject(BackendInterface::classname##Class, parent)); \
    } \
    return 0; \
}
#define FACTORY_IMPL_1ARG(classname) \
QObject *Factory::create ## classname(int arg1, QObject *parent) \
{ \
    if (backend()) { \
        return registerQObject(qobject_cast<BackendInterface *>(backend())->createObject(BackendInterface::classname##Class, parent, QList<QVariant>() << arg1)); \
    } \
    return 0; \
}

FACTORY_IMPL(MediaObject)
FACTORY_IMPL_1ARG(Effect)
FACTORY_IMPL(VolumeFaderEffect)
FACTORY_IMPL(AudioOutput)
FACTORY_IMPL(AudioDataOutput)
FACTORY_IMPL(Visualization)
FACTORY_IMPL(VideoDataOutput)
FACTORY_IMPL(VideoWidget)

#undef FACTORY_IMPL

PlatformPlugin *FactoryPrivate::platformPlugin()
{
    if (m_platformPlugin) {
        return m_platformPlugin;
    }
    if (m_noPlatformPlugin) {
        return 0;
    }
#ifndef QT_NO_DBUS
    if (!QCoreApplication::instance() || QCoreApplication::applicationName().isEmpty()) {
        pWarning() << "Phonon needs QCoreApplication::applicationName to be set to export audio output names through the DBUS interface";
    }
#endif
    const QString suffix(QLatin1String("/phonon_platform/"));
    Q_ASSERT(QCoreApplication::instance());
    foreach (QString libPath, QCoreApplication::libraryPaths()) {
        libPath += suffix;
        const QDir dir(libPath);
        if (!dir.exists()) {
            pDebug() << Q_FUNC_INFO << dir.absolutePath() << "does not exist";
            continue;
        }
        foreach (const QString &pluginName, dir.entryList(QDir::Files)) {
            QPluginLoader pluginLoader(libPath + pluginName);
            if (!pluginLoader.load()) {
                pDebug() << Q_FUNC_INFO << "  platform plugin load failed:"
                    << pluginLoader.errorString();
                continue;
            }
            pDebug() << pluginLoader.instance();
            QObject *qobj = pluginLoader.instance();
            m_platformPlugin = qobject_cast<PlatformPlugin *>(qobj);
            pDebug() << m_platformPlugin;
            if (m_platformPlugin) {
                connect(qobj, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)),
                        SLOT(objectDescriptionChanged(ObjectDescriptionType)));
                return m_platformPlugin;
            } else {
                pDebug() << Q_FUNC_INFO << dir.absolutePath() << "exists but the platform plugin was not loadable:" << pluginLoader.errorString();
                pluginLoader.unload();
            }
        }
    }
    pDebug() << Q_FUNC_INFO << "phonon_platform/kde plugin could not be loaded";
    m_noPlatformPlugin = true;
    return 0;
}

PlatformPlugin *Factory::platformPlugin()
{
    return globalFactory->platformPlugin();
}

QObject *Factory::backend(bool createWhenNull)
{
    if (globalFactory.isDestroyed()) {
        return 0;
    }
    if (createWhenNull && globalFactory->m_backendObject == 0) {
        globalFactory->createBackend();
        // XXX: might create "reentrancy" problems:
        // a method calls this method and is called again because the
        // backendChanged signal is emitted
        emit globalFactory->backendChanged();
    }
    return globalFactory->m_backendObject;
}

#define GET_STRING_PROPERTY(name) \
QString Factory::name() \
{ \
    if (globalFactory->m_backendObject) { \
        return globalFactory->m_backendObject->property(#name).toString(); \
    } \
    return QString(); \
} \

GET_STRING_PROPERTY(identifier)
GET_STRING_PROPERTY(backendName)
GET_STRING_PROPERTY(backendComment)
GET_STRING_PROPERTY(backendVersion)
GET_STRING_PROPERTY(backendIcon)
GET_STRING_PROPERTY(backendWebsite)

QObject *Factory::registerQObject(QObject *o)
{
    if (o) {
        QObject::connect(o, SIGNAL(destroyed(QObject *)), globalFactory, SLOT(objectDestroyed(QObject *)), Qt::DirectConnection);
        globalFactory->objects.append(o);
    }
    return o;
}

} //namespace Phonon

QT_END_NAMESPACE

#include "factory.moc"
#include "moc_factory_p.cpp"

// vim: sw=4 ts=4
<|endoftext|>