Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Toonz includes
Toshihiro Shimizu 890ddd
#include "tvectorimage.h"
Toshihiro Shimizu 890ddd
#include "trasterimage.h"
Toshihiro Shimizu 890ddd
#include "tlevel_io.h"
Toshihiro Shimizu 890ddd
#include "tofflinegl.h"
Toshihiro Shimizu 890ddd
#include "tropcm.h"
Toshihiro Shimizu 890ddd
#include "tvectorrenderdata.h"
Toshihiro Shimizu 890ddd
#include "tsystem.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//Qt includes
Toshihiro Shimizu 890ddd
#include <qdir></qdir>
Toshihiro Shimizu 890ddd
#include <qimage></qimage>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/stylemanager.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace stuff
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TFilePath rootPath;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void convertRaster32ToImage(TRaster32P ras, QImage *image)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int lx = ras->getLx();
Toshihiro Shimizu 890ddd
	int ly = ras->getLy();
Toshihiro Shimizu 890ddd
	int i, j;
Toshihiro Shimizu 890ddd
	ras->lock();
Toshihiro Shimizu 890ddd
	for (i = 0; i < lx; i++)
Toshihiro Shimizu 890ddd
		for (j = 0; j < ly; j++) {
Toshihiro Shimizu 890ddd
			TPixel32 pix = ras->pixels(ly - 1 - j)[i];
Toshihiro Shimizu 890ddd
			QRgb value;
Toshihiro Shimizu 890ddd
			value = qRgba(pix.r, pix.g, pix.b, pix.m);
Toshihiro Shimizu 890ddd
			image->setPixel(i, j, value);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	ras->unlock();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} //namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    StyleLoaderTask definition
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class CustomStyleManager::StyleLoaderTask : public TThread::Runnable
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	CustomStyleManager *m_manager;
Toshihiro Shimizu 890ddd
	TFilePath m_fp;
Toshihiro Shimizu 890ddd
	PatternData m_data;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	StyleLoaderTask(CustomStyleManager *manager, const TFilePath &fp);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void run();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void onFinished(TThread::RunnableP sender);
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
CustomStyleManager::StyleLoaderTask::StyleLoaderTask(CustomStyleManager *manager, const TFilePath &fp)
Toshihiro Shimizu 890ddd
	: m_manager(manager), m_fp(fp)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	connect(this, SIGNAL(finished(TThread::RunnableP)), this, SLOT(onFinished(TThread::RunnableP)));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void CustomStyleManager::StyleLoaderTask::run()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	try {
Toshihiro Shimizu 890ddd
		//Fetch the level
Toshihiro Shimizu 890ddd
		TLevelReaderP lr(m_fp);
Toshihiro Shimizu 890ddd
		TLevelP level = lr->loadInfo();
Toshihiro Shimizu 890ddd
		if (!level || level->getFrameCount() == 0)
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Fetch the image of the first frame in the level
Toshihiro Shimizu 890ddd
		TLevel::Iterator frameIt = level->begin();
Toshihiro Shimizu 890ddd
		if (frameIt == level->end())
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		TImageP img = lr->getFrameReader(frameIt->first)->load();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		//Process the image
Toshihiro Shimizu 890ddd
		const QSize &qChipSize = m_manager->getChipSize();
Toshihiro Shimizu 890ddd
		TDimension chipSize(qChipSize.width(), qChipSize.height());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TVectorImageP vimg = img;
Toshihiro Shimizu 890ddd
		TRasterImageP rimg = img;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TRaster32P ras;
Toshihiro Shimizu 890ddd
		if (vimg) {
Toshihiro Shimizu 890ddd
			assert(level->getPalette());
Toshihiro Shimizu 890ddd
			TPalette *vPalette = level->getPalette();
Toshihiro Shimizu 890ddd
			assert(vPalette);
Toshihiro Shimizu 890ddd
			vimg->setPalette(vPalette);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			TOfflineGL *glContext = 0;
Toshihiro Shimizu 890ddd
			glContext = TOfflineGL::getStock(chipSize);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			glContext->clear(TPixel32::White);
Toshihiro Shimizu 890ddd
			TRectD bbox = img->getBBox();
Toshihiro Shimizu 890ddd
			double scx = 0.8 * chipSize.lx / bbox.getLx();
Toshihiro Shimizu 890ddd
			double scy = 0.8 * chipSize.ly / bbox.getLy();
Toshihiro Shimizu 890ddd
			double sc = tmin(scx, scy);
Toshihiro Shimizu 890ddd
			double dx = 0.5 * chipSize.lx;
Toshihiro Shimizu 890ddd
			double dy = 0.5 * chipSize.ly;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			TAffine aff = TTranslation(dx, dy) * TScale(sc) *
Toshihiro Shimizu 890ddd
						  TTranslation(-0.5 * (bbox.x0 + bbox.x1), -0.5 * (bbox.y0 + bbox.y1));
Toshihiro Shimizu 890ddd
			TVectorRenderData rd(aff, chipSize, vPalette, 0, true);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			glContext->draw(img, rd);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			//No need to clone! The received raster already is a copy of the context's buffer
Toshihiro Shimizu 890ddd
			ras = glContext->getRaster(); //->clone();
Toshihiro Shimizu 890ddd
		} else if (rimg) {
Toshihiro Shimizu 890ddd
			TDimension size = rimg->getRaster()->getSize();
Toshihiro Shimizu 890ddd
			if (size == chipSize)
Toshihiro Shimizu 890ddd
				ras = rimg->getRaster()->clone(); //Yep, this may be necessary
Toshihiro Shimizu 890ddd
			else {
Toshihiro Shimizu 890ddd
				TRaster32P rout(chipSize);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				TRop::resample(rout, rimg->getRaster(),
Toshihiro Shimizu 890ddd
							   TScale((double)chipSize.lx / size.lx, (double)chipSize.ly / size.ly));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				TRop::addBackground(rout, TPixel::White);
Toshihiro Shimizu 890ddd
				ras = rout;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		} else
Toshihiro Shimizu 890ddd
			assert(!"unsupported type for custom styles!");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		QImage *image = new QImage(chipSize.lx, chipSize.ly, QImage::Format_RGB32);
Toshihiro Shimizu 890ddd
		convertRaster32ToImage(ras, image);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_data.m_patternName = m_fp.getName();
Toshihiro Shimizu 890ddd
		m_data.m_isVector = (m_fp.getType() == "pli" || m_fp.getType() == "svg");
Toshihiro Shimizu 890ddd
		m_data.m_image = image;
Toshihiro Shimizu 890ddd
	} catch (...) {
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void CustomStyleManager::StyleLoaderTask::onFinished(TThread::RunnableP sender)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//On the main thread...
Toshihiro Shimizu 890ddd
	if (m_data.m_image) //Everything went ok
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_manager->m_patterns.push_back(m_data);
Toshihiro Shimizu 890ddd
		emit m_manager->patternAdded();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
//    CustomStyleManager implementation
Toshihiro Shimizu 890ddd
//********************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
CustomStyleManager::CustomStyleManager(
Toshihiro Shimizu 890ddd
	const TFilePath &stylesFolder, QString filters, QSize chipSize)
Toshihiro Shimizu 890ddd
	: m_stylesFolder(stylesFolder), m_filters(filters), m_chipSize(chipSize)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_executor.setMaxActiveTasks(1);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int CustomStyleManager::getPatternCount()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return m_patterns.size();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
CustomStyleManager::PatternData CustomStyleManager::getPattern(int index)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return (index < 0 || index >= m_patterns.size()) ? PatternData() : m_patterns[index];
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TFilePath CustomStyleManager::getRootPath()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return ::rootPath;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void CustomStyleManager::setRootPath(const TFilePath &rootPath)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	::rootPath = rootPath;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void CustomStyleManager::loadItems()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	//Build the folder to be read
Toshihiro Shimizu 890ddd
	const TFilePath &rootFP(getRootPath());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(rootFP != TFilePath());
Toshihiro Shimizu 890ddd
	if (rootFP == TFilePath())
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QDir patternDir(QString::fromStdWString((rootFP + m_stylesFolder).getWideString()));
Toshihiro Shimizu 890ddd
	patternDir.setNameFilters(m_filters.split(' '));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Read the said folder
Toshihiro Shimizu 890ddd
	TFilePathSet fps;
Toshihiro Shimizu 890ddd
	try {
Toshihiro Shimizu 890ddd
		TSystem::readDirectory(fps, patternDir);
Toshihiro Shimizu 890ddd
	} catch (...) {
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Delete patterns no longer in the folder
Toshihiro Shimizu 890ddd
	TFilePathSet newFps;
Toshihiro Shimizu 890ddd
	TFilePathSet::iterator it;
Toshihiro Shimizu 890ddd
	int i;
Toshihiro Shimizu 890ddd
	for (i = 0; i < m_patterns.size(); i++) {
Toshihiro Shimizu 890ddd
		PatternData data = m_patterns.at(i);
Toshihiro Shimizu 890ddd
		for (it = fps.begin(); it != fps.end(); ++it) {
Toshihiro Shimizu 890ddd
			if (data.m_patternName == it->getName() && data.m_isVector == (it->getType() == "pli"))
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (it == fps.end()) {
Toshihiro Shimizu 890ddd
			m_patterns.removeAt(i);
Toshihiro Shimizu 890ddd
			i--;
Toshihiro Shimizu 890ddd
		} else
Toshihiro Shimizu 890ddd
			fps.erase(it); //The style is not new, so don't generate tasks for it
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//For each (now new) file entry, generate a fetching task
Toshihiro Shimizu 890ddd
	for (TFilePathSet::iterator it = fps.begin(); it != fps.end(); it++)
Toshihiro Shimizu 890ddd
		m_executor.addTask(new StyleLoaderTask(this, *it));
Toshihiro Shimizu 890ddd
}