00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifdef HAVE_CONFIG_H
00021 #include <config.h>
00022 #endif
00023
00024 #ifdef HAVE_SYS_TYPES_H
00025 #include <sys/types.h>
00026 #endif
00027
00028 #include <math.h>
00029
00030 #include <netinet/in.h>
00031 #include <limits.h>
00032 #include <stdlib.h>
00033
00034 #include <qimage.h>
00035 #include <qpoint.h>
00036 #include <qvaluevector.h>
00037 #include <qfile.h>
00038 #include <qregexp.h>
00039 #include <qstringlist.h>
00040 #include <qtextstream.h>
00041
00042 #include <kdebug.h>
00043 #include <klocale.h>
00044 #include <kapplication.h>
00045
00046 #include "kis_global.h"
00047 #include "kis_paint_device.h"
00048 #include "kis_imagepipe_brush.h"
00049 #include "kis_brush.h"
00050 #include "kis_alpha_mask.h"
00051 #include "kis_layer.h"
00052 #include "kis_meta_registry.h"
00053 #include "kis_colorspace_factory_registry.h"
00054
00055
00056 KisPipeBrushParasite::KisPipeBrushParasite(const QString& source)
00057 {
00058 needsMovement = false;
00059 QRegExp basicSplitter(" ", true);
00060 QRegExp parasiteSplitter(":", true);
00061 QStringList parasites = QStringList::split(basicSplitter, source);
00062 for (uint i = 0; i < parasites.count(); i++) {
00063 QStringList splitted = QStringList::split(parasiteSplitter, *parasites.at(i));
00064 if (splitted.count() != 2) {
00065 kdWarning(41001) << "Wrong count for this parasite key/value:" << *parasites.at(i) << endl;
00066 continue;
00067 }
00068 QString index = *splitted.at(0);
00069 if (index == "dim") {
00070 dim = (*splitted.at(1)).toInt();
00071 if (dim < 1 || dim > MaxDim) {
00072 dim = 1;
00073 }
00074 } else if (index.startsWith("sel")) {
00075 int selIndex = index.mid(strlen("sel")).toInt();
00076 if (selIndex >= 0 && selIndex < dim) {
00077 QString selectionMode = *splitted.at(1);
00078 if (selectionMode == "incremental")
00079 selection[selIndex] = Incremental;
00080 else if (selectionMode == "angular") {
00081 selection[selIndex] = Angular;
00082 needsMovement = true;
00083 } else if (selectionMode == "random")
00084 selection[selIndex] = Random;
00085 else if (selectionMode == "pressure")
00086 selection[selIndex] = Pressure;
00087 else if (selectionMode == "xtilt")
00088 selection[selIndex] = TiltX;
00089 else if (selectionMode == "ytilt")
00090 selection[selIndex] = TiltY;
00091 else
00092 selection[selIndex] = Constant;
00093 } else {
00094 kdWarning(41001)<< "Sel: wrong index: " << selIndex << "(dim = " << dim << ")" << endl;
00095 }
00096 } else if (index.startsWith("rank")) {
00097 int rankIndex = index.mid(strlen("rank")).toInt();
00098 if (rankIndex < 0 || rankIndex > dim) {
00099 kdWarning(41001) << "Rankindex out of range: " << rankIndex << endl;
00100 continue;
00101 }
00102 rank[rankIndex] = (*splitted.at(1)).toInt();
00103 } else if (index == "ncells") {
00104 ncells = (*splitted.at(1)).toInt();
00105 if (ncells < 1 ) {
00106 kdWarning(41001) << "ncells out of range: " << ncells << endl;
00107 ncells = 1;
00108 }
00109 }
00110 }
00111
00112 for (int i = 0; i < dim; i++) {
00113 index[i] = 0;
00114 }
00115
00116 setBrushesCount();
00117 }
00118
00119 void KisPipeBrushParasite::setBrushesCount() {
00120
00121 brushesCount[0] = ncells / rank[0];
00122 for (int i = 1; i < dim; i++) {
00123 brushesCount[i] = brushesCount[i-1] / rank[i];
00124 }
00125 }
00126
00127 bool KisPipeBrushParasite::saveToDevice(QIODevice* dev) const {
00128
00129
00130
00131 QTextStream stream(dev);
00133 stream << ncells << " ncells:" << ncells << " dim:" << dim;
00134
00135 for (int i = 0; i < dim; i++) {
00136 stream << " rank" << i << ":" << rank[i] << " sel" << i << ":";
00137 switch (selection[i]) {
00138 case Constant: stream << "constant"; break;
00139 case Incremental: stream << "incremental"; break;
00140 case Angular: stream << "angular"; break;
00141 case Velocity: stream << "velocity"; break;
00142 case Random: stream << "random"; break;
00143 case Pressure: stream << "pressure"; break;
00144 case TiltX: stream << "xtilt"; break;
00145 case TiltY: stream << "ytilt"; break;
00146 }
00147 }
00148
00149 return true;
00150 }
00151
00152 KisImagePipeBrush::KisImagePipeBrush(const QString& filename) : super(filename)
00153 {
00154 m_brushType = INVALID;
00155 m_numOfBrushes = 0;
00156 m_currentBrush = 0;
00157 }
00158
00159 KisImagePipeBrush::KisImagePipeBrush(const QString& name, int w, int h,
00160 QValueVector< QValueVector<KisPaintDevice*> > devices,
00161 QValueVector<KisPipeBrushParasite::SelectionMode> modes)
00162 : super("")
00163 {
00164 Q_ASSERT(devices.count() == modes.count());
00165 Q_ASSERT(devices.count() > 0);
00166 Q_ASSERT(devices.count() < 2);
00167
00168 setName(name);
00169
00170 m_parasite.dim = devices.count();
00171
00172 m_parasite.ncells = devices.at(0).count();
00173 m_parasite.rank[0] = m_parasite.ncells;
00174 m_parasite.selection[0] = modes.at(0);
00175
00176
00177 m_parasite.setBrushesCount();
00178
00179 for (uint i = 0; i < devices.at(0).count(); i++) {
00180 m_brushes.append(new KisBrush(devices.at(0).at(i), 0, 0, w, h));
00181 }
00182
00183 setImage(m_brushes.at(0)->img());
00184
00185 m_brushType = PIPE_IMAGE;
00186 }
00187
00188 KisImagePipeBrush::~KisImagePipeBrush()
00189 {
00190 m_brushes.setAutoDelete(true);
00191 m_brushes.clear();
00192 }
00193
00194 bool KisImagePipeBrush::load()
00195 {
00196 QFile file(filename());
00197 file.open(IO_ReadOnly);
00198 m_data = file.readAll();
00199 file.close();
00200 return init();
00201 }
00202
00203 bool KisImagePipeBrush::init()
00204 {
00205
00206
00207
00208
00209 QValueVector<char> line1;
00210
00211 Q_UINT32 i = 0;
00212
00213 while (m_data[i] != '\n' && i < m_data.size()) {
00214 line1.append(m_data[i]);
00215 i++;
00216 }
00217 setName(i18n(QString::fromUtf8(&line1[0], i).ascii()));
00218
00219 i++;
00220
00221
00222
00223
00224 QValueVector<char> line2;
00225 while (m_data[i] != '\n' && i < m_data.size()) {
00226 line2.append(m_data[i]);
00227 i++;
00228 }
00229
00230 QString paramline = QString::fromUtf8((&line2[0]), line2.size());
00231 Q_UINT32 m_numOfBrushes = paramline.left(paramline.find(' ')).toUInt();
00232 m_parasite = paramline.mid(paramline.find(' ') + 1);
00233 i++;
00234
00235 Q_UINT32 numOfBrushes = 0;
00236 while (numOfBrushes < m_numOfBrushes && i < m_data.size()){
00237 KisBrush * brush = new KisBrush(name() + "_" + numOfBrushes,
00238 m_data,
00239 i);
00240 Q_CHECK_PTR(brush);
00241
00242 m_brushes.append(brush);
00243
00244 numOfBrushes++;
00245 }
00246
00247 if (!m_brushes.isEmpty()) {
00248 setValid(true);
00249 if (m_brushes.at( 0 )->brushType() == MASK) {
00250 m_brushType = PIPE_MASK;
00251 }
00252 else {
00253 m_brushType = PIPE_IMAGE;
00254 }
00255 setSpacing(m_brushes.at(m_brushes.count() - 1)->spacing());
00256 setWidth(m_brushes.at(0)->width());
00257 setHeight(m_brushes.at(0)->height());
00258 }
00259
00260 m_data.resize(0);
00261 return true;
00262 }
00263
00264 bool KisImagePipeBrush::save()
00265 {
00266 QFile file(filename());
00267 file.open(IO_WriteOnly | IO_Truncate);
00268 bool ok = saveToDevice(&file);
00269 file.close();
00270 return ok;
00271 }
00272
00273 bool KisImagePipeBrush::saveToDevice(QIODevice* dev) const
00274 {
00275 QCString utf8Name = name().utf8();
00276 char const* name = utf8Name.data();
00277 int len = qstrlen(name);
00278
00279 if (parasite().dim != 1) {
00280 kdWarning(41001) << "Save to file for pipe brushes with dim != not yet supported!" << endl;
00281 return false;
00282 }
00283
00284
00285
00286
00287
00288
00289
00290 if (dev->writeBlock(name, len) == -1)
00291 return false;
00292
00293 if (dev->putch('\n') == -1)
00294 return false;
00295
00296
00297 if (!m_parasite.saveToDevice(dev))
00298 return false;
00299
00300 if (dev->putch('\n') == -1)
00301 return false;
00302
00303
00304 for (uint i = 0; i < m_brushes.count(); i++)
00305 if (!m_brushes.at(i)->saveToDevice(dev))
00306 return false;
00307
00308 return true;
00309 }
00310
00311 QImage KisImagePipeBrush::img()
00312 {
00313 if (m_brushes.isEmpty()) {
00314 return 0;
00315 }
00316 else {
00317 return m_brushes.at(0)->img();
00318 }
00319 }
00320
00321 KisAlphaMaskSP KisImagePipeBrush::mask(const KisPaintInformation& info, double subPixelX, double subPixelY) const
00322 {
00323 if (m_brushes.isEmpty()) return 0;
00324 selectNextBrush(info);
00325 return m_brushes.at(m_currentBrush)->mask(info, subPixelX, subPixelY);
00326 }
00327
00328 KisPaintDeviceSP KisImagePipeBrush::image(KisColorSpace * colorSpace, const KisPaintInformation& info, double subPixelX, double subPixelY) const
00329 {
00330 if (m_brushes.isEmpty()) return 0;
00331 selectNextBrush(info);
00332 return m_brushes.at(m_currentBrush)->image(colorSpace, info, subPixelX, subPixelY);
00333 }
00334
00335 void KisImagePipeBrush::setParasiteString(const QString& parasite)
00336 {
00337 m_parasiteString = parasite;
00338 m_parasite = KisPipeBrushParasite(parasite);
00339 }
00340
00341
00342 enumBrushType KisImagePipeBrush::brushType() const
00343 {
00344 if (m_brushType == PIPE_IMAGE && useColorAsMask()) {
00345 return PIPE_MASK;
00346 }
00347 else {
00348 return m_brushType;
00349 }
00350 }
00351
00352 bool KisImagePipeBrush::useColorAsMask() const
00353 {
00354 if (m_brushes.count() > 0) {
00355 return m_brushes.at(0)->useColorAsMask();
00356 }
00357 else {
00358 return false;
00359 }
00360 }
00361
00362 void KisImagePipeBrush::setUseColorAsMask(bool useColorAsMask)
00363 {
00364 for (uint i = 0; i < m_brushes.count(); i++) {
00365 m_brushes.at(i)->setUseColorAsMask(useColorAsMask);
00366 }
00367 }
00368
00369 bool KisImagePipeBrush::hasColor() const
00370 {
00371 if (m_brushes.count() > 0) {
00372 return m_brushes.at(0)->hasColor();
00373 }
00374 else {
00375 return false;
00376 }
00377 }
00378
00379 KisBoundary KisImagePipeBrush::boundary() {
00380 Q_ASSERT(!m_brushes.isEmpty());
00381 return m_brushes.at(0)->boundary();
00382 }
00383
00384 void KisImagePipeBrush::selectNextBrush(const KisPaintInformation& info) const {
00385 m_currentBrush = 0;
00386 double angle;
00387 for (int i = 0; i < m_parasite.dim; i++) {
00388 int index = m_parasite.index[i];
00389 switch (m_parasite.selection[i]) {
00390 case KisPipeBrushParasite::Constant: break;
00391 case KisPipeBrushParasite::Incremental:
00392 index = (index + 1) % m_parasite.rank[i]; break;
00393 case KisPipeBrushParasite::Random:
00394 index = int(float(m_parasite.rank[i])*KApplication::random() / RAND_MAX); break;
00395 case KisPipeBrushParasite::Pressure:
00396 index = static_cast<int>(info.pressure * (m_parasite.rank[i] - 1) + 0.5); break;
00397 case KisPipeBrushParasite::Angular:
00398
00399 angle = atan2(info.movement.y(), info.movement.x()) + M_PI_2;
00400
00401 if (angle < 0)
00402 angle += 2.0 * M_PI;
00403 else if (angle > 2.0 * M_PI)
00404 angle -= 2.0 * M_PI;
00405 index = static_cast<int>(angle / (2.0 * M_PI) * m_parasite.rank[i]);
00406 break;
00407 default:
00408 kdWarning(41001) << "This parasite selectionMode has not been implemented. Reselecting"
00409 << " to Incremental" << endl;
00410 m_parasite.selection[i] = KisPipeBrushParasite::Incremental;
00411 index = 0;
00412 }
00413 m_parasite.index[i] = index;
00414 m_currentBrush += m_parasite.brushesCount[i] * index;
00415 }
00416 }
00417
00418 bool KisImagePipeBrush::canPaintFor(const KisPaintInformation& info) {
00419 if (info.movement.isNull() && m_parasite.needsMovement)
00420 return false;
00421 return true;
00422 }
00423
00424 void KisImagePipeBrush::makeMaskImage() {
00425 for (uint i = 0; i < m_brushes.count(); i++)
00426 m_brushes.at(i)->makeMaskImage();
00427
00428 setBrushType(PIPE_MASK);
00429 setUseColorAsMask(false);
00430 }
00431
00432 KisImagePipeBrush* KisImagePipeBrush::clone() const {
00433
00434
00435
00436 QValueVector< QValueVector<KisPaintDevice*> > devices;
00437 QValueVector<KisPipeBrushParasite::SelectionMode> modes;
00438
00439 devices.push_back(QValueVector<KisPaintDevice*>());
00440 modes.push_back(m_parasite.selection[0]);
00441
00442 for (uint i = 0; i < m_brushes.count(); i++) {
00443 KisPaintDevice* pd = new KisPaintDevice(
00444 KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("RGBA",""),""), "clone pd" );
00445 pd->convertFromQImage(m_brushes.at(i)->img(), "");
00446 devices.at(0).append(pd);
00447 }
00448
00449 KisImagePipeBrush* c = new KisImagePipeBrush(name(), width(), height(), devices, modes);
00450
00451
00452 return c;
00453 }
00454
00455 #include "kis_imagepipe_brush.moc"
00456