diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2011-06-26 00:41:16 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2011-06-26 00:41:16 +0000 |
commit | 698569f8428ca088f764d704034a1330517b98c0 (patch) | |
tree | bf45be6946ebbbee9cce5a5bcf838f4c952d87e6 /chalk/colorspaces/wetsticky | |
parent | 2785103a6bd4de55bd26d79e34d0fdd4b329a73a (diff) | |
download | koffice-698569f8428ca088f764d704034a1330517b98c0.tar.gz koffice-698569f8428ca088f764d704034a1330517b98c0.zip |
Finish rebranding of Krita as Chalk
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1238363 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'chalk/colorspaces/wetsticky')
43 files changed, 6780 insertions, 0 deletions
diff --git a/chalk/colorspaces/wetsticky/Makefile.am b/chalk/colorspaces/wetsticky/Makefile.am new file mode 100644 index 00000000..4ade368a --- /dev/null +++ b/chalk/colorspaces/wetsticky/Makefile.am @@ -0,0 +1,25 @@ +kde_services_DATA = chalkwsplugin.desktop +INCLUDES = -I$(srcdir)/../../sdk \ + -I$(srcdir)/../../core \ + -I$(srcdir)/../../core/color_strategy \ + -I$(srcdir)/../../../chalkcolor/color_strategy/ \ + -I$(srcdir)/../../../color_strategy/ \ + -I$(srcdir)/../../ui \ + $(KOFFICE_INCLUDES) \ + -I$(interfacedir) \ + $(KOPAINTER_INCLUDES) \ + $(all_includes) + +kde_module_LTLIBRARIES = chalkwsplugin.la + +chalkwsplugin_la_SOURCES = wet_sticky_plugin.cc kis_wet_sticky_colorspace.cc kis_ws_engine_filter.cc +noinst_HEADERS = wet_sticky_plugin.h kis_wet_sticky_colorspace.h kis_ws_engine_filter.h + +chalkwsplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +chalkwsplugin_la_LIBADD = ../../chalkcolor/libchalkcolor.la + +chalkwsplugin_la_METASOURCES = AUTO + +SUBDIRS=brushop + + diff --git a/chalk/colorspaces/wetsticky/README b/chalk/colorspaces/wetsticky/README new file mode 100644 index 00000000..b1844466 --- /dev/null +++ b/chalk/colorspaces/wetsticky/README @@ -0,0 +1,42 @@ +Wet & Sticky + +The Chalk Wet & Sticky module is derived from the seminal dissertation +"Wet & Stick: A Novel Model for Computer-Based Painting" by Malcom Tunde +Cockshott, and the implementation of that model by Tunde Cockshott, +David England and Kevin Waite. The complete source code to the first +implementation is included in the module_ws/ws and is released under +the terms of the GPL. + +The W&S model is implemented in the following components: + +* A color strategy +* A paint op +* A filter + +The color strategy implements the canvas; the paint op implements the +application of paint and the filter implements the paint simulation +engine. + +This system adds the following interesting capabilities to Chalk: + +* Extending the tool options dialog with a widget describing the + paint op. + +* Extending the paint op class with properties beyond opacity and + color to a more generic structure with can contain the many different + properties needed by more complex color models to calculate bitBlt's. + + All the ordinary paint ops still work, but they act as if they are + applying dry, thin paint, conforming to Cockshott's analysis of the + Shoup model (which Chalk implemented in the first instance) as a subset + of the W&S model. + +* Adding continuously running filters (either in separate threads or + called by a timer) to a particular paint device. + +* Adding a new way to mix colour; the older colour selection widgets + still work, but only give completely dry, infinitely thin paint. + +* Creating a layer with a fill of 'substrate' cells -- i.e, filling not just + with colour, but also with certain calculated amounts of height, + gravity and absorbency. diff --git a/chalk/colorspaces/wetsticky/TODO b/chalk/colorspaces/wetsticky/TODO new file mode 100644 index 00000000..513df2ff --- /dev/null +++ b/chalk/colorspaces/wetsticky/TODO @@ -0,0 +1,7 @@ +* Add paintopbox to toolbox +* Make all paint tools use the paintop from the paintop box +* Add paintop properties palette +* Add continuously running filters +* Add filler objects that can fill a given area computationally +* Add extensible properties for paint devices (to control things like drying) +* Add default fill hook dependent on colorspace diff --git a/chalk/colorspaces/wetsticky/brushop/Makefile.am b/chalk/colorspaces/wetsticky/brushop/Makefile.am new file mode 100644 index 00000000..8df4d61e --- /dev/null +++ b/chalk/colorspaces/wetsticky/brushop/Makefile.am @@ -0,0 +1,28 @@ +kde_services_DATA = chalkwsbrushpaintop.desktop + +chalkimagesdir = $(prefix)/share/apps/chalk/images +chalkimages_DATA = wetpaintbrush.png + +# all_includes must remain last! +INCLUDES = -I$(srcdir)/../../../sdk \ + -I$(srcdir)/../../../chalkcolor/color_strategy/ \ + -I$(srcdir)/../../../color_strategy/ \ + -I$(srcdir)/../../../core/ \ + -I$(srcdir)/../../../ui \ + $(KOFFICE_INCLUDES) $(KOPAINTER_INCLUDES) $(all_includes) + + +chalkwsbrushpaintop_la_SOURCES = \ + wsbrushpaintop_plugin.cc \ + kis_wsbrushop.cc + +noinst_HEADERS= \ + wsbrushpaintop_plugin.h \ + kis_wsbrushop.h + +kde_module_LTLIBRARIES = chalkwsbrushpaintop.la + +chalkwsbrushpaintop_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN) +chalkwsbrushpaintop_la_LIBADD = ../../..//libchalkcommon.la $(LIB_KOPAINTER) $(LIB_KOFFICECORE) + +chalkwsbrushpaintop_la_METASOURCES = AUTO diff --git a/chalk/colorspaces/wetsticky/brushop/README b/chalk/colorspaces/wetsticky/brushop/README new file mode 100644 index 00000000..81156a89 --- /dev/null +++ b/chalk/colorspaces/wetsticky/brushop/README @@ -0,0 +1,2 @@ +Template for plugin paintops. Paint tools use the paintop to determine how +to deposit their paint on the canvas, exactly. diff --git a/chalk/colorspaces/wetsticky/brushop/chalkwsbrushpaintop.desktop b/chalk/colorspaces/wetsticky/brushop/chalkwsbrushpaintop.desktop new file mode 100644 index 00000000..aa087bb9 --- /dev/null +++ b/chalk/colorspaces/wetsticky/brushop/chalkwsbrushpaintop.desktop @@ -0,0 +1,73 @@ +[Desktop Entry] +Name=Wet & Sticky Paintbrush Paintop +Name[bg]=Мокра и лепкава четка +Name[ca]=Pinzell humit i viscós de Paintop +Name[cy]=Brws paent gwlyb gludiog +Name[da]=Maleoperation med våd og klæbrig malerpensel +Name[de]=Maloperation mit feuchtem & klebrigem Farbpinsel +Name[el]=Βούρτσα υγρής και κολλώδους μπογιάς +Name[eo]=KDED-testmodulo +Name[es]=Pincel mojado y pegajoso para pintar +Name[et]=Märja lõuendi joonistamistoiming +Name[fa]=Paintop قلمموی چسبناک و مرطوب +Name[fr]=Pinceau paintop mouillé et gluant +Name[fy]=Kwasten foar wiete en kliemske ferfhannelings +Name[gl]=Pintado Mollado e Pegoñento +Name[hu]=Nedves és ragadós ecset +Name[is]=Blautur & klístraður pensill +Name[it]=Operazione con pennello bagnato e appiccicoso +Name[km]=ជក់ទឹក & ស្អិត Paintop +Name[nb]=Fargemodell for våt og klissete pensel +Name[nds]=Malen mit en natten backigen Pinsel +Name[ne]=ओसिलो र टाँसिने पेन्टब्रस पेन्टप +Name[nl]=Kwasten voor natte en kleverige verfverrichtingen +Name[pl]=Mokre i lepkie włosie pędzla +Name[pt]=Modelo de Cores Molhado e Pegajoso +Name[pt_BR]=Modelo de Cores Molhado e Pegajoso +Name[ru]=Кисть с параметрами влажности и прилипания +Name[sk]=Mokrý a lepkavý štetec Paintop +Name[sl]=Slikanje z mokrim in lepljivim čopičem +Name[sr]=Модел боја мокре и лепљиве четкице +Name[sr@Latn]=Model boja mokre i lepljive četkice +Name[sv]=Målningsoperation med våt och klibbig målarpensel +Name[uk]=Пензель з параметрами вогкості і клейкості +Name[zh_CN]=湿性和粘性画布 +Name[zh_TW]=濕 & 黏的筆刷頭 +Comment=Wet & Sticky paintbrush +Comment[bg]=Мокра и лепкава четка +Comment[ca]=Pinzell humit i viscós +Comment[cy]=Brws paent gwlyb gludiog +Comment[da]=Våd og klæbrig malerpensel +Comment[de]=Feuchter & klebriger Farbpinsel +Comment[el]=Βούρτσα υγρής και κολλώδους μπογιάς +Comment[eo]=Malseka & Glueca peniko +Comment[es]=Pincel mojado y pegajoso +Comment[et]=Märja lõuendi pintsel +Comment[fa]=قلمموی چسبناک و مرطوب +Comment[fr]=Pinceau mouillé et gluant +Comment[fy]=Kwast foar wiete en kliemske ferfhannelings +Comment[gl]=Un pincel mollado e pegaxoso +Comment[hu]=Nedves és ragadós ecset +Comment[is]=Blautur og klístraður pensill +Comment[it]=Pennello bagnato e appiccicoso +Comment[ja]=Wet & Sticky ペイントブラシ +Comment[km]=ជក់ទឹក & ស្អិត +Comment[nb]=Våt og klissete pensel +Comment[nds]=Natt un backig Pinsel +Comment[ne]=ओसिलो र टाँसिने पेन्टब्रस +Comment[nl]=Kwast voor nat en kleverige verfverichtingen +Comment[pl]=Mokry i lepki pędzel +Comment[pt]=Um pincel molhado e pegajoso +Comment[pt_BR]=Modelo de cores de tela Molhada & Pegajosa +Comment[ru]=Кисть с параметрами влажности и прилипания +Comment[sk]=Mokrý a lepkavý štetec +Comment[sl]=Moker in lepljiv čopič +Comment[sr]=Мокра и лепљива четкица +Comment[sr@Latn]=Mokra i lepljiva četkica +Comment[sv]=Våt och klibbig målarpensel +Comment[uk]=Пензель з параметрами вогкості і клейкості +Comment[zh_TW]=濕 & 黏的筆刷 +ServiceTypes=Chalk/ColorSpace +Type=Service +X-KDE-Library=chalkwsbrushpaintop +X-Chalk-Version=2 diff --git a/chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.cc b/chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.cc new file mode 100644 index 00000000..8b182e08 --- /dev/null +++ b/chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.cc @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <tqrect.h> + +#include <kdebug.h> + +#include "kis_brush.h" +#include "kis_global.h" +#include "kis_paint_device.h" +#include "kis_painter.h" +#include "kis_types.h" +#include "kis_paintop.h" + +#include "kis_wsbrushop.h" + +KisPaintOp * KisWSBrushOpFactory::createOp(const KisPaintOpSettings */*settings*/, KisPainter * painter) +{ + KisPaintOp * op = new KisWSBrushOp(painter); + Q_CHECK_PTR(op); + return op; +} + +KisWSBrushOp::KisWSBrushOp(KisPainter * painter) + : super(painter) +{ +} + +KisWSBrushOp::~KisWSBrushOp() +{ +} + +void KisWSBrushOp::paintAt(const KisPoint &pos, + const double pressure, + const double /*xTilt*/, + const double /*yTilt*/) +{ + // Painting should be implemented according to the following algorithm: + // retrieve brush + // if brush == tqmask + // retrieve tqmask + // else if brush == image + // retrieve image + // subsample (tqmask | image) for position -- pos should be double! + // apply filters to tqmask (colour | gradient | pattern | etc. + // composite filtered tqmask into temporary layer + // composite temporary layer into target layer + // @see: doc/brush.txt + + if (!m_painter -> device()) return; + + KisBrush *brush = m_painter -> brush(); + + Q_ASSERT(brush); + if (!brush) return; + + KisPaintDeviceSP device = m_painter -> device(); + + KisPoint hotSpot = brush -> hotSpot(pressure); + KisPoint pt = pos - hotSpot; + + // Split the coordinates into integer plus fractional parts. The integer + // is where the dab will be positioned and the fractional part determines + // the sub-pixel positioning. + TQ_INT32 x; + double xFraction; + TQ_INT32 y; + double yFraction; + + splitCoordinate(pt.x(), &x, &xFraction); + splitCoordinate(pt.y(), &y, &yFraction); + + KisLayerSP dab = 0; + + if (brush -> brushType() == IMAGE || brush -> brushType() == PIPE_IMAGE) { + dab = brush -> image(device -> colorSpace(), pressure, xFraction, yFraction); + } + else { + KisAlphaMaskSP tqmask = brush -> tqmask(pressure, xFraction, yFraction); + dab = computeDab(tqmask); + } + m_painter -> setPressure(pressure); + + TQRect dabRect = TQRect(0, 0, brush -> tqmaskWidth(pressure), brush -> tqmaskHeight(pressure)); + TQRect dstRect = TQRect(x, y, dabRect.width(), dabRect.height()); + + KisImage * image = device -> image(); + + if (image != 0) { + dstRect &= image -> bounds(); + } + + if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return; + + TQ_INT32 sx = dstRect.x() - x; + TQ_INT32 sy = dstRect.y() - y; + TQ_INT32 sw = dstRect.width(); + TQ_INT32 sh = dstRect.height(); + + m_painter -> bltSelection(dstRect.x(), dstRect.y(), m_painter -> compositeOp(), dab.data(), m_painter -> opacity(), sx, sy, sw, sh); + m_painter -> addDirtyRect(dstRect); +} diff --git a/chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.h b/chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.h new file mode 100644 index 00000000..65f5fb6c --- /dev/null +++ b/chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KIS_WSBRUSHOP_H_ +#define KIS_WSBRUSHOP_H_ + +#include "kis_paintop.h" +#include "kis_types.h" + +class KisPoint; +class KisPainter; + + +class KisWSBrushOpFactory : public KisPaintOpFactory { + +public: + KisWSBrushOpFactory() {} + virtual ~KisWSBrushOpFactory() {} + + virtual KisPaintOp * createOp(const KisPaintOpSettings *settings, KisPainter * painter); + virtual KisID id() { return KisID("wsbrush", i18n("Wet & Sticky Paintbrush")); } + virtual TQString pixmap() { return "wetpaintbrush.png"; } +}; + +class KisWSBrushOp : public KisPaintOp { + + typedef KisPaintOp super; + +public: + + KisWSBrushOp(KisPainter * painter); + virtual ~KisWSBrushOp(); + + void paintAt(const KisPoint &pos, + const double pressure, + const double /*xTilt*/, + const double /*yTilt*/); + +}; + +#endif // KIS_WSBRUSHOP_H_ diff --git a/chalk/colorspaces/wetsticky/brushop/wetpaintbrush.png b/chalk/colorspaces/wetsticky/brushop/wetpaintbrush.png Binary files differnew file mode 100644 index 00000000..8b681ec1 --- /dev/null +++ b/chalk/colorspaces/wetsticky/brushop/wetpaintbrush.png diff --git a/chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.cc b/chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.cc new file mode 100644 index 00000000..383bd9c5 --- /dev/null +++ b/chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.cc @@ -0,0 +1,56 @@ +/* + * wsbrushpaintop_plugin.cc -- Part of Chalk + * + * Copyright (c) 2005 Boudewijn Rempt ([email protected]) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include <klocale.h> +#include <kiconloader.h> +#include <kinstance.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <ktempfile.h> +#include <kdebug.h> +#include <kgenericfactory.h> + +#include <kis_paintop_registry.h> +#include <kis_debug_areas.h> +#include "kis_wsbrushop.h" + +#include "wsbrushpaintop_plugin.h" + +typedef KGenericFactory<WSBrushPaintOpPlugin> WSBrushPaintOpPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalkwsbrushpaintop, WSBrushPaintOpPluginFactory( "chalkcore" ) ) + + +WSBrushPaintOpPlugin::WSBrushPaintOpPlugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(WSBrushPaintOpPluginFactory::instance()); + + // This is not a gui plugin; only load it when the doc is created. + if ( tqparent->inherits("KisFactory") ) + { + KisPaintOpRegistry::instance() -> add ( new KisWSBrushOpFactory ); + } + +} + +WSBrushPaintOpPlugin::~WSBrushPaintOpPlugin() +{ +} + +#include "wsbrushpaintop_plugin.moc" diff --git a/chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.h b/chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.h new file mode 100644 index 00000000..7e77afec --- /dev/null +++ b/chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt ([email protected]) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef WSBRUSH_PAINTOP_PLUGIN_H_ +#define WSBRUSH_PAINTOP_PLUGIN_H_ + +#include <kparts/plugin.h> + +#include "kis_types.h" + +class KisView; + +/** + * A plugin wrapper that adds the paintop factories to the paintop registry. + */ +class WSBrushPaintOpPlugin : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + WSBrushPaintOpPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~WSBrushPaintOpPlugin(); + +private: + + KisView* m_view; +}; + +#endif // WSBRUSH_PAINTOP_PLUGIN_H_ diff --git a/chalk/colorspaces/wetsticky/chalkwsplugin.desktop b/chalk/colorspaces/wetsticky/chalkwsplugin.desktop new file mode 100644 index 00000000..12fdc286 --- /dev/null +++ b/chalk/colorspaces/wetsticky/chalkwsplugin.desktop @@ -0,0 +1,46 @@ +[Desktop Entry] +Name=Wet & Sticky Canvas Color Model +Name[bg]=Цветови модел за мокро и лепкаво платно +Name[ca]=Model de color de llenç humit i viscós +Name[cy]=Model Lliw Cynfas Gwlyb a Gludiog +Name[da]=Våd & klæbrig kanvasfarve-model +Name[de]=Farbmodell feuchte & klebrige Leinwand +Name[el]=Μοντέλο καμβά υγρής και κολλώδους μπογιάς +Name[en_GB]=Wet & Sticky Canvas Colour Model +Name[eo]=Kolormodelo por Malseka & Glueca Kanvaso +Name[es]=Modelo de color de lienzo mojado y pegajoso +Name[et]=Märja lõuendi värvimudel +Name[eu]=Oihal heze eta itsaskorraren kolore-eredua +Name[fa]=مدل رنگ صفحه مجازی چسبناک و مرطوب +Name[fi]=Märkä ja tahmea kangasvärimalli +Name[fr]=Modèle de couleurs gluantes et mouillées +Name[fy]=wiete en kliemske canvasmodel +Name[gl]=Modelo de Cores de Tea Mollado e Pegoñento +Name[hu]=Nedves és ragadós vászon színmodell +Name[is]=Blaut & klístruð litategund +Name[it]=Modello di colore per tela bagnata +Name[ja]=Wet & Sticky キャンバスカラーモデル +Name[km]=ម៉ូដែលពណ៌ទឹក & ស្អិត +Name[ms]=Model Warna Kanvas Basah & Lekit +Name[nb]=Fargemodell for vått og klissete lerret +Name[nds]=Klöörmodell natt un backig Lienwand +Name[ne]=ओसिलो र टाँसिने चित्रपट रङ मोडेल +Name[nl]=Nat en kleverig canvasmodel +Name[nn]=Fargemodell for vått lerret +Name[pl]=Przestrzeń barw mokrego i lepkiego płótna +Name[pt]=Modelo de Cores de Tela Molhado e Pegajoso +Name[pt_BR]=Modelo de cores de tela Molhada & Pegajosa +Name[ru]=Цветовое пространство с параметрами влажности и прилипания +Name[sk]=Model farieb pre mokré a lepkavé plátno +Name[sl]=Barvni model z mokrim in lepljivim platnom +Name[sr]=Модел боја мокрог и лепљивог платна +Name[sr@Latn]=Model boja mokrog i lepljivog platna +Name[sv]=Våt och klibbig dukfärgmodell +Name[uk]=Канва моделі кольорів з параметрами вогкості і клейкості +Name[zh_CN]=湿性/粘性画布色彩模型 +Name[zh_TW]=濕 & 黏的畫布色彩模型 +ServiceTypes=Chalk/ColorSpace +Type=Service +X-KDE-Library=chalkwsplugin +X-Chalk-Version=2 + diff --git a/chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.cc b/chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.cc new file mode 100644 index 00000000..44426382 --- /dev/null +++ b/chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.cc @@ -0,0 +1,605 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <limits.h> +#include <stdlib.h> + +#include <config.h> +#include LCMS_HEADER + +#include <tqimage.h> + +#include <klocale.h> +#include <kdebug.h> + +#include "kis_color_conversions.h" +#include "kis_abstract_colorspace.h" +#include "kis_colorspace_registry.h" +#include "kis_image.h" +#include "kis_wet_sticky_colorspace.h" +#include "kis_integer_maths.h" +#include "kis_types.h" +#include "kis_channelinfo.h" + +#define NOWSDEBUG + +using namespace WetAndSticky; + +enum WetStickyChannelIndex { + BLUE_CHANNEL_INDEX, + GREEN_CHANNEL_INDEX, + RED_CHANNEL_INDEX, + ALPHA_CHANNEL_INDEX, + HUE_CHANNEL_INDEX, + SATURATION_CHANNEL_INDEX, + LIGHTNESS_CHANNEL_INDEX, + LITQUID_CONTENT_CHANNEL_INDEX, + DRYING_RATE_CHANNEL_INDEX, + MISCIBILITY_CHANNEL_INDEX, + GRAVITATIONAL_DIRECTION_INDEX, + GRAVITATIONAL_STRENGTH_CHANNEL_INDEX, + ABSORBANCY_CHANNEL_INDEX, + PAINT_VOLUME_CHANNEL_INDEX +}; + +KisWetStickyColorSpace::KisWetStickyColorSpace() : + KisAbstractColorSpace(KisID("W&S", i18n("Wet & Sticky")), 0, icMaxEnumData) +{ + TQ_INT32 pos = 0; + + // Basic representational definition + m_channels.push_back(new KisChannelInfo(i18n("Blue"), "B", pos, COLOR, 1)); + m_channels.push_back(new KisChannelInfo(i18n("Green"), "G", ++pos, COLOR, 1)); + m_channels.push_back(new KisChannelInfo(i18n("Red"), "R", ++pos, COLOR, 1)); + m_channels.push_back(new KisChannelInfo(i18n("Alpha"), "A", ++pos, ALPHA, 1)); + + // Paint definition + m_channels.push_back(new KisChannelInfo(i18n("Hue"), "H", ++pos, COLOR, sizeof(float))); + m_channels.push_back(new KisChannelInfo(i18n("Saturation"), "S", pos+=sizeof(float) , COLOR, sizeof(float))); + m_channels.push_back(new KisChannelInfo(i18n("Lightness"), "L", pos+=sizeof(float), COLOR, sizeof(float))); + + m_channels.push_back(new KisChannelInfo(i18n("Liquid Content"), "Q", pos+=sizeof(float), SUBSTANCE, 1)); + m_channels.push_back(new KisChannelInfo(i18n("Drying Rate"), "D", ++pos, SUBSTANCE, 1)); + m_channels.push_back(new KisChannelInfo(i18n("Miscibility"), "M", ++pos, SUBSTANCE, 1)); + + // Substrate definition + m_channels.push_back(new KisChannelInfo(i18n("Gravitational Direction"), "Gd", ++pos, SUBSTRATE, sizeof(enumDirection))); + m_channels.push_back(new KisChannelInfo(i18n("Gravitational Strength"), "Gs", pos+=sizeof(enumDirection), SUBSTRATE, 1)); + + m_channels.push_back(new KisChannelInfo(i18n("Absorbency"), "Ad", ++pos, SUBSTRATE, 1)); + m_channels.push_back(new KisChannelInfo(i18n("Paint Volume"), "V", ++pos, SUBSTANCE, 1)); + + m_alphaPos = 3; + m_alphaSize = 1; + setDefaultProfile( 0 ); + +#ifdef WSDEBUG + TQValueVector<KisChannelInfo *>_it it; + int i = 0; + for (it = m_channels.begin(); it != m_channels.end(); ++it) + { + KisChannelInfo * ch = (*it); + kdDebug(DBG_AREA_CMS) << "Channel: " << ch->name() << ", " << ch->pos() << ", " << i << "\n"; + ++i; + } + + kdDebug(DBG_AREA_CMS) << "Size of cell: " << sizeof(CELL) << "\n"; +#endif +} + + +KisWetStickyColorSpace::~KisWetStickyColorSpace() +{ +} + +void KisWetStickyColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile) +{ + CELL_PTR p = (CELL_PTR) dst; + TQ_UINT8 r, g, b; + + r = c.red(); + g = c.green(); + b = c.blue(); + + p -> red = r; + p -> green = g; + p -> blue = b; + p -> alpha = OPACITY_OPAQUE; + + rgb_to_hls(r, g, b, &p->hue, &p->lightness, &p->saturation); + + p -> liquid_content = 0; + p -> drying_rate = 0; + p -> miscibility = 0; + + p -> direction = DOWN; + p -> strength = 10; + + p -> absorbancy = 10; + p -> volume = 0; + +#ifdef WSDEBUG + kdDebug(DBG_AREA_CMS) << "qcolor: " + << " r: " << c.red() << " b: " << c.blue() << " g: " << c.red() + << " native color: (" << TQString().setNum(p->red) << ", " + << TQString().setNum(p->green) << ", " + << TQString().setNum(p->blue) << ", " + << TQString().setNum(p->alpha) << ") " + << ", hls: (" << p->hue << ", " + << p->lightness << ", " + << p->saturation << ")\n"; +#endif +} + +void KisWetStickyColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile) +{ + CELL_PTR p = (CELL_PTR) dst; + TQ_UINT8 r, g, b; + + r = c.red(); + g = c.green(); + b = c.blue(); + + p -> red = r; + p -> green = g; + p -> blue = b; + p -> alpha = opacity; + rgb_to_hls(r, g, b, &p -> hue, &p -> lightness, &p -> saturation); + + p ->liquid_content = 0; + p ->drying_rate = 0; + p ->miscibility = 0; + + p -> direction = DOWN; + p -> strength = 10; + + p -> absorbancy = 10; + p -> volume = 0; + +#ifdef WSDEBUG + kdDebug(DBG_AREA_CMS) << "qcolor: " + << " r: " << c.red() << " b: " << c.blue() << " g: " << c.red() << " opacity: " << opacity + << " native color: (" << TQString().setNum(p->red) << ", " + << TQString().setNum(p->green) << ", " + << TQString().setNum(p->blue) << ", " + << TQString().setNum(p->alpha) << ") " + << ", hls: (" << p->hue << ", " + << p->lightness << ", " + << p->saturation << ")\n"; +#endif +} + +void KisWetStickyColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile) +{ + CELL_PTR p = (CELL_PTR) src; + + c -> setRgb(p -> red, + p -> green, + p -> blue); +#ifdef WSDEBUG + kdDebug(DBG_AREA_CMS) << "Created qcolor from wet & sticky: " << " r: " << c->red() << " b: " << c->blue() << " g: " << c->red() << "\n"; +#endif +} + +void KisWetStickyColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile) +{ + + CELL_PTR p = (CELL_PTR) src; + + c -> setRgb(p -> red, + p -> green, + p -> blue); + + *opacity = p -> alpha; +#ifdef WSDEBUG + kdDebug(DBG_AREA_CMS) << "Created qcolor from wet & sticky: " << " r: " << c->red() << " b: " << c->blue() << " g: " << c->red() << "\n"; +#endif +} + + + +KisPixelRO KisWetStickyColorSpace::toKisPixelRO(const TQ_UINT8 *src, KisProfile * profile) +{ + return KisPixelRO (src, src, this, profile); +} + +KisPixel KisWetStickyColorSpace::toKisPixel(TQ_UINT8 *src, KisProfile * profile) +{ + return KisPixel (src, src, this, profile); +} + +void KisWetStickyColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const +{ +} + +TQ_UINT8 KisWetStickyColorSpace::getAlpha(const TQ_UINT8 *pixel) const +{ + return ((CELL_PTR)pixel)->alpha; +} + +void KisWetStickyColorSpace::setAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const +{ + while (nPixels > 0) { + ((CELL_PTR)pixels)->alpha = alpha; + --nPixels; + pixels+=pixelSize(); + } +} + +void KisWetStickyColorSpace::applyAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels) +{ +} + +void KisWetStickyColorSpace::applyInverseAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels) +{ +} + +TQ_UINT8 KisWetStickyColorSpace::scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos) +{ + return 0; +} + +TQ_UINT16 KisWetStickyColorSpace::scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos) +{ + return 0; +} + + +TQValueVector<KisChannelInfo *> KisWetStickyColorSpace::channels() const +{ + return m_channels; +} + +bool KisWetStickyColorSpace::hasAlpha() const +{ + return true; +} + +TQ_INT32 KisWetStickyColorSpace::nChannels() const +{ + return 14; +} + +TQ_INT32 KisWetStickyColorSpace::nColorChannels() const +{ + return 3; +} + +TQ_INT32 KisWetStickyColorSpace::nSubstanceChannels() const +{ + return 4; + +} + +TQ_INT32 KisWetStickyColorSpace::pixelSize() const +{ + return sizeof(CELL); +} + + +TQImage KisWetStickyColorSpace::convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height, + KisProfile * /*srcProfile*/, KisProfile * /*dstProfile*/, + TQ_INT32 /*renderingIntent*/, float /*exposure*/) +{ + + TQImage img(width, height, 32, 0, TQImage::LittleEndian); + + TQ_INT32 i = 0; + uchar *j = img.bits(); + + CELL_PTR p = (CELL_PTR) data; + + while ( i < width * height) { + + const TQ_UINT8 PIXEL_BLUE = 0; + const TQ_UINT8 PIXEL_GREEN = 1; + const TQ_UINT8 PIXEL_RED = 2; + const TQ_UINT8 PIXEL_ALPHA = 3; + + *( j + PIXEL_ALPHA ) = p -> alpha; + *( j + PIXEL_RED ) = p -> red; + *( j + PIXEL_GREEN ) = p -> green; + *( j + PIXEL_BLUE ) = p -> blue; + + p++; + i++; + j += 4; // Because we're hard-coded 32 bits deep, 4 bytes + } + return img; +} + +bool KisWetStickyColorSpace::convertPixelsTo(const TQ_UINT8 * src, KisProfile * /*srcProfile*/, + TQ_UINT8 * dst, KisAbstractColorSpace * dstColorSpace, KisProfile * dstProfile, + TQ_UINT32 numPixels, + TQ_INT32 /*renderingIntent*/) +{ + TQ_INT32 dSize = dstColorSpace -> pixelSize(); + TQ_INT32 sSize = pixelSize(); + + TQ_UINT32 j = 0; + TQ_UINT32 i = 0; + TQColor c; + CELL_PTR cp; + while ( i < numPixels ) { + cp = (CELL_PTR) (src + i); + + c.setRgb(cp -> red, + cp -> green, + cp -> blue); + + dstColorSpace -> fromTQColor(c, cp -> alpha, (dst + j), dstProfile); + + i += sSize; + j += dSize; + + } + return true; + +} + +void KisWetStickyColorSpace::bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowStride, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *tqmask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op) +{ + switch (op.op()) { + case COMPOSITE_UNDEF: + // Undefined == no composition + break; + case COMPOSITE_OVER: + compositeOver(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + case COMPOSITE_COPY: + default: + compositeCopy(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity); + break; + } + +} + + +void KisWetStickyColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity) +{ + // XXX: This is basically the same as with rgb and used to composite layers for Composition for + // painting works differently + + + while (rows > 0) { + + const TQ_UINT8 *src = srcRowStart; + TQ_UINT8 *dst = dstRowStart; + const TQ_UINT8 *tqmask = tqmaskRowStart; + + TQ_INT32 columns = numColumns; + + while (columns > 0) { + + CELL_PTR dstCell = (CELL_PTR) dst; + CELL_PTR srcCell = (CELL_PTR) src; + +#ifdef WSDEBUG + kdDebug(DBG_AREA_CMS) << "Source: " << rows << ", " << columns << " color: " << + srcCell->red << ", " << srcCell->blue << ", " << srcCell->green << ", " << srcCell->alpha << ", " << srcCell->volume << "\n"; + + + kdDebug(DBG_AREA_CMS) << "Destination: " << rows << ", " << columns << " color: " << + dstCell->red << ", " << dstCell->blue << ", " << dstCell->green << ", " << dstCell->alpha << ", " << dstCell->volume << "\n"; + +#endif + + TQ_UINT8 srcAlpha = srcCell->alpha; + + // apply the alphatqmask + if(tqmask != 0) + { + if(*tqmask != OPACITY_OPAQUE) + srcAlpha = UINT8_MULT(srcAlpha, *tqmask); + tqmask++; + } + + if (srcAlpha != OPACITY_TRANSPARENT) { + + if (opacity != OPACITY_OPAQUE) { + srcAlpha = UINT8_MULT(srcCell->alpha, opacity); + } + + if (srcAlpha == OPACITY_OPAQUE) { + memcpy(dst, src, 3); // XXX: First three bytes for rgb? + } else { + TQ_UINT8 dstAlpha = dstCell->alpha; + + TQ_UINT8 srcBlend; + + if (dstAlpha == OPACITY_OPAQUE) { + srcBlend = srcAlpha; + } else { + TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); + dstCell->alpha = newAlpha; + + if (newAlpha != 0) { + srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); + } else { + srcBlend = srcAlpha; + } + } + + if (srcBlend == OPACITY_OPAQUE) { + memcpy(dst, src, 3); //XXX: First three bytes for rgb? + } else { + dstCell->red = UINT8_BLEND(srcCell->red, dstCell->red, srcBlend); + dstCell->green = UINT8_BLEND(srcCell->green, dstCell->green, srcBlend); + dstCell->blue = UINT8_BLEND(srcCell->blue, dstCell->blue, srcBlend); + } + } + } + columns--; + src += sizeof(CELL); + dst += sizeof(CELL); + } + rows--; + srcRowStart += srcRowStride; + dstRowStart += dstRowStride; + + if(tqmaskRowStart) + tqmaskRowStart += tqmaskRowStride; + } + +} + +void KisWetStickyColorSpace::compositeCopy(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity) +{ + TQ_INT32 linesize = sizeof(CELL) * columns; + TQ_UINT8 *d; + const TQ_UINT8 *s; + d = dst; + s = src; + + while (rows-- > 0) { + memcpy(d, s, linesize); + d += dstRowStride; + s += srcRowStride; + } + +} + + +KisCompositeOpList KisWetStickyColorSpace::userVisiblecompositeOps() const +{ + KisCompositeOpList list; + + list.append(KisCompositeOp(COMPOSITE_OVER)); + + return list; +} + +TQString KisWetStickyColorSpace::channelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < nChannels()); + const CELL *pixel = reinterpret_cast<const CELL *>(U8_pixel); + + switch (channelIndex) { + case BLUE_CHANNEL_INDEX: + return TQString().setNum(pixel -> blue); + case GREEN_CHANNEL_INDEX: + return TQString().setNum(pixel -> green); + case RED_CHANNEL_INDEX: + return TQString().setNum(pixel -> red); + case ALPHA_CHANNEL_INDEX: + return TQString().setNum(pixel -> alpha); + case HUE_CHANNEL_INDEX: + return TQString().setNum(pixel -> hue); + case SATURATION_CHANNEL_INDEX: + return TQString().setNum(pixel -> saturation); + case LIGHTNESS_CHANNEL_INDEX: + return TQString().setNum(pixel -> lightness); + case LITQUID_CONTENT_CHANNEL_INDEX: + return TQString().setNum(pixel -> liquid_content); + case DRYING_RATE_CHANNEL_INDEX: + return TQString().setNum(pixel -> drying_rate); + case MISCIBILITY_CHANNEL_INDEX: + return TQString().setNum(pixel -> miscibility); + case GRAVITATIONAL_DIRECTION_INDEX: + { + switch (pixel -> direction) { + case UP: + return i18n("Up"); + case DOWN: + return i18n("Down"); + case LEFT: + return i18n("Left"); + case RIGHT: + return i18n("Right"); + default: + Q_ASSERT(false); + return TQString(); + } + } + case GRAVITATIONAL_STRENGTH_CHANNEL_INDEX: + return TQString().setNum(pixel -> strength); + case ABSORBANCY_CHANNEL_INDEX: + return TQString().setNum(pixel -> absorbancy); + case PAINT_VOLUME_CHANNEL_INDEX: + return TQString().setNum(pixel -> volume); + default: + Q_ASSERT(false); + return TQString(); + } +} + +TQString KisWetStickyColorSpace::normalisedChannelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const +{ + Q_ASSERT(channelIndex < nChannels()); + const CELL *pixel = reinterpret_cast<const CELL *>(U8_pixel); + + //XXX: Are these right? + + switch (channelIndex) { + case BLUE_CHANNEL_INDEX: + return TQString().setNum(static_cast<float>(pixel -> blue) / UINT8_MAX); + case GREEN_CHANNEL_INDEX: + return TQString().setNum(static_cast<float>(pixel -> green) / UINT8_MAX); + case RED_CHANNEL_INDEX: + return TQString().setNum(static_cast<float>(pixel -> red) / UINT8_MAX); + case ALPHA_CHANNEL_INDEX: + return TQString().setNum(static_cast<float>(pixel -> alpha) / UINT8_MAX); + case HUE_CHANNEL_INDEX: + return TQString().setNum(pixel -> hue); + case SATURATION_CHANNEL_INDEX: + return TQString().setNum(pixel -> saturation); + case LIGHTNESS_CHANNEL_INDEX: + return TQString().setNum(pixel -> lightness); + case LITQUID_CONTENT_CHANNEL_INDEX: + return TQString().setNum(static_cast<float>(pixel -> liquid_content) / UINT8_MAX); + case DRYING_RATE_CHANNEL_INDEX: + return TQString().setNum(static_cast<float>(pixel -> drying_rate) / UINT8_MAX); + case MISCIBILITY_CHANNEL_INDEX: + return TQString().setNum(static_cast<float>(pixel -> miscibility) / UINT8_MAX); + case GRAVITATIONAL_DIRECTION_INDEX: + { + switch (pixel -> direction) { + case UP: + return i18n("Up"); + case DOWN: + return i18n("Down"); + case LEFT: + return i18n("Left"); + case RIGHT: + return i18n("Right"); + default: + Q_ASSERT(false); + return TQString(); + } + } + case GRAVITATIONAL_STRENGTH_CHANNEL_INDEX: + return TQString().setNum(static_cast<float>(pixel -> strength) / UINT8_MAX); + case ABSORBANCY_CHANNEL_INDEX: + return TQString().setNum(static_cast<float>(pixel -> absorbancy) / UINT8_MAX); + case PAINT_VOLUME_CHANNEL_INDEX: + return TQString().setNum(static_cast<float>(pixel -> volume) / UINT8_MAX); + default: + Q_ASSERT(false); + return TQString(); + } +} + diff --git a/chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.h b/chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.h new file mode 100644 index 00000000..57f3ac70 --- /dev/null +++ b/chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.h @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt <[email protected]> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef KIS_COLORSPACE_WET_STICKY_H_ +#define KIS_COLORSPACE_WET_STICKY_H_ + +#include <tqcolor.h> + +#include "kis_global.h" +#include "kis_abstract_colorspace.h" + +namespace WetAndSticky { + + /** + * A color is specified as a vector in HLS space. Hue is a value + * in the range 0..360 degrees with 0 degrees being red. Saturation + * and Lightness are both in the range [0,1]. A lightness of 0 means + * black, with 1 being white. A totally saturated color has saturation + * of 1. + */ + + enum enumDirection { + UP, + DOWN, + LEFT, + RIGHT + }; + + /** + * Defines the contents and attributes of a cell on the canvas. + */ + typedef struct cell { + TQ_UINT8 blue; + TQ_UINT8 green; + TQ_UINT8 red; + TQ_UINT8 alpha; + + float hue; + float saturation; + float lightness; + + TQ_UINT8 liquid_content; + TQ_UINT8 drying_rate; + TQ_UINT8 miscibility; + + enumDirection direction; + TQ_UINT8 strength; + + TQ_UINT8 absorbancy; /* How much paint can this cell hold? */ + TQ_UINT8 volume; /* The volume of paint. */ + + } CELL, *CELL_PTR; + + +} + + + +class KisWetStickyColorSpace : public KisAbstractColorSpace { +public: + KisWetStickyColorSpace(); + virtual ~KisWetStickyColorSpace(); + +public: + + + + virtual void fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile = 0); + virtual void fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile = 0); + + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile = 0); + virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile = 0); + + virtual TQ_UINT8 getAlpha(const TQ_UINT8 *pixel) const; + virtual void setAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const; + + virtual void applyAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels); + virtual void applyInverseAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels); + + virtual TQ_UINT8 scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos); + virtual TQ_UINT16 scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos); + + virtual TQValueVector<KisChannelInfo *> channels() const; + virtual bool hasAlpha() const; + virtual TQ_INT32 nChannels() const; + virtual TQ_INT32 nColorChannels() const; + virtual TQ_INT32 nSubstanceChannels() const; + virtual TQ_INT32 pixelSize() const; + + virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const; + + virtual TQImage convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height, + KisProfile * srcProfile, KisProfile * dstProfile, + TQ_INT32 renderingIntent = INTENT_PERCEPTUAL, + float exposure = 0.0f); + + + virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const; + virtual void convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const; + virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels); + virtual void darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const; + + virtual KisCompositeOpList userVisiblecompositeOps() const; + +protected: + + virtual void bitBlt(TQ_UINT8 *dst, + TQ_INT32 dstRowSize, + const TQ_UINT8 *src, + TQ_INT32 srcRowStride, + const TQ_UINT8 *srcAlphaMask, + TQ_INT32 tqmaskRowStride, + TQ_UINT8 opacity, + TQ_INT32 rows, + TQ_INT32 cols, + const KisCompositeOp& op); + + + virtual bool convertPixelsTo(const TQ_UINT8 * src, KisProfile * srcProfile, + TQ_UINT8 * dst, KisAbstractColorSpace * dstColorSpace, KisProfile * dstProfile, + TQ_UINT32 numPixels, + TQ_INT32 renderingIntent = INTENT_PERCEPTUAL); + + +private: + + void compositeOver(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeClear(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + void compositeCopy(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity); + +}; + +#endif // KIS_COLORSPACE_WET_STICKY_H_ diff --git a/chalk/colorspaces/wetsticky/kis_ws_engine_filter.cc b/chalk/colorspaces/wetsticky/kis_ws_engine_filter.cc new file mode 100644 index 00000000..040d3002 --- /dev/null +++ b/chalk/colorspaces/wetsticky/kis_ws_engine_filter.cc @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt ([email protected]) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include <stdlib.h> +#include <vector> +#include <math.h> + +#include <tqpoint.h> +#include <tqspinbox.h> +#include <tqrect.h> +#include <tqcolor.h> + +#include <klocale.h> +#include <kiconloader.h> +#include <kinstance.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <ktempfile.h> +#include <kdebug.h> +#include <kgenericfactory.h> +#include <knuminput.h> + +#include <kis_debug_areas.h> +#include <kis_image.h> +#include <kis_iterators_pixel.h> +#include <kis_layer.h> +#include <kis_filter_registry.h> +#include <kis_debug_areas.h> +#include <kis_types.h> +#include <kis_paint_device.h> +#include <kis_colorspace_registry.h> + +#include "kis_ws_engine_filter.h" +#include "kis_wet_sticky_colorspace.h" + +/** + * The Wet & Sticky Engine filter is based on the wet & sticky model + * for computer painting designed by Tunde Cockshott and implemented + * by David England and Kevin Waite. + * + * The filter implements the engine that moves the paint according to + * gravity, viscosity and absorbency. + * + */ +KisWSEngineFilter::KisWSEngineFilter() : KisFilter(id(), "", i18n("&Wet & Sticky paint engine...")) +{ +} + + +/** + * Sets the POINT giving the coordinate location of the next + * cell on the canvas to be visited. There is an even probability + * of each cell being visited. + */ +TQPoint next_cell(TQ_UINT32 width, TQ_UINT32 height) +{ + return TQPoint(random() * width, random() * height); +} + +void single_step(KisColorSpace * cs, KisPaintDeviceSP src, KisPaintDeviceSP dst, const TQRect & rect, bool native) +{ + using namespace WetAndSticky; + + + TQPoint p = next_cell( rect.width(), rect.height() ); + + // XXX: We could optimize by randomly doing lines of 64 pixels + // -- maybe that would be enough to avoid the windscreen wiper + // effect. + KisHLineIterator iter = src -> createHLineIterator(p.x(), p.y(), 1, false); + + TQ_UINT8 *orig = iter.rawData(); + TQ_UINT8 *pix = orig; + + if (!orig) return; + + if (!native ) { + TQColor c; + TQ_UINT8 opacity; + + src -> colorSpace() -> toTQColor(pix, &c, &opacity); + TQ_UINT8 *pix = new TQ_UINT8[sizeof( cell )]; + Q_CHECK_PTR(pix); + + cs -> fromTQColor(c, opacity, pix); + } + + // Process + + CELL_PTR c = ( CELL_PTR )pix; + + + if ( !native ) { + // Set RGBA back + } + +} + +void KisWSEngineFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* configuration, const TQRect& rect) +{ + + m_src = src; + m_dst = dst; + m_cfg = ( KisWSEngineFilterConfiguration * )configuration; + m_rect = rect; + + + kdDebug(DBG_AREA_FILTERS) << "WSEnginefilter called!\n"; + TQTime t; + t.restart(); + + // Two possibilities: we have our own, cool w&s pixel, and + // then we have real data to mess with, or we're filtering a + // boring shoup-model paint device and we can only work by + // synthesizing w&s pixels. + bool native = false; + // XXX: We need a better way to ID color strategies + if ( src -> colorSpace() -> id() == KisID("W&S","") ) native = true; + + // XXX: We need a better way to ID color strategies + KisColorSpace * cs = KisColorSpaceRegistry::instance()->get("W&S"); + + TQ_UINT32 pixels = 400; //m_cfg -> pixels(); + + kdDebug(DBG_AREA_FILTERS) << "Going to singlestep " << pixels << " pixels.\n"; + + // Determine whether we want an infinite loop + if ( pixels == 0 ) { + while ( true ) + single_step (cs, src, dst, rect, native); + } + // Or not. + else { + for ( TQ_UINT32 i = 0; i < pixels; ++i ) { + single_step (cs, src, dst, rect, native); + } + } + kdDebug(DBG_AREA_FILTERS) << "Done in " << t.elapsed() << " ms\n"; + +} + +KisFilterConfigWidget * KisWSEngineFilter::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev) +{ +// KisWSEngineFilterConfigurationWidget* kefcw = new KisWSEngineFilterConfigurationWidget(this,tqparent, ""); +// kdDebug(DBG_AREA_FILTERS) << kefcw << endl; +// return kefcw ; + return 0; +} + +KisFilterConfiguration* KisWSEngineFilter::configuration(TQWidget* nwidget, KisPaintDeviceSP dev) +{ +// KisWSEngineFilterConfigurationWidget* widget = (KisWSEngineFilterConfigurationWidget*) nwidget; + +// if( widget == 0 ) +// { +// return new KisWSEngineFilterConfiguration(30); +// } else { +// TQ_UINT32 depth = widget -> baseWidget() -> depthSpinBox -> value(); + +// return new KisWSEngineFilterConfiguration(depth); +// } + + + return new KisWSEngineFilterConfiguration( m_rect.height() * m_rect.width() ); +} + diff --git a/chalk/colorspaces/wetsticky/kis_ws_engine_filter.h b/chalk/colorspaces/wetsticky/kis_ws_engine_filter.h new file mode 100644 index 00000000..d1c23810 --- /dev/null +++ b/chalk/colorspaces/wetsticky/kis_ws_engine_filter.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt ([email protected]) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#ifndef _KIS_WS_ENGINE_FILTER_H_ +#define _KIS_WS_ENGINE_FILTER_H_ + +#include <kdebug.h> + +#include <kis_view.h> +#include <kis_filter.h> +#include <kis_id.h> + +class KisWSEngineFilterConfiguration : public KisFilterConfiguration +{ + +public: + + KisWSEngineFilterConfiguration() { m_pixels = 10000; } + + KisWSEngineFilterConfiguration(TQ_UINT32 pixels = 0) { m_pixels = pixels; } + + TQ_UINT32 pixels() { return m_pixels; } + +private: + + TQ_UINT32 m_pixels; // The number of pixels the filter should + // move. 0 means keep running indefinitely + + + +}; + +class KisWSEngineFilter : public KisFilter +{ + +public: + + KisWSEngineFilter(); + + virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* cfg, const TQRect& rc); + + static inline KisID id() { return KisID("Wet & Sticky Engine", i18n("Wet & Sticky")); }; + virtual bool supportsPainting() { return false; } + virtual bool supportsPreview() { return false; } + virtual bool supportsIncrementalPainting() { return false; } + +public: + virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev); + virtual KisFilterConfiguration* configuration(TQWidget*, KisPaintDeviceSP dev); + + +private: + +private: + + KisWSEngineFilterConfiguration * m_cfg; + KisPaintDeviceSP m_src; + KisPaintDeviceSP m_dst; + TQRect m_rect; + +}; + +#endif // _KIS_WS_ENGINE_FILTER_H_ diff --git a/chalk/colorspaces/wetsticky/wet_sticky_plugin.cc b/chalk/colorspaces/wetsticky/wet_sticky_plugin.cc new file mode 100644 index 00000000..525b18bb --- /dev/null +++ b/chalk/colorspaces/wetsticky/wet_sticky_plugin.cc @@ -0,0 +1,60 @@ +/* + * wet_sticky_plugin.cc -- Part of Chalk + * + * Copyright (c) 2005 Boudewijn Rempt ([email protected]) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include <klocale.h> +#include <kiconloader.h> +#include <kinstance.h> +#include <kmessagebox.h> +#include <kstandarddirs.h> +#include <ktempfile.h> +#include <kdebug.h> +#include <kgenericfactory.h> + +#include <kis_colorspace_registry.h> +#include <kis_debug_areas.h> +#include "wet_sticky_plugin.h" + +#include "kis_wet_sticky_colorspace.h" +#include "kis_ws_engine_filter.h" + +typedef KGenericFactory<WetStickyPlugin> WetStickyPluginFactory; +K_EXPORT_COMPONENT_FACTORY( chalkwsplugin, WetStickyPluginFactory( "chalkcore" ) ) + + +WetStickyPlugin::WetStickyPlugin(TQObject *tqparent, const char *name, const TQStringList &) + : KParts::Plugin(tqparent, name) +{ + setInstance(WetStickyPluginFactory::instance()); + + // This is not a gui plugin; only load it when the doc is created. + if ( tqparent->inherits("KisFactory") ) + { + KisColorSpace * colorSpaceWS = new KisWetStickyColorSpace(); + Q_CHECK_PTR(colorSpaceWS); + KisColorSpaceRegistry::instance() -> add(colorSpaceWS); + KisFilterRegistry::instance()->add(new KisWSEngineFilter()); + } + +} + +WetStickyPlugin::~WetStickyPlugin() +{ +} + +#include "wet_sticky_plugin.moc" diff --git a/chalk/colorspaces/wetsticky/wet_sticky_plugin.h b/chalk/colorspaces/wetsticky/wet_sticky_plugin.h new file mode 100644 index 00000000..fe981a59 --- /dev/null +++ b/chalk/colorspaces/wetsticky/wet_sticky_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2005 Boudewijn Rempt ([email protected]) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef WET_STICKY_PLUGIN_H_ +#define WET_STICKY_PLUGIN_H_ + +#include <kparts/plugin.h> + +/** + * A plugin wrapper around the Wet & Sticky colour space strategy. + * + * The Wet & Sticky paint system was first designed in 1991 by Tunde Cockshott + * and was further developed by David England and Kevin Waite. It was released + * under the GPL in 2005. + * + */ +class WetStickyPlugin : public KParts::Plugin +{ + Q_OBJECT + TQ_OBJECT +public: + WetStickyPlugin(TQObject *tqparent, const char *name, const TQStringList &); + virtual ~WetStickyPlugin(); + +}; + +#endif // WET_STICKY_PLUGIN_H_ diff --git a/chalk/colorspaces/wetsticky/ws/GNU b/chalk/colorspaces/wetsticky/ws/GNU new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/GNU diff --git a/chalk/colorspaces/wetsticky/ws/GNU Public Licence.txt b/chalk/colorspaces/wetsticky/ws/GNU Public Licence.txt new file mode 100644 index 00000000..5e79907b --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/GNU Public Licence.txt @@ -0,0 +1,341 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which tqcontains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it tqcontains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + diff --git a/chalk/colorspaces/wetsticky/ws/README b/chalk/colorspaces/wetsticky/ws/README new file mode 100644 index 00000000..15f55e77 --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/README @@ -0,0 +1,4 @@ + +The gear example + +This example program demonstrates how to use OpenGL display lists. diff --git a/chalk/colorspaces/wetsticky/ws/TODO b/chalk/colorspaces/wetsticky/ws/TODO new file mode 100644 index 00000000..91c48a03 --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/TODO @@ -0,0 +1,24 @@ +1/ Load in portable pixmaps (PPM). Set an arbitrary paint attribute +map for each different colour. Otherwise load in a paint attribute +map definition file. +2/ Input from "brush". Incremental development of brush input. +First simple mixing then +empty brush moving paint +paint on top of paint +attribute application. +3/ Animation +1000000 = 1 fps +500000 = 2 fps +250000 = 4 fps +125000 = 8 fps +62500 = 16 fps +41660 = 24 fps + +4/ NK times 178.9 real 49.4 user 13.3 sys + Orig times 636.6 real 111.1 user 43.6 sys + +5/ Cross section through volume + +6/ Separate Colour scale window + +7/ Transparency diff --git a/chalk/colorspaces/wetsticky/ws/after.jpg b/chalk/colorspaces/wetsticky/ws/after.jpg Binary files differnew file mode 100644 index 00000000..5116efdb --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/after.jpg diff --git a/chalk/colorspaces/wetsticky/ws/anim.c b/chalk/colorspaces/wetsticky/ws/anim.c new file mode 100644 index 00000000..995a3dff --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/anim.c @@ -0,0 +1,154 @@ +/* + FILE: x_interface.c + PURPOSE: Creation and access to an X windows interface + to wet+sticky using Athena Widgets + AUTHOR: David England + VERSION: 1.00 (13-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England [email protected] +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#define FRAME_LIMIT 36 + +#include <X11/Xos.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Intrinsic.h> + +#include <X11/cursorfont.h> +#include <X11/StringDefs.h> + +#include <X11/Shell.h> +#include <X11/Xaw/Box.h> +#include <X11/Xaw/Label.h> +#include <stdio.h> + +#include "constants.h" +#include "types.h" + +#include "engine.h" +#include "canvas.h" + +/* Window Heirarchy - + Three shell widgets, one for colour output, two for attributes +output + plus a back_up pixmap for redrawing +*/ + +static Widget top_level; +static Widget colour_shell; +static Widget colour_box; +static Widget colour_canvas; +static Pixmap colour_pm[FRAME_LIMIT]; + +static GC gc; +static GC tmp_gc; +static long tqmask; +static XGCValues values; + +Display *display; +char pix_file[32]; +unsigned int delay; + +main(argc, argv) +int argc; +char *argv[]; +{ + static Arg args[]={ + {XtNwidth, (XtArgVal) 0}, + {XtNheight, (XtArgVal)0} }; + + XEvent event; + int i, width, height; + int ret; + int c; + + extern char *optarg; + extern int optind; + + width = 300; + height = 300; + + args[0].value = (XtArgVal)width; + + args[1].value = (XtArgVal)height; + + top_level = XtInitialize("wet+sticky", "Wet+Sticky", NULL, + 0, &argc, argv); + + delay = 100000; /*default delay in microseconds between frames */ + + while ((c = getopt(argc, argv, "D:")) != -1) + switch (c) { + case 'D': + delay = atoi(optarg); + delay = delay * 1000000; + break; + } + + + display = XtDisplay(top_level); + + colour_shell = XtCreateApplicationShell("colour_frame", + topLevelShellWidgetClass, NULL, 0); + + colour_box = XtCreateManagedWidget("colour_box", boxWidgetClass, + colour_shell, NULL, 0); + + + colour_canvas = XtCreateManagedWidget("", labelWidgetClass, + colour_box, args, XtNumber(args)); + + + /*XtAddEventHandler(colour_canvas, ExposureMask, False, + expose_event, 0);*/ + + XtRealizeWidget(colour_shell); + + XSynchronize(display, True); + + tqmask = GCBackground| GCForeground| GCFunction; + + values.function = GXcopy; + values.background = 0; + values.foreground = 1; + + + gc = XtGetGC(colour_canvas, tqmask, &values); + + + + fprintf(stderr,"Read files ..."); + for (i=0; i < FRAME_LIMIT; i++) { + sprintf(pix_file,"pixmap.%d",i); + if ((XReadBitmapFile(display, XtWindow(colour_shell), pix_file, + &width, &height, &colour_pm[i], &ret, &ret)) != + BitmapSuccess) + perror("bad bitmap"); + } + fprintf(stderr,"done.\nBegin Animation\n"); + + + for (;;) { + for (i=0; i < FRAME_LIMIT; i++) { + XCopyPlane(display, colour_pm[i], + XtWindow(colour_canvas),gc, + 0, 0, 300, 300, 0, 0, 1); + fprintf(stderr,"pre sleep\n"); + usleep(delay); + } + + + } /* End for loop */ +}xk + diff --git a/chalk/colorspaces/wetsticky/ws/before.jpg b/chalk/colorspaces/wetsticky/ws/before.jpg Binary files differnew file mode 100644 index 00000000..fc26b989 --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/before.jpg diff --git a/chalk/colorspaces/wetsticky/ws/canvas.c b/chalk/colorspaces/wetsticky/ws/canvas.c new file mode 100644 index 00000000..77cfa17d --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/canvas.c @@ -0,0 +1,514 @@ +/* + FILE: canvas.c + PURPOSE: Hides the canvas and provides its access and + manipuation routines. + AUTHOR: Kevin Waite + VERSION: 1.00 (10-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England [email protected] +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "constants.h" +#include "types.h" +#include "canvas.h" +#include <stdio.h> + +/* Declare the canvas data structure local to this module. It can + only be accessed via routines given in the header file for this module. + The (0,0) location for the canvas is at the top-left. */ + +CELL canvas[CANVAS_WIDTH][CANVAS_HEIGHT]; + +/* This module maintains a list of the addresses of cells that have + been modified since the last redraw and therefore need updating. + Points are added to this list by the need_to_tqrepaint() routine + and are removed by the next_cell_for_tqrepaint() function. The + pointer to the current tail of the list is updated by side-effect. */ + +static POINT need_tqrepainting[REDRAW_LIMIT]; +static int next_free = 0; +static int next_to_tqrepaint = 0; + +/* *********************************************************************** */ + +int number_of_tqrepaints_needed() +/* Returns the number of cells that need to be tqrepainted. */ + +{ + return (next_free); +} + +/* *********************************************************************** */ + +void need_to_tqrepaint(point) +/* The cell at this location needs to be redrawn since it has + been altered. Scan the list to see if it is already + scheduled for a tqrepainting operation and only add it if + it is not there. */ + +POINT point; + +{ + int k; + + + /* If the list is already full then simply ignore the tqrepaint + request - it will get done eventually anyway. */ + + if (next_free == REDRAW_LIMIT) return; + + /* Check whether this point is already on the list. */ + + for (k=0; k < next_free; k++) { + if ((need_tqrepainting[k].x == point.x) && + (need_tqrepainting[k].y == point.y)) break; + } + + if (k < next_free) return; /* Already in the list. */ + + /* Add this new cell address to the end of the list. */ + + need_tqrepainting[next_free].x = point.x; + need_tqrepainting[next_free].y = point.y; + next_free++; +} + +/* *********************************************************************** */ + +void next_cell_for_tqrepaint(cell, locus) +/* This routine returns the next cell to be tqrepainted, together with its + location on the canvas. This is determined by taking the next point + from the need_tqrepainting list and accessing its cell. If the list is + empty then return NIL. + Note that the tqrepainting operation will clear out the list before + any other new positions are added. */ + + CELL_PTR *cell; + POINT_PTR locus; + +{ + if (next_to_tqrepaint >= next_free) { + next_to_tqrepaint = next_free = 0; + *(cell) = NIL; + return; + } + + *(cell) = get_cell(need_tqrepainting[next_to_tqrepaint]); + locus->x = need_tqrepainting[next_to_tqrepaint].x; + locus->y = need_tqrepainting[next_to_tqrepaint].y; + next_to_tqrepaint++; +} + +/* *********************************************************************** */ + +void next_cell_point (address) +/* Sets the POINT giving the coordinate location of the next + cell on the canvas to be visited. There is an even probability + of each cell being visited. */ + +POINT_PTR address; +{ + extern long random(); + + address->x = random() % CANVAS_WIDTH; + address->y = random() % CANVAS_HEIGHT; +} + + +/* *********************************************************************** */ + +CELL_PTR get_cell (point) +/* This function returns a pointer to the cell at the + given address on the canvas. */ + +POINT point; + +{ + return (&canvas[point.x][point.y]); +} + +/* *********************************************************************** */ + +DIRECTION anti_clockwise_from (arrow) +/* Returns the direction found going anti-clockwise from the + given direction. */ + +DIRECTION arrow; + +{ + switch (arrow) { + + case NORTH: return(WEST); + case EAST: return(NORTH); + case SOUTH: return(EAST); + case WEST: ; + + } + return(SOUTH); +} + +/* *********************************************************************** */ + +DIRECTION clockwise_from (arrow) +/* Returns the direction found going clockwise from the + given direction. */ + +DIRECTION arrow; + +{ + switch (arrow) { + + case NORTH: return(EAST); + case EAST: return(SOUTH); + case SOUTH: return(WEST); + case WEST: ; + + } + return(NORTH); +} + +/* *********************************************************************** */ + +BOOLEAN neighbour (aPoint, direction, bPoint) +/* Set bPoint to the coordinate of the point that can + be found by going one place in the given direction + from aPoint. The direction can be NORTH, EAST, WEST + or SOUTH. If bPoint will be off the canvas then the + function returns FALSE otherwise TRUE. */ + +POINT aPoint; +POINT_PTR bPoint; +DIRECTION direction; + +{ + int x, y; + + switch (direction) { + + case NORTH: x = 0; y = -1; break; + case EAST: x = 1; y = 0; break; + case SOUTH: x = 0; y = 1; break; + case WEST: x = -1; y = 0; break; + } + + bPoint->x = aPoint.x + x; + bPoint->y = aPoint.y + y; + + if ((bPoint->x >= CANVAS_WIDTH) || (bPoint->x < 0) || + (bPoint->y >= CANVAS_HEIGHT) || (bPoint->y < 0)) return(FALSE); + + return(TRUE); +} + +/* *********************************************************************** */ + +void initialise_paint (paint) +/* Set this paint to be a dry, unmixing white. */ + +PAINT_PTR paint; + +{ + paint->colour.hue = 255; + paint->colour.saturation = 0.0; + paint->colour.lightness = 1.0; + paint->liquid_content = 0; + paint->drying_rate = 0; + paint->miscibility = 0; +} + +/* *********************************************************************** */ + +void initialise_cell(cell) +/* Reset the given cell to a default value. */ + +CELL_PTR cell; + +{ + initialise_paint (&cell->contents); + + cell->volume = UNFILLED; /* Indicates that no paint has yet been applied. +*/ + cell->absorbancy = 10; + cell->gravity.direction = SOUTH; + cell->gravity.strength = DEFAULT_GRAVITY_STRENGTH; +} + + +/* *********************************************************************** */ + +void split_gravity() +/* This routine is for test purposes only. It causes the right + half of the canvas to have gravity going NORTH with the left + half having gravity going SOUTH. */ + +{ + POINT p; + CELL_PTR cell; + + /*for (p.x=CANVAS_WIDTH/2; p.x < CANVAS_WIDTH; p.x++) {*/ + for (p.x=165; p.x < CANVAS_WIDTH; p.x++) { + for (p.y=0; p.y < CANVAS_HEIGHT; p.y++) { + cell = get_cell (p); + cell->gravity.direction = NORTH; + } + } +} + +/* *********************************************************************** */ + +void initialise_canvas() +/* Before it can be used the canvas needs to be initialised to + a default state. This involves setting each of the cells to + have no paint and for gravity to be uniformly down. Each cell + has the default absorbancy value. */ + +{ + POINT p; + CELL_PTR cell; + + for (p.x=0; p.x < CANVAS_WIDTH; p.x++) { + for (p.y=0; p.y < CANVAS_HEIGHT; p.y++) { + cell = get_cell (p); + initialise_cell (cell); + } + } +} + +/* *********************************************************************** */ + +void print_cell_attributes(cell) +CELL_PTR cell; +{ + printf("Volume = %d\n", cell->volume); + + printf("Liquid content = %d%%\n", cell->contents.liquid_content); + printf("Drying rate = %d%%\n", cell->contents.drying_rate); + printf("Miscibility = %d%%\n\n", cell->contents.miscibility); + + printf("Saturation = %2f\n", cell->contents.colour.saturation); + printf("Lightness = %2f\n", cell->contents.colour.lightness); + printf("Hue = %d\n", cell->contents.colour.hue); + printf ("------------------------------\n\n"); +} + +/* *********************************************************************** */ + +void blob_cell_alpha (cell) +CELL_PTR cell; + +{ + cell->contents.liquid_content = 100; + cell->contents.drying_rate = 10; + cell->contents.miscibility = 80; + + cell->contents.colour.hue = 20; + cell->contents.colour.saturation = 1.0; + cell->contents.colour.lightness = 0.0; + + cell->volume = 50; + +} + +/* *********************************************************************** */ + +void blob_cell_beta (cell) +CELL_PTR cell; + +{ + cell->contents.liquid_content = 80; + cell->contents.drying_rate = 20; + cell->contents.miscibility = 90; + + cell->contents.colour.hue = 70; + cell->contents.colour.saturation = 1.0; + cell->contents.colour.lightness = 0.7; + + cell->volume = 30; + +} +/* *********************************************************************** */ + +void blob_cell_gamma (cell) +CELL_PTR cell; + +{ + cell->contents.liquid_content = 80; + cell->contents.drying_rate = 40; + cell->contents.miscibility = 80; + + cell->contents.colour.hue = 100; + cell->contents.colour.saturation = 0.5; + cell->contents.colour.lightness = 0.4; + + cell->volume = 50; + +} + +/* *********************************************************************** */ + +void old_blob(width) +/* This routine puts a square blob of various paints + of the given side length centred on the canvas. + This is used for test purposes. */ + +int width; + +{ + int count, lump, startx, starty, x, y; + + width = (width > CANVAS_WIDTH) ? CANVAS_WIDTH : width; + width = (width > CANVAS_HEIGHT) ? CANVAS_HEIGHT : width; + + printf("This run used a square blob of side %d pixels\n", width); + printf ("centred on the canvas. The blob was split into three equal\n"); + printf ("vertical strips with the following paint attributes:\n\n"); + + startx = (CANVAS_WIDTH - width) / 2; + starty = (CANVAS_HEIGHT - width) / 2; + lump = width / 3; + + count=0; + for (x = startx; x < startx + width; x++) { + for (y = starty; y < starty + width; y++) { + switch (count / lump) { + + case 0: blob_cell_alpha (&canvas[x][y]); break; + case 1: blob_cell_beta (&canvas[x][y]); break; + default: blob_cell_gamma (&canvas[x][y]); break; + + } + } + count++; + } + split_gravity(); + + print_cell_attributes (&canvas[startx][starty]); + print_cell_attributes (&canvas[startx + lump][starty]); + print_cell_attributes (&canvas[startx + (2*lump)][starty]); +} + +gravity_set(x,y,x1,y1,attr) +int x; +int y; +int x1; +int y1; +int attr; +{ + /* set the canavs absorbancy and gravity to various test values + in the region (x,y),(x1,y1) + */ + + int i,j; + + for (i=x; i < x1; i++ ) + for (j=y; j < y1; j++) { + canvas[i][j].absorbancy = 10; /* default 10 */ + canvas[i][j].gravity.direction = SOUTH; + canvas[i][j].gravity.strength = DEFAULT_GRAVITY_STRENGTH; + /*DEFAULT_GRAVITY_STRENGTH*/ + } +} + +blob_set(x, y, x1, y1, attr) +int x; +int y; +int x1; +int y1; +int attr; +{ + /* Set a blob of paint in the rectangle (x,y),(x1,y1) with + the attribute, attr (can be volume, liquidity or dryness*/ + int i,j; + float colour; + + colour = (3.6 * 122); + colour = 64; + fprintf(stderr, "attribute value %d %d\n", attr, (int)colour); + + + for (i=x; i < x1; i++ ) + for (j=y; j < y1; j++) { + canvas[i][j].contents.liquid_content = 80; + canvas[i][j].contents.drying_rate = 50; + canvas[i][j].contents.miscibility = 80; + + canvas[i][j].contents.colour.hue = (int)colour; + canvas[i][j].contents.colour.saturation = 1.0; + canvas[i][j].contents.colour.lightness = 0.7; + + canvas[i][j].volume = attr; + } + + +} + +void blob(type) +int type; +{ + + /* paint nine test blobs on the canvas */ + + /* X Example 1 All attributes at 80% except vol 0 - 100%*/ + + /* X Example 2 All attributes at 80% except liq 0 - 100% */ + + /* X Example 3 All attributes at 80% except dry 0 - 100% */ + + /* X Example 4 All attributes at 80% except absorp 100 - 0% */ + + /* X Example 5 All attributes at 80% except gravity 0 - 100% */ + + /* X Example 6 All attributes at 80% except direction N,S,E & W */ + + blob_set(20, 20, 80, 80, 0); + gravity_set(0, 0, 100, 100, SOUTH); + + blob_set(120,20, 180, 80, 22); + gravity_set(150, 0, 300, 150, EAST); + + blob_set(220,20,280,80,33); + gravity_set(0, 150, 150, 300, NORTH); + + blob_set(20,120,80,180,44); + gravity_set(150, 150, 300, 300, WEST); + + blob_set(120,120,180,180,55); + gravity_set(100, 100, 200, 200, 55); + + blob_set(220,120, 280,180, 66); + gravity_set(200, 100, 300, 200, 66); + + blob_set(20,220,80,280,77); + gravity_set(0, 200, 100, 300, 77); + + blob_set(120,220,180,280,88); + gravity_set(100, 200, 200, 300, 88); + + blob_set(220,220,280,280, 100); + gravity_set(200, 200, 300, 300, 100); + +} + +void +load_file(filename, width, height) +char *filename; +int *width; +int *height; +{ + + /* Load in a file using the load_ppm_format() function + This loads in a file in Portable Pixmap format + */ + + load_ppm_format(filename, canvas, width, height); +} diff --git a/chalk/colorspaces/wetsticky/ws/canvas.h b/chalk/colorspaces/wetsticky/ws/canvas.h new file mode 100644 index 00000000..c2f2bcbf --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/canvas.h @@ -0,0 +1,70 @@ +/* + FILE: canvas.h + PURPOSE: Defines the public routines for manipulating the canvas. + AUTHOR: Kevin Waite + VERSION: 1.00 (10-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England [email protected] +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + +*/ + + +extern int number_of_tqrepaints_needed(); +/* Returns the number of cells needing to tqrepainted. */ + +extern void need_to_tqrepaint (/* POINT */); +/* Requests that the cell at the given point be tqrepainted + at the next update as it has been modified. */ + +extern void next_cell_for_tqrepaint (/* *CELL_PTR, POINT_PTR */); +/* Returns a pointer to a cell that needs to be updated as well + as the location of that cell on the canvas. If there are + no more cells to be redrawn then the pointer will be NIL. */ + +extern void next_cell_point (/* POINT_PTR */); +/* Sets the POINT giving the coordinate location of the next + cell on the canvas to be visited. There is an even probability + of each cell being visited. */ + +extern CELL_PTR get_cell (/* POINT */); +/* This function returns a pointer to the cell at the + given address on the canvas. */ + +extern DIRECTION anti_clockwise_from (/* DIRECTION */); +/* Returns the direction found going clockwise from the + given direction. */ + +extern DIRECTION clockwise_from (/* DIRECTION */); +/* Returns the direction found going clockwise from the + given direction. */ + +extern BOOLEAN neighbour (/* POINT, DIRECTION, POINT_PTR */); +/* Set bPoint to the coordinate of the point that can + be found by going one place in the given direction + from aPoint. The direction can be NORTH, EAST, WEST + or SOUTH. If bPoint will be off the canvas then the + function returns FALSE otherwise TRUE. */ + +extern void initialise_canvas(); +/* Before it can be used the canvas needs to be initialised to + a default state. This involves setting each of the cells to + have no paint and for gravity to be uniformly down. Each cell + has the default absorbancy value. */ + +extern void blob( /* int */); +/* This routine puts a square blob of black paint + of the given side length centred on the canvas. + This is used for test purposes. */ + +extern void load_file(/*char *, int *, int * */); +/* Load a file from a portable pixmap into the canvas */ diff --git a/chalk/colorspaces/wetsticky/ws/cmap.c b/chalk/colorspaces/wetsticky/ws/cmap.c new file mode 100644 index 00000000..0f11eaf7 --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/cmap.c @@ -0,0 +1,681 @@ +/* + FILE: x_interface.c + PURPOSE: Creation and access to an X windows interface + to wet+sticky using Athena Widgets + AUTHOR: David England + VERSION: 1.00 (13-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England [email protected] +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include <X11/Xos.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Intrinsic.h> + +#include <X11/cursorfont.h> +#include <X11/StringDefs.h> + +#include <X11/Shell.h> +#include <X11/Xaw/Box.h> +#include <X11/Xaw/Label.h> +#include <stdio.h> + +#include "constants.h" +#include "types.h" +#include "engine.h" +#include "canvas.h" + +/* Window Heirarchy - + Three shell widgets, one for colour output, two for attributes output + plus a back_up pixmap for redrawing +*/ + +static Widget top_level; +static Widget colour_shell; +static Widget colour_box; +static Widget colour_canvas; +static Pixmap colour_pm; + +static Widget volume_shell; +static Widget volume_box; +static Widget volume_canvas; +static Pixmap volume_pm; + +static Widget dryness_shell; +static Widget dryness_box; +static Widget dryness_canvas; +static Pixmap dryness_pm; + +static GC gc; +static GC tmp_gc; +static long tqmask; +static XGCValues values; + +static Colormap cmap; +static XColor colours[256]; +void stroke(); +void stroke_motion(); + +Display *display; +int screen; +Screen *screen_ptr; +Window root; + +static int count=0; +static int frame_count=0; +char pix_file[64]; + +void StartWindow(); +void StartUpWindows(); + +static XtEventHandler +expose_event(w, event) +Widget w; +XEvent *event; +{ +/* Re-display the colour window if an exposure event is received */ +int width, height; + + width = height = 300; + + XCopyArea(XtDisplay(colour_canvas), colour_pm, + XtWindow(colour_canvas), gc, 0, 0, width, height, 0,0); + +} + + +static void +expose_volume(w, event) +Widget w; +XEvent *event; +{ +/* Re-display the volume window if an exposure event is received */ +int width, height; + + width = height = 300; + + XCopyArea(XtDisplay(volume_canvas), volume_pm, + XtWindow(volume_canvas), gc, 0, 0, width, height, 0,0); + + +} + +static void +expose_dryness(w, event) +Widget w; +XEvent *event; +{ +/* Re-display the dryness window if an exposure event is received */ +int width, height; + + width = height = 300; + + XCopyArea(XtDisplay(dryness_canvas), dryness_pm, + XtWindow(dryness_canvas), gc, 0, 0, width, height, 0,0); + + +} + +int +GetHueValue(red, green, blue) +int red; +int green; +int blue; +{ + XColor colour; + + colour.red = red * 257; + colour.green = green * 257; + colour.blue = blue * 257; + colour.flags = DoRed | DoGreen | DoBlue; + + if (XAllocColor(display, cmap, &colour) == 0) + fprintf(stderr,"colour allocation failed\n"); + + return (colour.pixel); +} + + +void +DrawPoint(x,y,colour) +int x; +int y; +int colour; +/* Draw a point on the window and the back-up Pixmap */ +{ + XSetForeground(XtDisplay(top_level), gc, colours[colour].pixel); + + XDrawPoint(XtDisplay(top_level), XtWindow(colour_canvas), gc, x, y); + XDrawPoint(XtDisplay(top_level), colour_pm, gc, x, y); +} + +int +DrawVolumePoint(x,y,attr) +int x; +int y; +int attr; +/* Draw a point on the window and the back-up Pixmap */ +{ + /* later - use the range of the volume to affect the colour + value + */ + + if (XtWindow(volume_canvas) == NULL) + return (-1); + + XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel); + + XDrawPoint(XtDisplay(top_level), XtWindow(volume_canvas), gc, x, y); + XDrawPoint(XtDisplay(top_level), volume_pm, gc, x, y); + + return(0); +} + +int +DrawDrynessPoint(x,y,attr) +int x; +int y; +int attr; +/* Draw a point on the window and the back-up Pixmap */ +{ + /* later - use the range of the dryness to affect the colour + value + */ + + if (XtWindow(dryness_canvas) == NULL) + return (-1); + + XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel); + + XDrawPoint(XtDisplay(top_level), XtWindow(dryness_canvas), gc, x, y); + XDrawPoint(XtDisplay(top_level), dryness_pm, gc, x, y); + + return(0); +} + +void +ClearWindow() +{ + XClearWindow(XtDisplay(top_level), XtWindow(colour_canvas)); +} + +static void +CleanWindow(win) +Drawable win; +/* Fill a window with a solid, white rectangle */ +{ +XGCValues values; +long tqmask; + + values.background = colours[0].pixel; + values.foreground = colours[255].pixel;; + values.fill_style = FillSolid; + values.function = GXclear; + + + tqmask = GCBackground| GCForeground| GCFillStyle | GCFunction; + + tmp_gc = XtGetGC(top_level, tqmask, &values); + + XFillRectangle(XtDisplay(top_level), win, tmp_gc, 0, 0, 300, 300); + +} + +void SetupCmap() +{ +int i; + + for (i=0;i<256;i++) { + colours[i].red = i*257; + colours[i].flags = DoRed | DoBlue | DoGreen; + } + + /* for (i=0;i<=127;i++) + colours[i].green = i*2*257; + + for (i=128;i>0;i--) + colours[255-i].green = (i-1)*2*257;*/ + + for (i=0;i<64;i++) + colours[i].green = i*4*257; + + for (i=64;i<128;i++) + colours[i].green = 65536-i*4*257; + + for (i=128;i<192;i++) + colours[i].green = (i-128)*2*257; + + for (i=192;i<255;i++) + colours[i].green = 65536-(i-128)*2*257; + + + for (i=0;i<256;i++) + colours[i].blue = 65536 - i*257; + + colours[0].red = 65535; + colours[0].green = 65535; + colours[0].blue = 65535; +} + +void +SetupGreyMap() +{ +int i; + + for (i=0;i<256;i++) { + colours[i].red = i*257; + colours[255 - i].flags = DoRed | DoBlue | DoGreen; + } + + + for (i=0;i<256;i++) + colours[i].green = i*257; + + for (i=0;i<256;i++) + colours[i].blue = i*257; + + colours[255].red = 255*257; + colours[255].green = 255*257; + colours[255].blue = 255*257; + +} + + +main(argc, argv) +int argc; +char **argv; +/* Create colour window heirarchy and add event handlers */ +{ + + static Arg args[]={ + {XtNwidth, (XtArgVal) 0}, + {XtNheight, (XtArgVal)0} }; + +int width; +int height; + int i; + + + width = 300; + height = 300; + + args[0].value = (XtArgVal)width; + + args[1].value = (XtArgVal)height; + + top_level = XtInitialize("wet+sticky", "Wet+Sticky", NULL, + 0, &argc, argv); + + + display = XtDisplay(top_level); + screen = DefaultScreen(display); + screen_ptr = ScreenOfDisplay(display, DefaultScreen(display)); + + root = RootWindow(display, screen); + + colour_shell = XtCreateApplicationShell("colour_frame", + topLevelShellWidgetClass, NULL, 0); + + + + colour_box = XtCreateManagedWidget("colour_box", boxWidgetClass, + colour_shell, NULL, 0); + + + colour_canvas = XtCreateManagedWidget("", labelWidgetClass, + colour_box, args, XtNumber(args)); + + + XtAddEventHandler(colour_canvas, ExposureMask, False, expose_event, 0); + + XtAddEventHandler(colour_canvas, ButtonPressMask, False, stroke, 0); + + XtAddEventHandler(colour_canvas, Button1MotionMask, + False, stroke_motion, 0); + + XtRealizeWidget(colour_shell); + + cmap = XCreateColormap( display, XtWindow(colour_shell), + XDefaultVisualOfScreen(screen_ptr), AllocAll); + + for (i=0; i <= 255; i++) + colours[i].pixel = i; + + XQueryColors(display, DefaultColormapOfScreen(screen_ptr),colours, 256); + + /*SetupCmap();*/ + + SetupGreyMap(); + + XStoreColors(display, cmap, colours, 256); + + i=0; + while( XAllocColorCells( display, DefaultColormapOfScreen(screen_ptr), + True, NULL, 0, &colours[i].pixel, 1 ) ) { + colours[i].pixel = i; + i++; + } + + XSetWindowColormap(display, XtWindow(colour_shell), cmap); + + XInstallColormap(display, cmap); + + tqmask = GCBackground| GCForeground| GCFunction; + + values.function = GXcopy; + values.background = colours[0].pixel; + values.foreground = colours[255].pixel; + + + gc = XtGetGC(colour_canvas, tqmask, &values); + + colour_pm = XCreatePixmap(XtDisplay(top_level), + XtWindow(colour_shell), width, height, + XDefaultDepth(XtDisplay(top_level), 0)); + + CleanWindow(colour_pm); + + StartWindow (CANVAS_WIDTH, CANVAS_HEIGHT); + + StartUpWindows(); +} + + +void StartWindow(width, height) +int width; +int height; +/* Create Volume heirarchy and add event handlers */ +{ + static Arg args[]={ + {XtNwidth, (XtArgVal) 0}, + {XtNheight, (XtArgVal)0} }; + + args[0].value = (XtArgVal)width; + + args[1].value = (XtArgVal)height; + + volume_shell = XtCreateApplicationShell("volume_frame", + topLevelShellWidgetClass, NULL, 0); + + volume_box = XtCreateManagedWidget("volume_box", boxWidgetClass, + volume_shell, NULL, 0); + + volume_canvas = XtCreateManagedWidget("", labelWidgetClass, + volume_box, args, XtNumber(args)); + + XtAddEventHandler(volume_canvas, ExposureMask, False, + expose_volume, 0); + + XtRealizeWidget(volume_shell); + + XSetWindowColormap(display, XtWindow(volume_shell), cmap); + + volume_pm = XCreatePixmap(XtDisplay(top_level), + XtWindow(colour_shell), width, height, + XDefaultDepth(XtDisplay(top_level), 0)); + + CleanWindow(volume_pm); + + +} + +void StartDrynessWindow(width, height) +int width; +int height; +/* Create dryness heirarchy and add event handlers */ +{ + static Arg args[]={ + {XtNwidth, (XtArgVal) 0}, + {XtNheight, (XtArgVal)0} }; + + args[0].value = (XtArgVal)width; + + args[1].value = (XtArgVal)height; + + dryness_shell = XtCreateApplicationShell("dryness_frame", + topLevelShellWidgetClass, NULL, 0); + + dryness_box = XtCreateManagedWidget("dryness_box", boxWidgetClass, + dryness_shell, NULL, 0); + dryness_canvas += XtCreateManagedWidget("", labelWidgetClass, + dryness_box, args, XtNumber(args)); + + XtAddEventHandler(dryness_canvas, ExposureMask, False, + expose_dryness, 0); + + XtRealizeWidget(dryness_shell); + + XSetWindowColormap(display, XtWindow(dryness_shell), cmap); + + dryness_pm = XCreatePixmap(XtDisplay(top_level), + XtWindow(colour_shell), width, height, + XDefaultDepth(XtDisplay(top_level), 0)); + + CleanWindow(dryness_pm); + +} + +static void +draw_labels() +{ + XSetForeground(XtDisplay(colour_shell), gc, colours[1].pixel); + + XDrawString(XtDisplay(colour_shell), XtWindow(colour_canvas), gc, 10, 10, + "Colour", strlen("Colour")); + XDrawString(XtDisplay(colour_shell), colour_pm, gc, 10, 10, + "Colour", strlen("Colour")); + + XSetForeground(XtDisplay(colour_shell), gc, colours[128].pixel); + + XDrawString(XtDisplay(colour_shell), XtWindow(volume_canvas), gc, 10, 10, + "Volume", strlen("Volume")); + XDrawString(XtDisplay(colour_shell), volume_pm, gc, 10, 10, + "Volume", strlen("Volume")); + + XSetForeground(XtDisplay(colour_shell), gc, colours[255].pixel); + + XDrawString(XtDisplay(colour_shell), XtWindow(dryness_canvas), gc, 10, 10, + "Bump Map", strlen("Bump Map")); + XDrawString(XtDisplay(colour_shell), dryness_pm, gc, 10, 10, + "Bump Map", strlen("Bump Map")); +} + +void paint_cell(cell, x, y) +CELL_PTR cell; +int x, y; + +{ + int colour, volColour, dryness; + POINT p; + + p.x = x; + p.y = y; + + /* The current display simply maps hue onto the indices of the colour + table. This involves some scaling since hues are in the range [0,360) + with the colour table being [0,256). */ + + colour = (int) (cell->contents.colour.hue * + ((float) MAX_COLOUR_INDEX / 360.0)); + + /*DrawPoint(x,y,colour); */ + + /* volColour is an index into the colour table in the range [0,255]. + It is used to give a false colour image of the canvas's volume. */ + + /*if (x < SCALE_WIDTH) return; Don't draw over colour scale. */ + + volColour = MIN(cell->volume * 2, 255); + volColour = MAX(volColour, 0); + /* Make unfilled cells have a zero vol. */ + + /*DrawVolumePoint(x,y,volColour);*/ + + /* Dryness will be in the range [0,255]. */ + dryness = (cell->contents.liquid_content * 255) / 100; + + /*DrawDrynessPoint(x,y,dryness);*/ +} + + + +void draw_false_colour_scale() +/* This routine places a scale along the top of the volume window + showing the colours being used. Low is at the left edge. + The colour palette has indices 0..255. */ +{ + int x, y; + + /*for (x=0; x < 255; x++) + for (y=0; y < SCALE_WIDTH; y++) DrawVolumePoint(x,y,MIN(x, 255));*/ +} + + +void draw_full_canvas() +{ + int x, y; + CELL_PTR cell; + POINT p; + + if (DEBUG) { + printf ("Starting to paint full canvas..."); + fflush(stdout); + } + + for (x=0; x < CANVAS_WIDTH; x++) { + for (y=0; y < CANVAS_HEIGHT; y++) { + p.x = x; + p.y = y; + /*cell = get_cell(p);*/ + paint_cell(cell, x, y); + } + } + draw_false_colour_scale(); + if (DEBUG) printf ("done.\n"); +} + +void +bump_map() +{ + POINT p; + CELL_PTR cell; + register int x, y; + register int colour; + + + for (x=0; x < CANVAS_WIDTH; x++) { + for (y=0; y < CANVAS_HEIGHT; y++) { + p.x = x; + p.y = y; + /*cell = get_cell(p);*/ + /*colour = (int) new_intensity_value(p);*/ + +/* colour = (int) (cell->contents.colour.hue * + ((float) MAX_COLOUR_INDEX / 360.0));*/ + DrawDrynessPoint(x,y,colour); + } + } + +} + + +void evolve_paint() +{ + +} + + + +void StartUpWindows() +{ +/* Start the X windows event loop and paint processing */ +XEvent event; + + + + for (;;) { + if (XtPending()) { + XtNextEvent(&event); + XtDispatchEvent(&event); + } + else { + /* Evolve paint and re-display*/ + evolve_paint(); + } + + } /* End for loop */ + + +} + +void +stroke(w, client_data, event) +Widget w; +caddr_t client_data; +XEvent *event; +{ +/* brush_stroke(event->xbutton.x, event->xbutton.y);*/ + + + /*if ((XEvent *)event != (XEvent *)NULL) + else + printf("Null event\n"); */ + +/* DrawPoint(event->xbutton.x, event->xbutton.y, 128); + DrawVolumePoint(event->xbutton.x, event->xbutton.y, 128); + DrawDrynessPoint(event->xbutton.x, event->xbutton.y, 128);*/ + + + XSetForeground(XtDisplay(top_level), gc, colours[128].pixel); + + XFillRectangle(XtDisplay(top_level), XtWindow(colour_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + + XFillRectangle(XtDisplay(top_level), XtWindow(volume_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + + /*XFillRectangle(XtDisplay(top_level), XtWindow(dryness_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1);*/ + + /*brush_stroke(event->xbutton.x, event->xbutton.y);*/ +} + + +void +stroke_motion(w, client_data, event) +Widget w; +caddr_t client_data; +XEvent *event; +{ + + + /*if ((XEvent *)event != (XEvent *)NULL) + else + printf("Null event\n"); */ + + + XSetForeground(XtDisplay(top_level), gc, colours[128].pixel); + + XFillRectangle(XtDisplay(top_level), XtWindow(colour_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + XFillRectangle(XtDisplay(top_level), XtWindow(volume_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + + XFillRectangle(XtDisplay(top_level), XtWindow(dryness_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + + /*brush_stroke(event->xbutton.x, event->xbutton.y);*/ +} + diff --git a/chalk/colorspaces/wetsticky/ws/constants.h b/chalk/colorspaces/wetsticky/ws/constants.h new file mode 100644 index 00000000..fa72bc92 --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/constants.h @@ -0,0 +1,69 @@ +/* + FILE: constants.h + PURPOSE: Constains all the #DEFINES for Wet&Sticky. + AUTHORS: Kevin Waite and David England + VERSION: 1.00 (10-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England [email protected] +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + +*/ + +/* Some utility constants. */ + +#define TRUE 1 +#define FALSE 0 +#define YES 1 +#define NO 0 +#define NIL 0 +#define DEBUG 1 +#define VERSION "1.0" + +/* Define the constants for colours in the HLS space. */ + +#define UNFILLED -1 +#define MAX_COLOUR_INDEX 255 + + +/* Define the dimensions of the intelligent canvas. */ + +#define CANVAS_WIDTH 300 +#define CANVAS_HEIGHT 300 +#define SCALE_WIDTH 30 + + +/* Define constants that control the evolution of the paint. */ + +#define STEP_LIMIT 200 +#define REDRAW_LIMIT 500 + + +/* Define some constants used in testing the system. */ + +#define DEFAULT_BLOB_SIZE (CANVAS_WIDTH / 3) +#define BLOB_NAME "-blob" + + +/* Constants used in modelling gravity. */ + +#define NORTH 0 +#define EAST 1 +#define SOUTH 2 +#define WEST 3 + +#define DEFAULT_GRAVITY_STRENGTH 10 + + +/* Define some macros. */ + +#define MAX(A,B) ((A) > (B) ? (A) : (B)) +#define MIN(A,B) ((A) < (B) ? (A) : (B)) diff --git a/chalk/colorspaces/wetsticky/ws/engine.c b/chalk/colorspaces/wetsticky/ws/engine.c new file mode 100644 index 00000000..2fb4917e --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/engine.c @@ -0,0 +1,802 @@ +/* + FILE: engine.c + PURPOSE: Defines the routines for the Paint Engine. + AUTHOR: Kevin Waite + VERSION: 1.00 (10-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England [email protected] +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "constants.h" +#include "types.h" +#include "canvas.h" +#include <math.h> + +extern double HEIGHT_SCALE; + +/* *********************************************************************** */ + +int random_percent() +/* This function returns a random number in the range [0,100]. */ +{ + extern long random(); + + return (random() % 101); +} + +/* *********************************************************************** */ + +BOOLEAN allow_event_based_on(value) +/* The given value is a percentage. Compare this value + with a randomly generated percentage and if it is larger + then allow the event to happen (i.e. return TRUE) other- + wise return FALSE. */ + +int value; + +{ + if (value > random_percent()) return(TRUE); + return(FALSE); +} + +/* *********************************************************************** */ + +BOOLEAN age_paint(cell) +/* Make the paint in the given cell older, i.e. let + if dry out a bit if it isn't already dry. This + function returns TRUE if the paint was already + dry or becomes so, and FALSE otherwise. */ + +CELL_PTR cell; + +{ + if (cell->volume == 0) return(TRUE); + if (cell->contents.liquid_content == 0) return(TRUE); + if (allow_event_based_on(cell->contents.drying_rate) == TRUE) + cell->contents.liquid_content--; + + if (cell->contents.liquid_content == 0) return(TRUE); + return(FALSE); +} + +/* *********************************************************************** */ + +BOOLEAN similar_paint(aPaint, bPaint) +/* Determine whether the two paints are similar. It is + assumed that aPaint has come from the host cell (and + so it is its miscibility value that is used). The + function returns TRUE if the paints are similar and + FALSE otherwise. */ + +PAINT aPaint, bPaint; + +{ + int delta; + + delta = abs(aPaint.liquid_content - bPaint.liquid_content); + if (delta <= aPaint.miscibility) return(TRUE); + return(FALSE); +} + +/* *********************************************************************** */ + +int surplus_paint(cell) +/* Returns the amount of paint held by this cell greater than its + absorbancy value. This is the amount of paint that can flow. */ + +CELL_PTR cell; + +{ + return (MAX(cell->volume - cell->absorbancy, 0)); +} + +/* *********************************************************************** */ + +BOOLEAN has_surplus_paint(cell) +/* Does the given cell have excess paint, i.e. can paint flow out + of this cell. Return TRUE if it can and FALSE otherwise. */ + +CELL_PTR cell; + +{ + if (surplus_paint(cell) > 0) return(TRUE); + return(FALSE); +} + +/* *********************************************************************** */ + +void stop() { /* Used for breakpointing. */ } + +void donate_paint(source, srcLocus, amount, dest, destLocus) +/* The source cell is donating the specified volume of its paint + to the destination cell. The destination cell must mix this + new paint with its existing paint to yield a new paint. + This routine is also responsible for recording which cells + have been updated and so need tqrepainting. + + A special case is recognised where the destination has not yet + had any paint applied. This causes the donated paint to become + to new contents of this cell. + +*/ + +CELL_PTR source, dest; +POINT srcLocus, destLocus; +int amount; + +{ + float delta, ratio; + int iDelta; + + source->volume -= amount; + + if (dest->volume == UNFILLED) { + + /* The donated paint is going into an unfilled cell. + Copy the source's attributes into the destination. */ + + dest->volume = amount; + dest->contents.colour.hue = source->contents.colour.hue; + dest->contents.colour.lightness = source->contents.colour.lightness; + dest->contents.colour.saturation = source->contents.colour.saturation; + dest->contents.liquid_content = source->contents.liquid_content; + dest->contents.miscibility = source->contents.miscibility; + dest->contents.drying_rate = source->contents.drying_rate; + + } else { + + /* Need to mix the existing paint in the dest with this amount + of new paint from the source. This is done using a linear + interpolation mechanism using the relative amounts of the + paint as the control. */ + + if (dest->volume != 0) + ratio = amount / (float)(dest->volume); + + iDelta = source->contents.colour.hue - dest->contents.colour.hue; + if (iDelta != 0) { + dest->contents.colour.hue += (int)(ratio * iDelta); + if (dest->contents.colour.hue >= 360) + dest->contents.colour.hue -= 360; + } + + iDelta = source->contents.drying_rate - dest->contents.drying_rate; + dest->contents.drying_rate += (int)((int)ratio * iDelta); + dest->contents.drying_rate %= 101; + + iDelta = source->contents.liquid_content - dest->contents.liquid_content; + dest->contents.liquid_content += (int)(ratio * iDelta); + dest->contents.liquid_content %= 101; + + iDelta = source->contents.miscibility - dest -> contents.miscibility; + dest->contents.miscibility += (int)(ratio * iDelta); + dest->contents.miscibility %= 101; + + delta = source -> contents.colour.saturation - dest -> contents.colour.saturation; + dest -> contents.colour.saturation += ratio * delta; + + delta = source->contents.colour.lightness - dest->contents.colour.lightness; + dest->contents.colour.lightness += ratio * delta; + + dest->volume += amount; /* The new volume of paint in dest. */ + + } + + need_to_tqrepaint(destLocus); +} + +/* *********************************************************************** */ + +void handle_surface_tension(cell, locus) +/* This routine handles the surface tension around the given cell. +*/ + +CELL_PTR cell; +POINT locus; + +{ + DIRECTION direction[3]; + POINT loci[3]; + CELL_PTR buddy[3]; + BOOLEAN ok, similar[3]; + int weakCount, weak[3], count[3], excess, chosen, side, start, finish, +k, lowest; + + if (has_surplus_paint(cell) == FALSE) return; + + direction[0] = cell->gravity.direction; + direction[1] = clockwise_from(direction[0]); + direction[2] = anti_clockwise_from(direction[0]); + + for (k=0; k < 3; k++) { + ok = neighbour(locus, direction[k], &loci[k]); + if (ok == TRUE) { + buddy[k] = get_cell(loci[k]); + count[k] = 0; + } else count[k] = -1; + } + + for (k=0; k < 3; k++) + similar[k] = (count[k] == -1) + ? FALSE + : similar_paint(cell->contents, buddy[k]->contents); + + for (k=0; k < 3; k++) { + if ((count[k] != -1) && (similar[k] == FALSE)) { + count[k] = 0; + start = MAX(k-1, 0); + finish = MIN(k+1, 2); + for (side=start; side <= finish; side++) + if ((count[side] != -1) && (similar[side] == FALSE)) count[k]++; + + } + } + + lowest = 4; + for (k=0; k < 3; k++) if (count[k] >= 0) lowest = MIN(count[k], lowest); + + weakCount = 0; + for (k=0; k < 3; k++) if (count[k] == lowest) weak[weakCount++] = k; + + /* The weak array now holds weakCount indices of those sides that have + the lowest surface tension and therefore where any paint would flow over. + Now it is necessary to see whether paint will actually flow based on + a probability level using the liquidity and volume of the paint in the + cell as parameters. Paint will flow over only one of the weakest sides + with the side chosen at random. */ + + if (random_percent() > cell->contents.liquid_content) return; /* Too +viscous. */ + + excess = surplus_paint(cell); + if (random_percent() > excess * 3) return; + /* The '3' in the previous statement is an empirically-derived multiplier. +*/ + + /* The paint will flow. Pick one of the weakest sides at random. */ + + chosen = weak[random_percent() % weakCount]; + donate_paint(cell, locus, (excess / 2), buddy[chosen], loci[chosen]); +} + +/* *********************************************************************** */ + +BOOLEAN diffuse_paint(cell, locus) +/* Diffuse paint among the neighbours of the given cell. + If this cell does not have surplus paint then return + TRUE otherwise return FALSE. */ + +CELL_PTR cell; +POINT locus; + +{ + extern long random(); + DIRECTION down, direction; + CELL_PTR buddy; + POINT nlocus; + BOOLEAN ok; + int excess; + + if (has_surplus_paint(cell) == FALSE) return(TRUE); + + down = cell->gravity.direction; + direction = ((random() & 01) == 0) + ? clockwise_from(down) + : anti_clockwise_from(down); + + ok = neighbour(locus, direction, &nlocus); + if (ok == FALSE) return(TRUE); + + buddy = get_cell(nlocus); + + if (similar_paint(cell->contents, buddy->contents) == FALSE) { + handle_surface_tension(cell, locus); + return(FALSE); + } + + if (buddy->volume >= cell->volume) return(FALSE); + + if (allow_event_based_on(cell->contents.liquid_content) == FALSE) + return(FALSE); + + /* Transfer one particle of paint from cell to its buddy. */ + + excess = (cell->volume - buddy->volume) / 2; + donate_paint(cell, locus, excess, buddy, nlocus); + return(FALSE); +} + +/* *********************************************************************** */ + +BOOLEAN apply_gravity(cell, locus) +/* Subject the contents of the given cell to the effects + of gravity. Note that the direction of gravity is local + to the given cell. Locus is the address of this cell. + This function returns TRUE if the paint in this cell + cannot flow and FALSE otherwise. +*/ + +CELL_PTR cell; +POINT locus; + +{ + extern long random(); + POINT downhill; + CELL_PTR down; + BOOLEAN ok, can_flow; + int barrier, excess; + + ok = neighbour(locus, cell->gravity.direction, &downhill); + if (ok == FALSE) return(TRUE); /* At bottom of canvas. */ + + down = get_cell(downhill); + + can_flow = down->volume < (cell->volume + cell->gravity.strength) + ? TRUE : FALSE; + + if (can_flow == FALSE) return(TRUE); + + /* Although this paint can flow introduce a random value that + uses the viscosity of the paint to determine whether it does + actually flow. */ + + barrier = random() % 10; + if (cell->contents.liquid_content > barrier) { + /* Paint is actually moving. Move half of the excess downward. */ + + excess = (cell->volume - cell->absorbancy) / 2; + donate_paint(cell, locus, excess, down, downhill); + } + + return(FALSE); +} + + +float lx, ly, lz; + +void +compute_shade_vectors() +{ + extern float lx, ly, lz; + float D; + + lx = 1.0; ly = -1.0; lz = 3.0; + + D = sqrt ( lx * lx + ly * ly + lz * lz ); + + lx = lx/D; ly = ly/D; lz = lz/D; + +} + +/* *********************************************************************** ** + ** +** new_intensity_value ** +** ** +** calculates shade value for a pixel from surface characteristics ** ** + ** +** Revision History ** +** ** +** Rev Date By Description ** +** 1.0 1/12/91 DE Original ** +** 1.1 1/04/92 DE Include Phong Shading ** +** 1.2 11/08/92 JWP Parameterized Specular Component ** ** + ** +*********************************************************************** */ + +float calc_d(); +float calc_g(); +float calc_f(); +float sqr(); +void printvector(); +void vectscale(); +void vectadd(); +float magnitude(); + +float +normalize (x, y, z) + float x, y, z; /*vector x, y, z components*/ +{ + float result; + + /* function calculates the amount to divide each vector component + to normalize it to a unit vector. The parameters are the x,y,z + components and the result is the amount to divide by */ + + result = sqrt (x*x + y*y + z*z); + return (result); + + } + + + +float Newnormalize(V, W) +float *V; +float *W; +{ + float temp; + + temp = normalize(V[0], V[1], V[2]); + + W[0] = V[0]/temp; + W[1] = V[1]/temp; + W[2] = V[2]/temp; + + return temp; +} + +float dot(V, W) + float V[3]; + float W[3]; +{ + + return ( (V[0])*(W[0]) + (V[1])*(W[1]) + (V[2])*(W[2]) ); + +} + +float Phong (Nv, Lv, Ev, shine) +float Nv[3]; +float Lv[3]; +float Ev[3]; +float shine; +{ + float Hv[3]; + + Newnormalize(Ev, Ev); + + Hv[0] = Ev[0] + Lv[0]; + Hv[1] = Ev[1] + Lv[1]; + Hv[2] = Ev[2] + Lv[2]; + + Newnormalize (Hv, Hv); + + shine = abs(shine); + return( pow(dot(Nv, Hv), shine) ); +} + + +/******************* Auxillary functions *****************************/ + +/* Function : calc_c +* Returns : the microfacet distribution function */ + +float calc_d(cos_alpha,c3) +float cos_alpha; +float c3; +{ +float d; +d=sqr( sqr(c3) / ( sqr(cos_alpha)*(sqr(c3) -1) +1)); return d; +} + +/* +* Function : calc_g +* Returns : the geometrical attenuation factor. * +* This function should return values between 0.0 and 1.0, so if it's * negative I will return 0.0 Anyway it does not seem to make any difference * at all whether I return 0.0, the negative value or the minimum of the * absolute values of (temp1,temp2,temp3) */ + +float calc_g(N,H,L,V) +float N[3]; /* Normal vector */ +float H[3]; /* Half-way vector */ +float L[3]; /* Light vector */ +float V[3]; /* View vector */ +{ + float temp1,temp2,temp3,ret; + float NdotH,NdotV,NdotL,VdotH; + NdotH=dot(N,H); + NdotV=dot(N,V); + NdotL=dot(N,L); + VdotH=dot(V,H); + temp1=1.0; + temp2=(2*NdotH*NdotV)/VdotH; + temp3=(2*NdotH*NdotL)/VdotH; + /* Find minimum value */ + if (temp1 < temp2) + if (temp1 < temp3) + ret=temp1; + else + ret=temp3; + else + if (temp2 < temp3) + ret=temp2; + else + ret=temp3; + if (ret < 0.0) + ret=0.0; + return ret; +} + +/* Function : calc_f +* Returns : the Fresnel term +*/ + +float calc_f(L,H,mu) +float L[3]; +float H[3]; +float mu; +{ + float temp1,temp2; + float c,g; + c=dot(L,H); + g=sqrt(sqr(mu)+sqr(c) -1); + temp1 = (sqr(g-c)/sqr(g+c))*0.5; + temp2 = 1+(sqr( c*(g+c)-1 ) / sqr( c*(g-c)+1)); return (temp1*temp2); +} + +/* Function : sqr +* Returns : the square of its argument +*/ + +float sqr(x) +float x; +{ + return (x*x); +} + +/* Function : printvector +* prints the contents of a vector with 3 elements */ + +void printvector(v) +float v[3]; +{ + printf("[%f,%f,%f] ",v[0],v[1],v[2]); +} + +void vectscale(v1, k, vout, n) +float *v1; +float k; +float *vout; +int n; +{ vout[0] = v1[0]*k; + vout[1] = v1[1]*k; + vout[2] = v1[2]*k; +} + +void vectadd(v1, v2, vout, n) +float *v1, *v2, *vout; +int n; +{ vout[0] = v1[0] + v2[0]; + vout[1] = v1[1] + v2[1]; + vout[2] = v1[2] + v2[2]; +} + +float magnitude(v) +float *v; +{ return( normalize(v[0], v[1], v[2]) ); +} + +float T_S(Nv, Lv, Ev, shine) +float Nv[3]; /* Normalized Normal vector */ +float Lv[3]; /* Normalized Light-source vector */ +float Ev[3]; /* Un-normalized Eye vector */ +float shine; /* parameter to absorb Phong coeff */ +{ + float Hv[3]; /* Half-way vector H */ + float cos_alpha; + float t; + float mdf; /* Micro facet distribtuion function */ + float gaf; /* Geometrical attenuation factor*/ float ft; /* The Fresnel term */ + float c3; + float mu; /* Refractive index */ + + /*initialize appearance constants*/ + c3 = shine; + mu = 200.0; + + /*normalize eye vector*/ + + Newnormalize(Ev, Ev); + +/* Calculate the half-way vector H, between the light vector and the +view vector */ + + vectadd(Ev,Lv,Hv,3); + t = magnitude(Hv,3); + + vectscale(Hv,(1/t),Hv,3); + + /* Calculate the micro-facet distribution function D */ + + cos_alpha=dot(Nv,Hv); + mdf=calc_d(cos_alpha,c3); + + + /* Calculate the geometrical attenuation factor */ + + gaf=calc_g(Nv,Hv,Lv,Ev); + + /* Calculate the Fresnel Term */ + + ft=calc_f(Lv,Hv,mu); + + /* Calculate specular component */ + + return( (mdf*gaf*ft) / dot(Nv,Lv) ); +} + + + + +float +new_intensity_value(a_pnt) +POINT a_pnt; +/* Calculate the new intensity value of a pixel +in order to construct a bump map of the paint surface +*/ +{ +float h, h1, h2, h3, h4; + float shininess; +float Ka, Kd, Ks; + float wetmax, degree, norm, distance; + float g; +float Nv[3]; + float Ev[3]; + float Hv[3]; + float Lv[3]; + extern float lx, ly, lz; +float intensity, light_intensity; +int liquid; +POINT b_pnt; +CELL_PTR cell; +CELL_PTR next_cell; + int x_cntr, y_cntr; + + Ka = 0.0; + Kd = 0.5; + Ks = 0.5; + + wetmax = 100.0; + distance = 2500.0; + light_intensity = 2.0; + shininess = 0.3; + + cell = get_cell(a_pnt); + + h = (float)cell->volume; + + if (neighbour(a_pnt, NORTH, &b_pnt)) { + next_cell = get_cell(b_pnt); + h1 = (float)next_cell->volume; + } else + h1 = h; + + if (neighbour(a_pnt, EAST, &b_pnt)) { + next_cell = get_cell(b_pnt); + h2 = (float)next_cell->volume; + } else + h2 = h; + + if (neighbour(a_pnt, SOUTH, &b_pnt)) { + next_cell = get_cell(b_pnt); + h3 = (float)next_cell->volume; + } else + h3 = h; + + if (neighbour(a_pnt, WEST, &b_pnt)) { + next_cell = get_cell(b_pnt); + h4 = (float)next_cell->volume; + } else + h4 = h; + + h1 = h1/HEIGHT_SCALE; + h2 = h2/HEIGHT_SCALE; + h3 = h3/HEIGHT_SCALE; + h4 = h4/HEIGHT_SCALE; + + /* test fix for "disappearing" paint */ + + if (cell->contents.liquid_content == 0) + liquid = 1; + else + liquid = cell->contents.liquid_content; + + degree = (float)abs(liquid)/wetmax; + + x_cntr= 150 - a_pnt.x; + y_cntr= 150 - a_pnt.y; + + Ks = light_intensity * Ks /* * degree*/ ; + + Kd = light_intensity * Kd; + +/* shininess = shininess/degree; */ + + + Nv[1] = h3 - h1; + Nv[0] = h4 - h2; + Nv[2] = 4.0; + + Newnormalize (Nv, Nv); + + Lv[0] = lx; + Lv[1] = ly; + Lv[2] = lz; + + g = dot(Lv, Nv)*Kd + Ka; + + g = g * (float)cell->contents.colour.hue; + + Ev[0] = (float)x_cntr; + Ev[1] = (float)y_cntr; + Ev[2] = distance; + + intensity = g + Ks*T_S(Nv, Lv, Ev, shininess); + + if ( intensity > 255.0 ) { + intensity = 0.0; + } else { + if (intensity < 0.0) + intensity = 255.0; + else + intensity = 255.0 - intensity; + } + + + /*printf("wetness %d colour %d intensity %f guraud %f phong %f\n", + cell->contents.liquid_content, + cell->contents.colour.hue, + intensity, + g, + intensity - g);*/ + + +return (intensity); +} + + +/* *********************************************************************** */ + +void single_step() +/* This routine defines the paint steps involved in the + basic cycle of the painting engine. */ + +{ + POINT locus; + CELL_PTR cell; + BOOLEAN done; + + next_cell_point(&locus); + cell = get_cell(locus); + + done = age_paint(cell); + if (done == TRUE) return; + + done = diffuse_paint(cell, locus); + if (done == TRUE) return; + + done = apply_gravity(cell, locus); +} + +brush_stroke(x,y) +int x; +int y; +{ + POINT pnt; + CELL_PTR cell; + + + pnt.x = x; + pnt.y = y; + + cell = get_cell(pnt); + + cell->contents.liquid_content = 100; + cell->contents.drying_rate = 10; + cell->contents.miscibility = 80; + + cell->contents.colour.hue = 128; + cell->contents.colour.saturation = 1.0; + cell->contents.colour.lightness = 0.0; + + cell->volume = 50; + +} + + diff --git a/chalk/colorspaces/wetsticky/ws/engine.h b/chalk/colorspaces/wetsticky/ws/engine.h new file mode 100644 index 00000000..b6072b0a --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/engine.h @@ -0,0 +1,33 @@ +/* + FILE: engine.h + PURPOSE: Defines the routines for the Paint Engine. + AUTHOR: Kevin Waite + VERSION: 1.00 (10-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England [email protected] +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + +*/ + +extern void single_step(); +/* This routine defines the paint steps involved in the + basic cycle of the painting engine. */ + +extern brush_stroke(); + +extern float intensity_value( /* POINT */); + +extern float new_intensity_value( /* POINT */); + +extern void compute_shade_vectors(); + + diff --git a/chalk/colorspaces/wetsticky/ws/engine3.c b/chalk/colorspaces/wetsticky/ws/engine3.c new file mode 100644 index 00000000..9fd274cd --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/engine3.c @@ -0,0 +1,617 @@ +/* + FILE: engine.c + PURPOSE: Defines the routines for the Paint Engine. + AUTHOR: Kevin Waite + VERSION: 1.00 (10-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England [email protected] +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "constants.h" +#include "types.h" +#include "canvas.h" +#include <math.h> + +#define HEIGHT_SCALE 1.0 + +/* *********************************************************************** */ + +int random_percent() +/* This function returns a random number in the range [0,100]. */ +{ + extern long random(); + + return (random() % 101); +} + +/* *********************************************************************** */ + +BOOLEAN allow_event_based_on(value) +/* The given value is a percentage. Compare this value + with a randomly generated percentage and if it is larger + then allow the event to happen (i.e. return TRUE) other- + wise return FALSE. */ + +int value; + +{ + if (value > random_percent()) return(TRUE); + return(FALSE); +} + +/* *********************************************************************** */ + +BOOLEAN age_paint(cell) +/* Make the paint in the given cell older, i.e. let + if dry out a bit if it isn't already dry. This + function returns TRUE if the paint was already + dry or becomes so, and FALSE otherwise. */ + +CELL_PTR cell; + +{ + if (cell->volume == 0) return(TRUE); + if (cell->contents.liquid_content == 0) return(TRUE); + if (allow_event_based_on(cell->contents.drying_rate) == TRUE) + cell->contents.liquid_content--; + + if (cell->contents.liquid_content == 0) return(TRUE); + return(FALSE); +} + +/* *********************************************************************** */ + +BOOLEAN similar_paint(aPaint, bPaint) +/* Determine whether the two paints are similar. It is + assumed that aPaint has come from the host cell (and + so it is its miscibility value that is used). The + function returns TRUE if the paints are similar and + FALSE otherwise. */ + +PAINT aPaint, bPaint; + +{ + int delta; + + delta = abs(aPaint.liquid_content - bPaint.liquid_content); + if (delta <= aPaint.miscibility) return(TRUE); + return(FALSE); +} + +/* *********************************************************************** */ + +int surplus_paint(cell) +/* Returns the amount of paint held by this cell greater than its + absorbancy value. This is the amount of paint that can flow. */ + +CELL_PTR cell; + +{ + return (MAX(cell->volume - cell->absorbancy, 0)); +} + +/* *********************************************************************** */ + +BOOLEAN has_surplus_paint(cell) +/* Does the given cell have excess paint, i.e. can paint flow out + of this cell. Return TRUE if it can and FALSE otherwise. */ + +CELL_PTR cell; + +{ + if (surplus_paint(cell) > 0) return(TRUE); + return(FALSE); +} + +/* *********************************************************************** */ + +void stop() { /* Used for breakpointing. */ } + +void donate_paint(source, srcLocus, amount, dest, destLocus) +/* The source cell is donating the specified volume of its paint + to the destination cell. The destination cell must mix this + new paint with its existing paint to yield a new paint. + This routine is also responsible for recording which cells + have been updated and so need tqrepainting. + + A special case is recognised where the destination has not yet + had any paint applied. This causes the donated paint to become + to new contents of this cell. + +*/ + +CELL_PTR source, dest; +POINT srcLocus, destLocus; +int amount; + +{ + float delta, ratio; + int iDelta; + + source->volume -= amount; + + if (dest->volume == UNFILLED) { + + /* The donated paint is going into an unfilled cell. + Copy the source's attributes into the destination. */ + + dest->volume = amount; + dest->contents.colour.hue = source->contents.colour.hue; + dest->contents.colour.lightness = source->contents.colour.lightness; + dest->contents.colour.saturation = source->contents.colour.saturation; + dest->contents.liquid_content = source->contents.liquid_content; + dest->contents.miscibility = source->contents.miscibility; + dest->contents.drying_rate = source->contents.drying_rate; + + } else { + + /* Need to mix the existing paint in the dest with this amount + of new paint from the source. This is done using a linear + interpolation mechanism using the relative amounts of the + paint as the control. */ + + ratio = amount / (float)(dest->volume); + + iDelta = source->contents.colour.hue - dest->contents.colour.hue; + if (iDelta != 0) { + dest->contents.colour.hue += (int)(ratio * iDelta); + if (dest->contents.colour.hue >= 360) + dest->contents.colour.hue -= 360; + } + + iDelta = source->contents.drying_rate - dest->contents.drying_rate; + dest->contents.drying_rate += (int)(ratio * iDelta); + dest->contents.drying_rate %= 101; + + iDelta = source->contents.liquid_content - dest->contents.liquid_content; + dest->contents.liquid_content += (int)(ratio * iDelta); + dest->contents.liquid_content %= 101; + + iDelta = source->contents.miscibility - dest->contents.miscibility; + dest->contents.miscibility += (int)(ratio * iDelta); + dest->contents.miscibility %= 101; + + delta = source->contents.colour.saturation - dest->contents.colour.saturation; + dest->contents.colour.saturation += ratio * delta; + + delta = source->contents.colour.lightness - dest->contents.colour.lightness; + dest->contents.colour.lightness += ratio * delta; + + dest->volume += amount; /* The new volume of paint in dest. */ + + } + + need_to_tqrepaint(destLocus); +} + +/* *********************************************************************** */ + +void handle_surface_tension(cell, locus) +/* This routine handles the surface tension around the given cell. +*/ + +CELL_PTR cell; +POINT locus; + +{ + DIRECTION direction[3]; + POINT loci[3]; + CELL_PTR buddy[3]; + BOOLEAN ok, similar[3]; + int weakCount, weak[3], count[3], excess, chosen, side, start, finish, k, lowest; + + if (has_surplus_paint(cell) == FALSE) return; + + direction[0] = cell->gravity.direction; + direction[1] = clockwise_from(direction[0]); + direction[2] = anti_clockwise_from(direction[0]); + + for (k=0; k < 3; k++) { + ok = neighbour(locus, direction[k], &loci[k]); + if (ok == TRUE) { + buddy[k] = get_cell(loci[k]); + count[k] = 0; + } else count[k] = -1; + } + + for (k=0; k < 3; k++) + similar[k] = (count[k] == -1) + ? FALSE + : similar_paint(cell->contents, buddy[k]->contents); + + for (k=0; k < 3; k++) { + if ((count[k] != -1) && (similar[k] == FALSE)) { + count[k] = 0; + start = MAX(k-1, 0); + finish = MIN(k+1, 2); + for (side=start; side <= finish; side++) + if ((count[side] != -1) && (similar[side] == FALSE)) count[k]++; + + } + } + + lowest = 4; + for (k=0; k < 3; k++) if (count[k] >= 0) lowest = MIN(count[k], lowest); + + weakCount = 0; + for (k=0; k < 3; k++) if (count[k] == lowest) weak[weakCount++] = k; + + /* The weak array now holds weakCount indices of those sides that have + the lowest surface tension and therefore where any paint would flow over. + Now it is necessary to see whether paint will actually flow based on + a probability level using the liquidity and volume of the paint in the + cell as parameters. Paint will flow over only one of the weakest sides + with the side chosen at random. */ + + if (random_percent() > cell->contents.liquid_content) return; /* Too viscous. */ + + excess = surplus_paint(cell); + if (random_percent() > excess * 3) return; + /* The '3' in the previous statement is an empirically-derived multiplier. */ + + /* The paint will flow. Pick one of the weakest sides at random. */ + + chosen = weak[random_percent() % weakCount]; + donate_paint(cell, locus, (excess / 2), buddy[chosen], loci[chosen]); +} + +/* *********************************************************************** */ + +BOOLEAN diffuse_paint(cell, locus) +/* Diffuse paint among the neighbours of the given cell. + If this cell does not have surplus paint then return + TRUE otherwise return FALSE. */ + +CELL_PTR cell; +POINT locus; + +{ + extern long random(); + DIRECTION down, direction; + CELL_PTR buddy; + POINT nlocus; + BOOLEAN ok; + int excess; + + if (has_surplus_paint(cell) == FALSE) return(TRUE); + + down = cell->gravity.direction; + direction = ((random() & 01) == 0) + ? clockwise_from(down) + : anti_clockwise_from(down); + + ok = neighbour(locus, direction, &nlocus); + if (ok == FALSE) return(TRUE); + + buddy = get_cell(nlocus); + + if (similar_paint(cell->contents, buddy->contents) == FALSE) { + handle_surface_tension(cell, locus); + return(FALSE); + } + + if (buddy->volume >= cell->volume) return(FALSE); + + if (allow_event_based_on(cell->contents.liquid_content) == FALSE) + return(FALSE); + + /* Transfer one particle of paint from cell to its buddy. */ + + excess = (cell->volume - buddy->volume) / 2; + donate_paint(cell, locus, excess, buddy, nlocus); + return(FALSE); +} + +/* *********************************************************************** */ + +BOOLEAN apply_gravity(cell, locus) +/* Subject the contents of the given cell to the effects + of gravity. Note that the direction of gravity is local + to the given cell. Locus is the address of this cell. + This function returns TRUE if the paint in this cell + cannot flow and FALSE otherwise. +*/ + +CELL_PTR cell; +POINT locus; + +{ + extern long random(); + POINT downhill; + CELL_PTR down; + BOOLEAN ok, can_flow; + int barrier, excess; + + ok = neighbour(locus, cell->gravity.direction, &downhill); + if (ok == FALSE) return(TRUE); /* At bottom of canvas. */ + + down = get_cell(downhill); + + can_flow = down->volume < (cell->volume + cell->gravity.strength) + ? TRUE : FALSE; + + if (can_flow == FALSE) return(TRUE); + + /* Although this paint can flow introduce a random value that + uses the viscosity of the paint to determine whether it does + actually flow. */ + + barrier = random() % 10; + if (cell->contents.liquid_content > barrier) { + /* Paint is actually moving. Move half of the excess downward. */ + + excess = (cell->volume - cell->absorbancy) / 2; + donate_paint(cell, locus, excess, down, downhill); + } + + return(FALSE); +} + + +float lx, ly, lz; + +void +compute_shade_vectors() +{ + extern float lx, ly, lz; + float D; + + lx = -1.0; ly = 1.0; lz = 2.0; + + D = sqrt ( lx * lx + ly * ly + lz * lz ); + + lx = lx/D; ly = ly/D; lz = lz/D; + +} + +/* *********************************************************************** ** ** +** new_intensity_value ** +** ** +** calculates shade value for a pixel from surface characteristics ** ** ** +** Revision History ** +** ** +** Rev Date By Description ** +** 1.0 1/12/91 DE Original ** +** 1.1 1/04/92 DE Include Phong Shading ** +** 1.2 11/08/92 JWP Parameterized Specular Component ** ** ** +*********************************************************************** */ +float +normalize (x, y, z) + float x, y, z; /*vector x, y, z components*/ +{ + float result; + + /* function calculates the amount to divide each vector component + to normalize it to a unit vector. The parameters are the x, y, +z + components and the result is the amount to divide by */ + + result = sqrt (x*x + y*y + z*z); + return (result); + + } + + + +float Newnormalize(V, W) +float *V; +float *W; +{ +float temp; + +temp = normalize(V[0], V[1], V[2]); + +W[0] = V[0]/temp; +W[1] = V[1]/temp; +W[2] = V[2]/temp; + +return temp; +} + +float dot(V, W) +float V[3]; +float W[3]; +{ + +return ( (V[0])*(W[0]) + (V[1])*(W[1]) + (V[2])*(W[2]) ); + +} + +float Phong (Nv, Lv, Ev, shine) +float Nv[3]; +float Lv[3]; +float Ev[3]; +float shine; +{ +float Hv[3]; + +Newnormalize(Ev, Ev); + +Hv[0] = Ev[0] + Lv[0]; +Hv[1] = Ev[1] + Lv[1]; +Hv[2] = Ev[2] + Lv[2]; + +Newnormalize (Hv, Hv); + +shine = abs(shine); +return( pow(dot(Nv, Hv), shine) ); +} + + +float +new_intensity_value(a_pnt) +POINT a_pnt; +/* Calculate the new intensity value of a pixel +in order to construct a bump map of the paint surface +*/ +{ +float h, h1, h2, h3, h4; + int shininess; +float Ka, Kd, Ks; + float wetmax, degree, norm, distance; + float g; +float Nv[3]; + float Ev[3]; + float Hv[3]; + float Lv[3]; + extern float lx, ly, lz; +float intensity, light_intensity; +POINT b_pnt; +CELL_PTR cell; +CELL_PTR next_cell; + int x_cntr, y_cntr; + +Ka = 0.1; +Kd = 0.6; + Ks = 0.4; + + wetmax = 100.0; + distance = 2500.0; + light_intensity = 2.0; + shininess = 200; + +cell = get_cell(a_pnt); + +h = (float)cell->volume; + +if (neighbour(a_pnt, NORTH, &b_pnt)) { +next_cell = get_cell(b_pnt); +h1 = (float)next_cell->volume; +} else +h1 = h; + +if (neighbour(a_pnt, EAST, &b_pnt)) { +next_cell = get_cell(b_pnt); +h2 = (float)next_cell->volume; +} else +h2 = h; + +if (neighbour(a_pnt, SOUTH, &b_pnt)) { +next_cell = get_cell(b_pnt); +h3 = (float)next_cell->volume; +} else +h3 = h; + +if (neighbour(a_pnt, WEST, &b_pnt)) { +next_cell = get_cell(b_pnt); +h4 = (float)next_cell->volume; +} else +h4 = h; + +h1 = h1/HEIGHT_SCALE; +h2 = h2/HEIGHT_SCALE; +h3 = h3/HEIGHT_SCALE; +h4 = h4/HEIGHT_SCALE; + + degree = (float)abs(cell->contents.liquid_content)/wetmax; + + x_cntr= 150 - a_pnt.x; + y_cntr= 150 - a_pnt.y; + + Ks = light_intensity * Ks * degree; + + Kd = light_intensity * Kd; + + shininess = (int)degree * shininess + 1; + + + Nv[1] = h3 - h1; + Nv[0] = h4 - h2; +Nv[2] = 4.0; + + Newnormalize (Nv, Nv); + + Lv[0] = lx; +Lv[1] = ly; + Lv[2] = lz; + + g = dot(Lv, Nv)*Kd + Ka; + + g = g * (float)cell->contents.colour.hue; + +Ev[0] = (float)x_cntr; +Ev[1] = (float)y_cntr; +Ev[2] = distance; + + intensity = g + Ks*Phong(Nv, Lv, Ev, (float)shininess); + + if ( intensity > 255.0 ) { + intensity = 0.0; + } else { + if (intensity < 0.0) + intensity = 255.0; + else + intensity = 255.0 - intensity; + } + + + /*printf("wetness %d colour %d intensity %f guraud %f phong %f\n", + cell->contents.liquid_content, + cell->contents.colour.hue, + intensity, + g, + intensity - g);*/ + + +return (intensity); +} + + +/* *********************************************************************** */ + +void single_step() +/* This routine defines the paint steps involved in the + basic cycle of the painting engine. */ + +{ + POINT locus; + CELL_PTR cell; + BOOLEAN done; + + next_cell_point(&locus); + cell = get_cell(locus); + + done = age_paint(cell); + if (done == TRUE) return; + + done = diffuse_paint(cell, locus); + if (done == TRUE) return; + + done = apply_gravity(cell, locus); +} + +brush_stroke(x,y) +int x; +int y; +{ + POINT pnt; + CELL_PTR cell; + + + pnt.x = x; + pnt.y = y; + + cell = get_cell(pnt); + + cell->contents.liquid_content = 100; + cell->contents.drying_rate = 10; + cell->contents.miscibility = 80; + + cell->contents.colour.hue = 128; + cell->contents.colour.saturation = 1.0; + cell->contents.colour.lightness = 0.0; + + cell->volume = 50; + +} + diff --git a/chalk/colorspaces/wetsticky/ws/load_ppm.c b/chalk/colorspaces/wetsticky/ws/load_ppm.c new file mode 100644 index 00000000..6368ee08 --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/load_ppm.c @@ -0,0 +1,244 @@ +/* + FILE: load_ppm.c + PURPOSE: Defines the routines to load a PPM portable pixmap image file. + AUTHOR: David England + VERSION: 1.00 (10-May-91) + + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England [email protected] +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "constants.h" +#include "types.h" +#include "canvas.h" + +#include <ctype.h> +#include <ppm.h> +#include <ppmcmap.h> + +/* Max number of colors allowed in ppm input. */ +#define MAXCOLORS 256 + +extern CELL canvas[CANVAS_WIDTH][CANVAS_HEIGHT]; + +float +max_rgb(r,g,b) +float r; +float g; +float b; +{ + if ((r > g) && (r > b)) + return (r); + + if ((b > g) && (b > r)) + return (b); + + if ((g > b) && (g > r)) + return (g); + + return(0); +} + +float +min_rgb(r,g,b) +float r; +float g; +float b; +{ + if ((r < g) && (b < g)) + return (r); + + if ((b < g) && (b < r)) + return (b); + + if ((g < b) && (g < r)) + return (g); + + return(0); +} + + +int +GetHue(red, green, blue) /* rgb to hls */ +int red; +int green; +int blue; +{ + float min_col, max_col; + float h,s,l; + float rc, gc, bc; + float r, g, b; + + r = (float)red/255.0; + b = (float)green/255.0; + g = (float)blue/255.0; + + max_col = (float)max_rgb(r, g, b); + min_col = (float)min_rgb(r, g, b); + + l = (max_col + min_col)/2.0 ; + + if ( max_col == min_col) { + s = 0.0; + h = 0.0; + } else { + if ( l < 0.5) { + s = (max_col - min_col)/(max_col + min_col); + } else s = (max_col - min_col)/(2 - max_col - min_col); + + rc = (max_col -r)/( max_col - min_col); + gc = (max_col -g)/(max_col - min_col); + bc = (max_col -b)/(max_col - min_col); + + if (r == max_col) + h = bc - gc; + else if (g == max_col ) + h = 2 + rc - bc; + else if (b == max_col) + h = 4 + gc -rc; + + h = h * 60; + + if ( h < 0.0) + h = h + 360; + } + + return ((int)h); + + +} + +GetHuePaint(r,g,b) +int r; +int g; +int b; +{ + + /*if ((r == 0) && (g == 0) && (b ==0)) { + canvas[i][j].contents.liquid_content = 0; + canvas[i][j].contents.drying_rate = 0; + canvas[i][j].contents.miscibility = 0; + + canvas[i][j].contents.colour.hue = 0; + canvas[i][j].contents.colour.saturation = 1.0; + canvas[i][j].contents.colour.lightness = 0.0; + canvas[i][j].volume = 80; + return (0); + } + + if ((r == 255) && (g == 255) && ( b == 255)) { + canvas[i][j].contents.liquid_content = 0; + canvas[i][j].contents.drying_rate = 0; + canvas[i][j].contents.miscibility = 0; + + canvas[i][j].contents.colour.hue = 128; + canvas[i][j].contents.colour.saturation = 1.0; + canvas[i][j].contents.colour.lightness = 0.0; + canvas[i][j].volume = 80; + return (128); + }*/ +} + +load_ppm_format(filename, width, height) +char *filename; +int *width; +int *height; +{ + + FILE* ifp; + pixel **pixels; + int rows, cols, i, j; + pixval maxval; + int red, green, blue; + int hue; + + /*ppm_init( &argc, argv );*/ + + + + ifp = pm_openr( filename); + + pixels = ppm_readppm( ifp, &cols, &rows, &maxval ); + + *(width) = cols; + *(height) = rows; + + fprintf(stderr,"Loading file %s, %dx%d. Please wait ", filename, rows, +cols); + + if (rows > CANVAS_HEIGHT) + rows = CANVAS_HEIGHT; + + if (cols > CANVAS_WIDTH) + cols = CANVAS_WIDTH; + + for (i=0; i< rows; i++) { + for (j=0; j< cols; j++) { + red = PPM_GETR(pixels[i][j]); + green = PPM_GETG(pixels[i][j]); + blue = PPM_GETB(pixels[i][j]); + + /*hue = GetHue(red, green, blue);*/ + + /* For gray scale only */ + + hue = 255 - red; + + + /*fprintf(stderr,"hue %d ", hue);*/ + /*GetHuePaint(red, green, blue, i, j);*/ + + canvas[i][j].contents.liquid_content = 80; + canvas[i][j].contents.drying_rate = 80; + canvas[i][j].contents.miscibility = 80; + + canvas[i][j].contents.colour.hue = hue; + canvas[i][j].contents.colour.saturation = 1.0; + canvas[i][j].contents.colour.lightness = 0.0; + canvas[i][j].volume = (float)hue/2.5; + + if (red == 0) + if (green == 0) + if ( blue == 0) { + canvas[i][j].contents.liquid_content = 0; + canvas[i][j].contents.drying_rate = 0; + canvas[i][j].contents.miscibility = 0; + canvas[i][j].contents.colour.hue = 0; + canvas[i][j].volume = 0; + } + + if (red == 255) + if (green == 255) + if ( blue == 255) { + canvas[i][j].contents.liquid_content = 0; + canvas[i][j].contents.drying_rate = 0; + canvas[i][j].contents.miscibility = 0; + canvas[i][j].contents.colour.hue = 360; + canvas[i][j].volume = 0; + } + + + } + if (( i %10) == 0){ + fprintf(stderr,"."); + fflush(stderr); + } + } + + printf(" done\n"); + + pm_close( ifp ); + + /*exit(0);*/ + +} diff --git a/chalk/colorspaces/wetsticky/ws/main.c b/chalk/colorspaces/wetsticky/ws/main.c new file mode 100644 index 00000000..8185557a --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/main.c @@ -0,0 +1,105 @@ +/* + FILE: main.c + PURPOSE: The top-level program for Wet&Sticky + AUTHOR: Kevin Waite and David England + VERSION: 1.00 (10-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England [email protected] +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "constants.h" +#include "types.h" +#include "canvas.h" +#include "win_interface.h" +#include <stdio.h> +#include <string.h> +#include <math.h> + +double HEIGHT_SCALE; + +void main(argc, argv) +int argc; +char *argv[]; + +/* + The Wet&Sticky program can be executed with optional parameters. + Those parameters used by the X graphics system are stripped out. + If no parameters are given then the program runs as a purely + interactive system. This requires input handling which is not + yet implemented. If the argument is the string '-blob' then the + program uses a square blob as the starting image. Otherwise the + program assumes the argument is a filename containing a previously + stored canvas. This is then loaded into the canvas as a starting + point. +*/ + +{ + char *filename; + extern void exit(); + int width; + int height; + extern int optind, opterr; + extern char *optarg; + int c,i; + int blob_flag; + + + fprintf(stdout, "Wet&Sticky Version %s\n", VERSION); + fprintf(stdout, "Implemented by K.Waite and D.England, 1991\n"); + fprintf(stdout, "Based on ideas by Tunde Cockshott\n\n"); + + + initialise_canvas(); + if (DEBUG) fprintf (stdout, "Finished initialising the canvas\n"); + + CreateWindows (&argc, argv, CANVAS_WIDTH , CANVAS_HEIGHT); + + filename = argv[1]; + + blob_flag = 1; + HEIGHT_SCALE = 20.0; + + opterr = 0; + fprintf(stderr, "HEIGHT %g\n", HEIGHT_SCALE); + + while ((c = getopt(argc, argv, "f:s:")) != EOF) + switch (c) { + case 'f': + filename = optarg; + load_file(filename, &width, &height); + blob_flag = 0; + break; + case 's': + fprintf(stderr, "HEIGHT string %s \n",optarg); + HEIGHT_SCALE = atof(optarg); + break; + case '?': + break; + } + + if (blob_flag) + blob (DEFAULT_BLOB_SIZE); + + fprintf(stderr, "HEIGHT %g\n", HEIGHT_SCALE); + + StartVolumeWindow (CANVAS_WIDTH, CANVAS_HEIGHT); + StartDrynessWindow (CANVAS_WIDTH, CANVAS_HEIGHT); + + if (DEBUG) fprintf (stdout, "Finished preparing X\n"); + + if (DEBUG) fprintf (stdout, "Passing control to window manager\n"); + StartWindows(); + exit(0); + +} diff --git a/chalk/colorspaces/wetsticky/ws/makefile b/chalk/colorspaces/wetsticky/ws/makefile new file mode 100644 index 00000000..a14beb9a --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/makefile @@ -0,0 +1,55 @@ +CFLAGS = -O3 +#CFLAGS = -g #-std +LINT_FLAGS = -bchxu + +SOURCES = load_ppm.c canvas.c engine.c x_interface.c main.c +OBJECTS = x_interface.o load_ppm.o engine.o canvas.o +OBJECTS2= ogl_interface.o load_ppm.o engine.o canvas.o + +GFX_LIB=-L/usr/X11R6/lib \ + -lXaw -lXmu -lXt -lX11 -lm -lppm -lpgm -lpbm + +#PPM_LIBS = ppm/libppm.a ppm/libpgm.a ppm/libpbm.a + +OGL_LIBS=-L/usr/X11R6/lib \ + -laux -lGLU -lGL -lXext -lX11 -limp -lm -lppm -lpgm -lpbm + +OGL_INCS=-I/usr2/share/src/OpenGL/libaux + +CC=cc + +wet+sticky: constants.h canvas.h engine.h $(OBJECTS) main.c + ${CC} -o wet+sticky $(CFLAGS) main.c $(OBJECTS) $(GFX_LIB) + +wet+sticky2: constants.h canvas.h engine.h $(OBJECTS2) main.c + ${CC} -o wet+sticky2 $(CFLAGS) main.c $(OBJECTS2) $(OGL_LIBS) + +cmap: cmap.o + ${CC} -g -o cmap cmap.o $(GFX_LIB) + +anim: constants.h canvas.h engine.h anim.c + ${CC} -o anim $(CFLAGS) anim.c $(GFX_LIB) + +engine.o: types.h constants.h canvas.h engine.h + ${CC} -c $(CFLAGS) engine3.c + +canvas.o: types.h constants.h canvas.h + ${CC} -c $(CFLAGS) canvas.c + +x_interface.o: constants.h types.h canvas.h engine.h x_interface.c + ${CC} -c $(CFLAGS) x_interface.c + +ogl_interface.o: constants.h types.h canvas.h engine.h ogl_interface.c + ${CC} -c $(CFLAGS) ${OGL_INCS} ogl_interface.c + +load_ppm.o: constants.h types.h canvas.h engine.h load_ppm.c + ${CC} -c $(CFLAGS) load_ppm.c + +cmap.o: cmap.c + ${CC} -c -g cmap.c + +clean: + /bin/rm -f core + /bin/rm -f *.o + +lint: alint $(LINT_FLAGS) $(SOURCES) diff --git a/chalk/colorspaces/wetsticky/ws/mona.pgm b/chalk/colorspaces/wetsticky/ws/mona.pgm Binary files differnew file mode 100644 index 00000000..2060ee90 --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/mona.pgm diff --git a/chalk/colorspaces/wetsticky/ws/ogl_interface.c b/chalk/colorspaces/wetsticky/ws/ogl_interface.c new file mode 100644 index 00000000..953b10c8 --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/ogl_interface.c @@ -0,0 +1,302 @@ +/* + FILE: xgl_interface.c + PURPOSE: Creation and access to a OpenGL window + to wet+sticky using OpenGL + AUTHOR: David England + VERSION: 1.00 (21-June-96) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England [email protected] +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include <GL/gl.h> +#include <GL/glu.h> +/*#include <imp.h>*/ +/*#include "aux.h"*/ + +#include <stdio.h> + +#include "constants.h" +#include "types.h" +#include "engine.h" +#include "canvas.h" + +static int count=0; + + +void nullProc() +{ +} + +void SetupCmap() +{ +} + +float Value(n1, n2, hue) +float n1, n2, hue; +{ + if (hue > 360 ) + hue = hue -360; + else if (hue < 0 ) + hue = hue +360; + if (hue < 60 ) + return n1+(n2-n1)*hue/60; + else if (hue < 180 ) + return n2; + else if (hue < 240 ) + return n1+(n2-n1)*(240-hue)/60; + else return n1; +} + + +RGB_COLOUR hls_to_rgb(h, l, s) +int h; +float l; +float s; +{ +RGB_COLOUR rgb_colour; +float m1, m2; + +if (l <= 0.5 ) + m2 = l*(1+s); +else + m2 = l+s - l*s; +m1 = 2*l-m2; + +rgb_colour.r = Value(m1, m2, h+120); +rgb_colour.g = Value(m1,m2, h); +rgb_colour.b = Value(m1,m2, h-120); + +return (rgb_colour); +} + +void +DrawPoint(x,y,hls_col) +int x; +int y; +HLS_COLOUR hls_col; +/* Draw a point on the window and the back-up Pixmap */ +{ +RGB_COLOUR rgb_colour; + + rgb_colour = hls_to_rgb(hls_col.hue, + hls_col.lightness, + hls_col.saturation); + + + printf("h %.2f l %.2f s %.2f\n", hls_col.hue, hls_col.lightness, + hls_col.saturation); + + printf( "r %.2f g %.2f b %.2f\n", rgb_colour.r, rgb_colour.g, + rgb_colour.b); + + glColor3f(rgb_colour.r, rgb_colour.g, rgb_colour.b); + + glBegin(GL_POINTS); + glVertex2s(x,y); + glVertex2s(x+1,y+1); + glEnd(); + +} + +void +DrawVolumePoint(x,y,attr) +int x; +int y; +int attr; +{ +/*set colour, draw point at offset */ +} + +void +DrawDrynessPoint(x,y,attr) +int x; +int y; +int attr; +/* Draw a point on the window and the back-up Pixmap */ +{ + +} + +void +ClearWindow() +{ + +} + +static void +CleanWindow() +/* Fill a window with a solid, white rectangle */ +{ +} + + +void CreateWindows(argc, argv, width, height) +int *argc; +char **argv; +int width; +int height; + +{ + + auxInitDisplayMode( AUX_RGBA); + + auxInitPosition(50,50, width*3, height); + + auxInitWindow(argv[0]); + + glClearColor(1.0, 1.0, 1.0, 0.0); + + glClear(GL_COLOR_BUFFER_BIT); + +} + + +static void +draw_labels() +{ +} + +void paint_cell(cell, x, y) +CELL_PTR cell; +int x, y; + +{ + DrawPoint(x,y, cell->contents.colour); + + /* volColour is an index into the colour table in the range [0,255]. + It is used to give a false colour image of the canvas's volume. */ + + /*DrawVolumePoint(x,y,volColour);*/ + + + /*DrawDrynessPoint(x,y,dryness);*/ +} + + + + +void draw_full_canvas() +{ + int x, y; + CELL_PTR cell; + POINT p; + + glClear(GL_COLOR_BUFFER_BIT); + + if (DEBUG) { + printf ("Starting to paint full canvas..."); + fflush(stdout); + } + + for (y=0; y < CANVAS_HEIGHT; y++) + for (x=0; x < CANVAS_WIDTH; x++) { + p.x = x; + p.y = y; + cell = get_cell(p); + paint_cell(cell, x, y); + } + + glFlush(); + sleep(10); + + if (DEBUG) printf ("done.\n"); +} + +void +bump_map() +{ + POINT p; + CELL_PTR cell; + register int x, y; + register int colour; + + + for (y=0; y < CANVAS_HEIGHT; y++) { + for (x=0; x < CANVAS_WIDTH; x++) { + p.x = x; + p.y = y; + cell = get_cell(p); + colour = (int) new_intensity_value(p); + +/* colour = (int) (cell->contents.colour.hue * + ((float) MAX_COLOUR_INDEX / 360.0));*/ + DrawDrynessPoint(x,y,colour); + } + } + +} + + +void evolve_paint() +{ + int k; + POINT p; + CELL_PTR cell; + int new_x, new_y; + extern int count; + + /*count++; + if (count > 500) { + fprintf(stderr,"."); + fflush(stderr); + bump_map(); + }*/ + + for (k=0; k < STEP_LIMIT; k++) single_step(); + while (TRUE) { + next_cell_for_tqrepaint(&cell, &p); + if (cell == NIL) return; + paint_cell(cell, p.x, p.y); + glFlush(); + } + + +} + +void StartVolumeWindow() +{ +} + +void StartDrynessWindow() +{ +} + +void StartWindows() +{ + + + draw_full_canvas(); + compute_shade_vectors(); /* Set vectors for shading */ + draw_labels(); + + /*auxIdleFunc(evolve_paint); + + auxMainLoop(draw_full_canvas);*/ + + +} + +void +stroke() +{ + +} + + +void +stroke_motion() +{ + +} + diff --git a/chalk/colorspaces/wetsticky/ws/test2.jpg b/chalk/colorspaces/wetsticky/ws/test2.jpg Binary files differnew file mode 100644 index 00000000..4254264f --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/test2.jpg diff --git a/chalk/colorspaces/wetsticky/ws/test3.jpg b/chalk/colorspaces/wetsticky/ws/test3.jpg Binary files differnew file mode 100644 index 00000000..2b25a0d5 --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/test3.jpg diff --git a/chalk/colorspaces/wetsticky/ws/types.h b/chalk/colorspaces/wetsticky/ws/types.h new file mode 100644 index 00000000..af671f53 --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/types.h @@ -0,0 +1,72 @@ +/* + FILE: types.h + PURPOSE: Defines all the main types used in Wet&Sticky. + AUTHORS: Kevin Waite and David England + VERSION: 1.00 (10-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England [email protected] +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + + +*/ + + +/* A colour is specified as a vector in HLS space. Hue is a value + in the range 0..360 degrees with 0 degrees being red. Saturation + and Lightness are both in the range [0,1]. A lightness of 0 means + black, with 1 being white. A totally saturated colour has saturation + of 1. +*/ + +typedef struct hls_colour { short int hue; float saturation, lightness; } +HLS_COLOUR; + +typedef struct rgb_colour {float r; float g; float b;} +RGB_COLOUR; + + +/* The address of a cell on the canvas. */ + +typedef struct point { int x, y; } POINT, *POINT_PTR; + + +/* A direction can be NORTH, EAST, SOUTH or WEST. */ + +typedef short int DIRECTION; + +typedef short int BOOLEAN; /* FALSE or TRUE */ + + +typedef struct paint { + HLS_COLOUR colour; + int liquid_content; /* [0,100]. */ + int drying_rate; /* [0,100]. */ + int miscibility; /* [0,inf]. */ +} PAINT, *PAINT_PTR; + + +/* Defines the strength and direction of gravity for a cell. */ + +typedef struct gravity { + DIRECTION direction; + int strength; /* [0,Infinity). */ +} GRAVITY, *GRAVITY_PTR; + + +/* Defines the contents and attributes of a cell on the canvas. */ + +typedef struct cell { + PAINT contents; /* The paint in this cell. */ + GRAVITY gravity; /* This cell's gravity. */ + short int absorbancy; /* How much paint can this cell hold? */ + short int volume; /* The volume of paint. */ +} CELL, *CELL_PTR; diff --git a/chalk/colorspaces/wetsticky/ws/win_interface.h b/chalk/colorspaces/wetsticky/ws/win_interface.h new file mode 100644 index 00000000..ee7a064b --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/win_interface.h @@ -0,0 +1,28 @@ +/* +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. + +Contact David England [email protected] +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + +Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky 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 General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA + + +*/ + +extern void DrawPoint(/* int x, int y; int colour*/); +extern int DrawVolumePoint(/* int x, int y; int attr*/); +extern int DrawDrynessPoint(/* int x, int y; int attr*/); +extern void ClearWindow(); +extern void CreateWindows(/* int *argc, char *argv[], int width, int height*/); +extern void StartWindows(); /* enter infinite loop */ +extern void StartVolumeWindow(/*int width, int height*/); + /* display attribute window */ +extern void StartDrynessWindow(/*int width, int height*/); + /* display attribute window */ + + diff --git a/chalk/colorspaces/wetsticky/ws/x_interface.c b/chalk/colorspaces/wetsticky/ws/x_interface.c new file mode 100644 index 00000000..a8b54b3e --- /dev/null +++ b/chalk/colorspaces/wetsticky/ws/x_interface.c @@ -0,0 +1,795 @@ +/* + FILE: x_interface.c + PURPOSE: Creation and access to an X windows interface + to wet+sticky using Athena Widgets + AUTHOR: David England + VERSION: 1.00 (13-May-91) + +Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England. +Contact David England [email protected] +School of Computing and Maths Sciences, +Liverpool John Moores University +Liverpool L3 3AF +United Kingdom +Phone +44 151 231 2271 + + +Wet and Sticky is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. Wet and Sticky 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 General Public License for more details. You +should have received a copy of the GNU General Public License along +with Wet and Sticky; if not, write to the Free Software Foundation, +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include <X11/Xos.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Intrinsic.h> + +#include <X11/cursorfont.h> +#include <X11/StringDefs.h> + +#include <X11/Shell.h> +#include <X11/Xaw/Box.h> +#include <X11/Xaw/Label.h> +#include <stdio.h> + +#include "constants.h" +#include "types.h" +#include "engine.h" +#include "canvas.h" + +/* Window Heirarchy - + Three shell widgets, one for colour output, two for attributes output + plus a back_up pixmap for redrawing +*/ + +static Widget top_level; +static Widget colour_shell; +static Widget colour_box; +static Widget colour_canvas; +static Pixmap colour_pm; + +static Widget volume_shell; +static Widget volume_box; +static Widget volume_canvas; +static Pixmap volume_pm; + +static Widget dryness_shell; +static Widget dryness_box; +static Widget dryness_canvas; +static Pixmap dryness_pm; + +static GC gc; +static GC tmp_gc; +static long tqmask; +static XGCValues values; + +static Colormap cmap; +static XColor colours[256]; +void stroke(); +void stroke_motion(); + +Display *display; +int screen; +Screen *screen_ptr; +Window root; + +static int count=0; +static int frame_count=0; +char pix_file[64]; + +static void +expose_event(w, event) +Widget w; +XEvent *event; +{ +/* Re-display the colour window if an exposure event is received */ +int width, height; + + width = height = 300; + + XCopyArea(XtDisplay(colour_canvas), colour_pm, + XtWindow(colour_canvas), gc, 0, 0, width, height, 0,0); + +} + + +static void +expose_volume(w, event) +Widget w; +XEvent *event; +{ +/* Re-display the volume window if an exposure event is received */ +int width, height; + + width = 300; + height = 300; + + XCopyArea(XtDisplay(volume_canvas), volume_pm, + XtWindow(volume_canvas), gc, 0, 0, width, height, 0,0); + + +} + +static void +expose_dryness(w, event) +Widget w; +XEvent *event; +{ +/* Re-display the dryness window if an exposure event is received */ +int width, height; + + width = height = 300; + + XCopyArea(XtDisplay(dryness_canvas), dryness_pm, + XtWindow(dryness_canvas), gc, 0, 0, width, height, 0,0); + + +} + +void expose_canvases() +{ +int width, height; + +width = height = 300; + + XCopyArea(XtDisplay(colour_canvas), colour_pm, + XtWindow(colour_canvas), gc, 0, 0, width, height, 0,0); + + XCopyArea(XtDisplay(dryness_canvas), dryness_pm, + XtWindow(dryness_canvas), gc, 0, 0, width, height, 0,0); + + XCopyArea(XtDisplay(dryness_canvas), dryness_pm, + XtWindow(dryness_canvas), gc, 0, 0, 300, 300, 0,0); + +} + +int +GetHueValue(red, green, blue) +int red; +int green; +int blue; +{ + XColor colour; + + colour.red = red * 257; + colour.green = green * 257; + colour.blue = blue * 257; + colour.flags = DoRed | DoGreen | DoBlue; + + if (XAllocColor(display, cmap, &colour) == 0) + fprintf(stderr,"colour allocation failed\n"); + + return (colour.pixel); +} + + +void +DrawPoint(x,y,colour) +int x; +int y; +int colour; +/* Draw a point on the window and the back-up Pixmap */ +{ + /* PROBS ? */ + + XSetForeground(XtDisplay(top_level), gc, colours[colour].pixel); + + XDrawPoint(XtDisplay(top_level), XtWindow(colour_canvas), gc, x, y); + XDrawPoint(XtDisplay(top_level), colour_pm, gc, x, y); +} + +void +DrawBackgroundPoint(x,y,colour) +int x; +int y; +int colour; +/* Draw a point on the window and the back-up Pixmap */ +{ + /* PROBS ? */ + + XSetForeground(XtDisplay(top_level), gc, colours[colour].pixel); + + XDrawPoint(XtDisplay(top_level), colour_pm, gc, x, y); +} + + +int +DrawVolumePoint(x,y,attr) +int x; +int y; +int attr; +/* Draw a point on the window and the back-up Pixmap */ +{ + if (XtWindow(volume_canvas) == NULL) + return (-1); + + XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel); + + XDrawPoint(XtDisplay(top_level), XtWindow(volume_canvas), gc, x, y); + XDrawPoint(XtDisplay(top_level), volume_pm, gc, x, y); + + return(0); +} + +int +DrawBackgroundVolumePoint(x,y,attr) +int x; +int y; +int attr; +/* Draw a point on the window and the back-up Pixmap */ +{ + if (XtWindow(volume_canvas) == NULL) + return (-1); + + XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel); + + XDrawPoint(XtDisplay(top_level), volume_pm, gc, x, y); + + return(0); +} + + +int +DrawDrynessPoint(x,y,attr) +int x; +int y; +int attr; +/* Draw a point on the window and the back-up Pixmap */ +{ + /* later - use the range of the dryness to affect the colour + value + */ + + if (XtWindow(dryness_canvas) == NULL) + return (-1); + + XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel); + +/* XDrawPoint(XtDisplay(top_level), XtWindow(dryness_canvas), gc, x, y); +*/ + XDrawPoint(XtDisplay(top_level), dryness_pm, gc, x, y); + + return(0); +} + +void +ClearWindow() +{ + XClearWindow(XtDisplay(top_level), XtWindow(colour_canvas)); +} + +static void +CleanWindow(win) +Drawable win; +/* Fill a window with a solid, white rectangle */ +{ +XGCValues values; +long tqmask; + + values.background = colours[0].pixel; + values.foreground = colours[255].pixel;; + values.fill_style = FillSolid; + values.function = GXclear; + + + tqmask = GCBackground| GCForeground| GCFillStyle | GCFunction; + + tmp_gc = XtGetGC(top_level, tqmask, &values); + + XFillRectangle(XtDisplay(top_level), win, tmp_gc, 0, 0, 300, 300); + +} + +void SetupCmap() +{ +int i; + + for (i=0;i<256;i++) { + colours[i].red = i*257; + colours[i].flags = DoRed | DoBlue | DoGreen; + } + + /* for (i=0;i<=127;i++) + colours[i].green = i*2*257; + + for (i=128;i>0;i--) + colours[255-i].green = (i-1)*2*257;*/ + + for (i=0;i<64;i++) + colours[i].green = i*4*257; + + for (i=64;i<128;i++) + colours[i].green = 65536-i*4*257; + + for (i=128;i<192;i++) + colours[i].green = (i-128)*2*257; + + for (i=192;i<255;i++) + colours[i].green = 65536-(i-128)*2*257; + + + for (i=0;i<256;i++) + colours[i].blue = 65536 - i*257; + + colours[0].red = 65535; + colours[0].green = 65535; + colours[0].blue = 65535; +} + +void +SetupGreyMap() +{ +int i; + + for (i=0;i<256;i++) { + colours[i].red = i*257; + colours[255 - i].flags = DoRed | DoBlue | DoGreen; + } + + + for (i=0;i<256;i++) + colours[i].green = i*257; + + for (i=0;i<256;i++) + colours[i].blue = i*257; + + colours[255].red = 255*257; + colours[255].green = 255*257; + colours[255].blue = 255*257; + +} + + +void CreateWindows(argc, argv, width, height) +int *argc; +char **argv; +int width; +int height; +/* Create colour window heirarchy and add event handlers */ +{ + + static Arg args[]={ + {XtNwidth, (XtArgVal) 0}, + {XtNheight, (XtArgVal)0} }; + + int i; + + args[0].value = (XtArgVal)width; + + args[1].value = (XtArgVal)height; + + top_level = XtInitialize("wet+sticky", "Wet+Sticky", NULL, + 0, argc, argv); + + + display = XtDisplay(top_level); + screen = DefaultScreen(display); + screen_ptr = ScreenOfDisplay(display, DefaultScreen(display)); + + root = RootWindow(display, screen); + + colour_shell = XtCreateApplicationShell("colour_frame", + topLevelShellWidgetClass, NULL, 0); + + + + colour_box = XtCreateManagedWidget("colour_box", boxWidgetClass, + colour_shell, NULL, 0); + + + colour_canvas = XtCreateManagedWidget("", labelWidgetClass, + colour_box, args, XtNumber(args)); + + + XtAddEventHandler(colour_canvas, ExposureMask, False, expose_event, 0); + + XtAddEventHandler(colour_canvas, ButtonPressMask, False, stroke, 0); + + XtAddEventHandler(colour_canvas, Button1MotionMask, + False, stroke_motion, 0); + + XtRealizeWidget(colour_shell); + + cmap = XCreateColormap( display, XtWindow(colour_shell), + XDefaultVisualOfScreen(screen_ptr), AllocAll); + + for (i=0; i <= 255; i++) + colours[i].pixel = i; + + XQueryColors(display, DefaultColormapOfScreen(screen_ptr),colours, 256); + + SetupCmap(); + + /*SetupGreyMap();*/ + + XStoreColors(display, cmap, colours, 256); + + i=0; + while( XAllocColorCells( display, DefaultColormapOfScreen(screen_ptr), + True, NULL, 0, &colours[i].pixel, 1 ) ) { + colours[i].pixel = i; + i++; + } + + XSetWindowColormap(display, XtWindow(colour_shell), cmap); + + XInstallColormap(display, cmap); + + tqmask = GCBackground| GCForeground| GCFunction; + + values.function = GXcopy; + values.background = colours[0].pixel; + values.foreground = colours[255].pixel; + + + gc = XtGetGC(colour_canvas, tqmask, &values); + + colour_pm = XCreatePixmap(XtDisplay(top_level), + XtWindow(colour_shell), width, height, + XDefaultDepth(XtDisplay(top_level), 0)); + + CleanWindow(colour_pm); + +} + + +void StartVolumeWindow(width, height) +int width; +int height; +/* Create Volume heirarchy and add event handlers */ +{ + static Arg args[]={ + {XtNwidth, (XtArgVal) 0}, + {XtNheight, (XtArgVal)0} }; + + args[0].value = (XtArgVal)width; + + args[1].value = (XtArgVal)height; + + volume_shell = XtCreateApplicationShell("volume_frame", + topLevelShellWidgetClass, NULL, 0); + + volume_box = XtCreateManagedWidget("volume_box", boxWidgetClass, + volume_shell, NULL, 0); + + volume_canvas = XtCreateManagedWidget("", labelWidgetClass, + volume_box, args, XtNumber(args)); + + XtAddEventHandler(volume_canvas, ExposureMask, False, + expose_volume, 0); + + XtRealizeWidget(volume_shell); + + XSetWindowColormap(display, XtWindow(volume_shell), cmap); + + volume_pm = XCreatePixmap(XtDisplay(top_level), + XtWindow(colour_shell), width, height, + XDefaultDepth(XtDisplay(top_level), 0)); + + CleanWindow(volume_pm); + + +} + +void StartDrynessWindow(width, height) +int width; +int height; +/* Create dryness heirarchy and add event handlers */ +{ + static Arg args[]={ + {XtNwidth, (XtArgVal) 0}, + {XtNheight, (XtArgVal)0} }; + + char name[32]; + + args[0].value = (XtArgVal)width; + + args[1].value = (XtArgVal)height; + + dryness_shell = XtCreateApplicationShell("dryness_frame", + topLevelShellWidgetClass, NULL, 0); + + dryness_box = XtCreateManagedWidget("dryness_box", boxWidgetClass, + dryness_shell, NULL, 0); + dryness_canvas = XtCreateManagedWidget("Name", labelWidgetClass, + dryness_box, args, XtNumber(args)); + + fprintf(stderr,"Bumps %d\n",(int)dryness_canvas); + + XtAddEventHandler(dryness_canvas, ExposureMask, False, + expose_dryness, 0); + + XtRealizeWidget(dryness_shell); + + XSetWindowColormap(display, XtWindow(dryness_shell), cmap); + + dryness_pm = XCreatePixmap(XtDisplay(top_level), + XtWindow(colour_shell), width, height, + XDefaultDepth(XtDisplay(top_level), 0)); + + XStoreName(display, XtWindow(dryness_shell), "bumps"); + + CleanWindow(dryness_pm); + +} + +static void +draw_labels() +{ + XSetForeground(XtDisplay(colour_shell), gc, colours[1].pixel); + + XDrawString(XtDisplay(colour_shell), XtWindow(colour_canvas), gc, 10, 10, + "Colour", strlen("Colour")); + XDrawString(XtDisplay(colour_shell), colour_pm, gc, 10, 10, + "Colour", strlen("Colour")); + + XSetForeground(XtDisplay(colour_shell), gc, colours[128].pixel); + + XDrawString(XtDisplay(colour_shell), XtWindow(volume_canvas), gc, 10, 10, + "Volume", strlen("Volume")); + XDrawString(XtDisplay(colour_shell), volume_pm, gc, 10, 10, + "Volume", strlen("Volume")); + + XSetForeground(XtDisplay(colour_shell), gc, colours[255].pixel); + + XDrawString(XtDisplay(colour_shell), XtWindow(dryness_canvas), gc, 10, 10, + "Bump Map", strlen("Bump Map")); + XDrawString(XtDisplay(colour_shell), dryness_pm, gc, 10, 10, + "Bump Map", strlen("Bump Map")); +} + +void paint_cell(cell, x, y) +CELL_PTR cell; +int x, y; + +{ + int colour, volColour, dryness; + POINT p; + + p.x = x; + p.y = y; + + /* The current display simply maps hue onto the indices of the colour + table. This involves some scaling since hues are in the range [0,360) + with the colour table being [0,256). */ + + colour = (int) (cell->contents.colour.hue * + ((float) MAX_COLOUR_INDEX / 360.0)); + + DrawBackgroundPoint(x,y,colour); + + /* volColour is an index into the colour table in the range [0,255]. + It is used to give a false colour image of the canvas's volume. */ + + /*if (x < SCALE_WIDTH) return; Don't draw over colour scale. */ + + volColour = MIN(cell->volume * 2, 255); + volColour = MAX(volColour, 0); + /* Make unfilled cells have a zero vol. */ + + DrawBackgroundVolumePoint(x,y,volColour); + + /* Dryness will be in the range [0,255]. */ + dryness = (cell->contents.liquid_content * 255) / 100; + + /*DrawDrynessPoint(x,y,dryness);*/ +} + + + +void draw_false_colour_scale() +/* This routine places a scale along the top of the volume window + showing the colours being used. Low is at the left edge. + The colour palette has indices 0..255. */ +{ + int x, y; + + /*for (x=0; x < 255; x++) + for (y=0; y < SCALE_WIDTH; y++) DrawVolumePoint(x,y,MIN(x, 255));*/ +} + + +void draw_full_canvas() +{ + int x, y; + CELL_PTR cell; + POINT p; + + if (DEBUG) { + printf ("Starting to paint full canvas..."); + fflush(stdout); + } + + for (y=0; y < CANVAS_HEIGHT; y++) + for (x=0; x < CANVAS_WIDTH; x++) { + p.x = x; + p.y = y; + cell = get_cell(p); + paint_cell(cell, x, y); + } + + expose_canvases(); + + draw_false_colour_scale(); + if (DEBUG) printf ("done.\n"); +} + +void +bump_map() +{ + POINT p; + CELL_PTR cell; + register int x, y; + register int colour; + + + for (y=0; y < CANVAS_HEIGHT; y++) { + for (x=0; x < CANVAS_WIDTH; x++) { + p.x = x; + p.y = y; + cell = get_cell(p); + colour = (int) new_intensity_value(p); + +/* colour = (int) (cell->contents.colour.hue * + ((float) MAX_COLOUR_INDEX / 360.0));*/ + DrawDrynessPoint(x,y,colour); + } + } + +} + +draw_cmap_line() + +{ + +int i; + + for (i=0; i< 255; i++) { + DrawDrynessPoint(0,i,i); + } +} + +void evolve_paint() +{ + int k; + POINT p; + CELL_PTR cell; + int new_x, new_y; + Window tempChild; + extern Window root; + extern int count; + extern int frame_count; + + count++; + if (count > 5000) { + fprintf(stderr,"."); + fflush(stderr); + bump_map(); + expose_canvases(); + + /*XTranslateCoordinates(display,XtWindow(dryness_canvas), root, + 0,0, &new_x, &new_y, &tempChild);*/ + /*if (frame_count < 10) + sprintf(pix_file,"xwd -name bumps -out pixmap0%d.xwd &" ,frame_count); + else + sprintf(pix_file,"xwd -name bumps -out pixmap%d.xwd &" ,frame_count); + */ + + + /*system(pix_file);*/ + /*XWriteBitmapFile(display, pix_file,dryness_pm, 300, 300,-1,-1 );*/ + count = 0; + frame_count++; + /*if (frame_count > 250) { + fprintf(stderr,"Done\n"); + sleep(2); + exit(0); + } */ + /*exit(0)*/; + } + + + + for (k=0; k < STEP_LIMIT; k++) single_step(); + while (TRUE) { + next_cell_for_tqrepaint(&cell, &p); + if (cell == NIL) return; + paint_cell(cell, p.x, p.y); + } + +} + + + +void StartWindows() +{ +/* Start the X windows event loop and paint processing */ +XEvent event; + + + draw_full_canvas(); + compute_shade_vectors(); /* Set vectors for shading */ + draw_labels(); + + for (;;) { + if (XtPending()) { + XtNextEvent(&event); + XtDispatchEvent(&event); + } + else { + /* Evolve paint and re-display*/ + evolve_paint(); + } + + } /* End for loop */ + + +} + +void +stroke(w, client_data, event) +Widget w; +caddr_t client_data; +XEvent *event; +{ +/* brush_stroke(event->xbutton.x, event->xbutton.y);*/ + + + /*if ((XEvent *)event != (XEvent *)NULL) + else + printf("Null event\n"); */ + +/* DrawPoint(event->xbutton.x, event->xbutton.y, 128); + DrawVolumePoint(event->xbutton.x, event->xbutton.y, 128); + DrawDrynessPoint(event->xbutton.x, event->xbutton.y, 128);*/ + + + XSetForeground(XtDisplay(top_level), gc, colours[128].pixel); + + XFillRectangle(XtDisplay(top_level), XtWindow(colour_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + + XFillRectangle(XtDisplay(top_level), XtWindow(volume_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + + XFillRectangle(XtDisplay(top_level), XtWindow(dryness_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + + brush_stroke(event->xbutton.x, event->xbutton.y); +} + + +void +stroke_motion(w, client_data, event) +Widget w; +caddr_t client_data; +XEvent *event; +{ + + + /*if ((XEvent *)event != (XEvent *)NULL) + else + printf("Null event\n"); */ + + + XSetForeground(XtDisplay(top_level), gc, colours[128].pixel); + + XFillRectangle(XtDisplay(top_level), XtWindow(colour_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + XFillRectangle(XtDisplay(top_level), XtWindow(volume_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + + XFillRectangle(XtDisplay(top_level), XtWindow(dryness_canvas), gc, + event->xmotion.x, event->xmotion.y ,1, 1); + + brush_stroke(event->xbutton.x, event->xbutton.y); +} + diff --git a/chalk/colorspaces/wetsticky/wstool.ui b/chalk/colorspaces/wetsticky/wstool.ui new file mode 100644 index 00000000..2f95d18b --- /dev/null +++ b/chalk/colorspaces/wetsticky/wstool.ui @@ -0,0 +1,262 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>WdgWSPaintOp</class> +<widget class="TQWidget"> + <property name="name"> + <cstring>WdgWSPaintOp</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>582</width> + <height>359</height> + </rect> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQGroupBox" row="0" column="0"> + <property name="name"> + <cstring>grpGravity</cstring> + </property> + <property name="title"> + <string>&Gravity</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQCheckBox" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>chkGravity</cstring> + </property> + <property name="text"> + <string>Paint &gravity</string> + </property> + </widget> + <widget class="TQLabel" row="1" column="0"> + <property name="name"> + <cstring>lblDirection</cstring> + </property> + <property name="text"> + <string>Direction:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>intDryingRate</cstring> + </property> + </widget> + <widget class="TQComboBox" row="1" column="1"> + <item> + <property name="text"> + <string>Up</string> + </property> + </item> + <item> + <property name="text"> + <string>Right</string> + </property> + </item> + <item> + <property name="text"> + <string>Down</string> + </property> + </item> + <item> + <property name="text"> + <string>Left</string> + </property> + </item> + <property name="name"> + <cstring>cmbGravitationalDirection</cstring> + </property> + </widget> + <widget class="TQLabel" row="2" column="0"> + <property name="name"> + <cstring>lblStrength</cstring> + </property> + <property name="text"> + <string>&Strength:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>intGravitationalStrength</cstring> + </property> + </widget> + <widget class="KIntNumInput" row="2" column="1"> + <property name="name"> + <cstring>intGravitationalStrength</cstring> + </property> + <property name="minValue"> + <number>0</number> + </property> + </widget> + </grid> + </widget> + <widget class="TQGroupBox" row="1" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>grpPaint</cstring> + </property> + <property name="title"> + <string>&Paint</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLabel" row="0" column="0"> + <property name="name"> + <cstring>lblDryingRate</cstring> + </property> + <property name="text"> + <string>&Drying rate:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>intDryingRate</cstring> + </property> + </widget> + <widget class="TQCheckBox" row="1" column="0" rowspan="2" colspan="4"> + <property name="name"> + <cstring>chkLiquid</cstring> + </property> + <property name="text"> + <string>&Liquid content:</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + <widget class="KIntNumInput" row="0" column="1" rowspan="1" colspan="3"> + <property name="name"> + <cstring>intDryingRate</cstring> + </property> + <property name="minValue"> + <number>0</number> + </property> + <property name="maxValue"> + <number>100</number> + </property> + </widget> + <widget class="KIntNumInput" row="2" column="2" rowspan="1" colspan="2"> + <property name="name"> + <cstring>intMiscibility</cstring> + </property> + </widget> + <widget class="KIntNumInput" row="3" column="3"> + <property name="name"> + <cstring>intLiquidContent</cstring> + </property> + <property name="minValue"> + <number>0</number> + </property> + <property name="maxValue"> + <number>100</number> + </property> + </widget> + <widget class="TQLabel" row="3" column="0" rowspan="1" colspan="3"> + <property name="name"> + <cstring>lblMiscibility</cstring> + </property> + <property name="text"> + <string>&Miscibility:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>intMiscibility</cstring> + </property> + </widget> + </grid> + </widget> + <widget class="TQGroupBox" row="0" column="1"> + <property name="name"> + <cstring>grpSubstrate</cstring> + </property> + <property name="title"> + <string>&Canvas</string> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="KIntNumInput" row="3" column="1"> + <property name="name"> + <cstring>intHeight</cstring> + </property> + </widget> + <widget class="TQLabel" row="3" column="0"> + <property name="name"> + <cstring>lblHeight</cstring> + </property> + <property name="text"> + <string>&Height:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>intHeight</cstring> + </property> + </widget> + <widget class="KIntNumInput" row="2" column="1"> + <property name="name"> + <cstring>intAbsorbency</cstring> + </property> + <property name="minValue"> + <number>0</number> + </property> + <property name="maxValue"> + <number>100</number> + </property> + </widget> + <widget class="TQLabel" row="2" column="0"> + <property name="name"> + <cstring>lblAbsorbency</cstring> + </property> + <property name="text"> + <string>&Absorbency:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>intAbsorbency</cstring> + </property> + </widget> + <widget class="TQLabel" row="1" column="0"> + <property name="name"> + <cstring>lblColor</cstring> + </property> + <property name="text"> + <string>&Color:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>bnCanvasColor</cstring> + </property> + </widget> + <widget class="TQCheckBox" row="0" column="0" rowspan="1" colspan="2"> + <property name="name"> + <cstring>chkCanvas</cstring> + </property> + <property name="text"> + <string>Paint canvas attributes</string> + </property> + <property name="accel"> + <string></string> + </property> + </widget> + <widget class="KColorButton" row="1" column="1"> + <property name="name"> + <cstring>bnCanvasColor</cstring> + </property> + <property name="text"> + <string></string> + </property> + </widget> + </grid> + </widget> + </grid> +</widget> +<customwidgets> +</customwidgets> +<tqlayoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> + <includehint>knuminput.h</includehint> +</includehints> +</UI> |